@bongos/core 1.19.1073 → 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 (377) hide show
  1. package/.bongos-core.json +404 -549
  2. package/.claude/skills/feedback/SKILL.md +2 -2
  3. package/bin/bongos.js +1 -3
  4. package/clients/bongos-client/README.md +1 -1
  5. package/clients/bongos-client/bongos-client.global.js +4 -60
  6. package/clients/bongos-client/index.cjs +4 -60
  7. package/clients/bongos-client/index.d.ts +5 -90
  8. package/clients/bongos-client/index.mjs +4 -60
  9. package/config/branding.neutral.json +1 -5
  10. package/config/modules.neutral.json +2 -3
  11. package/config/scheduled-routines.json +0 -2
  12. package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +1 -0
  13. package/docs/adr/0285-a-shared-box-holds-about-twelve-projects-per-gb-and-memory-is-the-wall.md +1 -0
  14. package/docs/adr/0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md +1 -1
  15. package/docs/adr/0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md +1 -1
  16. package/docs/adr/0341-the-page-is-the-unit-of-tweak-mode.md +2 -0
  17. package/docs/adr/0345-we-host-every-projects-hall-and-its-app-deploys-where-the-owner-chooses.md +94 -0
  18. package/docs/adr/README.md +1 -0
  19. package/docs/api/openapi.json +175 -1665
  20. package/docs/api-reference.md +9 -41
  21. package/docs/architecture.md +16 -1
  22. package/docs/branding-contract.md +0 -3
  23. package/docs/copy-inventory.md +454 -479
  24. package/docs/copy-registry.json +746 -978
  25. package/docs/file-map.md +5 -34
  26. package/docs/module-api-changelog.md +4 -0
  27. package/docs/modules-contract.md +13 -1
  28. package/docs/onboarding/diagrams/04-architecture.mmd +11 -22
  29. package/docs/onboarding/diagrams/README.md +3 -3
  30. package/docs/onboarding/diagrams/assertions.json +2 -22
  31. package/docs/onboarding/primer.md +9 -28
  32. package/docs/page-inventory.json +4 -1
  33. package/docs/page-readings.json +1032 -1077
  34. package/docs/recipes/render-pilot.md +29 -10
  35. package/migrations/core_257_module_store_registry.sql +87 -0
  36. package/migrations/core_258_drop_dev_box_tables.sql +55 -0
  37. package/modules/agents/module.json +1 -0
  38. package/modules/autonomy/module.json +1 -0
  39. package/modules/builder-settings/module.json +1 -0
  40. package/modules/builder-settings/render-prefs.js +4 -5
  41. package/modules/copy-desk/docx.js +78 -5
  42. package/modules/copy-desk/module.json +1 -0
  43. package/modules/copy-desk/routes/copy-desk.js +10 -10
  44. package/modules/copy-desk/tests/copy_docx.mjs +107 -1
  45. package/modules/copy-desk/tests/fixtures/word-docx.mjs +30 -0
  46. package/modules/discord/module.json +1 -0
  47. package/modules/discord/ship-broadcast.js +3 -3
  48. package/modules/economy/credits.js +2 -2
  49. package/modules/economy/module.json +1 -0
  50. package/modules/economy/routes/credits.js +1 -2
  51. package/modules/government/catalog.js +13 -17
  52. package/modules/government/migrations/government_019_retire_box_permissions.sql +33 -0
  53. package/modules/government/module.json +1 -0
  54. package/modules/government/protected-surfaces.json +3 -11
  55. package/modules/government/resolver.js +3 -46
  56. package/modules/government/routes/government.js +0 -2
  57. package/modules/government/session-scopes.js +43 -83
  58. package/modules/government/session-scopes.json +8 -18
  59. package/modules/grading/module.json +1 -0
  60. package/modules/hall-ui/module.json +1 -0
  61. package/modules/hall-ui/public/board-lib.js +2 -2
  62. package/modules/hall-ui/public/builders.js +29 -40
  63. package/modules/hall-ui/public/collab.html +1 -1
  64. package/modules/hall-ui/public/collab.js +1 -1
  65. package/modules/hall-ui/public/diagrams.html +3 -3
  66. package/modules/hall-ui/public/dom-utils.js +1 -1
  67. package/modules/hall-ui/public/gate.js +2 -2
  68. package/modules/hall-ui/public/gate.states.json +1 -1
  69. package/modules/hall-ui/public/hall-render.js +43 -79
  70. package/modules/hall-ui/public/index.html +5 -1
  71. package/modules/hall-ui/public/modules.js +1 -0
  72. package/modules/hall-ui/public/oversight.css +5 -5
  73. package/modules/hall-ui/public/palette.js +0 -11
  74. package/modules/hall-ui/public/primer.js +1 -1
  75. package/modules/hall-ui/public/sessions.html +1 -1
  76. package/modules/hall-ui/public/settings-sessions.js +1 -1
  77. package/modules/hall-ui/public/settings.css +0 -1
  78. package/modules/hall-ui/public/settings.html +4 -33
  79. package/modules/hall-ui/public/settings.js +3 -33
  80. package/modules/hall-ui/public/settings.states.json +2 -2
  81. package/modules/hall-ui/public/studio.html +1 -1
  82. package/modules/hall-ui/public/style.css +10 -13
  83. package/modules/hall-ui/public/task.html +4 -1
  84. package/modules/hall-ui/public/task.js +36 -1
  85. package/modules/hall-ui/public/tweak-editor-lib.js +18 -1
  86. package/modules/hall-ui/public/tweak-editor.css +16 -0
  87. package/modules/hall-ui/public/tweak-editor.html +26 -3
  88. package/modules/hall-ui/public/tweak-editor.js +32 -1
  89. package/modules/hall-ui/public/work.js +1 -1
  90. package/modules/hall-ui/records/tweak-editor.md +1 -0
  91. package/modules/ideas/module.json +1 -0
  92. package/modules/ideas/projection.js +1 -1
  93. package/modules/lifecycle/db-claim-reads.js +1 -58
  94. package/modules/lifecycle/db-ship.js +4 -9
  95. package/modules/lifecycle/db.js +0 -4
  96. package/modules/lifecycle/github-push.js +12 -14
  97. package/modules/lifecycle/kickoff-checklist.js +0 -4
  98. package/modules/lifecycle/lifecycle.js +0 -8
  99. package/modules/lifecycle/module.json +1 -0
  100. package/modules/lifecycle/publish-reconciler.js +10 -10
  101. package/modules/lifecycle/routes/tasks.js +13 -15
  102. package/modules/lifecycle/ship-card.js +1 -1
  103. package/modules/lifecycle/task-visuals.js +2 -2
  104. package/modules/memory/module.json +1 -0
  105. package/modules/memory/routes/memory.js +2 -2
  106. package/modules/npm-release/module.json +1 -0
  107. package/modules/onboarding/module.json +1 -0
  108. package/modules/onboarding/onboarding-state.js +17 -36
  109. package/modules/onboarding/routes/access-requests.js +3 -3
  110. package/modules/platform-identity/module.json +1 -0
  111. package/modules/platform-identity/platform-identity.js +13 -5
  112. package/modules/platform-identity/routes/sso.js +5 -4
  113. package/modules/platform-identity/tests/platform-identity.mjs +17 -3
  114. package/modules/provisioning/capacity.js +1 -1
  115. package/modules/provisioning/module.json +1 -0
  116. package/modules/provisioning/provisioning.js +6 -5
  117. package/modules/provisioning/routes/provisioning.js +4 -4
  118. package/modules/provisioning/starter-bundles.js +5 -25
  119. package/modules/public-landing/module.json +1 -0
  120. package/modules/public-landing/public/assets/cosmos.css +1 -1
  121. package/modules/public-landing/public/contact.html +1 -1
  122. package/modules/public-landing/public/privacy.html +1 -1
  123. package/modules/public-landing/public/projects.html +101 -32
  124. package/modules/public-landing/public/projects.probes.json +2 -2
  125. package/modules/public-landing/public/projects.states.json +4 -3
  126. package/modules/public-landing/public/terms.html +1 -1
  127. package/modules/security/module.json +1 -0
  128. package/modules/sessions/db.js +1 -1
  129. package/modules/sessions/module.json +1 -0
  130. package/modules/specialities/module.json +1 -0
  131. package/modules/status-ui/module.json +1 -0
  132. package/modules/ui-design/module.json +1 -0
  133. package/package-lock.json +2 -2
  134. package/package.json +1 -1
  135. package/release-notes.json +84 -0
  136. package/scripts/gds/artifact-format.js +203 -0
  137. package/scripts/gds/artifact-staleness.js +2 -2
  138. package/scripts/gds/audit-authorship.sh +1 -13
  139. package/scripts/gds/backfill-task-rewards.js +5 -5
  140. package/scripts/gds/claim.js +0 -15
  141. package/scripts/gds/claude-materialize.js +2 -2
  142. package/scripts/gds/cli-lib.js +15 -15
  143. package/scripts/gds/codemod-rename-src-gds.js +1 -1
  144. package/scripts/gds/context-pack.js +5 -7
  145. package/scripts/gds/diagram-facts.js +12 -23
  146. package/scripts/gds/do-api.js +13 -80
  147. package/scripts/gds/doc-cli-guard.js +2 -0
  148. package/scripts/gds/doctor.js +4 -4
  149. package/scripts/gds/feedback-latest.js +139 -9
  150. package/scripts/gds/fitness-checks-identity.js +2 -7
  151. package/scripts/gds/fitness-checks-packaging.js +4 -4
  152. package/scripts/gds/fitness-checks-write-validation.js +4 -0
  153. package/scripts/gds/fitness-ratchets.js +5 -5
  154. package/scripts/gds/fitness.js +10 -10
  155. package/scripts/gds/gen-api-client.js +4 -4
  156. package/scripts/gds/gen-api-docs.js +1 -1
  157. package/scripts/gds/gen-diagrams.js +49 -71
  158. package/scripts/gds/gen-repo-map.js +13 -14
  159. package/scripts/gds/gen-session-index.js +8 -8
  160. package/scripts/gds/http-api-client.js +12 -19
  161. package/scripts/gds/init.js +1 -1
  162. package/scripts/gds/leak-scan-allowlist.js +1 -1
  163. package/scripts/gds/lint-infra-exec.js +1 -1
  164. package/scripts/gds/local-preview-lib.js +8 -39
  165. package/scripts/gds/local-preview.js +2 -15
  166. package/scripts/gds/migration-namespace.js +3 -3
  167. package/scripts/gds/module-artifact.js +212 -0
  168. package/scripts/gds/module.js +95 -6
  169. package/scripts/gds/package-core.js +5 -116
  170. package/scripts/gds/plain-cards.js +1 -1
  171. package/scripts/gds/provision-config.js +2 -2
  172. package/scripts/gds/provision-net.js +2 -3
  173. package/scripts/gds/provision.js +9 -9
  174. package/scripts/gds/publish-manifest.js +1 -2
  175. package/scripts/gds/push-path-brief.js +10 -10
  176. package/scripts/gds/regen-instance-docs.js +1 -1
  177. package/scripts/gds/rename-history-check.js +1 -1
  178. package/scripts/gds/run-unit-tests.js +2 -16
  179. package/scripts/gds/sandbox-stage.js +39 -341
  180. package/scripts/gds/session-digest-build.js +2 -2
  181. package/scripts/gds/ship-deploy-target.js +13 -13
  182. package/scripts/gds/ship-flow.js +7 -7
  183. package/scripts/gds/ship-land.js +9 -10
  184. package/scripts/gds/ship-merge.js +4 -4
  185. package/scripts/gds/ship-preflight-steps.js +4 -4
  186. package/scripts/gds/ship-regen.js +15 -49
  187. package/scripts/gds/ship.js +13 -33
  188. package/scripts/gds/skill-preflight.js +9 -8
  189. package/scripts/gds/start.js +0 -15
  190. package/scripts/hall-preview/README.md +5 -5
  191. package/scripts/hall-preview/server.js +6 -6
  192. package/scripts/render-diagrams.sh +1 -1
  193. package/src/bongos/api-errors.js +1 -1
  194. package/src/bongos/api-prefix.js +4 -4
  195. package/src/bongos/auth-github.js +2 -3
  196. package/src/bongos/auth.js +51 -126
  197. package/src/bongos/db-kernel.js +2 -3
  198. package/src/bongos/db.js +5 -28
  199. package/src/bongos/module-scope-map.js +14 -29
  200. package/src/bongos/module-store.js +141 -0
  201. package/src/bongos/platform-visibility-gate.js +1 -1
  202. package/src/bongos/route-rank-check.js +3 -16
  203. package/src/bongos/routes/auth.js +0 -116
  204. package/src/bongos/routes/builders.js +5 -15
  205. package/src/bongos/routes/instance.js +8 -14
  206. package/src/bongos/routes/me.js +7 -23
  207. package/src/bongos/routes/modules.js +83 -0
  208. package/src/bongos/routes/security.js +3 -3
  209. package/src/bongos/routes.js +7 -2
  210. package/src/bongos/serve-internal.js +5 -6
  211. package/src/bongos-downloads.js +1 -6
  212. package/src/branding.js +2 -2
  213. package/src/build-info.js +4 -6
  214. package/src/instance-config.js +2 -2
  215. package/src/module-api.js +13 -6
  216. package/src/module-loader/catalog.js +3 -0
  217. package/src/module-loader/loader.js +4 -4
  218. package/src/module-loader/manifest-schema.js +16 -8
  219. package/src/module-seams.js +2 -3
  220. package/src/modules.js +42 -14
  221. package/tests/agents_spend_guard.mjs +1 -1
  222. package/tests/api_alias_caller_ratchet.mjs +1 -1
  223. package/tests/api_alias_exceptions.mjs +1 -1
  224. package/tests/api_client.mjs +1 -16
  225. package/tests/api_path_404.mjs +1 -1
  226. package/tests/auth_page_gate.mjs +10 -10
  227. package/tests/backfill_task_rewards.mjs +1 -1
  228. package/tests/canonical_profile_url.mjs +1 -3
  229. package/tests/claim_action.mjs +4 -1
  230. package/tests/claim_from_task_and_home.mjs +127 -0
  231. package/tests/{box_ship_permissions.mjs → cli_allowlist_permissions.mjs} +5 -5
  232. package/tests/cli_sessions.mjs +1 -1
  233. package/tests/consumer_layout_boot.mjs +2 -0
  234. package/tests/context_pack.mjs +13 -13
  235. package/tests/copy_desk_page_docx.mjs +33 -2
  236. package/tests/copy_inventory.mjs +7 -7
  237. package/tests/core_upgrade_runner.mjs +6 -6
  238. package/tests/credit_grant.mjs +2 -2
  239. package/tests/criterion_suggest.mjs +1 -1
  240. package/tests/deploy_divergence_line.mjs +11 -11
  241. package/tests/design_tokens_sync.mjs +3 -2
  242. package/tests/diagram_facts_offset.mjs +1 -1
  243. package/tests/do_api.mjs +106 -0
  244. package/tests/feedback_latest.mjs +122 -0
  245. package/tests/fitness.mjs +44 -42
  246. package/tests/fitness_ratchets.mjs +2 -2
  247. package/tests/gate_approvals.mjs +0 -1
  248. package/tests/github_push_land_proof.mjs +1 -1
  249. package/tests/go_live.mjs +3 -3
  250. package/tests/goal_advisory.mjs +3 -3
  251. package/tests/goal_suggest.mjs +3 -3
  252. package/tests/government_abuse_matrix.mjs +21 -19
  253. package/tests/government_ownership_scope.mjs +33 -35
  254. package/tests/government_parity.mjs +2 -2
  255. package/tests/government_protected_surfaces.mjs +56 -37
  256. package/tests/government_require_permission.mjs +3 -3
  257. package/tests/government_seed.mjs +37 -4
  258. package/tests/government_session_scope.mjs +92 -366
  259. package/tests/hall_audit.mjs +1 -1
  260. package/tests/hall_error_envelope.mjs +4 -0
  261. package/tests/hall_landing_boot.mjs +4 -1
  262. package/tests/hall_palette.mjs +1 -16
  263. package/tests/hall_record_world.mjs +6 -0
  264. package/tests/hall_tweak_editor.mjs +52 -1
  265. package/tests/helpers.mjs +1 -1
  266. package/tests/host_topology_skips.mjs +3 -4
  267. package/tests/html_comment_nesting.mjs +137 -0
  268. package/tests/infra_exec_paths.mjs +9 -10
  269. package/tests/init.mjs +4 -5
  270. package/tests/instance_manifest.mjs +18 -25
  271. package/tests/kickoff_checklist.mjs +1 -1
  272. package/tests/lib_sh_resolution.mjs +0 -221
  273. package/tests/local_preview.mjs +0 -12
  274. package/tests/migration_namespace.mjs +6 -6
  275. package/tests/module-scope-map.mjs +9 -9
  276. package/tests/module_api.mjs +2 -2
  277. package/tests/module_catalog.mjs +1 -1
  278. package/tests/module_cli.mjs +20 -20
  279. package/tests/module_contributions.mjs +6 -6
  280. package/tests/module_loader.mjs +6 -6
  281. package/tests/module_manifest.mjs +26 -17
  282. package/tests/module_route_rank.mjs +2 -2
  283. package/tests/module_store_publish.mjs +307 -0
  284. package/tests/module_store_publish_route.mjs +121 -0
  285. package/tests/module_store_registry_migration.mjs +70 -0
  286. package/tests/modules.mjs +56 -26
  287. package/tests/modules_route_wiring.mjs +1 -1
  288. package/tests/onboarding_route_signals.mjs +21 -31
  289. package/tests/onboarding_state.mjs +35 -49
  290. package/tests/paste_token_session_store.mjs +1 -1
  291. package/tests/permission_path.mjs +0 -3
  292. package/tests/platform_boot.mjs +1 -2
  293. package/tests/platform_visibility_gate.mjs +1 -1
  294. package/tests/profile_route.mjs +1 -6
  295. package/tests/project_modules_ui.mjs +17 -17
  296. package/tests/projects_hub.mjs +5 -5
  297. package/tests/projects_hub_app_step.mjs +138 -0
  298. package/tests/projects_hub_module_picker.mjs +77 -76
  299. package/tests/projects_hub_pre_uat.mjs +4 -5
  300. package/tests/provision.mjs +7 -7
  301. package/tests/provisioning_capacity.mjs +1 -1
  302. package/tests/provisioning_recommendations.mjs +2 -1
  303. package/tests/provisioning_starter_bundles.mjs +0 -22
  304. package/tests/publish_branch_route.mjs +11 -19
  305. package/tests/publish_manifest.mjs +2 -3
  306. package/tests/publish_reconciler.mjs +8 -8
  307. package/tests/push_path_brief.mjs +10 -9
  308. package/tests/rank_tier_single_source.mjs +1 -13
  309. package/tests/regrade_eligibility.mjs +1 -1
  310. package/tests/rename_history_restraint.mjs +1 -1
  311. package/tests/repo_map.mjs +12 -13
  312. package/tests/runner_drift.mjs +3 -21
  313. package/tests/sandbox_stage.mjs +57 -390
  314. package/tests/seam_wiring_guard.mjs +11 -11
  315. package/tests/search_isolation.mjs +3 -3
  316. package/tests/session_records.mjs +1 -1
  317. package/tests/session_rename_fallback.mjs +1 -22
  318. package/tests/session_start_freshness.mjs +3 -3
  319. package/tests/session_token_hash_db.mjs +1 -1
  320. package/tests/ship_card.mjs +1 -1
  321. package/tests/ship_ci_deploy.mjs +17 -17
  322. package/tests/ship_error_shape.mjs +1 -1
  323. package/tests/ship_premerge.mjs +1 -1
  324. package/tests/ship_resume.mjs +1 -1
  325. package/tests/skill_preflight.mjs +2 -2
  326. package/tests/skip_is_not_pass.mjs +1 -1
  327. package/tests/task_visual_slots.mjs +31 -0
  328. package/tests/terms_acceptance.mjs +2 -2
  329. package/tests/upgrade.mjs +4 -4
  330. package/tests/watch_sealed_floor.mjs +0 -1
  331. package/tests/wizard_draft_resume.mjs +2 -2
  332. package/tests/wizard_intent_resume.mjs +21 -10
  333. package/tests/wizard_preselect_why.mjs +18 -18
  334. package/docs/onboarding/browser-terminal-guide.md +0 -73
  335. package/docs/recipes/managed-settings-remote-control.md +0 -416
  336. package/modules/dev-box/CLAUDE.md +0 -15
  337. package/modules/dev-box/box-access.js +0 -623
  338. package/modules/dev-box/box-credential.js +0 -94
  339. package/modules/dev-box/box-onboard.js +0 -486
  340. package/modules/dev-box/boxes.js +0 -1038
  341. package/modules/dev-box/db.js +0 -39
  342. package/modules/dev-box/module.json +0 -19
  343. package/modules/dev-box/routes/box.js +0 -1223
  344. package/scripts/gds/box-auth-check.js +0 -160
  345. package/scripts/gds/box-infra.js +0 -321
  346. package/scripts/gds/box-sync.js +0 -216
  347. package/scripts/gds/box.js +0 -1332
  348. package/scripts/gds/cf-tunnel.js +0 -558
  349. package/scripts/gds/smoke-box.sh +0 -150
  350. package/scripts/gds/tree-preflight.js +0 -241
  351. package/src/bongos/app-pair.js +0 -172
  352. package/tests/app_pair.mjs +0 -168
  353. package/tests/box_access.mjs +0 -578
  354. package/tests/box_auth_check.mjs +0 -114
  355. package/tests/box_code_staleness.mjs +0 -129
  356. package/tests/box_connect_e2e.mjs +0 -196
  357. package/tests/box_cost.mjs +0 -70
  358. package/tests/box_credential.mjs +0 -125
  359. package/tests/box_dns_repoint.mjs +0 -153
  360. package/tests/box_env.mjs +0 -64
  361. package/tests/box_host_keys.mjs +0 -126
  362. package/tests/box_infra_resolve.mjs +0 -246
  363. package/tests/box_onboard.mjs +0 -317
  364. package/tests/box_scope_session.mjs +0 -119
  365. package/tests/box_sweep_docs.mjs +0 -119
  366. package/tests/box_sync.mjs +0 -55
  367. package/tests/box_sync_scope_report.mjs +0 -126
  368. package/tests/box_task_scope.mjs +0 -169
  369. package/tests/box_task_scope_pause.mjs +0 -66
  370. package/tests/box_terminal_ssrf.mjs +0 -96
  371. package/tests/boxes.mjs +0 -1585
  372. package/tests/cf_ruleset_preflight.mjs +0 -142
  373. package/tests/cf_tunnel.mjs +0 -496
  374. package/tests/docs_scrubber_damage.mjs +0 -111
  375. package/tests/module_scope_active_claims.mjs +0 -94
  376. package/tests/ship_api_client_pathspec.mjs +0 -100
  377. package/tests/tree_preflight.mjs +0 -243
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.1073",
3
+ "version": "1.19.1075",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.1073",
9
+ "version": "1.19.1075",
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.1073",
3
+ "version": "1.19.1075",
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",
@@ -7743,5 +7743,89 @@
7743
7743
  "id": "1004313",
7744
7744
  "text": "Tweak Mode is live on cloudbongos.com, and the artist gate is off. Artists can now open the lofi studio, take a whole page, rewrite it (in the studio or in Word), and approve the finished page before it ships. The seven old pe"
7745
7745
  }
7746
+ ],
7747
+ "1.19.1074": [
7748
+ {
7749
+ "id": "1004361",
7750
+ "text": "Fixed the test that had been blocking every new release of the platform since last evening. A test's sample module was missing the version number that modules now need, so the release step refused to run. With it fixed, the wa"
7751
+ },
7752
+ {
7753
+ "id": "1003895",
7754
+ "text": "The dev box's stored data is removed from the database: its four tables and the leftover dev-box login tokens. A fresh backup was taken first. Nothing else changes for builders."
7755
+ },
7756
+ {
7757
+ "id": "1004351",
7758
+ "text": "New projects now get a step that says we host their Builders Hall and asks where their app should run. Render is shown as coming soon; for now they can decide later."
7759
+ },
7760
+ {
7761
+ "id": "1003894",
7762
+ "text": "The leftover dev-box login tokens can no longer reach anything, and the three dev-box permissions are gone from every rank. Nobody's other permissions change. Sign-in and the rank and permission screens work as before."
7763
+ },
7764
+ {
7765
+ "id": "1004358",
7766
+ "text": "Tweak Mode's before-and-after screenshots can now be attached to a tweak. Every upload was being refused as too large, even though each picture was only about 100 KB, because a general size limit checked the upload before the"
7767
+ },
7768
+ {
7769
+ "id": "1004359",
7770
+ "text": "The Contact, Privacy and Terms pages had a scrap of behind-the-scenes note showing at the very top, above the menu. It came from a hidden note that accidentally closed itself too early. The note is reworded so it stays hidden,"
7771
+ },
7772
+ {
7773
+ "id": "1004311",
7774
+ "text": "The builders' hall no longer mentions dev boxes. Settings loses its Dev box section, the quick-jump menu loses its Dev box entry, and the architecture diagram now shows work running on your own machine. It also fixes a bug on"
7775
+ },
7776
+ {
7777
+ "id": "1004241",
7778
+ "text": "Area 5's task list is now honest: one stale task dropped, 14 rewritten to match the settled decisions, and the two waiting on the credit-economy area put back in backlog."
7779
+ },
7780
+ {
7781
+ "id": "1004354",
7782
+ "text": "A page you download as a Word file, edit in Google Docs and upload back now lands in your draft. Google Docs throws away the hidden details that said which page the file was, so the site used to refuse it as the wrong page. No"
7783
+ },
7784
+ {
7785
+ "id": "1004349",
7786
+ "text": "Decided: we host every project's Builders Hall, and owners choose where their app deploys, starting with Render. Also found and filed a sign-in cookie risk for halls on our addresses."
7787
+ },
7788
+ {
7789
+ "id": "1004356",
7790
+ "text": "The /feedback command works again: Claude Code can load your latest recorded walkthrough and its screenshots."
7791
+ },
7792
+ {
7793
+ "id": "1004142",
7794
+ "text": "A Bongos project now runs on Render, on its owner's own account: it starts, signs in, sets up its database and is backed up by Render, which clears the way to move projects off our server."
7795
+ },
7796
+ {
7797
+ "id": "1003459",
7798
+ "text": "You can now claim a task straight from its own page and from the \"Next up\" list on Home — both used to only tell you to claim it elsewhere. Every claim refusal (rank too low, someone else got there first, etc.) shows the same"
7799
+ },
7800
+ {
7801
+ "id": "1004310",
7802
+ "text": "New builders' setup checklist no longer asks them to connect a cloud dev box, and the sign-in path built for the retired dev box desktop app is gone. The builder guide now describes the one setup that exists: working from a co"
7803
+ },
7804
+ {
7805
+ "id": "1003892",
7806
+ "text": "Removed the dev box feature itself from the platform. Sites that still had it switched on in their settings keep starting normally — they now log a one-line note instead of failing to boot."
7807
+ },
7808
+ {
7809
+ "id": "1004271",
7810
+ "text": "Module authors can now publish a new version of their module to the Bongos module store with one command; the store checks it and keeps it ready for installs."
7811
+ },
7812
+ {
7813
+ "id": "1003893",
7814
+ "text": "Removed the machinery that created, parked and woke builders' cloud dev boxes, plus the scripts that ran on those boxes and the two background jobs that swept them. Nothing a builder uses today changes; the local preview and i"
7815
+ },
7816
+ {
7817
+ "id": "1003812",
7818
+ "text": "The module store now has somewhere to keep its list of modules, each published version, and what each one costs (free included)."
7819
+ },
7820
+ {
7821
+ "id": "1003781",
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
+ }
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
+ }
7746
7830
  ]
7747
7831
  }
@@ -0,0 +1,203 @@
1
+ // scripts/gds/artifact-format.js — the ONE packaging format Bongos ships code in:
2
+ // a deterministic ustar+gzip tarball plus a compression-independent tree pin
3
+ // (per-file sha256 + tree_sha256). Split out of package-core.js (task 1004271) so the
4
+ // module store (ADR 0338 D1: "no second packaging format") builds and VERIFIES module
5
+ // versions with the exact functions the core release uses — and so the always-on
6
+ // server can read a tarball without loading package-core.js's release machinery.
7
+ // Pure: no I/O beyond zlib/crypto, no git, no network.
8
+
9
+ const zlib = require('node:zlib');
10
+ const crypto = require('node:crypto');
11
+
12
+ function sha256hex(buf) {
13
+ return crypto.createHash('sha256').update(buf).digest('hex');
14
+ }
15
+
16
+ // The PIN. A canonical, compression-independent digest of a packaged tree: one
17
+ // "path\0mode\0filesha256\n" line per file, byte-sorted by path. A consumer
18
+ // recomputes this from the unpacked tree to prove an install matches the pin.
19
+ // `files` = [{ path, mode, sha256 }]. Modes are normalized so the pin is stable
20
+ // regardless of the checkout's umask.
21
+ function canonicalTreeHash(files) {
22
+ const lines = (files || [])
23
+ .map((f) => `${f.path}\u0000${normalizeMode(f.mode)}\u0000${f.sha256}`)
24
+ .sort();
25
+ return sha256hex(Buffer.from(lines.join('\n') + '\n', 'utf8'));
26
+ }
27
+
28
+ // Collapse ANY mode form — git's 100644/100755, our canonical 0000644/0000755, or a
29
+ // raw filesystem octal string like "755" — to two canonical tar modes, keyed only on
30
+ // the executable bit. IDEMPOTENT (normalizeMode(normalizeMode(x)) === normalizeMode(x))
31
+ // AND exec-aware, so the tree pin reproduces byte-identically whether a consumer
32
+ // recomputes it from the manifest's files[] (already-canonical modes) or from the
33
+ // unpacked tree's stat() modes. Expects a STRING (git mode / canonical mode / octal).
34
+ function normalizeMode(mode) {
35
+ const s = String(mode);
36
+ if (s === '100755' || s === '0000755' || s === '755') return '0000755';
37
+ const n = parseInt(s, 8);
38
+ if (Number.isFinite(n) && (n & 0o111)) return '0000755';
39
+ return '0000644';
40
+ }
41
+
42
+ // ---- a minimal, correct, DETERMINISTIC ustar+gzip writer (node-only, #686) ----
43
+ // Deterministic (fixed mtime/uid/gid, normalized mode, sorted entries) so the same
44
+ // source yields byte-identical bytes — a bonus over the tree_sha256 pin. Long paths
45
+ // use the ustar name/prefix split, falling back to a GNU 'L' longname entry (read
46
+ // by GNU tar, bsdtar/macOS, and node-tar) for the rare path that won't split.
47
+
48
+ function octal(n, width) {
49
+ // width-1 octal digits, zero-padded, then a NUL — the classic numeric field.
50
+ return Buffer.from(n.toString(8).padStart(width - 1, '0').slice(-(width - 1)) + '\0', 'ascii');
51
+ }
52
+
53
+ function tarChecksum(block) {
54
+ let sum = 0;
55
+ for (let i = 0; i < 512; i++) sum += (i >= 148 && i < 156) ? 0x20 : block[i];
56
+ return sum;
57
+ }
58
+
59
+ // Build one 512-byte ustar header. `name`/`prefix` must already fit (<=100 / <=155).
60
+ function ustarHeader({ name, prefix = '', mode, size, typeflag }) {
61
+ const h = Buffer.alloc(512, 0);
62
+ h.write(name, 0, 100, 'utf8');
63
+ octal(mode, 8).copy(h, 100);
64
+ octal(0, 8).copy(h, 108); // uid
65
+ octal(0, 8).copy(h, 116); // gid
66
+ octal(size, 12).copy(h, 124);
67
+ octal(0, 12).copy(h, 136); // mtime = 0 (determinism)
68
+ h.write(typeflag, 156, 1, 'ascii');
69
+ h.write('ustar\0', 257, 6, 'ascii');
70
+ h.write('00', 263, 2, 'ascii');
71
+ if (prefix) h.write(prefix, 345, 155, 'utf8');
72
+ // checksum field: 6 octal digits + NUL + space, computed with the field = spaces.
73
+ const cksum = tarChecksum(h);
74
+ h.write(cksum.toString(8).padStart(6, '0').slice(-6) + '\0 ', 148, 8, 'ascii');
75
+ return h;
76
+ }
77
+
78
+ // Split a >100-byte path into { name<=100, prefix<=155 } at a '/' boundary, or
79
+ // return null if no split fits (→ caller uses the GNU longname fallback).
80
+ function splitUstarName(fullPath) {
81
+ const bytes = Buffer.byteLength(fullPath, 'utf8');
82
+ if (bytes <= 100) return { name: fullPath, prefix: '' };
83
+ // Find the LAST '/' such that the tail (after it) is <=100 and the head <=155.
84
+ for (let i = fullPath.length - 1; i > 0; i--) {
85
+ if (fullPath[i] !== '/') continue;
86
+ const prefix = fullPath.slice(0, i);
87
+ const name = fullPath.slice(i + 1);
88
+ if (Buffer.byteLength(name, 'utf8') <= 100 && Buffer.byteLength(prefix, 'utf8') <= 155) {
89
+ return { name, prefix };
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+
95
+ function padTo512(buf) {
96
+ const rem = buf.length % 512;
97
+ return rem === 0 ? buf : Buffer.concat([buf, Buffer.alloc(512 - rem, 0)]);
98
+ }
99
+
100
+ // GNU longname pseudo-entry: a header (typeflag 'L', name '././@LongLink') whose
101
+ // BODY is the full path (incl. trailing NUL), immediately followed by the real
102
+ // file entry. Read by GNU tar, bsdtar/macOS, and node-tar.
103
+ function gnuLongName(fullPath) {
104
+ const payload = Buffer.from(fullPath + '\0', 'utf8');
105
+ const hdr = ustarHeader({ name: '././@LongLink', mode: 0o644, size: payload.length, typeflag: 'L' });
106
+ return Buffer.concat([hdr, padTo512(payload)]);
107
+ }
108
+
109
+ // entries: [{ name, mode, buf }] — `name` includes the TAR_ROOT prefix. Returns a
110
+ // gzip'd tar Buffer. Pure + deterministic given sorted entries.
111
+ function buildTar(entries) {
112
+ const sorted = [...entries].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
113
+ const chunks = [];
114
+ for (const e of sorted) {
115
+ const mode = e.mode & 0o7777;
116
+ const split = splitUstarName(e.name);
117
+ if (split) {
118
+ chunks.push(ustarHeader({ name: split.name, prefix: split.prefix, mode, size: e.buf.length, typeflag: '0' }));
119
+ } else {
120
+ chunks.push(gnuLongName(e.name));
121
+ chunks.push(ustarHeader({ name: e.name.slice(0, 100), mode, size: e.buf.length, typeflag: '0' }));
122
+ }
123
+ chunks.push(padTo512(e.buf));
124
+ }
125
+ // two zero blocks terminate the archive
126
+ chunks.push(Buffer.alloc(1024, 0));
127
+ const tar = Buffer.concat(chunks);
128
+ return zlib.gzipSync(tar, { level: 9 });
129
+ }
130
+
131
+
132
+
133
+ // ---- the matching READER (task 1004271) -------------------------------------
134
+ // Reads back exactly what buildTar writes — plain ustar file entries (name/prefix
135
+ // split) and GNU 'L' longname entries — into [{ name, mode, buf }]. It is the store's
136
+ // side of the format, so it is strict rather than permissive: any other entry type
137
+ // (a directory, a symlink, a pax header), a size or count over the caps, a truncated
138
+ // archive or a bad header checksum is a THROWN error, never a skipped entry. A server
139
+ // that verifies uploads must not quietly accept a shape it did not check.
140
+ //
141
+ // Two entry points over one parser: readTar (sync — the CLI and tests) and
142
+ // readTarAsync, which inflates on libuv's thread pool so a server verifying an upload
143
+ // does not hold the event loop for the decompression. The parse itself is a single
144
+ // linear pass over the inflated bytes.
145
+ const DEFAULT_READ_LIMITS = { maxUnpackedBytes: 64 * 1024 * 1024, maxFiles: 5000 };
146
+ const gunzipAsync = require('node:util').promisify(zlib.gunzip);
147
+
148
+ const unreadable = (maxUnpackedBytes, e) =>
149
+ new Error(`not a readable gzip tarball within ${maxUnpackedBytes} bytes (${e.code || e.message})`);
150
+
151
+ function readTar(tgz, { maxUnpackedBytes = DEFAULT_READ_LIMITS.maxUnpackedBytes, maxFiles = DEFAULT_READ_LIMITS.maxFiles } = {}) {
152
+ let tar;
153
+ try { tar = zlib.gunzipSync(tgz, { maxOutputLength: maxUnpackedBytes }); }
154
+ catch (e) { throw unreadable(maxUnpackedBytes, e); }
155
+ return parseTar(tar, { maxFiles });
156
+ }
157
+
158
+ async function readTarAsync(tgz, { maxUnpackedBytes = DEFAULT_READ_LIMITS.maxUnpackedBytes, maxFiles = DEFAULT_READ_LIMITS.maxFiles } = {}) {
159
+ let tar;
160
+ try { tar = await gunzipAsync(tgz, { maxOutputLength: maxUnpackedBytes }); }
161
+ catch (e) { throw unreadable(maxUnpackedBytes, e); }
162
+ return parseTar(tar, { maxFiles });
163
+ }
164
+
165
+ function parseTar(tar, { maxFiles }) {
166
+ const cstr = (b, from, len) => {
167
+ const s = b.subarray(from, from + len);
168
+ const z = s.indexOf(0);
169
+ return (z < 0 ? s : s.subarray(0, z)).toString('utf8');
170
+ };
171
+ const out = [];
172
+ let off = 0;
173
+ let longName = null;
174
+ while (true) {
175
+ if (off + 512 > tar.length) throw new Error('tarball is truncated (no end-of-archive marker)');
176
+ const h = tar.subarray(off, off + 512);
177
+ if (h.every((x) => x === 0)) break;
178
+ const stored = parseInt(cstr(h, 148, 8).trim(), 8);
179
+ if (stored !== tarChecksum(h)) throw new Error(`tar header checksum mismatch at byte ${off}`);
180
+ const size = parseInt(cstr(h, 124, 12).trim() || '0', 8);
181
+ if (!Number.isFinite(size) || size < 0) throw new Error(`bad entry size at byte ${off}`);
182
+ const type = String.fromCharCode(h[156] || 48);
183
+ const bodyStart = off + 512;
184
+ const bodyEnd = bodyStart + size;
185
+ if (bodyEnd > tar.length) throw new Error('tarball is truncated mid-entry');
186
+ const body = tar.subarray(bodyStart, bodyEnd);
187
+ off = bodyStart + size + ((512 - (size % 512)) % 512);
188
+ if (type === 'L') { longName = cstr(body, 0, body.length); continue; }
189
+ if (type !== '0' && type !== '\u0000') throw new Error(`unsupported tar entry type "${type}" — only regular files are allowed`);
190
+ const prefix = cstr(h, 345, 155);
191
+ const name = longName || (prefix ? `${prefix}/${cstr(h, 0, 100)}` : cstr(h, 0, 100));
192
+ longName = null;
193
+ out.push({ name, mode: parseInt(cstr(h, 100, 8).trim() || '0', 8), buf: Buffer.from(body) });
194
+ if (out.length > maxFiles) throw new Error(`tarball has more than ${maxFiles} files`);
195
+ }
196
+ return out;
197
+ }
198
+
199
+ module.exports = {
200
+ sha256hex, canonicalTreeHash, normalizeMode,
201
+ octal, tarChecksum, ustarHeader, splitUstarName, padTo512, gnuLongName, buildTar,
202
+ readTar, readTarAsync,
203
+ };
@@ -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
@@ -151,13 +151,6 @@ ALLOWLIST=(
151
151
  # hardcoded in code.
152
152
  'CODEOWNERS'
153
153
 
154
- # Dev Box app distribution (#904, ADR 0044): the PUBLIC releases repo lives
155
- # under the same GitHub account that owns the main repo — repo-hosting
156
- # identity (same nature as provision-staging.sh above), not a builder
157
- # identity. The test pins the committed config's repo string.
158
- 'config/devbox-app.json'
159
- 'tests/devbox_downloads.mjs'
160
-
161
154
  # This audit script's own self-reference (it documents what it's looking for).
162
155
  'scripts/gds/audit-authorship.sh'
163
156
 
@@ -173,21 +166,18 @@ ALLOWLIST=(
173
166
 
174
167
  # Test DATA that pins a real contract (task 1002640) — identity in an
175
168
  # assertion IS the contract, not a mis-attribution: owner approval RECORDS
176
- # the Archon's login (gate_approvals), the terminal-URL SSRF guard validates
177
- # term-<login> hostnames (box_terminal_ssrf), packaging/provisioning tests
169
+ # the Archon's login (gate_approvals), packaging/provisioning tests
178
170
  # exercise the real repo owner + the mirror-redaction floor. Listed per file
179
171
  # (never a blanket tests/ exclusion) so a NEW test file is still scanned.
180
172
  'tests/provision.mjs'
181
173
  'tests/package_core.mjs'
182
174
  'tests/init.mjs'
183
- 'tests/box_terminal_ssrf.mjs'
184
175
  'tests/gate_approvals.mjs'
185
176
  'tests/publish_reconciler.mjs'
186
177
  'tests/dev_lib.mjs'
187
178
  'tests/ship_card.mjs'
188
179
  'tests/scrubber_corpus.mjs'
189
180
  'tests/module_submissions.mjs'
190
- 'tests/boxes.mjs'
191
181
  'tests/provisioning_onboard_mode.mjs'
192
182
  'tests/instance_manifest.mjs'
193
183
  'tests/bongos_downloads.mjs'
@@ -199,10 +189,8 @@ ALLOWLIST=(
199
189
  'tests/currency_label.mjs'
200
190
  'tests/cloud_bongos_pack.mjs'
201
191
  'tests/bump_version.mjs'
202
- 'tests/box_scope_session.mjs'
203
192
  'tests/auth_inactive_builder.mjs'
204
193
  'tests/auth_anthropic_identity.mjs'
205
- 'modules/dev-box/app/test/unit.mjs'
206
194
 
207
195
  # The mirror-redaction floor: PRIOR_INSTANCE_FLOOR carries the prior
208
196
  # instance's owner literal precisely so packaging can SCRUB it from every
@@ -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
  }
@@ -7,21 +7,6 @@
7
7
  // On success: prints the claim id, the task title, and the touches[] so the
8
8
  // builder knows the parallel-safety boundary they're working within.
9
9
 
10
- // TREE PREFLIGHT (task 1003098). A task-scoped dev box carries scripts/ and
11
- // src/bongos/ but not every modules/ directory, so the requires below can fail —
12
- // and Node's loader names only the FIRST missing one, which turned recovery into
13
- // guess-read-fix-repeat. This enumerates every missing requirement in one message
14
- // and exits before the first such require runs. It must stay ABOVE them.
15
- //
16
- // A PRE-REQUEST hard exit, like the usage banner and worktree guard: nothing has
17
- // been sent yet, so there is no in-flight request for cliExit to drain.
18
- const { action: _surfaceAction } = require('./surface.js');
19
- const { checkTree: _checkTree } = require('./tree-preflight.js');
20
- {
21
- const _fault = _checkTree(__filename, { command: _surfaceAction("claim") });
22
- if (_fault) { console.error(_fault); process.exit(1); }
23
- }
24
-
25
10
  const { execSync } = require('node:child_process');
26
11
  const fs = require('node:fs');
27
12
  const path = require('node:path');
@@ -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
@@ -139,8 +139,8 @@ function hallBase(base = API_BASE) {
139
139
  // still be mid-close when the caller's process.exit() runs, tripping a
140
140
  // UV_HANDLE_CLOSING assertion that corrupts piped JSON stdout. Connection reuse
141
141
  // buys these one-shot processes nothing, so route requests through a dispatcher
142
- // with keep-alive effectively disabled (mirrors cf-tunnel.js's dispatcher
143
- // pattern). Degrades to the default dispatcher if undici can't be required.
142
+ // with keep-alive effectively disabled. Degrades to the default dispatcher if
143
+ // undici can't be required.
144
144
  //
145
145
  // task 1002734 — THIS ALONE IS NOT ENOUGH, and the measurements say so: with the
146
146
  // dispatcher wired in and undici resolving fine, `node scripts/gds/api.js GET
@@ -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 });
@@ -1069,12 +1069,11 @@ function detectWorktreeName() {
1069
1069
  // summary — that emitCard consumes directly.
1070
1070
  //
1071
1071
  // WHY THIS READS THE PAYLOAD AND NEVER require()s render-prefs.js. The ladder
1072
- // lives in modules/builder-settings/render-prefs.js, and requiring it from here
1073
- // would work on a full checkout and BREAK on a task-scoped dev box, which
1074
- // carries scripts/ and src/bongos/ but not every modules/ directory (task
1075
- // 1003098 — tree-preflight exists precisely to fail an entry point that reaches
1076
- // for module code, and start.js is one). So the server resolves the rung and
1077
- // ships the answers on `render.flags`; this function only picks them up.
1072
+ // lives in modules/builder-settings/render-prefs.js, and a CLI reaches a
1073
+ // module's logic through the server, never by require — the module may be
1074
+ // disabled on the instance, and a require would couple every CLI to one
1075
+ // module's internals. So the server resolves the rung and ships the answers on
1076
+ // `render.flags`; this function only picks them up.
1078
1077
  //
1079
1078
  // TWO SERVER SHAPES, deliberately. `render.flags` is the ladder (task 1002518);
1080
1079
  // `render.widgets_enabled` is the boolean that predates it. A CLI newer than the
@@ -1174,6 +1173,7 @@ module.exports = {
1174
1173
  repairMsysMangledPath,
1175
1174
  resolveQuiet,
1176
1175
  readSessionToken,
1176
+ CLI_USER_AGENT,
1177
1177
  apiCall,
1178
1178
  cliExit,
1179
1179
  isDispatcherIncompatError,
@@ -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
  //
@@ -174,18 +174,12 @@ const CONCEPTUAL_TASK_IDS = {
174
174
  246: 'R26 — karma surfaced on profile + sortable on leaderboard',
175
175
  };
176
176
 
177
- // 04-architecture (the DEV BOX + box→prod flow) — where a builder's work runs
178
- // and how code reaches prod. Same "LIVE iff its backing GDS task is 'shipped'"
179
- // contract as the memory chain above; these were merged into the single
180
- // 04-architecture diagram (was the standalone 06-dev-box). Live ids verified
181
- // 2026-06-14 — the whole chain is now shipped, including 1027 + 1028. Each entry
182
- // documents the piece it drives in scripts/gds/gen-diagrams.js `architectureMmd`:
183
- // 904 — the OTB Dev Box desktop app (menu-bar/tray on-off switch)
184
- // 774 — the browser-only box terminal (ttyd over an outbound tunnel)
185
- // 897 — the per-builder sandbox live game preview on the box
186
- // 919 — the scoped dev-box session (box token deny-by-default)
187
- // 1025 — server-mediated branch publish (box uploads bundle, server pushes)
188
- // 1027 — hardware-verify of the box→prod flow end-to-end (now SHIPPED)
177
+ // 04-architecture (the ship flow) — how code on a builder's machine reaches
178
+ // prod. Same "LIVE iff its backing GDS task is 'shipped'" contract as the memory
179
+ // chain above. Each entry documents the piece it drives in
180
+ // scripts/gds/gen-diagrams.js `architectureMmd`:
181
+ // 1025 — server-mediated branch publish (a checkout with no GitHub push
182
+ // credential uploads a bundle, the server pushes it)
189
183
  // 1028 — replaced the standing push PAT with a GitHub App (now SHIPPED)
190
184
  //
191
185
  // Every id here MUST drive a piece of the diagram. An id no consumer reads is
@@ -194,15 +188,10 @@ const CONCEPTUAL_TASK_IDS = {
194
188
  // stop 03 + 04 from regenerating at all (the failure shape task 1002667 fixed
195
189
  // for the offset case). Do NOT re-add 859 (CI self-deploy): the deploy leg is
196
190
  // the standalone AUTO-PULL of ADR 0108/0129, not a task-gated Actions job, so
197
- // gen-diagrams.js deliberately excludes it — see its comment at `box → prod`.
191
+ // gen-diagrams.js deliberately excludes it — see its comment at `ship flow`.
198
192
  // Removed in task 1002674.
199
- const DEV_BOX_TASK_IDS = {
200
- 904: 'devbox-app — desktop on-off switch',
201
- 774: 'browser-only box terminal (ttyd over tunnel)',
202
- 897: 'per-builder sandbox live preview',
203
- 919: 'scoped dev-box session (box token deny-by-default)',
204
- 1025: 'server-mediated branch publish (box uploads bundle, server pushes)',
205
- 1027: 'hardware-verify the box-to-prod flow end-to-end',
193
+ const SHIP_FLOW_TASK_IDS = {
194
+ 1025: 'server-mediated branch publish (a checkout with no push credential uploads a bundle, the server pushes)',
206
195
  1028: 'GitHub App hardening (replace the standing push PAT)',
207
196
  };
208
197
 
@@ -290,10 +279,10 @@ async function conceptualFacts({ repo, migs, api }) {
290
279
  // process via cli-lib's guidance path (see the loop's degrade-to-null below).
291
280
  api = await cliClient({ allowUnauthenticated: true });
292
281
  }
293
- // 03's pieces + 04-architecture's memory chain + its dev-box/ship-flow pieces
282
+ // 03's pieces + 04-architecture's memory chain + its ship-flow pieces
294
283
  // share one fetch + one taskStatus map; any unreachable id degrades the WHOLE
295
284
  // conceptual bundle (so 03 + 04 skip together rather than emit partial data).
296
- const ALL_TASK_IDS = { ...CONCEPTUAL_TASK_IDS, ...DEV_BOX_TASK_IDS };
285
+ const ALL_TASK_IDS = { ...CONCEPTUAL_TASK_IDS, ...SHIP_FLOW_TASK_IDS };
297
286
  const ids = Object.keys(ALL_TASK_IDS).map(Number);
298
287
  const status = {};
299
288
  let lockedOffset = null;
@@ -360,7 +349,7 @@ module.exports = {
360
349
  repoSlug,
361
350
  conceptualFacts,
362
351
  CONCEPTUAL_TASK_IDS,
363
- DEV_BOX_TASK_IDS,
352
+ SHIP_FLOW_TASK_IDS,
364
353
  IMPORT_ID_OFFSETS,
365
354
  gatherFacts,
366
355
  };