@bongos/core 1.19.1074 → 1.19.1076

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 (179) hide show
  1. package/.bongos-core.json +196 -211
  2. package/.claude/skills/blocker-solve/SKILL.md +1 -1
  3. package/README.md +1 -1
  4. package/bin/bongos.js +1 -3
  5. package/docs/adr/0031-cloud-dev-environments-for-builders.md +1 -1
  6. package/docs/adr/0035-builder-onboarding-three-paths.md +1 -1
  7. package/docs/adr/0044-per-box-live-game-preview.md +1 -1
  8. package/docs/adr/0045-devbox-desktop-app.md +1 -1
  9. package/docs/adr/0046-sandbox-first-review-gate.md +1 -1
  10. package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +1 -1
  11. package/docs/adr/0053-scoped-dev-box-session.md +1 -1
  12. package/docs/adr/0055-server-mediated-branch-publish.md +1 -1
  13. package/docs/adr/0057-container-cost-ledger.md +1 -1
  14. package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +1 -1
  15. package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +1 -1
  16. package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +1 -1
  17. package/docs/adr/0072-dev-box-code-staleness-visibility.md +1 -1
  18. package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +1 -1
  19. package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +1 -1
  20. package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +1 -1
  21. package/docs/adr/0145-devbox-app-branding-driven-module.md +1 -1
  22. package/docs/adr/0148-task-scoped-box-source-access.md +2 -2
  23. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +1 -1
  24. package/docs/adr/0193-pause-task-scoped-box-slices.md +1 -1
  25. package/docs/adr/0277-a-box-is-in-use-only-while-a-human-is-attached.md +1 -1
  26. package/docs/adr/0346-dev-boxes-are-retired.md +69 -0
  27. package/docs/adr/README.md +1 -0
  28. package/docs/api/openapi.json +4 -4
  29. package/docs/architecture.md +5 -6
  30. package/docs/branding-contract.md +2 -2
  31. package/docs/canonical-permissions.md +10 -18
  32. package/docs/copy-inventory.md +3 -3
  33. package/docs/copy-registry.json +3 -3
  34. package/docs/design/gate-navigation-direction.md +1 -1
  35. package/docs/design/hall-direction-v2.md +3 -3
  36. package/docs/design/modular-architecture/00-research-report.md +1 -1
  37. package/docs/design/modular-architecture/01-architecture.md +3 -3
  38. package/docs/design/modular-architecture/02-module-map.md +1 -2
  39. package/docs/design/modular-architecture/03-builder-flows.md +22 -20
  40. package/docs/design/modular-architecture/04-module-lifecycle.md +1 -1
  41. package/docs/design/modular-architecture/README.md +4 -2
  42. package/docs/design/reviews/hall-v2/README.md +2 -2
  43. package/docs/design/vanilla-hall-ui-redesign-scope.md +4 -4
  44. package/docs/file-map.md +5 -5
  45. package/docs/handoff-template.md +1 -1
  46. package/docs/module-api-changelog.md +8 -0
  47. package/docs/modules-contract.md +11 -14
  48. package/docs/page-readings.json +63 -63
  49. package/docs/recipes/bongos-cli-release.md +1 -2
  50. package/docs/recipes/multi-builder-merge.md +1 -1
  51. package/docs/recipes/ops-gotchas.md +0 -9
  52. package/docs/recipes/self-host.md +1 -1
  53. package/docs/recipes/windows-builders.md +1 -1
  54. package/migrations/core_258_drop_dev_box_tables.sql +3 -0
  55. package/modules/copy-desk/routes/copy-desk.js +1 -1
  56. package/modules/discord/ship-broadcast.js +3 -3
  57. package/modules/economy/credits.js +2 -2
  58. package/modules/hall-ui/public/palette.js +143 -3
  59. package/modules/ideas/projection.js +1 -1
  60. package/modules/lifecycle/db-ship.js +4 -4
  61. package/modules/lifecycle/github-push.js +12 -14
  62. package/modules/lifecycle/publish-reconciler.js +10 -10
  63. package/modules/lifecycle/routes/tasks.js +8 -8
  64. package/modules/lifecycle/ship-card.js +1 -1
  65. package/modules/lifecycle/task-visuals.js +2 -2
  66. package/modules/memory/routes/memory.js +2 -2
  67. package/modules/platform-identity/routes/sso.js +3 -2
  68. package/modules/provisioning/capacity.js +1 -1
  69. package/modules/provisioning/provisioning.js +4 -3
  70. package/modules/provisioning/routes/provisioning.js +4 -4
  71. package/modules/sessions/db.js +1 -1
  72. package/package-lock.json +2 -2
  73. package/package.json +1 -1
  74. package/release-notes.json +28 -0
  75. package/scripts/gds/artifact-staleness.js +2 -2
  76. package/scripts/gds/backfill-task-rewards.js +5 -5
  77. package/scripts/gds/claude-materialize.js +2 -2
  78. package/scripts/gds/cli-lib.js +7 -7
  79. package/scripts/gds/codemod-rename-src-gds.js +1 -1
  80. package/scripts/gds/context-pack.js +5 -7
  81. package/scripts/gds/dev-box-guard.js +165 -0
  82. package/scripts/gds/doctor.js +3 -3
  83. package/scripts/gds/fitness-checks-packaging.js +4 -4
  84. package/scripts/gds/fitness-lib.js +10 -0
  85. package/scripts/gds/fitness-ratchets.js +1 -1
  86. package/scripts/gds/fitness.js +2 -10
  87. package/scripts/gds/gen-api-client.js +4 -4
  88. package/scripts/gds/gen-api-docs.js +1 -1
  89. package/scripts/gds/gen-repo-map.js +13 -14
  90. package/scripts/gds/gen-session-index.js +8 -8
  91. package/scripts/gds/leak-scan-allowlist.js +1 -1
  92. package/scripts/gds/plain-cards.js +1 -1
  93. package/scripts/gds/push-path-brief.js +10 -10
  94. package/scripts/gds/rename-history-check.js +1 -1
  95. package/scripts/gds/run-unit-tests.js +4 -0
  96. package/scripts/gds/session-digest-build.js +2 -2
  97. package/scripts/gds/ship-deploy-target.js +13 -13
  98. package/scripts/gds/ship-flow.js +1 -1
  99. package/scripts/gds/ship-land.js +6 -6
  100. package/scripts/gds/ship-merge.js +4 -4
  101. package/scripts/gds/ship-preflight-steps.js +4 -4
  102. package/scripts/gds/ship-regen.js +9 -12
  103. package/scripts/gds/ship.js +9 -9
  104. package/scripts/gds/skill-preflight.js +9 -8
  105. package/src/bongos/api-prefix.js +4 -4
  106. package/src/bongos/module-scope-map.js +1 -1
  107. package/src/bongos/platform-visibility-gate.js +1 -1
  108. package/src/bongos/routes/me.js +1 -1
  109. package/src/bongos/routes/security.js +3 -3
  110. package/src/bongos/routes.js +2 -2
  111. package/src/bongos/serve-internal.js +5 -6
  112. package/src/bongos-downloads.js +1 -6
  113. package/src/branding.js +2 -2
  114. package/src/build-info.js +4 -6
  115. package/src/instance-config.js +2 -2
  116. package/src/module-api.js +3 -3
  117. package/src/module-loader/manifest-schema.js +1 -1
  118. package/tests/api_alias_caller_ratchet.mjs +1 -1
  119. package/tests/api_alias_exceptions.mjs +1 -1
  120. package/tests/api_client.mjs +1 -1
  121. package/tests/api_path_404.mjs +1 -1
  122. package/tests/backfill_task_rewards.mjs +1 -1
  123. package/tests/{box_ship_permissions.mjs → cli_allowlist_permissions.mjs} +5 -5
  124. package/tests/cli_sessions.mjs +1 -1
  125. package/tests/context_pack.mjs +13 -13
  126. package/tests/copy_inventory.mjs +7 -7
  127. package/tests/core_258_box_session_claims_db.mjs +180 -0
  128. package/tests/credit_grant.mjs +2 -2
  129. package/tests/criterion_suggest.mjs +1 -1
  130. package/tests/design_tokens_sync.mjs +3 -2
  131. package/tests/fitness.mjs +89 -0
  132. package/tests/fitness_ratchets.mjs +2 -2
  133. package/tests/github_push_land_proof.mjs +1 -1
  134. package/tests/goal_advisory.mjs +3 -3
  135. package/tests/goal_suggest.mjs +3 -3
  136. package/tests/government_abuse_matrix.mjs +4 -3
  137. package/tests/hall_audit.mjs +1 -1
  138. package/tests/hall_palette.mjs +224 -11
  139. package/tests/helpers.mjs +1 -1
  140. package/tests/host_topology_skips.mjs +2 -2
  141. package/tests/migration_namespace.mjs +6 -6
  142. package/tests/module_api.mjs +2 -2
  143. package/tests/module_cli.mjs +5 -5
  144. package/tests/module_manifest.mjs +13 -13
  145. package/tests/module_route_rank.mjs +2 -2
  146. package/tests/modules_route_wiring.mjs +1 -1
  147. package/tests/onboarding_route_signals.mjs +1 -1
  148. package/tests/paste_token_session_store.mjs +1 -1
  149. package/tests/platform_visibility_gate.mjs +1 -1
  150. package/tests/project_modules_ui.mjs +17 -17
  151. package/tests/projects_hub_module_picker.mjs +75 -74
  152. package/tests/provisioning_capacity.mjs +1 -1
  153. package/tests/provisioning_recommendations.mjs +3 -2
  154. package/tests/publish_branch_route.mjs +1 -1
  155. package/tests/publish_manifest.mjs +1 -1
  156. package/tests/publish_reconciler.mjs +8 -8
  157. package/tests/push_path_brief.mjs +10 -9
  158. package/tests/regrade_eligibility.mjs +1 -1
  159. package/tests/rename_history_restraint.mjs +1 -1
  160. package/tests/repo_map.mjs +9 -9
  161. package/tests/seam_wiring_guard.mjs +11 -11
  162. package/tests/search_isolation.mjs +3 -3
  163. package/tests/session_records.mjs +1 -1
  164. package/tests/session_rename_fallback.mjs +1 -1
  165. package/tests/session_start_freshness.mjs +3 -3
  166. package/tests/session_token_hash_db.mjs +1 -1
  167. package/tests/ship_card.mjs +1 -1
  168. package/tests/ship_ci_deploy.mjs +17 -17
  169. package/tests/ship_premerge.mjs +1 -1
  170. package/tests/ship_resume.mjs +1 -1
  171. package/tests/skill_preflight.mjs +2 -2
  172. package/tests/skip_is_not_pass.mjs +1 -1
  173. package/tests/terms_acceptance.mjs +1 -1
  174. package/docs/design/reviews/hall-v2/harbor--archon.webp +0 -0
  175. package/docs/design/reviews/hall-v2/harbor--metic.webp +0 -0
  176. package/docs/design/reviews/hall-v2/harbor--xenos.webp +0 -0
  177. package/docs/design/reviews/hall-v2/pair--archon.webp +0 -0
  178. package/docs/design/reviews/hall-v2/pair--metic.webp +0 -0
  179. package/docs/design/reviews/hall-v2/pair--xenos.webp +0 -0
@@ -2,7 +2,7 @@
2
2
  // surface (ADR 0111 §1/§2, task #1942). Instance hosting + domains: the web-tier
3
3
  // REQUEST + STATE surface for standing up + operating a Cloud Bongos instance.
4
4
  //
5
- // THE TRUST BOUNDARY (ADR 0111 §2 / ADR 0016 / the dev-box /box precedent). The
5
+ // THE TRUST BOUNDARY (ADR 0111 §2 / ADR 0016). The
6
6
  // internet-facing web process NEVER calls a cloud API and holds NO provider tokens.
7
7
  // A mutation route only ENQUEUES an intent (provision | teardown) into
8
8
  // provisioning_intents and returns; the control-plane runner (scripts/gds/
@@ -27,7 +27,7 @@
27
27
  // task 1003581 — see the handler)
28
28
  // POST /provisioning/instances/:id/teardown — request teardown of one's own
29
29
  // GET /provisioning/instances/:id/invite-suggestions — who is worth inviting (R28, ADR 0251)
30
- // Archon-scoped (requireRank('archon') — the fleet, the /boxes precedent):
30
+ // Archon-scoped (requireRank('archon') — the fleet):
31
31
  // GET /provisioning/fleet — the full instance roster + the box's slot `capacity` (ADR 0285)
32
32
  // GET /provisioning/fleet/cost-ledger — per-instance cost to us + to its owner, with totals
33
33
  // POST /provisioning/instances/:id/force-teardown — tear down ANY instance
@@ -204,7 +204,7 @@ module.exports = function provisioningRoutes() {
204
204
  // it. Archon-first keeps every route classifying to its true gate.
205
205
 
206
206
  // GET /provisioning/fleet — the full instance roster across all owners.
207
- // rank: archon (exposes every owner's instance + cost; the /boxes precedent).
207
+ // rank: archon (exposes every owner's instance + cost).
208
208
  router.get('/provisioning/fleet', auth.requireBuilder, auth.requirePermission('provisioning.fleet.manage'), async (req, res) => {
209
209
  try {
210
210
  const status = req.query.status || undefined;
@@ -217,7 +217,7 @@ module.exports = function provisioningRoutes() {
217
217
  });
218
218
 
219
219
  // GET /provisioning/fleet/cost-ledger — per-instance monthly cost to us + estimated cost to its owner, with totals.
220
- // rank: archon — cost oversight across the fleet (the /boxes/cost-ledger precedent).
220
+ // rank: archon — cost oversight across the fleet.
221
221
  // Declared among the archon routes (archon-first) for correct auditor classification.
222
222
  router.get('/provisioning/fleet/cost-ledger', auth.requireBuilder, auth.requirePermission('provisioning.fleet.manage'), async (req, res) => {
223
223
  try {
@@ -187,7 +187,7 @@ async function syncSessionDrachmaeEarnedTx(client, builderId, sessionId) {
187
187
  // safe, and lets a later, costlier ship in the same session book its increment.
188
188
  // task 1676: pass totalTokens so the reward can fall back to pricing the
189
189
  // session's real token total when modelUsage is empty/unpriceable — the
190
- // dev-box/CI agent path that historically paid $0 cost-plus (ADR 0097).
190
+ // CI agent path that historically paid $0 cost-plus (ADR 0097).
191
191
  async function awardSessionTokenRewardTx(client, { builderId, sessionId, modelUsage, totalTokens }) {
192
192
  const reward = seams.resolveOptional('reward');
193
193
  if (!reward) return { drachmae: 0, trueCostUsd: 0, awarded: false, unknownModels: [], deferred: false };
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.1074",
3
+ "version": "1.19.1076",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.1074",
9
+ "version": "1.19.1076",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.1074",
3
+ "version": "1.19.1076",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -7821,5 +7821,33 @@
7821
7821
  "id": "1003781",
7822
7822
  "text": "Every module now has its own version number, shown in the module list and the hall's Modules tab — the first step toward publishing and updating modules through the store."
7823
7823
  }
7824
+ ],
7825
+ "1.19.1075": [
7826
+ {
7827
+ "id": "1003897",
7828
+ "text": "Cleanup: the code, tests and settings no longer describe the dev box as if it still existed, and seven code-quality limits are tightened to today's better numbers. Nothing changes for builders."
7829
+ }
7830
+ ],
7831
+ "1.19.1076": [
7832
+ {
7833
+ "id": "1004363",
7834
+ "text": "Fixed the test that was still stopping new releases. It created a sample task without saying what kind of work it was, which the database no longer allows. With it fixed, the release carrying the database fix can go out, and t"
7835
+ },
7836
+ {
7837
+ "id": "1003460",
7838
+ "text": "Ctrl-K now searches the project's memory: typing prose merges in matching tasks/ideas/blockers from the existing recall search endpoint, debounced and gracefully degrading if the endpoint is ever unavailable — jumping by id, p"
7839
+ },
7840
+ {
7841
+ "id": "1003899",
7842
+ "text": "The dev box can't quietly come back: an automated check now fails the build if its code, tables, permissions or files reappear, and points whoever tripped it to the decision record that explains why."
7843
+ },
7844
+ {
7845
+ "id": "1004362",
7846
+ "text": "Fixed the database update that kept making the site upgrade roll back. It tried to delete old dev-box logins while one past task claim still pointed at one of them, and the database refused. The update now clears that pointer"
7847
+ },
7848
+ {
7849
+ "id": "1003898",
7850
+ "text": "The dev box's removal is written up in one decision record (ADR 0346), and the 20 older records that described it now point there. The live guides, the design mockups and the README no longer tell anyone to use a dev box."
7851
+ }
7824
7852
  ]
7825
7853
  }
@@ -32,8 +32,8 @@
32
32
  //
33
33
  // ── WHERE THIS MAY RUN — read before scheduling it anywhere new ───────────────
34
34
  //
35
- // ONLY where the artifacts are SUPPOSED to already exist: a deployed instance, or a
36
- // dev box after its source-fetch regen. NEVER in CI. A fresh `git clone` legitimately
35
+ // ONLY where the artifacts are SUPPOSED to already exist: a deployed instance after its
36
+ // source-fetch regen. NEVER in CI. A fresh `git clone` legitimately
37
37
  // has no `docs/repo-map.md` — it is gitignored, so it is not in the repository at all
38
38
  // — and this check would report it absent on every single run. A monitor that is red
39
39
  // every run teaches its reader to ignore it, which is the exact failure ADR 0110's
@@ -4,12 +4,12 @@
4
4
  // scripts/gds/backfill-task-rewards.js — retroactive drachmae backfill for
5
5
  // shipped tasks that paid 0 reward (task 1672, ADR 0097).
6
6
  //
7
- // THE GAP. A task's `credits_reward` defaults to 0; many early/dev-box/CI ships
7
+ // THE GAP. A task's `credits_reward` defaults to 0; many early and CI ships
8
8
  // never had an author-estimated reward set, so the kind-multiplied task-confirm
9
9
  // credit (modules/economy/credits.js insertMultipliedConfirmCredit) computed
10
10
  // `0 × multiplier = 0` and minted nothing. The cost-plus *session* reward
11
11
  // (reason='session.token_reward', ADR 0054) was supposed to backstop those, but
12
- // it pays ~0 for dev-box/CI agent ships (no priced model usage uploaded), so
12
+ // it pays ~0 for CI agent ships (no priced model usage uploaded), so
13
13
  // those builders earned nothing for real shipped work. This script lets an
14
14
  // Archon retroactively pay a *fair, reviewed* per-task amount — once, safely.
15
15
  //
@@ -133,7 +133,7 @@ function planForBuilder(builderId, taskRewards, costPlusAlreadyPaid, alreadyBack
133
133
  // =========================================================================
134
134
 
135
135
  function loadPool() {
136
- // Lazy + guarded: a builder box has no DATABASE_URL / no peer-auth Postgres,
136
+ // Lazy + guarded: a builder machine has no DATABASE_URL / no peer-auth Postgres,
137
137
  // so --help and --dry-run must not crash here. We only reach for the pool when
138
138
  // we actually need to read/write the DB, and we report a clean message if the
139
139
  // connection is unavailable rather than throwing a raw stack.
@@ -230,7 +230,7 @@ async function buildPlan(pool, mapping, defaultRaw) {
230
230
  // session-level (task_id NULL), so we net at the BUILDER level — the audit
231
231
  // question is "did the cost-plus stream already compensate this builder for
232
232
  // the work these tasks represent". The dry-run surfaces this number so the
233
- // Archon can see whether it actually fired (it pays ~0 for dev-box/CI ships).
233
+ // Archon can see whether it actually fired (it pays ~0 for CI ships).
234
234
  const { rows: costPlusRows } = await pool.query(
235
235
  `SELECT builder_id, COALESCE(SUM(delta), 0)::int AS paid
236
236
  FROM credit_log
@@ -334,7 +334,7 @@ async function main() {
334
334
  try {
335
335
  pool = loadPool();
336
336
  } catch (err) {
337
- console.error('No DB connection available (expected on a builder box with no prod credentials).');
337
+ console.error('No DB connection available (expected on a builder machine with no prod credentials).');
338
338
  console.error('This script is inert here — run --help for usage. Detail:', err.message);
339
339
  process.exit(2);
340
340
  }
@@ -352,7 +352,7 @@ const STARTER_COMMANDS = [
352
352
  // `git diff|log|show` rule, also on purpose: the harness already runs their
353
353
  // read-only forms unprompted, and a prefix rule would switch off its flag check
354
354
  // (`--output=<file>` writes anywhere, `diff --no-index` reads any file).
355
- // tests/box_ship_permissions.mjs pins this list to the core's, rule for rule.
355
+ // tests/cli_allowlist_permissions.mjs pins this list to the core's, rule for rule.
356
356
  'bongos start:*',
357
357
  'bongos status:*',
358
358
  'bongos recall:*',
@@ -381,7 +381,7 @@ const STARTER_COMMANDS = [
381
381
  ];
382
382
  // One rule per command PER SHELL TOOL (task 1004014): the shell tool is `PowerShell` on a Windows
383
383
  // laptop, and a `Bash(...)` rule says nothing about its commands. The tools are the ones the guards
384
- // see (`.claude/hooks/shell-tools.js`) — held equal by tests/box_ship_permissions.mjs, not a require.
384
+ // see (`.claude/hooks/shell-tools.js`) — held equal by tests/cli_allowlist_permissions.mjs, not a require.
385
385
  const STARTER_SHELL_TOOLS = ['Bash', 'PowerShell'];
386
386
  const STARTER_ALLOW = STARTER_SHELL_TOOLS.flatMap((tool) => STARTER_COMMANDS.map((command) => `${tool}(${command})`));
387
387
 
@@ -24,12 +24,12 @@ const ic = require('../../src/instance-config');
24
24
  // namespaced instance, still resolves (R61 / task 1200). os.homedir() keeps it
25
25
  // per-user on any machine.
26
26
  //
27
- // WHY THE OLD NAMES STAY READABLE. This file is on disk on every builder machine
28
- // and every live dev box. Renaming it with no fallback signs all of them out at
29
- // once and every /builder-* command dies with 'no Bongos session'. So a read that
30
- // resolves through a superseded name MIGRATES forward (see loadSession), and the
31
- // old file is deliberately LEFT IN PLACE — a builder may roll back to an older
32
- // CLI, which can only see the old name. Part 4 (task 1003706) deletes it behind a
27
+ // WHY THE OLD NAMES STAY READABLE. This file is on disk on every builder machine.
28
+ // Renaming it with no fallback signs all of them out at once and every /builder-*
29
+ // command dies with 'no Bongos session'. So a read that resolves through a
30
+ // superseded name MIGRATES forward (see loadSession), and the old file is
31
+ // deliberately LEFT IN PLACE — a builder may roll back to an older CLI, which
32
+ // can only see the old name. Part 4 (task 1003706) deletes it behind a
33
33
  // test of its absence. (task 1003704)
34
34
  //
35
35
  // Order is FILENAME-major, not directory-major: the newest name found in ANY read
@@ -330,7 +330,7 @@ async function writeSessionToStore(session) {
330
330
  // upgrading would still lose it.
331
331
  // 2. store the incoming one under its own host.
332
332
  // 3. write the ACTIVE pointer exactly where it has always gone, so every existing reader —
333
- // in-repo skills, hooks, the dev box — behaves identically.
333
+ // in-repo skills and hooks — behaves identically.
334
334
  async function saveSession(session) {
335
335
  const dir = path.dirname(SESSION_PATH);
336
336
  await fsp.mkdir(dir, { recursive: true });
@@ -12,7 +12,7 @@
12
12
  // never clobbered:
13
13
  // src/gds/... -> src/bongos/... (directory refs)
14
14
  // "src/gds" -> "src/bongos" (bare, at a boundary)
15
- // src/gds-client -> src/gds-client (UNCHANGED: devbox-app/src/gds-client.js)
15
+ // src/gds-client -> src/gds-client (UNCHANGED: a look-alike file name)
16
16
  // src/gdsx -> src/gdsx (UNCHANGED here: prefix-edge fixture)
17
17
  //
18
18
  // Regex: /src\/gds(?![A-Za-z0-9_-])/g -- trailing guard only. No LEADING guard:
@@ -31,13 +31,11 @@ const path = require('node:path');
31
31
  // so importing it from a CLI is safe — same precedent as next-number.js reading
32
32
  // the repo tree directly. This is the "not hand-maintained" guarantee.
33
33
  //
34
- // OPTIONAL, because the file may not be ON DISK (task 1003085). A task-scoped box
35
- // (ADR 0148) materializes modules/<key> only for the modules the CLAIM puts in
36
- // scope, so on a box with NO active claim modules/lifecycle is absent and this
37
- // require threw MODULE_NOT_FOUND at import time. That killed /builder-start AND
38
- // /builder-claim — the exact two commands needed to escape the state, since the
39
- // claim is what would fetch the module. A deadlock, escapable only by calling
40
- // POST /claims with curl. The header's FAIL-OPEN promise ("must NEVER throw or
34
+ // OPTIONAL, because the file may not be ON DISK (task 1003085). A sparse checkout
35
+ // can lack modules/lifecycle, and when it did this require threw
36
+ // MODULE_NOT_FOUND at import time. That killed /builder-start AND /builder-claim
37
+ // — the two commands a builder needs to recover — leaving a deadlock escapable
38
+ // only by calling POST /claims with curl. The header's FAIL-OPEN promise ("must NEVER throw or
41
39
  // block a claim") was already the right rule; this require was the line that did
42
40
  // not keep it.
43
41
  //
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ // scripts/gds/dev-box-guard.js — the dev box stays retired (task 1003899, goal
3
+ // 1000120; ADR 0346).
4
+ //
5
+ // WHY. The dev box was removed across a dozen areas: a module, a third of it
6
+ // leaked into the core, four tables, a session source, three permissions, a CLI,
7
+ // a desktop app, hall pages. A removal spread that wide rots back in one careless
8
+ // import, fixture or copied migration. This is the ratchet that holds it: every
9
+ // tracked file outside the historical record is scanned for the retired names,
10
+ // and any hit fails CI with a pointer to ADR 0346, so the next builder learns WHY
11
+ // and not only THAT.
12
+ //
13
+ // WHAT COUNTS, narrowly — each rule names a thing that only ever meant the box:
14
+ // • module-key the key `dev-box` used AS A KEY: quoted ('dev-box', "dev-box",
15
+ // `dev-box`) or as a path segment (modules/dev-box/). Matched
16
+ // with fitness-lib's delimited-token matcher, so `dev-boxes`
17
+ // and an ADR filename like 0072-dev-box-code-… never hit. Prose
18
+ // ("the dev-box removal") is deliberately not a key.
19
+ // • identifier the dropped tables and columns: builder_boxes, box_intents,
20
+ // box_events, builder_ssh_keys, box_blocked*.
21
+ // • permission a quoted permission key of the retired `box.*.*` family.
22
+ // • session-source a session `source` compared or assigned to 'box'.
23
+ // • path a tracked file under scripts/gds/box*, infra/box-*,
24
+ // modules/dev-box/ or .devcontainer/.
25
+ // "box" alone is NOT a rule: it also means a server (the co-hosting box, box.env).
26
+
27
+ 'use strict';
28
+
29
+ const fs = require('fs');
30
+ const path = require('path');
31
+ const { execFileSync } = require('node:child_process');
32
+ const { keyTokenRe } = require('./fitness-lib.js');
33
+
34
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
35
+ const ADR = 'docs/adr/0346-dev-boxes-are-retired.md';
36
+ const NAME = 'the dev box stays retired (ADR 0346)';
37
+
38
+ // THE EXEMPTION LIST — the one place a file may still name the box. Each entry is
39
+ // `path-or-prefix` → why. A prefix ends in '/'. Keep reasons about the file's
40
+ // PURPOSE, never about what the tree happens to contain today.
41
+ const DEV_BOX_EXEMPT = new Map([
42
+ // The historical record — superseded, never rewritten (ADR README "Superseding").
43
+ ['docs/adr/', 'historical record: ADRs are superseded by ADR 0346, never rewritten'],
44
+ ['docs/session-logs/', 'historical record: dated session logs'],
45
+ ['docs/audits/', 'historical record: dated audit reports'],
46
+ ['docs/governance/', 'historical record: dated governance reports'],
47
+ ['limitations/', 'historical record: shipped-version scope archives'],
48
+ ['docs/module-api-changelog.md', 'history ledger of doorway releases; entries are appended, never rewritten'],
49
+ // Applied migrations: they created the box objects and, last, dropped them. Named one
50
+ // by one so a NEW migration is still checked. The column drop of task 1004360 joins
51
+ // this list when it lands.
52
+ ['migrations/067_builder_boxes.sql', 'applied migration (created the box tables)'],
53
+ ['migrations/069_builder_ssh_keys.sql', 'applied migration'],
54
+ ['migrations/070_box_intents.sql', 'applied migration'],
55
+ ['migrations/071_box_first_provision_approval.sql', 'applied migration'],
56
+ ['migrations/073_box_terminal_access.sql', 'applied migration'],
57
+ ['migrations/078_box_claude_active.sql', 'applied migration'],
58
+ ['migrations/079_box_first_connected_at.sql', 'applied migration'],
59
+ ['migrations/090_box_scoped_sessions.sql', 'applied migration (added the box session source)'],
60
+ ['migrations/102_remove_box_first_provision_approval.sql', 'applied migration'],
61
+ ['migrations/104_builder_box_blocked.sql', 'applied migration (added the box_blocked columns)'],
62
+ ['migrations/105_box_host_keys.sql', 'applied migration'],
63
+ ['migrations/121_box_code_version.sql', 'applied migration'],
64
+ ['migrations/core_236_rank_floor_backfill.sql', 'applied migration (names the key in an example)'],
65
+ ['migrations/core_237_box_widen_paths.sql', 'applied migration'],
66
+ ['migrations/core_238_box_unattended_cap.sql', 'applied migration'],
67
+ ['migrations/core_248_module_enablement_overrides.sql', 'applied migration (names the key in an example)'],
68
+ ['migrations/core_258_drop_dev_box_tables.sql', 'the migration that drops the box tables and session source by name (task 1003895)'],
69
+ ['modules/government/migrations/governance_002_seed_and_backfill.sql', 'applied migration (seeded the box.* keys)'],
70
+ ['modules/government/migrations/governance_007_delegate_archon_ops_to_metic.sql', 'applied migration'],
71
+ ['modules/government/migrations/government_019_retire_box_permissions.sql', 'the migration that revokes the box.* keys by name (task 1003894)'],
72
+ ['modules/provisioning/migrations/provisioning_014_module_selection.sql', 'applied migration (names the key in an example)'],
73
+ ['modules/provisioning/migrations/provisioning_001_tables.sql', 'applied migration (its comments cite the box queue it was modelled on)'],
74
+ // Retirement guards: code and tests whose JOB is to name the retired thing.
75
+ ['src/modules.js', 'RETIRED_MODULE_KEYS: an instance config still saying "dev-box": true boots with a warning'],
76
+ ['tests/modules.mjs', 'proves the retired-key tolerance (and that a typo like "dev-boxes" still throws)'],
77
+ ['tests/government_session_scope.mjs', 'proves a leftover source=box session is refused'],
78
+ ['tests/auth_page_gate.mjs', 'proves a leftover source=box session is refused a page'],
79
+ ['tests/terms_acceptance.mjs', 'proves a leftover source=box session cannot mint an acceptance'],
80
+ ['tests/government_seed.mjs', 'proves government_019 revoked the box.* keys from every rank'],
81
+ ['tests/core_258_box_session_claims_db.mjs', 'proves core_258 applies over a claim created from a box session (task 1004362)'],
82
+ ['tests/government_protected_surfaces.mjs', 'RETIRED_SINCE_R101: retired protected paths may leave the registry only once gone'],
83
+ ['scripts/gds/dev-box-guard.js', 'this guard (it defines the rules)'],
84
+ // Captured data and seed history that name real records.
85
+ ['scripts/gds/seed-', 'one-shot task seeders: their subject is the historical tasks they filed'],
86
+ ['scripts/hall-preview/fixtures/', 'captured API responses: the ledger still holds these task and goal rows'],
87
+ ['.bongos-core.json', 'a 1.0.0 seed manifest from July (commit b6ee5d29) that this repo never regenerates'],
88
+ ]);
89
+
90
+ const TEXT_EXT = /\.(js|mjs|cjs|json|md|sql|sh|html|css|yml|yaml|txt|toml)$/;
91
+ const PATH_RULE = /^(scripts\/gds\/box|infra\/box-|modules\/dev-box\/|\.devcontainer\/)/;
92
+
93
+ function exemptionFor(rel) {
94
+ for (const [entry, why] of DEV_BOX_EXEMPT) {
95
+ if (entry.endsWith('/') || entry.endsWith('-') ? rel.startsWith(entry) : rel === entry) return why;
96
+ }
97
+ return null;
98
+ }
99
+
100
+ // The key used as a key: fitness-lib's delimited match, with a quote, backtick or
101
+ // slash on both sides (a colon may close it, as in a JSON key).
102
+ // Compiled once for the whole scan; a global regex is stateful, so lastIndex is reset per line.
103
+ const KEY_RE = new RegExp(keyTokenRe('dev-box').source, 'g');
104
+ function namesModuleKey(line) {
105
+ const re = KEY_RE;
106
+ re.lastIndex = 0;
107
+ let m;
108
+ while ((m = re.exec(line))) {
109
+ if (/['"`/]/.test(m[1] || '') && /['"`/:]/.test(m[2] || '')) { re.lastIndex = 0; return true; }
110
+ re.lastIndex = m.index + 1;
111
+ }
112
+ return false;
113
+ }
114
+
115
+ const LINE_RULES = [
116
+ ['module-key', namesModuleKey],
117
+ ['identifier', (l) => /\b(builder_boxes|box_intents|box_events|builder_ssh_keys|box_blocked\w*)\b/.test(l)],
118
+ ['permission', (l) => /['"`]box\.[a-z_]+\.[a-z_]+['"`]/.test(l)],
119
+ ['session-source', (l) => /\bsource\b\s*(?:===?|!==?|:|=|IN\s*\()[^\n]{0,40}['"]box['"]/i.test(l)],
120
+ ];
121
+
122
+ // Pure: scan one file's text. Returns [{ rule, line }].
123
+ function scanText(text) {
124
+ const hits = [];
125
+ String(text == null ? '' : text).split('\n').forEach((l, i) => {
126
+ for (const [rule, test] of LINE_RULES) if (test(l)) hits.push({ rule, line: i + 1 });
127
+ });
128
+ return hits;
129
+ }
130
+
131
+ function trackedFiles(root = REPO_ROOT) {
132
+ return execFileSync('git', ['ls-files'], { cwd: root, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, timeout: 30000 })
133
+ .split('\n').filter(Boolean);
134
+ }
135
+
136
+ // The fitness check. `files` and `read` are injectable so the tests can plant a
137
+ // violation without touching the tree.
138
+ function checkNoDevBox({ files, read } = {}) {
139
+ const list = files || trackedFiles();
140
+ const readFile = read || ((rel) => fs.readFileSync(path.join(REPO_ROOT, rel), 'utf8'));
141
+ const violations = [];
142
+ for (const rel of list) {
143
+ if (exemptionFor(rel)) continue;
144
+ if (PATH_RULE.test(rel)) violations.push(`${rel} — path: a retired dev-box location (ADR 0346)`);
145
+ if (!TEXT_EXT.test(rel)) continue;
146
+ let text;
147
+ try { text = readFile(rel); } catch { continue; }
148
+ for (const { rule, line } of scanText(text)) violations.push(`${rel}:${line} — ${rule}: a retired dev-box name (ADR 0346)`);
149
+ }
150
+ const note = `The dev box was removed on purpose (${ADR}). ${list.length} tracked file(s) scanned for its module key, tables/columns, box.* permissions, box session source and paths. `
151
+ + `A hit means use what replaced it (a local checkout; server-mediated publish for a checkout with no push credential). Only a retirement guard or a historical record may name the box: add it to DEV_BOX_EXEMPT in scripts/gds/dev-box-guard.js, with its reason.`;
152
+ if (list.length === 0) {
153
+ return { name: NAME, ok: false, hardFail: true, violations: ['scan defect — enumerated 0 tracked files; a broken enumeration, not a clean result.'], warnings: [], note };
154
+ }
155
+ return { name: NAME, ok: violations.length === 0, hardFail: violations.length > 0, violations, warnings: [], note };
156
+ }
157
+
158
+ module.exports = { checkNoDevBox, scanText, namesModuleKey, exemptionFor, DEV_BOX_EXEMPT, PATH_RULE };
159
+
160
+ if (require.main === module) {
161
+ const r = checkNoDevBox();
162
+ console.log(`${r.ok ? 'PASS' : 'FAIL'} ${r.name}\n${r.note}`);
163
+ for (const v of r.violations) console.log(` ✗ ${v}`);
164
+ process.exitCode = r.ok ? 0 : 1;
165
+ }
@@ -371,7 +371,7 @@ function checkDeployTooling() {
371
371
  }
372
372
 
373
373
  // ADR 0055 / task 1025: in ci mode there are two publish paths. A machine with
374
- // no GitHub push credential (a dev box) ships SERVER-MEDIATED — it uploads its
374
+ // no GitHub push credential ships SERVER-MEDIATED — it uploads its
375
375
  // branch to the GDS, which pushes + opens the PR with the server's credential —
376
376
  // so gh is NOT needed here. Resolve the same path ship.js will take and skip the
377
377
  // gh requirement when it's server-mediated.
@@ -382,7 +382,7 @@ function checkDeployTooling() {
382
382
  /* keep 'local'; the gh checks below are the safe, stricter default */
383
383
  }
384
384
  if (via === 'server') {
385
- ok('deploy', `Deploy mode: ci (server-mediated publish) — this machine has no GitHub push credential, so the GDS pushes your branch + opens the PR for you. gh is not required here. NOTE: on a dev box, run /builder-reauth (browser) first so your session is a real cli session, not the box-scoped one.`);
385
+ ok('deploy', `Deploy mode: ci (server-mediated publish) — this machine has no GitHub push credential, so the GDS pushes your branch + opens the PR for you. gh is not required here.`);
386
386
  return;
387
387
  }
388
388
 
@@ -425,7 +425,7 @@ function checkDeployTooling() {
425
425
 
426
426
  // Intent-runner drift (task 1002722): a runner on a stale core once turned a domain-attach
427
427
  // into a teardown (task 1002716). Only a host with *intent-runner* units shows this section,
428
- // so a builder laptop or dev box sees nothing.
428
+ // so a builder laptop sees nothing.
429
429
  function runnerDriftRows(results) {
430
430
  return (results || []).map((r) => {
431
431
  const msg = `${r.name}: ${r.reason}`;
@@ -24,7 +24,7 @@ const { CORE_ROOT, rel, walkJs, walkJsAllRoots } = require('./fitness-lib.js');
24
24
  // ============================================================================
25
25
  //
26
26
  // A vanilla self-host boot ships only the PUBLISHABLE tree (publish-manifest.js). An
27
- // instance-only config (config/devbox-app.json, config/bongos-cli.json, config/branding.json,
27
+ // instance-only config (config/bongos-cli.json, config/branding.json,
28
28
  // config/modules.json, …) is boundary-EXCLUDED, so a bare `require('../../config/<excluded>.json')`
29
29
  // in core code throws MODULE_NOT_FOUND and CRASHES the boot on a fresh instance — the exact
30
30
  // class that shipped in R88 (two hard-requires in src/bongos/serve-internal.js; task 1824). The
@@ -81,9 +81,9 @@ function checkCoreRequiresExcludedConfig() {
81
81
  // require()s a boundary-EXCLUDED module (modules/game, modules/art-pipeline,
82
82
  // modules/character-anim, …) throws MODULE_NOT_FOUND once that module lives in the
83
83
  // consumer's instance repo rather than the core package (R89 split). The cure is
84
- // either to reclassify the module INTO core (if it belongs there — e.g. provisioning,
85
- // sibling of dev-box) or to exclude the requiring file with the feature it serves
86
- // (art tooling). Catches BOTH require forms: a direct literal
84
+ // either to reclassify the module INTO core (if it belongs there — e.g. provisioning)
85
+ // or to exclude the requiring file with the feature it serves (art tooling).
86
+ // Catches BOTH require forms: a direct literal
87
87
  // require('../modules/<key>/…') AND a require(path.join(<root>, 'modules/<key>/…')).
88
88
  // Only an EXCLUDED module required from a PUBLISHABLE file is a violation; requiring a
89
89
  // publishable (core) module is fine, and the loader's DYNAMIC dispatch
@@ -70,8 +70,18 @@ function walkJsAllRoots(subpath, roots = MODULE_ROOTS) {
70
70
  return out;
71
71
  }
72
72
 
73
+ // Match a module key as a DELIMITED token so `art-pipeline` hits in `'art-pipeline'` /
74
+ // `mount('art-pipeline')` but never inside `art-pipelines` or `xart-pipeline`. Hyphens are
75
+ // non-word chars, so the boundary guards against word-chars AND hyphens on both
76
+ // sides (no lookbehind — portable on every node the unit gate runs). Moved here from
77
+ // fitness.js (task 1003899) so dev-box-guard.js matches the retired key the same way.
78
+ function keyTokenRe(key) {
79
+ const esc = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
80
+ return new RegExp(`(^|[^\\w-])${esc}($|[^\\w-])`);
81
+ }
73
82
 
74
83
  module.exports = {
84
+ keyTokenRe,
75
85
  CORE_ROOT,
76
86
  INSTANCE_ROOT,
77
87
  MODULE_ROOTS,
@@ -350,7 +350,7 @@ const METRIC_HINTS = {
350
350
  legacy_api_gds_callers:
351
351
  ' — a NEW in-repo caller was written against the permanent `/api/gds` alias (task 1004064, '
352
352
  + 'idea 1001030). Ask for `/api/bongos` instead: the alias exists for callers we CANNOT update '
353
- + '(shipped Dev Box binaries, live dev boxes), not for code in this repo. Run '
353
+ + '(shipped binaries, live instances), not for code in this repo. Run '
354
354
  + '`node scripts/gds/api-alias-caller-scan.js --files` to see every counted line. The alias '
355
355
  + 'contract, the pinned OAuth callbacks, the uptime poller + smoke, the rename guardrails, '
356
356
  + 'tests/, docs/, migrations/ and captured fixtures are excluded by construction — and so is '
@@ -33,7 +33,7 @@ const { resolveCoreRoot, resolveInstanceRoot } = require('../../src/instance-con
33
33
  // live beside it — the shared roots/walkers and three check clusters. They are
34
34
  // IMPORTED (not registered by path) so the CHECKS array and module.exports below
35
35
  // stay byte-identical to the single-file version every test was written against.
36
- const { CORE_ROOT, INSTANCE_ROOT, MODULE_ROOTS, REPO_ROOT, rel, walkJs, walkJsAllRoots } = require('./fitness-lib.js');
36
+ const { CORE_ROOT, INSTANCE_ROOT, MODULE_ROOTS, REPO_ROOT, keyTokenRe, rel, walkJs, walkJsAllRoots } = require('./fitness-lib.js');
37
37
  const { IDENTITY_SCAN_ALLOWED, IDENTITY_SCAN_EXCLUDE, IDENTITY_SCAN_EXTRA_FILES, IDENTITY_SCAN_EXTS, IDENTITY_SCAN_ROOTS, IDENTITY_SCAN_SKIP_DIRS, PROMPT_IDENTITY_LITERALS, checkDesignContract, checkKernelPromptsNoHardcodedIdentity, checkNeutralConfigsNoHostIdentity, collectIdentityFiles, scanPromptIdentity, stripCommentsForIdentity } = require('./fitness-checks-identity.js');
38
38
  const { WRITE_VALIDATION_BASELINE, WRITE_VALIDATION_EXEMPT, checkWriteRoutesValidated, scanUnvalidatedWriteRoutes } = require('./fitness-checks-write-validation.js');
39
39
  const { GOAL_VOCAB_CITATION, GOAL_VOCAB_LINE_SCOPED, GOAL_VOCAB_SURFACE, LIFECYCLE_DB_FILES, PRELAUNCH_SURFACE, RENAME_IDENTITY_RE, VOCAB_ALLOW, VOCAB_BANNED, VOCAB_CITATION, VOCAB_EXTS, VOCAB_HISTORICAL_REF, VOCAB_SURFACE, checkGoalMembershipVocabulary, checkGovernmentRenameIdentity, checkPrelaunchVocabulary, checkVocabularyWall, vocabFilesToScan } = require('./fitness-checks-vocabulary.js');
@@ -683,15 +683,6 @@ function moduleDir(key) {
683
683
  return path.join(CORE_ROOT, 'modules', key);
684
684
  }
685
685
 
686
- // Match a module key as a DELIMITED token so `art-pipeline` hits in `'art-pipeline'` /
687
- // `mount('art-pipeline')` but never inside `art-pipelines` or `xart-pipeline`. Hyphens are
688
- // non-word chars, so the boundary guards against word-chars AND hyphens on both
689
- // sides (no lookbehind — portable on every node the unit gate runs).
690
- function keyTokenRe(key) {
691
- const esc = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
692
- return new RegExp(`(^|[^\\w-])${esc}($|[^\\w-])`);
693
- }
694
-
695
686
  // Pure: scan kernel source text for any hardcoded module key, skipping comment
696
687
  // lines. Returns violation strings (one per hit). Exported for the negative test
697
688
  // (mirrors scanScopeMapSource / scanDeterministicBody).
@@ -1350,6 +1341,7 @@ const CHECKS = [
1350
1341
  // Task 1003206 carved this file from 2,004 lines to ~1,350, so that toll is paid
1351
1342
  // and the check gets its own line back.
1352
1343
  require('./version-literal-guard.js').checkNoVersionLiterals,
1344
+ require('./dev-box-guard.js').checkNoDevBox, // task 1003899 / ADR 0346: the retired dev box stays out (its exemption list lives in that file)
1353
1345
  require('./control-manifest.js').checkControlsExist, // Check 21 — task 1003131: goal-1000076 controls assert their own existence (the ADR 0022 assurance-of-assurance)
1354
1346
  require('./routine-schedule.js').checkRoutineCadencesScheduled, // Check 25 — task 1003209: a routine that declares a cadence must have a scheduler firing it AT that period (ADR 0188)
1355
1347
  require('./baseline-staleness.js').checkBaselineFloors, // Check 26 — task 1003210: a shrink-only baseline that never shrinks is unmanaged debt; a floor exempting one must say why
@@ -208,8 +208,8 @@ function stripEsmExports(esm) {
208
208
  .replace(/^export default createClient;\n?/m, '');
209
209
  }
210
210
 
211
- // index.cjs — for Node consumers that use require() (e.g. the devbox Electron
212
- // app, which is a zero-dep CJS subproject and vendors this file at package time).
211
+ // index.cjs — for Node consumers that use require() (e.g. a zero-dep CJS subproject
212
+ // that vendors this file at package time).
213
213
  function renderClientCjs(esm) {
214
214
  const header =
215
215
  '// @bongos/client (CommonJS build) — GENERATED from index.mjs by\n' +
@@ -394,8 +394,8 @@ function renderPackageJson(spec) {
394
394
  // updated while the API it is generated FROM moved 500+ core versions. It had zero consumers
395
395
  // the whole time: nothing across the core or any instance repo ever declared it as a
396
396
  // dependency — every consumer VENDORS a copy instead. That was two places when this was
397
- // written; task 1003891 deleted the Dev Box Electron app and ADR 0324 retired
398
- // @cloudbongos/cli, so there is now no vendoring consumer left at all. The
397
+ // written; both have since been deleted or retired (ADR 0324 retired
398
+ // @cloudbongos/cli), so there is now no vendoring consumer left at all. The
399
399
  // owner removed it from the registry on 2026-09-09.
400
400
  //
401
401
  // The manifest itself stays: `main`/`types`/`exports` are what make the vendored copy and a
@@ -837,7 +837,7 @@ function buildOpenapi(model) {
837
837
  license: { name: 'AGPL-3.0-or-later', url: 'https://www.gnu.org/licenses/agpl-3.0.html' },
838
838
  description: [
839
839
  `The Bongos API — the build-methodology backend`,
840
- `(builders, tasks, claims, credits, grading, memory, dev boxes).`,
840
+ `(builders, tasks, claims, credits, grading, memory).`,
841
841
  ``,
842
842
  `**API version:** \`${API_VERSION}\` — served at \`${VERSIONED_API_PREFIX}\`. The`,
843
843
  `unversioned \`${API_PREFIX}\` and legacy \`/api/gds\` are permanent aliases`,
@@ -11,7 +11,7 @@
11
11
  // interpretive prose stays put while the file list / signatures can't silently drift.
12
12
  //
13
13
  // Zero-dependency on purpose: the codebase is CommonJS JS, and a portable-core capability must
14
- // regenerate in CI and on every dev box with no native build / no node-gyp / no WASM grammar to
14
+ // regenerate in CI and on any checkout with no native build / no node-gyp / no WASM grammar to
15
15
  // fetch (the whole point of Paths B+C is keeping every instance navigable cheaply). A line+regex
16
16
  // extractor is accurate enough for an *advisory* navigation aid (it is not a compiler input). A
17
17
  // richer tree-sitter/WASM backend can slot in behind extractFile() later for polyglot instances
@@ -25,9 +25,9 @@
25
25
  // node scripts/gds/gen-repo-map.js --check-block # exit 2 only if a TRACKED nested block would change (the CI gate)
26
26
  // node scripts/gds/gen-repo-map.js --check-whole # exit 2 only if docs/repo-map.md would change
27
27
  // node scripts/gds/gen-repo-map.js --whole-only # WRITE docs/repo-map.md only; never touch the
28
- // # tracked nested blocks (what a SPARSE dev-box
28
+ // # tracked nested blocks (what a SPARSE
29
29
  // # checkout must use — task 1002962)
30
- // docs/repo-map.md is GITIGNORED + regenerated at deploy/box-fetch since ADR 0110 (task 1926);
30
+ // docs/repo-map.md is GITIGNORED + regenerated at deploy since ADR 0110 (task 1926);
31
31
  // only the nested-doc symbol blocks stay tracked, so CI gates the block bucket, not the whole file.
32
32
  // node scripts/gds/gen-repo-map.js --json # print the extracted model as JSON (debug)
33
33
 
@@ -458,7 +458,7 @@ function injectBlock(existing, block) {
458
458
  function main() {
459
459
  // Two artifact BUCKETS, gated separately since ADR 0110 (task 1926):
460
460
  // • 'whole' — docs/repo-map.md, which is now GITIGNORED and regenerated at
461
- // deploy / box-source-fetch (the gen-atlas.js model), so it carries no
461
+ // deploy (the gen-atlas.js model), so it carries no
462
462
  // committed copy and two parallel branches can never collide on it.
463
463
  // • 'block' — the generated symbol BLOCK inside each nested CLAUDE.md, which
464
464
  // stays hand-written prose + a tracked block, so it MUST stay fresh in git.
@@ -472,16 +472,15 @@ function main() {
472
472
  // 1002962). --whole-only regenerates the GITIGNORED docs/repo-map.md and leaves
473
473
  // the TRACKED nested blocks alone.
474
474
  //
475
- // WHY a caller ever needs this: a dev box is a SPARSE checkout (box-access.js
476
- // materializes only the claim's module cone). The block ordering is
477
- // `b.refs - a.refs || name`, and `refs` counts references across the VISIBLE
478
- // corpus — so a box with 7 of 20 modules computes different counts and emits a
479
- // legitimately different block. Written into a tracked file that dirties the
480
- // working tree, and box-source-fetch.sh's NEXT `git pull` aborts with "local
481
- // changes would be overwritten" — a silent, permanent sync deadlock (one box sat
482
- // 257 commits behind for three days). A box CONSUMES these blocks; they arrive
483
- // correct with the pull, generated by CI from the whole tree. Only a full
484
- // checkout may produce them.
475
+ // WHY a caller ever needs this: a SPARSE checkout materializes only part of the
476
+ // tree. The block ordering is `b.refs - a.refs || name`, and `refs` counts
477
+ // references across the VISIBLE corpus — so a checkout with 7 of 20 modules
478
+ // computes different counts and emits a legitimately different block. Written
479
+ // into a tracked file that dirties the working tree, and the NEXT `git pull`
480
+ // aborts with "local changes would be overwritten" — a silent, permanent sync
481
+ // deadlock (one checkout sat 257 commits behind for three days). A sparse
482
+ // checkout CONSUMES these blocks; they arrive correct with the pull, generated
483
+ // by CI from the whole tree. Only a full checkout may produce them.
485
484
  const wholeOnly = process.argv.includes('--whole-only');
486
485
  const model = buildModel();
487
486