@bongos/core 1.19.1074 → 1.19.1075

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 (114) hide show
  1. package/.bongos-core.json +122 -122
  2. package/bin/bongos.js +1 -3
  3. package/docs/api/openapi.json +4 -4
  4. package/docs/module-api-changelog.md +2 -0
  5. package/modules/copy-desk/routes/copy-desk.js +1 -1
  6. package/modules/discord/ship-broadcast.js +3 -3
  7. package/modules/economy/credits.js +2 -2
  8. package/modules/ideas/projection.js +1 -1
  9. package/modules/lifecycle/db-ship.js +4 -4
  10. package/modules/lifecycle/github-push.js +12 -14
  11. package/modules/lifecycle/publish-reconciler.js +10 -10
  12. package/modules/lifecycle/routes/tasks.js +8 -8
  13. package/modules/lifecycle/ship-card.js +1 -1
  14. package/modules/lifecycle/task-visuals.js +2 -2
  15. package/modules/memory/routes/memory.js +2 -2
  16. package/modules/platform-identity/routes/sso.js +3 -2
  17. package/modules/provisioning/capacity.js +1 -1
  18. package/modules/provisioning/provisioning.js +4 -3
  19. package/modules/provisioning/routes/provisioning.js +4 -4
  20. package/modules/sessions/db.js +1 -1
  21. package/package-lock.json +2 -2
  22. package/package.json +1 -1
  23. package/release-notes.json +6 -0
  24. package/scripts/gds/artifact-staleness.js +2 -2
  25. package/scripts/gds/backfill-task-rewards.js +5 -5
  26. package/scripts/gds/claude-materialize.js +2 -2
  27. package/scripts/gds/cli-lib.js +7 -7
  28. package/scripts/gds/codemod-rename-src-gds.js +1 -1
  29. package/scripts/gds/context-pack.js +5 -7
  30. package/scripts/gds/doctor.js +3 -3
  31. package/scripts/gds/fitness-checks-packaging.js +4 -4
  32. package/scripts/gds/fitness-ratchets.js +1 -1
  33. package/scripts/gds/gen-api-client.js +4 -4
  34. package/scripts/gds/gen-api-docs.js +1 -1
  35. package/scripts/gds/gen-repo-map.js +13 -14
  36. package/scripts/gds/gen-session-index.js +8 -8
  37. package/scripts/gds/leak-scan-allowlist.js +1 -1
  38. package/scripts/gds/plain-cards.js +1 -1
  39. package/scripts/gds/push-path-brief.js +10 -10
  40. package/scripts/gds/rename-history-check.js +1 -1
  41. package/scripts/gds/session-digest-build.js +2 -2
  42. package/scripts/gds/ship-deploy-target.js +13 -13
  43. package/scripts/gds/ship-flow.js +1 -1
  44. package/scripts/gds/ship-land.js +6 -6
  45. package/scripts/gds/ship-merge.js +4 -4
  46. package/scripts/gds/ship-preflight-steps.js +4 -4
  47. package/scripts/gds/ship-regen.js +9 -12
  48. package/scripts/gds/ship.js +9 -9
  49. package/scripts/gds/skill-preflight.js +9 -8
  50. package/src/bongos/api-prefix.js +4 -4
  51. package/src/bongos/platform-visibility-gate.js +1 -1
  52. package/src/bongos/routes/me.js +1 -1
  53. package/src/bongos/routes/security.js +3 -3
  54. package/src/bongos/routes.js +2 -2
  55. package/src/bongos/serve-internal.js +5 -6
  56. package/src/bongos-downloads.js +1 -6
  57. package/src/branding.js +2 -2
  58. package/src/build-info.js +4 -6
  59. package/src/instance-config.js +2 -2
  60. package/src/module-api.js +3 -3
  61. package/src/module-loader/manifest-schema.js +1 -1
  62. package/tests/api_alias_caller_ratchet.mjs +1 -1
  63. package/tests/api_alias_exceptions.mjs +1 -1
  64. package/tests/api_client.mjs +1 -1
  65. package/tests/api_path_404.mjs +1 -1
  66. package/tests/backfill_task_rewards.mjs +1 -1
  67. package/tests/{box_ship_permissions.mjs → cli_allowlist_permissions.mjs} +5 -5
  68. package/tests/cli_sessions.mjs +1 -1
  69. package/tests/context_pack.mjs +13 -13
  70. package/tests/copy_inventory.mjs +7 -7
  71. package/tests/credit_grant.mjs +2 -2
  72. package/tests/criterion_suggest.mjs +1 -1
  73. package/tests/design_tokens_sync.mjs +3 -2
  74. package/tests/fitness_ratchets.mjs +2 -2
  75. package/tests/github_push_land_proof.mjs +1 -1
  76. package/tests/goal_advisory.mjs +3 -3
  77. package/tests/goal_suggest.mjs +3 -3
  78. package/tests/government_abuse_matrix.mjs +4 -3
  79. package/tests/hall_audit.mjs +1 -1
  80. package/tests/helpers.mjs +1 -1
  81. package/tests/host_topology_skips.mjs +2 -2
  82. package/tests/migration_namespace.mjs +6 -6
  83. package/tests/module_api.mjs +2 -2
  84. package/tests/module_cli.mjs +5 -5
  85. package/tests/module_manifest.mjs +13 -13
  86. package/tests/module_route_rank.mjs +2 -2
  87. package/tests/modules_route_wiring.mjs +1 -1
  88. package/tests/onboarding_route_signals.mjs +1 -1
  89. package/tests/paste_token_session_store.mjs +1 -1
  90. package/tests/platform_visibility_gate.mjs +1 -1
  91. package/tests/project_modules_ui.mjs +17 -17
  92. package/tests/projects_hub_module_picker.mjs +75 -74
  93. package/tests/provisioning_capacity.mjs +1 -1
  94. package/tests/provisioning_recommendations.mjs +2 -1
  95. package/tests/publish_branch_route.mjs +1 -1
  96. package/tests/publish_manifest.mjs +1 -1
  97. package/tests/publish_reconciler.mjs +8 -8
  98. package/tests/push_path_brief.mjs +10 -9
  99. package/tests/regrade_eligibility.mjs +1 -1
  100. package/tests/rename_history_restraint.mjs +1 -1
  101. package/tests/repo_map.mjs +9 -9
  102. package/tests/seam_wiring_guard.mjs +11 -11
  103. package/tests/search_isolation.mjs +3 -3
  104. package/tests/session_records.mjs +1 -1
  105. package/tests/session_rename_fallback.mjs +1 -1
  106. package/tests/session_start_freshness.mjs +3 -3
  107. package/tests/session_token_hash_db.mjs +1 -1
  108. package/tests/ship_card.mjs +1 -1
  109. package/tests/ship_ci_deploy.mjs +17 -17
  110. package/tests/ship_premerge.mjs +1 -1
  111. package/tests/ship_resume.mjs +1 -1
  112. package/tests/skill_preflight.mjs +2 -2
  113. package/tests/skip_is_not_pass.mjs +1 -1
  114. package/tests/terms_acceptance.mjs +1 -1
@@ -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
  //
@@ -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
@@ -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 '
@@ -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
 
@@ -26,8 +26,8 @@
26
26
  // node scripts/gds/gen-session-index.js --check-block # exit 2 only if the tracked CLAUDE.md §13 snippet drifts (CI gate)
27
27
  // node scripts/gds/gen-session-index.js --check-whole # exit 2 only if docs/session-log-index.md drifts
28
28
  // node scripts/gds/gen-session-index.js --whole-only # WRITE the index only; never touch the tracked
29
- // # CLAUDE.md snippet (sparse dev-box use; task 1002962)
30
- // docs/session-log-index.md is GITIGNORED + regenerated at deploy/box-fetch since ADR 0110 (task 1926).
29
+ // # CLAUDE.md snippet (sparse-checkout use; task 1002962)
30
+ // docs/session-log-index.md is GITIGNORED + regenerated at deploy since ADR 0110 (task 1926).
31
31
  // node scripts/gds/gen-session-index.js --json # print the parsed entries as JSON (debug)
32
32
 
33
33
  const fs = require('node:fs');
@@ -164,7 +164,7 @@ function computeWrites() {
164
164
  const writes = [];
165
165
 
166
166
  // Two buckets (ADR 0110, task 1926): 'whole' = docs/session-log-index.md, now
167
- // GITIGNORED + regenerated at deploy/box-fetch (no committed copy → no branch
167
+ // GITIGNORED + regenerated at deploy (no committed copy → no branch
168
168
  // collisions); 'block' = the bounded CLAUDE.md §13 snippet, still tracked, so it
169
169
  // stays a HARD CI gate. main() gates them separately (--check-block vs --check-whole).
170
170
  const idxNext = renderIndex(entries);
@@ -197,11 +197,11 @@ function main() {
197
197
  return;
198
198
  }
199
199
  // WRITE-side bucket selection — the sibling of the --check-* flags (task 1002962,
200
- // the gen-repo-map --whole-only twin). A dev box is a SPARSE checkout, so writing
201
- // the TRACKED bucket there dirties the tree and the next `git pull` in
202
- // box-source-fetch.sh aborts on "local changes would be overwritten" — a silent,
203
- // permanent sync deadlock. A box regenerates only the gitignored artifact; the
204
- // tracked CLAUDE.md §13 snippet arrives with the pull, generated from the whole tree.
200
+ // the gen-repo-map --whole-only twin). On a SPARSE checkout, writing the TRACKED
201
+ // bucket dirties the tree and the next `git pull` aborts on "local changes would
202
+ // be overwritten" — a silent, permanent sync deadlock. A sparse checkout
203
+ // regenerates only the gitignored artifact; the tracked CLAUDE.md §13 snippet
204
+ // arrives with the pull, generated from the whole tree.
205
205
  const wholeOnly = process.argv.includes('--whole-only');
206
206
  const all = computeWrites().writes;
207
207
  const writes = wholeOnly ? all.filter((w) => w.bucket === 'whole') : all;
@@ -167,7 +167,7 @@ const FILE_ALLOWLIST = [
167
167
  path: 'tests/lib_sh_resolution.mjs',
168
168
  classes: ['token'],
169
169
  reason:
170
- 'Carries the host-identity scan pattern it runs over the baked box scripts — a detector '
170
+ 'Carries the host-identity scan pattern it runs over the bash smoke scripts — a detector '
171
171
  + 'pattern, the same case as fitness-checks-identity.js.',
172
172
  },
173
173
  {
@@ -8,7 +8,7 @@
8
8
  // what happened, what the agent will do next, whether a PERSON is needed (and who), and
9
9
  // whether this is a rule rather than a fault. That last one is the expensive mistake:
10
10
  // an agent that reads a deliberate restriction as breakage goes looking for a way round
11
- // it (the box session that asked the owner for a personal access token).
11
+ // it (the agent that asked the owner for a personal access token).
12
12
  //
13
13
  // STATIC TEXT ONLY. A card interpolates nothing — no task title, no server message — so
14
14
  // printing it adds no prompt-injection surface (the strand-watch / push-path-brief rule).
@@ -4,19 +4,19 @@
4
4
  // scripts/gds/push-path-brief.js — say out loud, at session start, that this machine
5
5
  // cannot push (task 1003259 / idea 1000838).
6
6
  //
7
- // THE GAP. On 2026-08-24 a dev-box agent hit auth failures on every raw git probe,
8
- // concluded "no push credential exists", and asked the owner to mint a fine-grained
9
- // PAT and store it in ~/.git-credentials on the box — the exact anti-pattern the
10
- // server-mediated publish path (ADR 0055) exists to avoid. The agent was not being
11
- // careless: from inside a box every direct GitHub probe fails BY DESIGN (the clone
12
- // token is one-shot and scrubbed from .git/config after each fetch — ADR 0031 §6),
7
+ // THE GAP. On 2026-08-24 an agent on a credential-less checkout hit auth failures on
8
+ // every raw git probe, concluded "no push credential exists", and asked the owner to
9
+ // mint a fine-grained PAT and store it in ~/.git-credentials — the exact anti-pattern
10
+ // the server-mediated publish path (ADR 0055) exists to avoid. The agent was not being
11
+ // careless: on that checkout every direct GitHub probe failed BY DESIGN (the
12
+ // clone token was one-shot and scrubbed from .git/config after each fetch — ADR 0031 §6),
13
13
  // so "missing credential" is the only story the local evidence supports, and the true
14
14
  // state at the time (branch already pushed, PR open, CI red) was invisible to it.
15
- // Nothing the box session loads says the model out loud. This says it out loud.
15
+ // Nothing the session loads says the model out loud. This says it out loud.
16
16
  //
17
17
  // SO: the third SessionStart truth-teller, beside deploy-divergence.js and
18
18
  // strand-watch.js. On the server-publish path (pushVia() 'server' — no authenticated
19
- // gh, i.e. a dev box or any credential-less checkout) it prints ONE line stating the
19
+ // gh, i.e. any credential-less checkout) it prints ONE line stating the
20
20
  // credential model and where the truth about published work lives
21
21
  // (GET /api/bongos/tasks/:id/publish-status). On a laptop that pushes locally
22
22
  // (pushVia() 'local') it prints NOTHING — a line that fires on every healthy laptop
@@ -58,7 +58,7 @@ function briefLine(via) {
58
58
 
59
59
  // Lazy require so a broken or partial checkout degrades to silence, not a stack
60
60
  // trace injected into the session. pushVia() honors <PREFIX>_PUSH_VIA_SERVER, else
61
- // probes for an authenticated gh (absent on every box → 'server' instantly).
61
+ // probes for an authenticated gh (absent on a credential-less checkout → 'server' instantly).
62
62
  function detectVia() {
63
63
  return require('./ship-deploy-target.js').pushVia();
64
64
  }
@@ -70,7 +70,7 @@ function report(via) {
70
70
  console.log(' Publish path');
71
71
  console.log(' ──────────────────────────────────────────────────────────');
72
72
  if (via === 'server') {
73
- console.log(' server-mediated (no authenticated gh — a dev box or credential-less checkout).');
73
+ console.log(' server-mediated (no authenticated gh — a credential-less checkout).');
74
74
  console.log(` ${BRIEF}`);
75
75
  for (const line of plainCardLines('no_push_credential')) console.log(line);
76
76
  } else if (via === 'local') {
@@ -45,7 +45,7 @@
45
45
  // notices if a blanket find-replace rewrites them. This does.
46
46
  //
47
47
  // 4. ALIAS MOUNTS — '/api/gds' is a PERMANENT alias (src/bongos/api-prefix.js
48
- // says never to remove it: shipped Dev Box binaries and live dev boxes
48
+ // says never to remove it: shipped binaries and live instances
49
49
  // call it and cannot be force-updated). Asserted against the real exported
50
50
  // mount list. The DISPATCH half — that the alias is a live mount and so
51
51
  // gets no corrective 404 hint — is already covered by
@@ -155,7 +155,7 @@ function buildSessionDigest(entries, opts = {}) {
155
155
  mu.input += tin; mu.output += tout; mu.cache_read += tcr; mu.cache_creation += tcc;
156
156
  } else {
157
157
  // task 1676: a token-bearing turn with NO model id. Previously dropped
158
- // from model_usage (→ total_tokens>0 but priced $0 on the dev-box/CI
158
+ // from model_usage (→ total_tokens>0 but priced $0 on the CI
159
159
  // path; ADR 0097). Accumulate the unlabeled tokens so the digest can
160
160
  // attribute them to a real, priceable family bucket after the loop.
161
161
  m._unlabeled.input += tin; m._unlabeled.output += tout;
@@ -233,7 +233,7 @@ function buildSessionDigest(entries, opts = {}) {
233
233
  m.total_tokens = m.tokens.input + m.tokens.output + m.tokens.cache_read + m.tokens.cache_creation;
234
234
  // task 1676 — cost-plus reward zero-out fix. The cost-plus session reward
235
235
  // (ADR 0054) prices `model_usage` server-side. model_usage is keyed on msg.model
236
- // and SKIPS any token-bearing turn whose model id is missing. On the dev-box/CI
236
+ // and SKIPS any token-bearing turn whose model id is missing. On the CI
237
237
  // agent path that gap was the difference between total_tokens>0 (so the digest
238
238
  // passes the route's empty-session guard + gets stored) and model_usage={} (so
239
239
  // priceModelUsage returns $0 → 0 drachmae) — ADR 0097's "upload no priced model
@@ -32,7 +32,7 @@ const { REPO_ROOT } = require('./ship-state.js');
32
32
  // `bongos upgrade` (pin-bump), NOT an SSH deploy (ADR 0108). When a target IS
33
33
  // set it requires that host's SSH key, so only the operator can land.
34
34
  //
35
- // 'ci' — NO builder box holds the prod key. ship pushes the branch, opens a
35
+ // 'ci' — NO builder machine holds the prod key. ship pushes the branch, opens a
36
36
  // PR, and enables GitHub auto-merge; once required checks pass, GitHub
37
37
  // merges to main and .github/workflows/deploy-prod.yml deploys from
38
38
  // Actions. ship then CONFIRMS the deploy landed (PR merged + the
@@ -62,8 +62,8 @@ function parseDeployMode(envVal, configRaw) {
62
62
  // effectiveDeployMode — credential- and protection-aware adjustment of the parsed
63
63
  // mode (pure; exported for the regression test). The 'laptop' land path pushes
64
64
  // main + SSHes the droplet FROM THIS MACHINE, so it requires a local GitHub push
65
- // credential. A machine without one — a dev box, or a fresh/stale local clone that
66
- // can't even `git pull` (token-less origin, ADR 0053) — physically cannot run it;
65
+ // credential. A machine without one — a fresh/stale local clone that can't
66
+ // even `git pull` (token-less origin, ADR 0053) — physically cannot run it;
67
67
  // it must ship via the 'ci' server-mediated publish path instead
68
68
  // (pushVia()==='server', ADR 0055), which lets the GDS server push with its own
69
69
  // credential. So when the parsed mode is 'laptop' but the machine can't push
@@ -314,10 +314,10 @@ function fetchDeployedVersion(url = deployedVersionUrl()) {
314
314
  // pushVia — which publish path ship uses in 'ci' mode (ADR 0055 / task 1025):
315
315
  // 'local' — this machine pushes the branch + opens the PR with git + gh
316
316
  // (laptop: gh present + authenticated). Today's behaviour.
317
- // 'server' — this machine has NO GitHub push credential (a dev box: no gh, a
317
+ // 'server' — this machine has NO GitHub push credential (no gh, a
318
318
  // credential-less origin). ship uploads a thin branch bundle to the
319
319
  // GDS, which pushes + opens the PR + auto-merges with the SERVER's
320
- // credential. The box holds nothing (#919 model preserved).
320
+ // credential. This machine holds nothing (#919 model preserved).
321
321
  // Override with <PREFIX>_PUSH_VIA_SERVER=1 (force server) / =0 (force local) for tests.
322
322
  function ghAvailableAndAuthed() {
323
323
  try {
@@ -338,15 +338,15 @@ function pushVia() {
338
338
  if (o === '1') return 'server';
339
339
  if (o === '0') return 'local';
340
340
  // No explicit override: a machine that can run an authenticated gh (laptop)
341
- // takes the local path; everything else (a dev box) goes server-mediated.
341
+ // takes the local path; everything else goes server-mediated.
342
342
  return ghAvailableAndAuthed() ? 'local' : 'server';
343
343
  }
344
344
 
345
345
  // broadcastHandledByServer — task 1045: on the server-mediated publish path the
346
346
  // SERVER posts the Discord ship-broadcast after it confirms the deploy (it holds
347
- // the webhook secrets; the box does NOT — ADR 0053). So ship.js must NOT also post
348
- // locally there, or the box would either double-post (impossible — no secret) or,
349
- // as before, fail silently. True only when the publish actually goes server-side:
347
+ // the webhook secrets; the local machine does NOT — ADR 0053). So ship.js must NOT
348
+ // also post locally there, or this machine would either double-post (impossible — no
349
+ // secret) or, as before, fail silently. True only when the publish actually goes server-side:
350
350
  // ci deploy mode AND this machine has no GitHub push credential (pushVia 'server').
351
351
  // The laptop path (pushVia 'local') keeps posting locally, exactly as today. Pure
352
352
  // w.r.t. its inputs (env + committed deploy.json) + exported so the gate is tested.
@@ -355,12 +355,12 @@ function broadcastHandledByServer() {
355
355
  }
356
356
 
357
357
  // shouldBailOnFetchFailure — autoMerge's decision when `git fetch origin main`
358
- // fails. A credential-less dev box (private origin, scrubbed clone token —
358
+ // fails. A credential-less checkout (private origin, no creds —
359
359
  // ADR 0053) CANNOT fetch origin, and that is FINE for the server-mediated
360
- // publish path (ADR 0055): ciLandServer bundles against the box's LOCAL
360
+ // publish path (ADR 0055): ciLandServer bundles against this machine's LOCAL
361
361
  // origin/main and the SERVER tops up main with its own credential. So a fetch
362
- // failure is fatal ONLY when we are NOT taking that path — otherwise the box can
363
- // never reach ciLand and strands every ship at confirmed (the bug task 1027
362
+ // failure is fatal ONLY when we are NOT taking that path — otherwise such a
363
+ // machine can never reach ciLand and strands every ship at confirmed (the bug task 1027
364
364
  // surfaced: ADR 0055 shipped the server path but left this fetch guard in front
365
365
  // of it). Pure + exported for the regression test (no git, no network).
366
366
  // NOTE: callers must still guard the pushVia() gh-probe behind `!fetchedMain` so
@@ -318,7 +318,7 @@ async function shipMain() {
318
318
 
319
319
  // ---- Module drift check (BV1.R53, task 1422) ----
320
320
  // If the task carries a module_key, verify the committed diff doesn't stray
321
- // into a DIFFERENT module's territory. "You said game, you touched dev-box" is
321
+ // into a DIFFERENT module's territory. "You said game, you touched provisioning" is
322
322
  // the semantic violation this catches. Files no module owns are allowed —
323
323
  // they're cross-cutting — as is the territory of a CROSS-CUTTING module, which
324
324
  // every craft legitimately writes into. Only contact with a different OWNING
@@ -274,11 +274,11 @@ function reconciledCardStatus(liveStatus, preMergeStatus) {
274
274
  return liveStatus === 'shipped' ? 'shipped' : preMergeStatus;
275
275
  }
276
276
 
277
- // task 1052 (E): the box-appropriate next step when a ship lands the task at
278
- // 'confirmed' without finishing. A dev box (pushVia 'server' — no authed gh)
279
- // CANNOT run /merge-mode (it needs gh + a main checkout), so the old "for
280
- // /merge-mode" advice was a dead end ON A BOX (the #1027 retrospective: the agent
281
- // had to reverse-engineer recovery from source). Point a box at the resume
277
+ // task 1052 (E): the machine-appropriate next step when a ship lands the task at
278
+ // 'confirmed' without finishing. A machine with no push credential (pushVia 'server' —
279
+ // no authed gh) CANNOT run /merge-mode (it needs gh + a main checkout), so the old
280
+ // "for /merge-mode" advice was a dead end there (the #1027 retrospective: the agent
281
+ // had to reverse-engineer recovery from source). Point such a machine at the resume
282
282
  // instead (task 941); a laptop keeps /merge-mode (with resume as the alternative).
283
283
  // Pure + exported for unit tests.
284
284
  function strandNextStep(taskId, via) {
@@ -371,7 +371,7 @@ function prAssigneeLine(login) {
371
371
  }
372
372
 
373
373
  // task 1003988 — what to tell a builder while their PR sits RED. The poll used to
374
- // wait out its nine minutes in silence, so a credential-less box learned only that
374
+ // wait out its nine minutes in silence, so a credential-less checkout learned only that
375
375
  // the land was "pending" and pushed the same commit again (PR 922: nine red runs).
376
376
  // `md` is publish-status's merge_driver; null means nothing red to report. Pure +
377
377
  // exported so the wording is pinned by tests/unit_report_status.mjs.
@@ -103,7 +103,7 @@ function regenerateShipArtifacts() {
103
103
  regenerateCopyInventory();
104
104
  // Refresh the generated OpenAPI spec + API reference from the shipped route tree (task 1918).
105
105
  regenerateApiDocs();
106
- // ...then the typed client FROM that spec (+ the devbox vendored copy) on the same beat (task 2051).
106
+ // ...then the typed client FROM that spec on the same beat (task 2051).
107
107
  regenerateApiClient();
108
108
  }
109
109
 
@@ -168,10 +168,10 @@ async function mergeLocally(taskId, valueSummary, { dbOnly = false } = {}) {
168
168
  // nothing to push, merge, or deploy. Short-circuit so the caller's POST
169
169
  // /tasks/:id/ship still flips status to shipped instead of stranding the
170
170
  // task at confirmed forever.
171
- // A credential-less dev box can't `git fetch origin main` (private origin, no
171
+ // A credential-less checkout can't `git fetch origin main` (private origin, no
172
172
  // creds — ADR 0053), but that's only fatal OFF the server-publish path: the
173
- // box's ADR-0055 path bundles against its LOCAL origin/main and the server tops
174
- // up main. Without this, the box dead-ends here and strands every ship at
173
+ // ADR-0055 path bundles against its LOCAL origin/main and the server tops
174
+ // up main. Without this, such a checkout dead-ends here and strands every ship at
175
175
  // confirmed (task 1027). The `!fetchedMain &&` short-circuit keeps the gh-probe
176
176
  // (pushVia) off the happy laptop path, so laptop behavior is byte-for-byte.
177
177
  const fetchedMain = shellOk('git fetch origin main');
@@ -238,22 +238,22 @@ function decidePreMerge({ branch, behind, via }) {
238
238
  if (!branch || branch === 'main' || branch === 'HEAD') {
239
239
  return { action: 'skip', reason: `not on a feature branch (${branch})` };
240
240
  }
241
- // Server-mediated publish (ADR 0055): a credential-less partial-clone dev box
241
+ // Server-mediated publish (ADR 0055): a credential-less partial-clone checkout
242
242
  // (blob:none, HTTPS origin, no gh/credential-helper — ADR 0053) CANNOT run a
243
243
  // local `git merge origin/main` — the ort merge lazily fetches main's blobs
244
244
  // from the promisor remote and there are no credentials to authenticate that
245
- // fetch, so the box strands here and can never ship while behind main, i.e.
245
+ // fetch, so such a checkout strands here and can never ship while behind main, i.e.
246
246
  // ≈always (idea #364). It also does not NEED to: ciLandServer bundles
247
247
  // `origin/main..HEAD` and the SERVER reconciles the branch with the real main
248
248
  // when it pushes + opens + auto-merges the PR; a genuine conflict surfaces
249
249
  // server-side as merge_conflict (publish-reconciler / conflict-resolve,
250
250
  // ADR 0082). The local pre-merge (#1068) is a LAPTOP-path optimization (so the
251
251
  // sandbox-reviewed tree == the shipped tree); it stays exactly as-is there
252
- // (via 'local'/undefined) and is simply skipped on the box.
252
+ // (via 'local'/undefined) and is simply skipped on the server path.
253
253
  if (via === 'server') {
254
254
  return {
255
255
  action: 'skip',
256
- reason: 'server-mediated publish reconciles with origin/main server-side (credential-less partial-clone box cannot fetch main blobs locally — idea #364)',
256
+ reason: 'server-mediated publish reconciles with origin/main server-side (credential-less partial-clone checkout cannot fetch main blobs locally — idea #364)',
257
257
  };
258
258
  }
259
259
  if (!Number.isFinite(behind) || behind === 0) {
@@ -26,21 +26,21 @@ function currentBranch() {
26
26
  //
27
27
  // Returns a status string ('skipped-server' | 'regen-failed' | 'current' |
28
28
  // 'committed' | 'committed-nofatal') so the regression test (task 1046) can
29
- // prove the dev-box skip without git or a headless browser.
29
+ // prove the server-publish skip without git or a headless browser.
30
30
  function regenerateDiagrams() {
31
- // task 1046: on the server-mediated-publish path (a dev box — pushVia 'server'),
31
+ // task 1046: on the server-mediated-publish path (pushVia 'server'),
32
32
  // there is no headless browser, so render-diagrams.sh fails and gen-diagrams.js
33
33
  // exits non-zero AFTER writing the regenerated .mmd + assertions.json — which
34
34
  // shellOk() then treats as a failed regen and returns BEFORE the commit below,
35
35
  // leaving those files UNCOMMITTED in the builder's tree (had to be reverted by
36
- // hand). The box must not attempt the regen at all: skip here and let a
36
+ // hand). That path must not attempt the regen at all: skip here and let a
37
37
  // render-capable ship (the laptop path, which CAN render the PNGs) refresh them
38
38
  // as a matched .mmd+.png+assertions set; the diagram-drift routine backstops any
39
39
  // staleness in the meantime. Skipping entirely (vs --no-render) avoids committing
40
40
  // a .mmd/.png mismatch to main. Mirrors gen-diagrams.js's own non-fatal skip when
41
41
  // bash itself is absent (ENOENT).
42
42
  if (pushVia() === 'server') {
43
- console.log(' diagram regen skipped on the dev-box ship path (no GDS session for the conceptual diagrams) — a full-clone ship refreshes the .mmd; drift checker backstops staleness');
43
+ console.log(' diagram regen skipped on the server-publish ship path (no GDS session for the conceptual diagrams) — a full-clone ship refreshes the .mmd; drift checker backstops staleness');
44
44
  return 'skipped-server';
45
45
  }
46
46
  // ADR 0110 pt.3 (task 2027): the .svg/.png RENDERS are now gitignored and
@@ -74,7 +74,7 @@ function regenerateDiagrams() {
74
74
 
75
75
  // task 1224 (Path B / ADR 0063): refresh the generated symbol skeleton from the shipped tree so the
76
76
  // altitude map can't drift. Pure JS (no headless browser, no render) — unlike the diagrams it is safe
77
- // on EVERY ship path, including the dev-box server-publish path. Non-fatal: a hiccup must never block
77
+ // on EVERY ship path, including the server-publish path. Non-fatal: a hiccup must never block
78
78
  // a ship. ADR 0110 (task 1926): docs/repo-map.md is now GITIGNORED + regenerated at deploy — the
79
79
  // generator still WRITES it (untracked, harmless), but ship commits ONLY the tracked nested-doc
80
80
  // blocks. It is deliberately absent from the git add/status lists below: `git add <ignored path>`
@@ -101,12 +101,12 @@ function regenerateRepoMap() {
101
101
 
102
102
  // Refresh the generated session-log index (docs/session-log-index.md) + the bounded CLAUDE.md §13
103
103
  // "recent sessions" snippet from the shipped tree's docs/session-logs/*.md (ADR 0062 §8, task 1226).
104
- // Pure JS (reads files, no DB, no headless browser) — safe on EVERY ship path including the dev-box
104
+ // Pure JS (reads files, no DB, no headless browser) — safe on EVERY ship path including the
105
105
  // server-publish path. Non-fatal: a hiccup must never block a ship; the Path-C CI gate
106
106
  // (`gen-session-index --check`) backstops staleness on main.
107
107
  // Refresh the generated API docs (docs/api/openapi.json + docs/api-reference.md +
108
108
  // docs/routes-permissions.md) from the shipped route tree (task 1918). Pure JS (reads
109
- // route files, no DB, no headless browser) — safe on EVERY ship path incl. the dev-box
109
+ // route files, no DB, no headless browser) — safe on EVERY ship path incl. the
110
110
  // server-publish path. Non-fatal: a hiccup must never block a ship; the fitness
111
111
  // `gen-api-docs --check` gate backstops staleness on main.
112
112
  function regenerateApiDocs() {
@@ -135,10 +135,7 @@ function regenerateApiDocs() {
135
135
  // so a route change left the client stale until the api_client test caught it in CI.
136
136
  // Non-fatal + safe on every ship path; the api_client freshness test backstops main.
137
137
 
138
- // The regenerated client's git pathspec. It used to carry a second, conditional path —
139
- // a vendored copy inside a desktop app, named only when on disk because `git add` of an
140
- // unmatched pathspec aborts the whole stage (task 1002417). The app is gone (task
141
- // 1003891), so the pathspec is the one directory the generator writes.
138
+ // The regenerated client's git pathspec: the one directory the generator writes.
142
139
  const API_CLIENT_PATHSPEC = 'clients/bongos-client';
143
140
 
144
141
  function regenerateApiClient() {
@@ -186,7 +183,7 @@ function regenerateSessionIndex() {
186
183
  // Refresh the generated file-map sections (.claude/skills/ + .claude/scheduled-tasks/ trees in
187
184
  // docs/file-map.md) from what is on disk (ADR 0066, task 1276). Pure JS (reads dirs + the
188
185
  // docs/file-map.notes.json sidecar, no DB, no headless browser) — safe on EVERY ship path including
189
- // the dev-box server-publish path. Non-fatal: a hiccup must never block a ship; the Path-C CI gate
186
+ // the server-publish path. Non-fatal: a hiccup must never block a ship; the Path-C CI gate
190
187
  // (`gen-file-map --check`, in fitness.js) backstops staleness on main. NB gen-file-map exits 2 when
191
188
  // a skill/routine has no note, so shellOk may report "failed" on a legit note-gap ship — that is
192
189
  // fine, we still commit whatever it wrote and CI surfaces the missing note.
@@ -273,8 +273,8 @@ module.exports = {
273
273
  // preflight's upstream-deletion warning — exported so it's unit-tested
274
274
  // without a live git repo.
275
275
  parseDeletedUpstreamPaths,
276
- // task 1052 (E): box-aware "what to do next" for a confirmed-strand — a box
277
- // (via 'server') is pointed at the resume, never at gh-only /merge-mode.
276
+ // task 1052 (E): path-aware "what to do next" for a confirmed-strand — a machine
277
+ // on the server path (via 'server') is pointed at the resume, never at gh-only /merge-mode.
278
278
  strandNextStep,
279
279
  // task 1002606: the success-pending banner lines, pure — pinned so the strand
280
280
  // detection story ("NOT a failure" + how you WILL find out if it fails) can't drift.
@@ -293,20 +293,20 @@ module.exports = {
293
293
  // #858: commit-pinned deploy confirmation via the /version endpoint.
294
294
  deployedCommitStatus,
295
295
  // ADR 0055 / task 1025: which ci-mode publish path this machine uses
296
- // ('local' = git+gh here; 'server' = server-mediated, e.g. a dev box) — so
296
+ // ('local' = git+gh here; 'server' = server-mediated, no local push credential) — so
297
297
  // doctor.js reports the same path ship will take instead of failing on
298
298
  // missing gh where gh isn't needed.
299
299
  pushVia,
300
- // task 1046: diagram regen returns a status string and SKIPS on the dev-box
301
- // (server-publish) path so a box never leaves uncommitted .mmd/assertions in
302
- // its tree — exported so the regression test proves the skip without git.
300
+ // task 1046: diagram regen returns a status string and SKIPS on the server-publish
301
+ // path so such a checkout never leaves uncommitted .mmd/assertions in its tree —
302
+ // exported so the regression test proves the skip without git.
303
303
  regenerateDiagrams,
304
304
  regenerateRepoMap,
305
305
  regenerateSessionIndex,
306
306
  // ADR 0066 / task 1276: regenerate docs/file-map.md's skills + scheduled-tasks sections from disk.
307
307
  regenerateFileMap,
308
308
  // task 1037: autoMerge's fetch-failure decision — fatal only OFF the server-
309
- // publish path (a credential-less dev box can't fetch but ships via ADR 0055).
309
+ // publish path (a credential-less checkout can't fetch but ships via ADR 0055).
310
310
  // Exported pure so the regression test proves the truth table without git.
311
311
  shouldBailOnFetchFailure,
312
312
  // task 391 (idea #37): autoMerge's zero-commit verdict — refuse a zero-commit
@@ -342,8 +342,8 @@ module.exports = {
342
342
  if (require.main === module) {
343
343
  // --print-deploy-mode (task 1003221): the EFFECTIVE mode, one word, no session or
344
344
  // network. The /merge-mode skill used to probe parseDeployMode directly, which
345
- // defaults to 'laptop' when config/deploy.json is absent — as it is on every dev
346
- // box (ADR 0148) — sending the builder down a push path they had no credential for.
345
+ // defaults to 'laptop' when config/deploy.json is absent — sending the
346
+ // builder down a push path they had no credential for.
347
347
  if (process.argv.slice(2).includes('--print-deploy-mode')) {
348
348
  console.log(require('./ship-deploy-target.js').resolveDeployMode());
349
349
  process.exit(0);