@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
@@ -1,11 +1,12 @@
1
1
  // tests/push_path_brief.mjs
2
2
  //
3
- // Task 1003259 / idea 1000838 — a dev-box agent, unable to see WHY its git probes were
4
- // failing, asked the owner to mint a PAT and store it on the box. push-path-brief.js is
5
- // the SessionStart line that states the credential model natively so that request never
6
- // gets made again. These tests pin BOTH halves: the line fires on the server-publish
7
- // path with the load-bearing phrases intact, and it is SILENT everywhere else — the
8
- // silence is half the design (a line firing on every healthy laptop becomes wallpaper).
3
+ // Task 1003259 / idea 1000838 — an agent on a checkout with no GitHub push credential, unable
4
+ // to see WHY its git probes were failing, asked the owner to mint a PAT and store it on the
5
+ // machine. push-path-brief.js is the SessionStart line that states the credential model
6
+ // natively so that request never gets made again. These tests pin BOTH halves: the line
7
+ // fires on the server-publish path with the load-bearing phrases intact, and it is SILENT
8
+ // everywhere else — the silence is half the design (a line firing on every healthy laptop
9
+ // becomes wallpaper).
9
10
  //
10
11
  // DB-free + network-free: briefLine is pure, and the CLI cases force the path with
11
12
  // OTB_PUSH_VIA_SERVER so pushVia() never spawns gh. Run: node tests/push_path_brief.mjs
@@ -31,14 +32,14 @@ t('server path gets the brief, with every load-bearing phrase', () => {
31
32
  const l = brief.briefLine('server');
32
33
  assert.ok(typeof l === 'string' && l.length > 0, 'expected a line on the server path');
33
34
  // Each phrase is one of the three facts the 2026-08-24 incident showed an agent
34
- // cannot infer from inside a box. Losing any of them re-opens the gap.
35
+ // cannot infer from inside such a checkout. Losing any of them re-opens the gap.
35
36
  for (const must of [
36
37
  'NO GitHub push credential',
37
38
  'BY DESIGN',
38
39
  '/builder-ship',
39
40
  'NEVER ask the owner for a PAT',
40
41
  'publish-status',
41
- // task 1003988: a box that cannot see which test failed re-pushes blind.
42
+ // task 1003988: a session that cannot see which test failed re-pushes blind.
42
43
  'merge_driver.failing_tests',
43
44
  'checks_unreadable',
44
45
  ]) {
@@ -58,7 +59,7 @@ t('undetermined path stays silent (fail-open, exact vocabulary only)', () => {
58
59
  });
59
60
 
60
61
  t('the line is the exported static constant — nothing is interpolated', () => {
61
- // Trust boundary: this string is injected into every box session's context. Pinning
62
+ // Trust boundary: this string is injected into every server-publish session's context. Pinning
62
63
  // it to the constant proves no builder-authored text can ever ride along.
63
64
  assert.equal(brief.briefLine('server'), brief.BRIEF);
64
65
  });
@@ -202,7 +202,7 @@ test('buildGradePayload confidence defaults to null when signals omit it', () =>
202
202
  //
203
203
  // The 'confirmed' answer hardcoded "run /merge-mode", which lands by pushing main
204
204
  // via push-main.js (SEC #863 / ADR 0043) and needs an authenticated gh plus a main
205
- // checkout. A server-mediated builder (pushVia()==='server' — every dev box) has
205
+ // checkout. A server-mediated builder (pushVia()==='server' — a checkout with no GitHub push credential) has
206
206
  // neither, so the advice was unreachable by construction. It cost a real builder
207
207
  // 163 minutes on 2026-08-21. strandNextStep already had the right wording for both
208
208
  // modes; these pin that the two modes now diverge and that neither regresses.
@@ -123,7 +123,7 @@ test('the alias mount passes while present and FAILS when dropped', () => {
123
123
  assert.equal(check.checkAliasMounts({ mounts: ['/api/bongos/v1', '/api/bongos', '/api/gds'], required }).ok, true);
124
124
 
125
125
  const r = check.checkAliasMounts({ mounts: ['/api/bongos/v1', '/api/bongos'], required });
126
- assert.equal(r.ok, false, 'shipped Dev Box binaries call the alias and cannot be force-updated');
126
+ assert.equal(r.ok, false, 'shipped binaries and live instances call the alias and cannot be force-updated');
127
127
  assert.deepEqual(r.missing, ['/api/gds']);
128
128
  });
129
129
 
@@ -94,14 +94,14 @@ test('extractor parses functions, classes, arrow consts, and module.exports', ()
94
94
  assert.ok(apiCall && apiCall.exported && apiCall.kind === 'fn', 'exported arrow/fn const detected with export flag');
95
95
  });
96
96
 
97
- test('--whole-only never writes a TRACKED nested block (the sparse-box deadlock guard, task 1002962)', () => {
98
- // A dev box is a SPARSE checkout — box-access.js materializes only the claim's
99
- // module cone. The block ordering is `b.refs - a.refs || name` and `refs` counts
100
- // references across the VISIBLE corpus, so a box with 7 of 20 modules emits a
101
- // legitimately different block. box-source-fetch.sh used to write it, dirtying
102
- // tracked files, and the NEXT `git pull` aborted on "local changes would be
103
- // overwritten" — a silent permanent sync deadlock (one box sat 257 commits behind
104
- // for three days). A box CONSUMES these blocks; only a full checkout may write them.
97
+ test('--whole-only never writes a TRACKED nested block (the sparse-checkout deadlock guard, task 1002962)', () => {
98
+ // A SPARSE checkout holds only part of the module tree. The block ordering is
99
+ // `b.refs - a.refs || name` and `refs` counts references across the VISIBLE
100
+ // corpus, so a checkout with 7 of 20 modules emits a legitimately different block.
101
+ // A fetch script used to write it, dirtying tracked files, and the NEXT `git pull`
102
+ // aborted on "local changes would be overwritten" — a silent permanent sync
103
+ // deadlock (one checkout sat 257 commits behind for three days). A sparse checkout
104
+ // CONSUMES these blocks; only a full checkout may write them.
105
105
  //
106
106
  // Asserted on CONTENT, not on the log line: dirty a tracked block, run --whole-only,
107
107
  // and require the block to come back byte-identical. A regression that re-enabled the
@@ -116,7 +116,7 @@ test('--whole-only never writes a TRACKED nested block (the sparse-box deadlock
116
116
  assert.equal(
117
117
  readFileSync(tracked, 'utf8'),
118
118
  drifted,
119
- '--whole-only rewrote a tracked nested block — this is the deadlock that stranded a box 257 commits behind',
119
+ '--whole-only rewrote a tracked nested block — this is the deadlock that stranded a checkout 257 commits behind',
120
120
  );
121
121
  assert.ok(!r.stdout.includes('CLAUDE.md'), `--whole-only must not report a nested-doc write; got: ${r.stdout.trim()}`);
122
122
  } finally {
@@ -46,12 +46,12 @@ const nothingExists = () => false;
46
46
  // ---------------------------------------------------------------------------
47
47
 
48
48
  test('reports a declared poller whose file was never shipped, naming module + seam', () => {
49
- const r = scanSeamWiring([mod('dev-box', { pollers: ['ghost'] })], { exists: nothingExists });
49
+ const r = scanSeamWiring([mod('discord', { pollers: ['ghost'] })], { exists: nothingExists });
50
50
  assert.equal(r.ok, false);
51
51
  assert.equal(r.findings.length, 1);
52
- assert.match(r.findings[0], /module "dev-box"/);
52
+ assert.match(r.findings[0], /module "discord"/);
53
53
  assert.match(r.findings[0], /contributes\.pollers: "ghost"/);
54
- assert.match(r.findings[0], /modules\/dev-box\/pollers\/ghost\.js does not exist/);
54
+ assert.match(r.findings[0], /modules\/discord\/pollers\/ghost\.js does not exist/);
55
55
  // and it says what to do about it — the three legitimate resolutions
56
56
  assert.match(r.findings[0], /Ship the artifact, drop the declaration, or record it in declarativeSeams\.pollers/);
57
57
  });
@@ -100,39 +100,39 @@ test('a disciplines entry absent from the registry is reported', () => {
100
100
 
101
101
  test('a declarative-only entry is recorded, not reported — the load-bearing nuance', () => {
102
102
  const r = scanSeamWiring(
103
- [mod('dev-box', { pollers: ['box-lifecycle'] }, { pollers: ['box-lifecycle'] })],
103
+ [mod('discord', { pollers: ['discord-bot'] }, { pollers: ['discord-bot'] })],
104
104
  { exists: nothingExists },
105
105
  );
106
106
  assert.equal(r.ok, true, r.findings.join('; '));
107
- assert.deepEqual(r.declarative, [{ key: 'dev-box', seam: 'pollers', entry: 'box-lifecycle' }]);
107
+ assert.deepEqual(r.declarative, [{ key: 'discord', seam: 'pollers', entry: 'discord-bot' }]);
108
108
  assert.deepEqual(r.wired, []);
109
109
  });
110
110
 
111
111
  test('the exemption is per-ENTRY, not a blanket skip of the seam', () => {
112
112
  const r = scanSeamWiring(
113
- [mod('dev-box', { pollers: ['box-lifecycle', 'ghost'] }, { pollers: ['box-lifecycle'] })],
113
+ [mod('discord', { pollers: ['discord-bot', 'ghost'] }, { pollers: ['discord-bot'] })],
114
114
  { exists: nothingExists },
115
115
  );
116
116
  assert.equal(r.ok, false);
117
117
  assert.equal(r.findings.length, 1);
118
118
  assert.match(r.findings[0], /"ghost"/);
119
- assert.deepEqual(r.declarative.map((d) => d.entry), ['box-lifecycle']);
119
+ assert.deepEqual(r.declarative.map((d) => d.entry), ['discord-bot']);
120
120
  });
121
121
 
122
122
  test('a STALE exemption — the artifact exists now — is itself reported', () => {
123
123
  const r = scanSeamWiring(
124
- [mod('dev-box', { pollers: ['box-lifecycle'] }, { pollers: ['box-lifecycle'] })],
125
- { exists: only('modules/dev-box/pollers/box-lifecycle.js') },
124
+ [mod('discord', { pollers: ['discord-bot'] }, { pollers: ['discord-bot'] })],
125
+ { exists: only('modules/discord/pollers/discord-bot.js') },
126
126
  );
127
127
  assert.equal(r.ok, false);
128
- assert.match(r.findings[0], /exempts pollers "box-lifecycle" as declarative-only, but modules\/dev-box\/pollers\/box-lifecycle\.js exists/);
128
+ assert.match(r.findings[0], /exempts pollers "discord-bot" as declarative-only, but modules\/discord\/pollers\/discord-bot\.js exists/);
129
129
  assert.match(r.findings[0], /drop the stale declarativeSeams\.pollers entry/);
130
130
  assert.deepEqual(r.declarative, [], 'a stale exemption must not also count as declarative-only');
131
131
  });
132
132
 
133
133
  test('an exemption on one seam does not leak to another seam of the same module', () => {
134
134
  const r = scanSeamWiring(
135
- [mod('dev-box', { pollers: ['x'], uiSections: ['x'] }, { pollers: ['x'] })],
135
+ [mod('discord', { pollers: ['x'], uiSections: ['x'] }, { pollers: ['x'] })],
136
136
  { exists: nothingExists },
137
137
  );
138
138
  assert.equal(r.findings.length, 1);
@@ -21,8 +21,8 @@
21
21
  // DB in a rolled-back transaction at ship time (the authoritative evidence).
22
22
  //
23
23
  // Run: node tests/search_isolation.mjs
24
- // (Layer C runs only where a Postgres is reachable — the integration gate / a
25
- // dev box; it skips cleanly otherwise so the DB-free unit gate stays green.)
24
+ // (Layer C runs only where a Postgres is reachable — the integration gate / any
25
+ // machine with one; it skips cleanly otherwise so the DB-free unit gate stays green.)
26
26
 
27
27
  import { strict as assert } from 'node:assert';
28
28
  import { createRequire } from 'node:module';
@@ -159,7 +159,7 @@ async function dbReachable() {
159
159
 
160
160
  const client = await dbReachable();
161
161
  if (!client) {
162
- console.log(' SKIP no reachable Postgres — Layer C runs in the integration gate / on a dev box.');
162
+ console.log(' SKIP no reachable Postgres — Layer C runs in the integration gate / wherever a Postgres is reachable.');
163
163
  console.log(' (The same scoping cases were proven on the prod DB in a rolled-back transaction at ship time.)');
164
164
  // END THE POOL ON THE SKIP PATH TOO (task 1003848). Only the else-branch below
165
165
  // ended it, so when Postgres was unreachable the Pool survived with libuv handles
@@ -397,7 +397,7 @@ test('buildSessionDigest accumulates per-model usage (model_usage), skipping syn
397
397
  });
398
398
 
399
399
  test('buildSessionDigest (task 1676): folds unlabeled token-bearing turns into a priceable model bucket', () => {
400
- // The dev-box/CI symptom: a token-bearing turn with no model id (or '<synthetic>')
400
+ // The CI symptom: a token-bearing turn with no model id (or '<synthetic>')
401
401
  // contributes to total_tokens but was DROPPED from model_usage — so the digest
402
402
  // stored total_tokens>0 yet priced to $0 (ADR 0097). The fix attributes the
403
403
  // unaccounted remainder to a real, priceable family bucket so cost-plus pays.
@@ -3,7 +3,7 @@
3
3
  // Two artefacts get renamed here, and the whole risk is in the fallback, not the rename:
4
4
  //
5
5
  // 1. ~/.config/<instance>/gds-session.json → bongos-session.json. This file is on disk on every
6
- // builder machine and every live dev box. Renaming it with no fallback signs all of them out
6
+ // builder machine. Renaming it with no fallback signs all of them out
7
7
  // at once and every /builder-* command dies with 'no Bongos session'.
8
8
  // 2. The `gds_session` browser cookie → `bongos_session`. Renaming it logs out every signed-in
9
9
  // session, the owner's included. The read-list is THREE names, because `pms_session` predates
@@ -66,7 +66,7 @@ test('clean main full clone, strictly behind → pull', () => {
66
66
 
67
67
  // ---------- pull: a clean, strictly-behind checkout self-heals (task 1284) ----------
68
68
  // FF is now safe on ANY branch and ANY clone type when ahead===0 and the tree is
69
- // clean — that's what lets a dev-box worktree (feature branch off a partial clone)
69
+ // clean — that's what lets a worktree (feature branch off a partial clone)
70
70
  // stop silently running stale code.
71
71
 
72
72
  test('feature branch, clean, ahead 0 → pull (self-heal, not warn)', () => {
@@ -75,13 +75,13 @@ test('feature branch, clean, ahead 0 → pull (self-heal, not warn)', () => {
75
75
  assert.equal(d.reason, 'safe-fast-forward');
76
76
  });
77
77
 
78
- test('partial/blobless clone, clean, ahead 0 → pull (boxes self-heal)', () => {
78
+ test('partial/blobless clone, clean, ahead 0 → pull (partial clones self-heal)', () => {
79
79
  const d = decideFreshness({ ...SAFE, isPartialClone: true });
80
80
  assert.equal(d.action, 'pull');
81
81
  assert.equal(d.reason, 'safe-fast-forward');
82
82
  });
83
83
 
84
- test('the dev-box case: feature branch + partial clone + clean + ahead 0 → pull', () => {
84
+ test('the partial-clone worktree case: feature branch + partial clone + clean + ahead 0 → pull', () => {
85
85
  const d = decideFreshness({ behind: 12, ahead: 0, branch: 'claude/poincare', hasTrackedChanges: false, isPartialClone: true });
86
86
  assert.equal(d.action, 'pull');
87
87
  assert.equal(d.reason, 'safe-fast-forward');
@@ -12,7 +12,7 @@
12
12
  // (2) is the one worth a real database. It is the whole reason the migration
13
13
  // backfills instead of letting sessions re-mint, and it can only be proved by
14
14
  // running the actual SQL against rows in the actual old shape. A mistake here
15
- // does not fail loudly in review — it signs out every builder and every dev box
15
+ // does not fail loudly in review — it signs out every builder
16
16
  // on deploy day, including whoever would have to log in to fix it.
17
17
  //
18
18
  // The sibling `session_token_hash.mjs` is DB-free and pins the hash itself plus
@@ -127,7 +127,7 @@ test('confirmed + bailed land: says NOT landed, names the reason, warns', () =>
127
127
  });
128
128
 
129
129
  test('confirmed + bailed land: the bail reaches the printed monospace card', () => {
130
- // The monospace card is the ALWAYS-printed fallback (headless, cron, dev box).
130
+ // The monospace card is the ALWAYS-printed fallback (headless, cron).
131
131
  // If the reason stops at the model, the builder still never sees it.
132
132
  const out = card.renderMonospaceCard(card.buildCardModel(bailed));
133
133
  assert.match(out, /NOT landed/);
@@ -298,8 +298,8 @@ test('pending is NOT a bail: no reason, so the card keeps "landing automatically
298
298
  assert.equal(o.reason, null);
299
299
  });
300
300
 
301
- test('strandCommand: a box gets the resume, a laptop gets /merge-mode', () => {
302
- // /merge-mode needs gh + a main checkout a dev box doesn't have (task 1052).
301
+ test('strandCommand: a server-publish checkout gets the resume, a laptop gets /merge-mode', () => {
302
+ // /merge-mode needs gh + a main checkout a credential-less checkout doesn't have (task 1052).
303
303
  assert.equal(strandCommand(77, 'server'), 'node scripts/gds/ship.js 77');
304
304
  assert.equal(strandCommand(77, 'local'), '/merge-mode');
305
305
  });
@@ -352,11 +352,11 @@ test('config/deploy.json — when present ships as ci; absent is fine on the neu
352
352
  'To roll back to operator-laptop deploys, set mode "laptop" AND disarm the PROD_DEPLOY_VIA_CI repo var.');
353
353
  });
354
354
 
355
- // ---- 6. shouldBailOnFetchFailure: the task-1037 dev-box publish fix ----
355
+ // ---- 6. shouldBailOnFetchFailure: the task-1037 server-publish fix ----
356
356
  //
357
357
  // autoMerge() ran `git fetch origin main` as a HARD precondition before
358
- // dispatching to the land path. A credential-less dev box (private origin,
359
- // scrubbed clone token — ADR 0053) can't fetch, so it bailed here and stranded
358
+ // dispatching to the land path. A credential-less checkout (private origin,
359
+ // no clone token) can't fetch, so it bailed here and stranded
360
360
  // every ship at confirmed — never reaching the ADR-0055 server-mediated publish
361
361
  // built precisely for it (the bug task 1027 surfaced). The fix makes a fetch
362
362
  // failure fatal ONLY off the server path. Truth table, proven without git:
@@ -367,8 +367,8 @@ test('shouldBailOnFetchFailure: fetch OK never bails (regardless of path)', () =
367
367
  assert.equal(shouldBailOnFetchFailure(true, 'laptop', 'local'), false);
368
368
  });
369
369
 
370
- test('shouldBailOnFetchFailure: fetch FAILED on the dev-box server path does NOT bail', () => {
371
- // The fix: ci + server (a credential-less box) proceeds to ciLandServer, which
370
+ test('shouldBailOnFetchFailure: fetch FAILED on the server-publish path does NOT bail', () => {
371
+ // The fix: ci + server (a credential-less checkout) proceeds to ciLandServer, which
372
372
  // bundles against the local origin/main while the server tops up main.
373
373
  assert.equal(shouldBailOnFetchFailure(false, 'ci', 'server'), false);
374
374
  });
@@ -424,15 +424,15 @@ test('classifyLandOutcome: NOT merged + deploy unconfigured → pending, never s
424
424
  assert.equal(classifyLandOutcome({ pr_state: 'closed', merged: false, deploy_status: 'unconfigured' }), 'failed');
425
425
  });
426
426
 
427
- // ---- 8. strandNextStep: box-aware recovery guidance, never gh-only /merge-mode on a box (task 1052) ----
428
- // The #1027 retrospective: a confirmed-strand on a dev box pointed the builder at
429
- // /merge-mode, which needs gh + a main checkout a box lacks — a dead end.
427
+ // ---- 8. strandNextStep: recovery guidance that fits the push path, never gh-only /merge-mode on the server path (task 1052) ----
428
+ // The #1027 retrospective: a confirmed-strand on a server-publish checkout pointed the builder at
429
+ // /merge-mode, which needs gh + a main checkout that checkout lacks — a dead end.
430
430
 
431
- test('strandNextStep: a dev box (via "server") is pointed at resume, NOT /merge-mode', () => {
431
+ test('strandNextStep: a server-publish checkout (via "server") is pointed at resume, NOT /merge-mode', () => {
432
432
  const s = strandNextStep(1027, 'server');
433
433
  assert.match(s, /ship\.js 1027/, 'names the resume command with the task id');
434
434
  assert.match(s, /resume|resumes/i);
435
- assert.match(s, /NOT available/, 'explicitly says /merge-mode is not available on a box');
435
+ assert.match(s, /NOT available/, 'explicitly says /merge-mode is not available there');
436
436
  });
437
437
 
438
438
  test('strandNextStep: a laptop (via "local") keeps /merge-mode, with resume as the alternative', () => {
@@ -441,25 +441,25 @@ test('strandNextStep: a laptop (via "local") keeps /merge-mode, with resume as t
441
441
  assert.match(s, /ship\.js 1027/, 'and resume is offered as the alternative');
442
442
  });
443
443
 
444
- test('task 1046: regenerateDiagrams SKIPS on the dev-box (server-publish) path and leaves the tree untouched', () => {
444
+ test('task 1046: regenerateDiagrams SKIPS on the server-publish path and leaves the tree untouched', () => {
445
445
  const { execSync } = require('node:child_process');
446
446
  const ROOT = path.resolve(__dirname, '..');
447
447
  const status = () => execSync('git status --porcelain docs/onboarding/diagrams', { cwd: ROOT }).toString();
448
448
  const before = status();
449
449
  const prev = process.env.OTB_PUSH_VIA_SERVER;
450
- process.env.OTB_PUSH_VIA_SERVER = '1'; // force pushVia()==='server' (a credential-less dev box)
450
+ process.env.OTB_PUSH_VIA_SERVER = '1'; // force pushVia()==='server' (a credential-less checkout)
451
451
  try {
452
- // On a box there is no headless browser; attempting the render strands the
452
+ // On the server-publish path there is no headless browser; attempting the render strands the
453
453
  // regenerated .mmd + assertions.json UNCOMMITTED in the tree (#1046). The
454
454
  // guard must return early BEFORE any regen/render, so the call is a pure no-op.
455
455
  assert.equal(ship.regenerateDiagrams(), 'skipped-server',
456
- 'on a dev box the diagram regen must skip entirely (no render attempt)');
456
+ 'on the server-publish path the diagram regen must skip entirely (no render attempt)');
457
457
  } finally {
458
458
  if (prev === undefined) delete process.env.OTB_PUSH_VIA_SERVER;
459
459
  else process.env.OTB_PUSH_VIA_SERVER = prev;
460
460
  }
461
461
  assert.equal(status(), before,
462
- '#1046: the dev-box skip must not write or stage any diagram artifact (no uncommitted .mmd/assertions left behind)');
462
+ '#1046: the server-publish skip must not write or stage any diagram artifact (no uncommitted .mmd/assertions left behind)');
463
463
  });
464
464
 
465
465
  // ---- 9. pickStaleGateReviewRun: the gate-author-trust re-run nudge (task 1169) ----
@@ -43,7 +43,7 @@ t('decidePreMerge: single commit behind still merges', () => {
43
43
  assert.equal(ship.decidePreMerge({ branch: 'claude/feat', behind: 1 }).action, 'merge');
44
44
  });
45
45
 
46
- // idea #364: a credential-less partial-clone dev box (pushVia 'server') cannot run
46
+ // idea #364: a credential-less partial-clone checkout (pushVia 'server') cannot run
47
47
  // the local `git merge origin/main` (no creds to lazily fetch main's blobs) and
48
48
  // does not need to — the server reconciles with main at publish time (ADR 0055).
49
49
  // So the server path SKIPS the pre-merge regardless of how far behind it is, while
@@ -8,7 +8,7 @@
8
8
  // strands the task with no claim:
9
9
  // - grade fail → task stuck at `completed` → re-run should RE-GRADE
10
10
  // - merge/deploy fail → task stuck at `confirmed` → re-run should RE-MERGE
11
- // (the exact task-1027 dev-box nightmare)
11
+ // (the exact task-1027 nightmare)
12
12
  // evaluateResumeAction is the pure decision behind that routing. We prove the
13
13
  // full truth table here — no git, no network.
14
14
  //
@@ -2,8 +2,8 @@
2
2
  // guards-skill-declares-machine.
3
3
  //
4
4
  // THE INCIDENT. /merge-mode states in its own prose that it assumes the Archon's
5
- // Mac or the droplet. It was run on a dev box anyway — and ship.js ALREADY knew,
6
- // because strandNextStep() tells a box "/merge-mode is NOT available here". The
5
+ // Mac or the droplet. It was run on a checkout with no gh and no main checkout anyway — and ship.js
6
+ // ALREADY knew, because strandNextStep() tells such a checkout "/merge-mode is NOT available here". The
7
7
  // knowledge existed in two places and neither stopped the run: prose cannot
8
8
  // refuse, and the one executable copy sat on a different code path.
9
9
  //
@@ -4,7 +4,7 @@
4
4
  //
5
5
  // modules/security/tests/sanitize_rebuild.mjs gated its two physical-confinement symlink
6
6
  // cases behind canSymlink() and, in the else-branch, printed `ok` and did `passed += 2`.
7
- // So on any machine that cannot create symlinks — the Windows dev box, a container without
7
+ // So on any machine that cannot create symlinks — a Windows machine, a container without
8
8
  // CAP_SYMLINK, a non-admin account — the suite reported two passes for two cases that never
9
9
  // ran, and those two are the ONLY coverage of physical confinement.
10
10
  //
@@ -500,7 +500,7 @@ await ta('a session of an undeclared source (a leftover dev-box token) cannot mi
500
500
  pool.accounts.clear();
501
501
  const res = await authorize();
502
502
  assert.equal(res.status, 403);
503
- assert.equal(pool.accounts.size, 0, 'a box-scoped session recorded a platform T&C acceptance');
503
+ assert.equal(pool.accounts.size, 0, 'a session of an undeclared source recorded a platform T&C acceptance');
504
504
  });
505
505
 
506
506
  // ===========================================================================