@bongos/core 1.19.804 → 1.19.805

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/.bongos-core.json +257 -237
  2. package/.claude/skills/ask-for-help/SKILL.md +6 -6
  3. package/.claude/skills/backlog-review/SKILL.md +1 -1
  4. package/.claude/skills/blocker-review/SKILL.md +7 -7
  5. package/.claude/skills/blocker-solve/SKILL.md +5 -5
  6. package/.claude/skills/bug-triage/SKILL.md +7 -7
  7. package/.claude/skills/builder-claim/SKILL.md +3 -3
  8. package/.claude/skills/builder-cost/SKILL.md +2 -2
  9. package/.claude/skills/builder-end/SKILL.md +2 -2
  10. package/.claude/skills/builder-exit/SKILL.md +7 -7
  11. package/.claude/skills/builder-key/SKILL.md +2 -2
  12. package/.claude/skills/builder-reauth/SKILL.md +2 -2
  13. package/.claude/skills/builder-redteam/SKILL.md +7 -7
  14. package/.claude/skills/builder-release/SKILL.md +2 -2
  15. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  16. package/.claude/skills/builder-setup/SKILL.md +3 -3
  17. package/.claude/skills/builder-ship/SKILL.md +1 -1
  18. package/.claude/skills/builder-stage/SKILL.md +1 -1
  19. package/.claude/skills/builder-start/SKILL.md +1 -1
  20. package/.claude/skills/fix-task/SKILL.md +4 -4
  21. package/.claude/skills/goal-create/SKILL.md +18 -18
  22. package/.claude/skills/goal-review/SKILL.md +7 -7
  23. package/.claude/skills/grade-audit/SKILL.md +5 -5
  24. package/.claude/skills/grade-recover/SKILL.md +4 -4
  25. package/.claude/skills/grader-health/SKILL.md +6 -6
  26. package/.claude/skills/idea-triage/SKILL.md +14 -14
  27. package/.claude/skills/merge-mode/SKILL.md +3 -3
  28. package/.claude/skills/planning-session/SKILL.md +20 -20
  29. package/.claude/skills/priority-session/SKILL.md +10 -10
  30. package/.claude/skills/recall/SKILL.md +1 -1
  31. package/.claude/skills/scan-before-install/SKILL.md +3 -3
  32. package/.claude/skills/status/SKILL.md +2 -2
  33. package/.claude/skills/strand-fix/SKILL.md +2 -2
  34. package/clients/bongos-client/README.md +1 -1
  35. package/clients/bongos-client/bongos-client.global.js +2 -0
  36. package/clients/bongos-client/index.cjs +2 -0
  37. package/clients/bongos-client/index.d.ts +2 -0
  38. package/clients/bongos-client/index.mjs +2 -0
  39. package/docs/api/openapi.json +45 -11
  40. package/docs/api-reference.md +11 -10
  41. package/docs/module-api-changelog.md +2 -0
  42. package/modules/builder-settings/profile-nudge-prefs.js +1 -1
  43. package/modules/builder-settings/render-prefs.js +1 -1
  44. package/modules/dev-box/app/README.md +1 -1
  45. package/modules/dev-box/app/src/gds-client.js +11 -9
  46. package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
  47. package/modules/dev-box/app/test/unit.mjs +13 -13
  48. package/modules/dev-box/box-access.js +3 -3
  49. package/modules/dev-box/box-onboard.js +7 -7
  50. package/modules/discord/bug-attachments.js +1 -1
  51. package/modules/economy/cost-classify.js +6 -6
  52. package/modules/grading/grader-rubric.json +1 -1
  53. package/modules/grading/grader-score.js +1 -1
  54. package/modules/hall-ui/module.json +1 -1
  55. package/modules/hall-ui/public/drachmae.js +3 -3
  56. package/modules/hall-ui/public/idea.js +1 -1
  57. package/modules/hall-ui/public/md-reader.js +1 -1
  58. package/modules/hall-ui/public/people.html +1 -1
  59. package/modules/hall-ui/public/people.js +2 -2
  60. package/modules/hall-ui/public/primer.js +4 -4
  61. package/modules/hall-ui/public/roster.js +1 -1
  62. package/modules/hall-ui/public/shell.js +1 -1
  63. package/modules/hall-ui/public/task.js +1 -1
  64. package/modules/ideas/inbox.js +2 -2
  65. package/modules/lifecycle/db-analytics.js +1 -1
  66. package/modules/lifecycle/done-when.js +4 -4
  67. package/modules/lifecycle/version-close.js +1 -1
  68. package/modules/memory/learnings.js +2 -2
  69. package/modules/memory/memory.js +1 -1
  70. package/modules/onboarding/onboarding.js +1 -1
  71. package/modules/platform-identity/routes/my-projects.js +1 -1
  72. package/modules/platform-identity/routes/sso.js +2 -2
  73. package/modules/public-landing/public/index.html +2 -2
  74. package/modules/public-landing/public/projects-floor.states.json +1 -1
  75. package/modules/public-landing/public/projects.html +1 -1
  76. package/modules/public-landing/public/projects.states.json +1 -1
  77. package/modules/sessions/db.js +120 -0
  78. package/modules/sessions/module.json +2 -2
  79. package/modules/sessions/pollers/session-upload-health.js +111 -0
  80. package/modules/sessions/pulse.js +2 -2
  81. package/modules/sessions/routes/sessions.js +46 -0
  82. package/modules/sessions/upload-health.js +197 -0
  83. package/modules/status-ui/module.json +1 -1
  84. package/modules/status-ui/public/explore.js +1 -1
  85. package/package-lock.json +2 -2
  86. package/package.json +1 -1
  87. package/scripts/gds/agent-invoke.js +3 -3
  88. package/scripts/gds/api.js +4 -4
  89. package/scripts/gds/api.sh +1 -1
  90. package/scripts/gds/architect-audit.js +1 -1
  91. package/scripts/gds/artifact-audit.js +2 -2
  92. package/scripts/gds/audit-ships.js +2 -2
  93. package/scripts/gds/backfill-cost.js +1 -1
  94. package/scripts/gds/backfill-sessions.js +1 -1
  95. package/scripts/gds/backfill-subagent-rewards.js +1 -1
  96. package/scripts/gds/backfill-task-rewards.js +2 -2
  97. package/scripts/gds/box-auth-check.js +1 -1
  98. package/scripts/gds/box-sync.js +3 -3
  99. package/scripts/gds/box.js +10 -10
  100. package/scripts/gds/build-cli-package.js +3 -3
  101. package/scripts/gds/capture.js +2 -2
  102. package/scripts/gds/ci-grade.js +1 -1
  103. package/scripts/gds/claim-recall.js +2 -2
  104. package/scripts/gds/cli-lib.js +3 -3
  105. package/scripts/gds/context-pack.js +1 -1
  106. package/scripts/gds/copy-apply.js +2 -2
  107. package/scripts/gds/dev-lib.js +2 -2
  108. package/scripts/gds/fetch-art-key.js +2 -2
  109. package/scripts/gds/fetch-sound-prefs.js +3 -3
  110. package/scripts/gds/grade-smoke.js +1 -1
  111. package/scripts/gds/hooks/pre-push.js +1 -1
  112. package/scripts/gds/init.js +9 -9
  113. package/scripts/gds/key-card.js +1 -1
  114. package/scripts/gds/learning-capture.js +2 -2
  115. package/scripts/gds/linkify-refs.js +2 -2
  116. package/scripts/gds/local-preview-lib.js +1 -1
  117. package/scripts/gds/login.js +11 -10
  118. package/scripts/gds/main-audit.js +1 -1
  119. package/scripts/gds/newcomer-floor.config.json +1 -1
  120. package/scripts/gds/newcomer-floor.js +2 -2
  121. package/scripts/gds/newcomer-floor.templates.json +2 -2
  122. package/scripts/gds/onboarding-ship.js +1 -1
  123. package/scripts/gds/paste-token.js +3 -3
  124. package/scripts/gds/portability-smoke-memory.sh +5 -5
  125. package/scripts/gds/prove-strict-versioning.js +2 -2
  126. package/scripts/gds/provision-net.js +2 -2
  127. package/scripts/gds/provision-units.js +3 -3
  128. package/scripts/gds/pulse.js +2 -2
  129. package/scripts/gds/push-path-brief.js +2 -2
  130. package/scripts/gds/reauth.js +1 -1
  131. package/scripts/gds/recall.js +1 -1
  132. package/scripts/gds/redteam-patrol.js +3 -3
  133. package/scripts/gds/render-ideas.js +5 -5
  134. package/scripts/gds/repo-metrics.js +1 -1
  135. package/scripts/gds/sandbox-stage.js +3 -3
  136. package/scripts/gds/seed-adopt-tasks.js +3 -3
  137. package/scripts/gds/seed-board-room-tasks.js +1 -1
  138. package/scripts/gds/seed-bongos-app-tasks.js +2 -2
  139. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
  140. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
  141. package/scripts/gds/seed-bongos-tasks.js +5 -5
  142. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
  143. package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
  144. package/scripts/gds/seed-bv1-community-tasks.js +1 -1
  145. package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
  146. package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
  147. package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
  148. package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
  149. package/scripts/gds/seed-gds-v4-tasks.js +3 -3
  150. package/scripts/gds/seed-medusa-tasks.js +1 -1
  151. package/scripts/gds/seed-productization-tasks.js +1 -1
  152. package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
  153. package/scripts/gds/seed-provisioning-tasks.js +2 -2
  154. package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
  155. package/scripts/gds/seed-v2-world-tasks.js +2 -2
  156. package/scripts/gds/seed-verify-criteria.js +1 -1
  157. package/scripts/gds/session-digest.js +1 -1
  158. package/scripts/gds/session.js +2 -2
  159. package/scripts/gds/setup.js +7 -7
  160. package/scripts/gds/ship-flow.js +3 -3
  161. package/scripts/gds/ship-grade-steps.js +3 -3
  162. package/scripts/gds/ship-memory-sync.js +1 -1
  163. package/scripts/gds/ship-session-upload.js +3 -3
  164. package/scripts/gds/smoke-batch-claim.sh +10 -10
  165. package/scripts/gds/smoke-batch-release.sh +14 -14
  166. package/scripts/gds/smoke-claim-consistency.sh +19 -19
  167. package/scripts/gds/smoke-dependencies.sh +9 -9
  168. package/scripts/gds/smoke-write.sh +11 -11
  169. package/scripts/gds/start.js +1 -1
  170. package/scripts/gds/status.js +2 -2
  171. package/scripts/gds/strand-watch.js +1 -1
  172. package/scripts/gds/triage.js +4 -4
  173. package/scripts/gds/version-close.js +2 -2
  174. package/scripts/hall-preview/README.md +1 -1
  175. package/scripts/hall-preview/server.js +1 -1
  176. package/src/bongos/auth-admission.js +3 -3
  177. package/src/bongos/auth-idp.js +2 -2
  178. package/src/bongos/auth.js +3 -3
  179. package/src/bongos/db.js +2 -2
  180. package/src/bongos/llm-cache.js +2 -2
  181. package/src/bongos/metrics.js +1 -1
  182. package/src/bongos/middleware/audit.js +3 -3
  183. package/src/bongos/middleware/rate-limit.js +1 -1
  184. package/src/bongos/platform-visibility-gate.js +2 -2
  185. package/src/bongos/routes/_helpers.js +1 -1
  186. package/src/bongos/routes/audit-log.js +1 -1
  187. package/src/bongos/routes/auth.js +5 -5
  188. package/src/bongos/routes/backup.js +1 -1
  189. package/src/bongos/routes/builders.js +1 -1
  190. package/src/bongos/routes/instance.js +1 -1
  191. package/src/bongos/routes/live.js +1 -1
  192. package/src/bongos/routes/me.js +2 -2
  193. package/src/bongos/routes/modules.js +2 -2
  194. package/src/bongos/routes/public.js +1 -1
  195. package/src/bongos/routes/security.js +4 -4
  196. package/src/bongos/routes.js +1 -1
  197. package/src/bongos/serve-internal.js +6 -6
  198. package/src/branding.js +1 -1
  199. package/src/module-api.js +1 -1
  200. package/src/module-seams.js +2 -2
  201. package/src/platform-server.js +2 -2
  202. package/tests/api_alias_exceptions.mjs +67 -0
  203. package/tests/application_echo.mjs +12 -12
  204. package/tests/artifact_audit.mjs +1 -1
  205. package/tests/auth_page_gate.mjs +4 -4
  206. package/tests/auth_web_recovery.mjs +11 -11
  207. package/tests/bongos_login.mjs +7 -4
  208. package/tests/box_env.mjs +6 -6
  209. package/tests/bug_attachments.mjs +1 -1
  210. package/tests/cli_sessions.mjs +1 -1
  211. package/tests/dev_lib.mjs +1 -1
  212. package/tests/discord_bugs.mjs +2 -2
  213. package/tests/discord_inbound.mjs +2 -2
  214. package/tests/explore_visible_states.mjs +1 -1
  215. package/tests/government_page_gates.mjs +1 -1
  216. package/tests/hall_reference_world.mjs +1 -1
  217. package/tests/idea_ideate_full.mjs +1 -1
  218. package/tests/idp_federation.mjs +2 -2
  219. package/tests/llm-cache.mjs +1 -1
  220. package/tests/manage_manifest_shared_read.mjs +3 -3
  221. package/tests/people_directory_clip.mjs +1 -1
  222. package/tests/planning_session_skill.mjs +1 -1
  223. package/tests/platform_visibility_gate.mjs +15 -15
  224. package/tests/profile_route.mjs +25 -25
  225. package/tests/projects_hub.mjs +2 -2
  226. package/tests/provision.mjs +2 -2
  227. package/tests/provision_settings_apply.mjs +4 -4
  228. package/tests/sandbox_stage.mjs +8 -8
  229. package/tests/scouting_owner_access_and_reach.mjs +3 -3
  230. package/tests/session_upload_health.mjs +329 -0
  231. package/tests/setup_device_flow_fallback.mjs +1 -1
  232. package/tests/skill_ask_for_help.mjs +3 -3
  233. package/tests/skill_grade_audit.mjs +2 -2
  234. package/tests/skill_grader_health.mjs +3 -3
  235. package/tests/smoke_write_contract.mjs +1 -1
@@ -198,7 +198,7 @@ function buildApp() {
198
198
  const app = express();
199
199
  app.use(express.json());
200
200
  app.use(attachFail); // res.fail() ahead of the routers, exactly as the real app does
201
- app.use('/api/gds', buildBuildersRouter());
201
+ app.use('/api/bongos', buildBuildersRouter());
202
202
  return app;
203
203
  }
204
204
 
@@ -227,7 +227,7 @@ function get(port, path, headers) {
227
227
  const { server, port } = await listen(buildApp());
228
228
 
229
229
  await t('known id → 200 with the public field subset', async () => {
230
- const r = await get(port, '/api/gds/builders/95/profile');
230
+ const r = await get(port, '/api/bongos/builders/95/profile');
231
231
  assert.equal(r.status, 200);
232
232
  assert.ok(r.json && r.json.builder, 'response has a builder object');
233
233
  for (const k of PUBLIC_KEYS) {
@@ -242,7 +242,7 @@ await t('known id → 200 with the public field subset', async () => {
242
242
  });
243
243
 
244
244
  await t('known id → NO private column leaks on the builder object', async () => {
245
- const r = await get(port, '/api/gds/builders/95/profile');
245
+ const r = await get(port, '/api/bongos/builders/95/profile');
246
246
  assert.equal(r.status, 200);
247
247
  for (const k of PRIVATE_KEYS) {
248
248
  assert.ok(!(k in r.json.builder), `private field "${k}" must NOT be present on the builder`);
@@ -250,7 +250,7 @@ await t('known id → NO private column leaks on the builder object', async () =
250
250
  });
251
251
 
252
252
  await t('known id → no secret sentinel leaks ANYWHERE in the response body', async () => {
253
- const r = await get(port, '/api/gds/builders/95/profile');
253
+ const r = await get(port, '/api/bongos/builders/95/profile');
254
254
  assert.equal(r.status, 200);
255
255
  for (const secret of [SECRET_EMAIL, SECRET_USER, SECRET_REASON]) {
256
256
  assert.ok(!r.text.includes(secret), `response body must not contain the secret "${secret}"`);
@@ -258,13 +258,13 @@ await t('known id → no secret sentinel leaks ANYWHERE in the response body', a
258
258
  });
259
259
 
260
260
  await t('unknown id → 404 builder_not_found', async () => {
261
- const r = await get(port, '/api/gds/builders/99999/profile');
261
+ const r = await get(port, '/api/bongos/builders/99999/profile');
262
262
  assert.equal(r.status, 404);
263
263
  assert.equal(r.json && r.json.error && r.json.error.code, 'builder_not_found');
264
264
  });
265
265
 
266
266
  await t('non-numeric id → 400 bad_builder_id', async () => {
267
- const r = await get(port, '/api/gds/builders/not-a-number/profile');
267
+ const r = await get(port, '/api/bongos/builders/not-a-number/profile');
268
268
  assert.equal(r.status, 400);
269
269
  assert.equal(r.json && r.json.error && r.json.error.code, 'bad_builder_id');
270
270
  });
@@ -275,7 +275,7 @@ await t('non-numeric id → 400 bad_builder_id', async () => {
275
275
  // hub posture for the tests below.
276
276
 
277
277
  await t('hub port ABSENT → no cross_project key + the cacheable posture stays', async () => {
278
- const r = await get(port, '/api/gds/builders/95/profile');
278
+ const r = await get(port, '/api/bongos/builders/95/profile');
279
279
  assert.equal(r.status, 200);
280
280
  assert.ok(!('cross_project' in r.json), 'cross_project must be absent on a non-hub instance');
281
281
  assert.equal(r.headers['cache-control'], 'public, max-age=60');
@@ -292,7 +292,7 @@ seams.registerProvider('platform-identity.hub', {
292
292
  });
293
293
 
294
294
  await t('hub port present → cross_project carries exactly the whitelist shape', async () => {
295
- const r = await get(port, '/api/gds/builders/95/profile');
295
+ const r = await get(port, '/api/bongos/builders/95/profile');
296
296
  assert.equal(r.status, 200);
297
297
  const cp = r.json.cross_project;
298
298
  assert.ok(cp, 'cross_project attached when the port resolves');
@@ -302,7 +302,7 @@ await t('hub port present → cross_project carries exactly the whitelist shape'
302
302
  });
303
303
 
304
304
  await t('hub port present → module-internal sentinels leak NOWHERE in the response', async () => {
305
- const r = await get(port, '/api/gds/builders/95/profile');
305
+ const r = await get(port, '/api/bongos/builders/95/profile');
306
306
  assert.equal(r.status, 200);
307
307
  for (const secret of [SECRET_CLIENT_ID, SECRET_PROJECT_NAME, SECRET_EMAIL, SECRET_USER, SECRET_REASON]) {
308
308
  assert.ok(!r.text.includes(secret), `response body must not contain "${secret}"`);
@@ -311,13 +311,13 @@ await t('hub port present → module-internal sentinels leak NOWHERE in the resp
311
311
  });
312
312
 
313
313
  await t('hub port present → hide must beat the cache: Cache-Control is no-store', async () => {
314
- const r = await get(port, '/api/gds/builders/95/profile');
314
+ const r = await get(port, '/api/bongos/builders/95/profile');
315
315
  assert.equal(r.headers['cache-control'], 'no-store');
316
316
  });
317
317
 
318
318
  await t('hub port returns null (hidden/provisional/none) → cross_project: null, still no-store', async () => {
319
319
  hubExtras = null;
320
- const r = await get(port, '/api/gds/builders/95/profile');
320
+ const r = await get(port, '/api/bongos/builders/95/profile');
321
321
  assert.equal(r.status, 200);
322
322
  assert.ok('cross_project' in r.json, 'the key is present on the hub');
323
323
  assert.equal(r.json.cross_project, null, 'null — no partial numbers, indistinguishable from no-account');
@@ -472,7 +472,7 @@ const buildScoutingRoutes = require('../modules/platform-identity/routes/scoutin
472
472
  hubPublicRead = (githubId) => pi.getPublicProfileExtras(githubId, { pool: engine });
473
473
 
474
474
  await t('R06.1 a two-project builder\'s COMBINED record shows to another account', async () => {
475
- const r = await get(port, '/api/gds/builders/95/profile');
475
+ const r = await get(port, '/api/bongos/builders/95/profile');
476
476
  assert.equal(r.status, 200);
477
477
  const cp = r.json.cross_project;
478
478
  assert.ok(cp, 'the record is served');
@@ -500,7 +500,7 @@ await t('R06.1 a name needs the map AND the Public door — every other shape is
500
500
  try {
501
501
  for (const [label, catalog] of Object.entries(unnamed)) {
502
502
  other.catalog = catalog;
503
- const r = await get(port, '/api/gds/builders/95/profile');
503
+ const r = await get(port, '/api/bongos/builders/95/profile');
504
504
  const cp = r.json.cross_project;
505
505
  assert.deepEqual(cp.projects.map((p) => p.name), [pub.name], `${label}: only the Public project is named`);
506
506
  assert.equal(cp.more_projects, 1, `${label}: counted`);
@@ -509,7 +509,7 @@ await t('R06.1 a name needs the map AND the Public door — every other shape is
509
509
  // The positive control: the same row IS named once Public and on the map, so the
510
510
  // refusals above are the door, not a fixture nothing could ever name.
511
511
  other.catalog = { ...original, visibility: 'public' };
512
- const r = await get(port, '/api/gds/builders/95/profile');
512
+ const r = await get(port, '/api/bongos/builders/95/profile');
513
513
  assert.deepEqual(r.json.cross_project.projects.map((p) => p.name), [pub.name, SECRET_PROJECT_NAME]);
514
514
  } finally {
515
515
  other.catalog = original;
@@ -517,8 +517,8 @@ await t('R06.1 a name needs the map AND the Public door — every other shape is
517
517
  });
518
518
 
519
519
  await t('R06.1 the record is viewer-INDEPENDENT — another account sees the same body', async () => {
520
- const anon = await get(port, '/api/gds/builders/95/profile');
521
- const other = await get(port, '/api/gds/builders/95/profile', { Cookie: 'gds_session=some-other-builder' });
520
+ const anon = await get(port, '/api/bongos/builders/95/profile');
521
+ const other = await get(port, '/api/bongos/builders/95/profile', { Cookie: 'gds_session=some-other-builder' });
522
522
  assert.equal(other.status, 200);
523
523
  assert.equal(other.text, anon.text, 'one response shape for every reader (ADR 0171 D4)');
524
524
  });
@@ -564,7 +564,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
564
564
  try {
565
565
  // (a) a module-internal key on the object itself.
566
566
  hubPublicRead = async () => ({ ...(await rollup()), client_id: SECRET_CLIENT_ID });
567
- let r = await get(port, '/api/gds/builders/95/profile');
567
+ let r = await get(port, '/api/bongos/builders/95/profile');
568
568
  assert.throws(() => assertCrossProjectContract(r.json.cross_project, r.text),
569
569
  /cross_project keys are exactly the contract/, 'an extra top-level key must turn the guard red');
570
570
 
@@ -573,7 +573,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
573
573
  const cp = await rollup();
574
574
  return { ...cp, projects: cp.projects.map((p) => ({ ...p, is_public: true })) };
575
575
  };
576
- r = await get(port, '/api/gds/builders/95/profile');
576
+ r = await get(port, '/api/bongos/builders/95/profile');
577
577
  assert.throws(() => assertCrossProjectContract(r.json.cross_project, r.text),
578
578
  /project rows carry only the whitelisted keys/, 'an extra project-row key must turn the guard red');
579
579
 
@@ -583,7 +583,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
583
583
  const cp = await rollup();
584
584
  return { ...cp, projects: [{ ...cp.projects[0], name: SECRET_PROJECT_NAME }] };
585
585
  };
586
- r = await get(port, '/api/gds/builders/95/profile');
586
+ r = await get(port, '/api/bongos/builders/95/profile');
587
587
  assert.deepEqual(Object.keys(r.json.cross_project).sort(), [...CP_PUBLIC_KEYS].sort(),
588
588
  'the planted leak is shape-legal — only the sentinel scan can catch it');
589
589
  assert.throws(() => assertCrossProjectContract(r.json.cross_project, r.text),
@@ -594,7 +594,7 @@ await t('R06.4 NEGATIVE CONTROL: the leak guard goes red when a private field is
594
594
  });
595
595
 
596
596
  await t('R06.2 hide_stats removes the record on the IMMEDIATE next load', async () => {
597
- const before = await get(port, '/api/gds/builders/95/profile');
597
+ const before = await get(port, '/api/bongos/builders/95/profile');
598
598
  assert.ok(before.json.cross_project, 'public before the flip');
599
599
  assert.equal(before.headers['cache-control'], 'no-store');
600
600
 
@@ -604,7 +604,7 @@ await t('R06.2 hide_stats removes the record on the IMMEDIATE next load', async
604
604
  assert.equal(row.hide_stats, true, 'the write path set the flag');
605
605
 
606
606
  // No sleep, no second server, no cache warm-up: the very next load.
607
- const after = await get(port, '/api/gds/builders/95/profile');
607
+ const after = await get(port, '/api/bongos/builders/95/profile');
608
608
  assert.equal(after.status, 200);
609
609
  assert.equal(after.json.cross_project, null, 'gone on the next load');
610
610
  assert.equal(after.headers['cache-control'], 'no-store', 'hide must beat the cache (ADR 0171 D5)');
@@ -616,7 +616,7 @@ await t('R06.5 no PARTIAL numbers survive the hide (a count beside a hidden tota
616
616
  // Set the flag here too, so this proof stands on its own rather than on
617
617
  // whatever R06.2 left behind.
618
618
  await pi.setAccountHideStats({ githubId: HUB_GITHUB_ID, githubLogin: 'jaxri', hide: true }, { pool: engine });
619
- const r = await get(port, '/api/gds/builders/95/profile');
619
+ const r = await get(port, '/api/bongos/builders/95/profile');
620
620
  assert.equal(r.json.cross_project, null);
621
621
  for (const key of ['totals', 'works_shipped', 'more_projects', 'last_active', 'rank_held']) {
622
622
  assert.ok(!r.text.includes(key), `nothing derived from the rollup may survive — found "${key}"`);
@@ -632,12 +632,12 @@ await t('R06.5 no PARTIAL numbers survive the hide (a count beside a hidden tota
632
632
 
633
633
  const scoutApp = express();
634
634
  scoutApp.use(attachFail);
635
- scoutApp.use('/api/gds', buildScoutingRoutes());
635
+ scoutApp.use('/api/bongos', buildScoutingRoutes());
636
636
  const scout = await listen(scoutApp);
637
637
 
638
638
  await t('R06.3 GET /scouting drops the hidden, the provisional AND the private builder', async () => {
639
639
  engine.calls.length = 0;
640
- const r = await get(scout.port, '/api/gds/scouting');
640
+ const r = await get(scout.port, '/api/bongos/scouting');
641
641
  assert.equal(r.status, 200);
642
642
  const logins = r.json.builders.map((b) => b.github_login);
643
643
  assert.deepEqual(logins, ['r06-visible'],
@@ -662,7 +662,7 @@ await t('R06.3 the /people page reads /scouting and nothing else', async () => {
662
662
  // assembled is the page's business.
663
663
  const args = [...sourceOf('modules/hall-ui/public/people.js').matchAll(/\bfetch\(\s*([^,)]+)/g)].map((m) => m[1].trim());
664
664
  assert.equal(args.length, 1, '/people has exactly one data source');
665
- assert.match(args[0], /^'\/api\/gds\/scouting\?limit='/,
665
+ assert.match(args[0], /^'\/api\/bongos\/scouting\?limit='/,
666
666
  'and it is the scouting rollup — nothing may re-enter through a second endpoint');
667
667
  });
668
668
 
@@ -1426,7 +1426,7 @@ test('what the project RUNS comes only from its own manifest, and every answer i
1426
1426
  const runs = fnHub('loadVisRuns');
1427
1427
  const manifest = fnHub('ensureManifest');
1428
1428
  assert.match(runs, /inst\.status !== 'active' \|\| !inst\.domain/, 'only a live project with an address can be asked');
1429
- assert.match(manifest, /'https:\/\/' \+ domain \+ '\/api\/gds\/instance'/,
1429
+ assert.match(manifest, /'https:\/\/' \+ domain \+ '\/api\/bongos\/instance'/,
1430
1430
  'the same public GET /instance the platform’s runner reads after a restart');
1431
1431
  assert.doesNotMatch(runs, /fetch\(/, 'the card fires no GET of its own — one manifest read serves the pair (task 1003554)');
1432
1432
  assert.match(runs, /m\.brand && m\.brand\.project/);
@@ -1600,7 +1600,7 @@ test('the join door is read on entry + tab return, like every other settings sec
1600
1600
  // door yet, and a line that could only ever say "your project doesn’t report
1601
1601
  // this" is worse than no line. The read-back lands with the enforcement.
1602
1602
  const load = fnHub('loadDoor');
1603
- assert.doesNotMatch(load, /api\/gds\/instance/, 'this section asks the project’s manifest nothing');
1603
+ assert.doesNotMatch(load, /api\/bongos\/instance/, 'this section asks the project’s manifest nothing');
1604
1604
  });
1605
1605
 
1606
1606
  test('the joinability choices are the platform’s vocabulary, each in plain words, and the pick is a real radio group', () => {
@@ -220,7 +220,7 @@ t('webEnvBody: an instance is never pinned to the neutral pack, so it serves its
220
220
  // into every instance's web.env — a leftover from the shared-checkout co-tenant model. Under
221
221
  // ADR 0108 each instance has its own checkout and its own config/branding.json, and
222
222
  // src/branding.js's ENV_OVERRIDES cover domains/auth.idp/landing but NEVER identity.productName.
223
- // So the pin made every hosted instance answer GET /api/gds/instance with the PLATFORM's name:
223
+ // So the pin made every hosted instance answer GET /api/bongos/instance with the PLATFORM's name:
224
224
  // hermeslines-marketing, mercury and demo all said "Cloud Bongos" while their own packs on disk
225
225
  // said otherwise, and `bongos login <instance>` greeted newcomers with the wrong project.
226
226
  const b = P.webEnvBody({ ...coTenant, domain: 'mercury.example.com' });
@@ -262,7 +262,7 @@ t('identityVerdict: a live instance serving the PLATFORM name is caught, not shr
262
262
 
263
263
  t('identityCmd: probes the manifest over loopback, like healthzCmd', () => {
264
264
  const N = require('../scripts/gds/provision-net.js');
265
- assert.match(N.identityCmd({ port: 3011 }), /127\.0\.0\.1:3011\/api\/gds\/instance/);
265
+ assert.match(N.identityCmd({ port: 3011 }), /127\.0\.0\.1:3011\/api\/bongos\/instance/);
266
266
  });
267
267
 
268
268
  t('webEnvBody: a domain writes the single-host origin overrides so the hall loads (task 1972)', () => {
@@ -151,7 +151,7 @@ t('null (unknown) when the manifest carries no project block — a core that pre
151
151
  assert.equal(P.settingsConsumed(JSON.stringify({ brand: { project: 'nope' } }), GATED), null);
152
152
  });
153
153
  t('instanceManifestCmd asks the instance on loopback, like healthzCmd', () => {
154
- assert.equal(P.instanceManifestCmd({ port: 3010 }), 'curl -sS --max-time 5 http://127.0.0.1:3010/api/gds/instance');
154
+ assert.equal(P.instanceManifestCmd({ port: 3010 }), 'curl -sS --max-time 5 http://127.0.0.1:3010/api/bongos/instance');
155
155
  });
156
156
 
157
157
  // ── the handler ──────────────────────────────────────────────────────────────
@@ -166,7 +166,7 @@ function recorder({ apply = false, envBody = LIVE_ENV, readFails = false, health
166
166
  cmds.push(cmd);
167
167
  if (/\bcat /.test(cmd)) return readFails ? { ok: true, stdout: '', softFailed: true } : { ok: true, stdout: envBody };
168
168
  if (/healthz/.test(cmd)) return healthzFails ? { ok: true, stdout: '', softFailed: true } : { ok: true, stdout: '{"ok":true}' };
169
- if (/api\/gds\/instance/.test(cmd)) return { ok: true, stdout: manifestOut };
169
+ if (/api\/bongos\/instance/.test(cmd)) return { ok: true, stdout: manifestOut };
170
170
  if (/systemctl restart/.test(cmd) && restartThrows && apply) throw new Error(`Command failed: ${cmd}`);
171
171
  return { ok: true, stdout: '' };
172
172
  };
@@ -218,7 +218,7 @@ await ta('--apply, active standalone: read web.env → patch ONLY the settings l
218
218
  assert.ok(idx(/systemctl restart spike/) >= 0, 'RESTART (not reload) so the process re-reads its env');
219
219
  assert.ok(idx(/cat /) < idx(/restart spike/), 'read before restart');
220
220
  assert.ok(idx(/restart spike/) < idx(/healthz/), 'healthz after the restart');
221
- assert.ok(idx(/healthz/) < idx(/api\/gds\/instance/), 'the read-back only after it answers');
221
+ assert.ok(idx(/healthz/) < idx(/api\/bongos\/instance/), 'the read-back only after it answers');
222
222
  assert.ok(!cmds.some((c) => /systemctl (stop|disable)|caddy|box-dns/.test(c)), 'no teardown / DNS / caddy legs — settings only');
223
223
  });
224
224
 
@@ -355,7 +355,7 @@ await ta('--apply: a restart that never answers /healthz is a VERDICT after the
355
355
  assert.deepEqual(probes, [{ id: 18, up: false }]);
356
356
  assert.match(events[0].detail, /not answering \/healthz yet/);
357
357
  assert.equal(cmds.filter((c) => /healthz/.test(c)).length, MANIFEST_VERIFY_TRIES, 'the same patience as the manifest probe (F23) — a slow boot is not slandered');
358
- assert.ok(!cmds.some((c) => /api\/gds\/instance/.test(c)), 'no manifest probe when it never answered');
358
+ assert.ok(!cmds.some((c) => /api\/bongos\/instance/.test(c)), 'no manifest probe when it never answered');
359
359
  });
360
360
 
361
361
  await ta('--apply: a domainless instance that answers records up=true immediately (provisionInstance step-7 rule)', async () => {
@@ -242,9 +242,9 @@ function boxDeps(markerFile, overrides = {}) {
242
242
  return '';
243
243
  },
244
244
  // task 1002607: emulate a real PREVIEW — 200 on the health URL, 404 on the
245
- // /api/gds/healthz discriminator (the game-only entry mounts no /api/gds).
245
+ // /api/bongos/healthz discriminator (the game-only entry mounts no /api/bongos).
246
246
  // A flat always-200 mock would now read as "the MAIN server answered".
247
- fetchImpl: async (url) => ({ status: String(url).includes('/api/gds/healthz') ? 404 : 200 }),
247
+ fetchImpl: async (url) => ({ status: String(url).includes('/api/bongos/healthz') ? 404 : 200 }),
248
248
  markerPath: markerFile,
249
249
  cwd: tmp,
250
250
  pollMs: 1,
@@ -541,7 +541,7 @@ await ta('1002607 waitHealthy: 404 at the health URL is NOT healthy (was: anythi
541
541
 
542
542
  await ta('1002607 waitHealthy: a 200 answered by the MAIN server (api healthz 200) is an impostor, not a healthy preview', async () => {
543
543
  // The full server binds the same 127.0.0.1:3000 — root answers 200, and so does
544
- // /api/gds/healthz. The game-only preview (ADR 0052) would 404 the latter.
544
+ // /api/bongos/healthz. The game-only preview (ADR 0052) would 404 the latter.
545
545
  const r = await sbx.waitHealthy({ fetchImpl: async () => ({ status: 200 }), timeoutMs: 1000, pollMs: 1 });
546
546
  assert.equal(r.ok, false, 'a dead preview must not report healthy off the main server');
547
547
  assert.match(r.reason, /MAIN server/);
@@ -550,7 +550,7 @@ await ta('1002607 waitHealthy: a 200 answered by the MAIN server (api healthz 20
550
550
 
551
551
  await ta('1002607 waitHealthy: a real preview (root 200, api healthz 404) is healthy', async () => {
552
552
  const r = await sbx.waitHealthy({
553
- fetchImpl: async (url) => ({ status: String(url).includes('/api/gds/healthz') ? 404 : 200 }),
553
+ fetchImpl: async (url) => ({ status: String(url).includes('/api/bongos/healthz') ? 404 : 200 }),
554
554
  timeoutMs: 1000, pollMs: 1,
555
555
  });
556
556
  assert.equal(r.ok, true);
@@ -559,7 +559,7 @@ await ta('1002607 waitHealthy: a real preview (root 200, api healthz 404) is hea
559
559
  await ta('1002607 waitHealthy: a discriminator probe that ERRORS counts as "not the main server" (preview healthy)', async () => {
560
560
  const r = await sbx.waitHealthy({
561
561
  fetchImpl: async (url) => {
562
- if (String(url).includes('/api/gds/healthz')) throw new Error('ECONNREFUSED on a path the preview never mounts');
562
+ if (String(url).includes('/api/bongos/healthz')) throw new Error('ECONNREFUSED on a path the preview never mounts');
563
563
  return { status: 200 };
564
564
  },
565
565
  timeoutMs: 1000, pollMs: 1,
@@ -568,8 +568,8 @@ await ta('1002607 waitHealthy: a discriminator probe that ERRORS counts as "not
568
568
  });
569
569
 
570
570
  t('1002607 apiHealthzProbeUrl: same origin as the health URL, api path; null on garbage', () => {
571
- assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3000/'), 'http://127.0.0.1:3000/api/gds/healthz');
572
- assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3100/healthz'), 'http://127.0.0.1:3100/api/gds/healthz');
571
+ assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3000/'), 'http://127.0.0.1:3000/api/bongos/healthz');
572
+ assert.equal(sbx.apiHealthzProbeUrl('http://127.0.0.1:3100/healthz'), 'http://127.0.0.1:3100/api/bongos/healthz');
573
573
  assert.equal(sbx.apiHealthzProbeUrl('not a url'), null);
574
574
  });
575
575
 
@@ -599,7 +599,7 @@ function localDeps(markerFile, overrides = {}) {
599
599
  },
600
600
  execFileSync: (cmd, args, opts) => (cmd === 'git' ? execFileSync(cmd, args, opts) : ''),
601
601
  // task 1002607: preview-shaped mock — health 200, API-healthz discriminator 404.
602
- fetchImpl: async (url) => ({ status: String(url).includes('/api/gds/healthz') ? 404 : 200 }),
602
+ fetchImpl: async (url) => ({ status: String(url).includes('/api/bongos/healthz') ? 404 : 200 }),
603
603
  markerPath: markerFile,
604
604
  cwd: tmp,
605
605
  pollMs: 1,
@@ -364,7 +364,7 @@ const { attachFail } = require('../src/bongos/middleware/error-envelope.js');
364
364
 
365
365
  const app = express();
366
366
  app.use(attachFail);
367
- app.use('/api/gds', buildScoutingRoutes());
367
+ app.use('/api/bongos', buildScoutingRoutes());
368
368
  const server = app.listen(0, '127.0.0.1');
369
369
  await new Promise((r) => server.once('listening', r));
370
370
  const port = server.address().port;
@@ -381,7 +381,7 @@ function getScouting(caller, query = '') {
381
381
  currentCaller = caller;
382
382
  calls = [];
383
383
  return new Promise((resolve, reject) => {
384
- const req = http.request({ host: '127.0.0.1', port, method: 'GET', path: `/api/gds/scouting${query}` }, (res) => {
384
+ const req = http.request({ host: '127.0.0.1', port, method: 'GET', path: `/api/bongos/scouting${query}` }, (res) => {
385
385
  const chunks = [];
386
386
  res.on('data', (c) => chunks.push(c));
387
387
  res.on('end', () => resolve({ status: res.statusCode, text: Buffer.concat(chunks).toString('utf8') }));
@@ -606,7 +606,7 @@ await t('CALIBRATION: the interpreter refuses what it cannot model, rather than
606
606
 
607
607
  await t('/people is the SAME endpoint, so "absent from /people" is true by construction', async () => {
608
608
  const page = fs.readFileSync(path.join(repo, 'modules/hall-ui/public/people.js'), 'utf8');
609
- assert.match(page, /fetch\('\/api\/gds\/scouting/,
609
+ assert.match(page, /fetch\('\/api\/bongos\/scouting/,
610
610
  'the hall directory reads GET /scouting; if it ever grows its own query, this proof stops covering it');
611
611
  const source = fs.readFileSync(path.join(repo, 'modules/platform-identity/platform-identity.js'), 'utf8');
612
612
  assert.match(source, /scoutingListableSql\('pa'\)/,