@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
@@ -2,7 +2,7 @@
2
2
  // surface (ADR 0111 §1/§2, task #1942). Instance hosting + domains: the web-tier
3
3
  // REQUEST + STATE surface for standing up + operating a Cloud Bongos instance.
4
4
  //
5
- // THE TRUST BOUNDARY (ADR 0111 §2 / ADR 0016 / the dev-box /box precedent). The
5
+ // THE TRUST BOUNDARY (ADR 0111 §2 / ADR 0016). The
6
6
  // internet-facing web process NEVER calls a cloud API and holds NO provider tokens.
7
7
  // A mutation route only ENQUEUES an intent (provision | teardown) into
8
8
  // provisioning_intents and returns; the control-plane runner (scripts/gds/
@@ -27,7 +27,7 @@
27
27
  // task 1003581 — see the handler)
28
28
  // POST /provisioning/instances/:id/teardown — request teardown of one's own
29
29
  // GET /provisioning/instances/:id/invite-suggestions — who is worth inviting (R28, ADR 0251)
30
- // Archon-scoped (requireRank('archon') — the fleet, the /boxes precedent):
30
+ // Archon-scoped (requireRank('archon') — the fleet):
31
31
  // GET /provisioning/fleet — the full instance roster + the box's slot `capacity` (ADR 0285)
32
32
  // GET /provisioning/fleet/cost-ledger — per-instance cost to us + to its owner, with totals
33
33
  // POST /provisioning/instances/:id/force-teardown — tear down ANY instance
@@ -204,7 +204,7 @@ module.exports = function provisioningRoutes() {
204
204
  // it. Archon-first keeps every route classifying to its true gate.
205
205
 
206
206
  // GET /provisioning/fleet — the full instance roster across all owners.
207
- // rank: archon (exposes every owner's instance + cost; the /boxes precedent).
207
+ // rank: archon (exposes every owner's instance + cost).
208
208
  router.get('/provisioning/fleet', auth.requireBuilder, auth.requirePermission('provisioning.fleet.manage'), async (req, res) => {
209
209
  try {
210
210
  const status = req.query.status || undefined;
@@ -217,7 +217,7 @@ module.exports = function provisioningRoutes() {
217
217
  });
218
218
 
219
219
  // GET /provisioning/fleet/cost-ledger — per-instance monthly cost to us + estimated cost to its owner, with totals.
220
- // rank: archon — cost oversight across the fleet (the /boxes/cost-ledger precedent).
220
+ // rank: archon — cost oversight across the fleet.
221
221
  // Declared among the archon routes (archon-first) for correct auditor classification.
222
222
  router.get('/provisioning/fleet/cost-ledger', auth.requireBuilder, auth.requirePermission('provisioning.fleet.manage'), async (req, res) => {
223
223
  try {
@@ -75,21 +75,6 @@ const ALWAYS_ON_CORE = Object.freeze([
75
75
  // own npm package is a later, deliberate removal from this list — with picker copy.
76
76
  const HUB_ONLY_MODULES = Object.freeze(['platform-identity', 'provisioning', 'npm-release']);
77
77
 
78
- // Modules that were once offered and are being WITHDRAWN. A retired key is still
79
- // a module on disk — its manifest, routes and tables are deleted by later tasks —
80
- // but it must stop being OFFERED the moment the withdrawal starts, or an owner
81
- // creating a project today opts into something that is on its way out.
82
- //
83
- // WHY A LIST AND NOT JUST DELETING THE ROW. The integrity test below pins
84
- // OPTIONAL_MODULES against the on-disk `default: false` manifests, so that a new
85
- // opt-in module cannot ship without owner-facing copy. Dropping a row while its
86
- // manifest is still on disk would trip exactly that guard. Naming the withdrawal
87
- // keeps the guard honest in both directions: the catalog may omit a RETIRED
88
- // module and may omit nothing else. The entry is deleted when the module is
89
- // (goal 1000091, task 1003892) — at which point the manifest is gone and the
90
- // plain drift check covers it again.
91
- const RETIRED_MODULES = Object.freeze(['dev-box']);
92
-
93
78
  // The OPT-IN catalog as the creation picker renders it (BV1.R20, task 1002339):
94
79
  // every module an owner may actually choose, in the order the picker lists them,
95
80
  // with copy written for someone who has met none of them.
@@ -159,9 +144,7 @@ const OPTIONAL_MODULE_KEYS = Object.freeze(OPTIONAL_MODULES.map((m) => m.key));
159
144
  //
160
145
  // Deliberately tiny: ADR 0237 already made the per-type preset the opinion, and
161
146
  // today's opt-in catalog is two modules wide — so this table's job is to correct
162
- // a preset the owner's answer contradicts, not to re-derive it. The two rules that
163
- // added and removed `dev-box` by team shape went with the module (task 1003886):
164
- // a rule about a module nobody can select adjusts nothing.
147
+ // a preset the owner's answer contradicts, not to re-derive it.
165
148
  //
166
149
  // A rule may only ever name an OPT-IN module. Adding or removing an always-on one
167
150
  // would be a toggle that toggles nothing (ADR 0237 §3's argument, and
@@ -193,10 +176,8 @@ const RULED_TEAM_SHAPES = Object.freeze([...new Set(TEAM_SHAPE_RULES.map((r) =>
193
176
  // The lists are SHORT on purpose. A preselect an owner has to audit is worse than
194
177
  // none, and today's opt-in catalog is genuinely small (`agents`, `discord`); a
195
178
  // bundle grows as the catalog does, which is exactly why this is a declaration and
196
- // not a rule engine. `dev-box` was preselected by the game and business bundles
197
- // until it was retired (goal 1000091, task 1003886) — withdrawing it left both
198
- // bundles one module wide, which is the floor working as intended, not a gap to
199
- // backfill with a module an owner did not ask for.
179
+ // not a rule engine. A bundle one module wide is the floor working as intended,
180
+ // not a gap to backfill with a module an owner did not ask for.
200
181
  const STARTER_BUNDLES = Object.freeze({
201
182
  game: Object.freeze({
202
183
  label: 'Game starter',
@@ -287,8 +268,8 @@ function adjustBundle(bundle, teamShape) {
287
268
  for (const rule of TEAM_SHAPE_RULES) {
288
269
  if (rule.teamShape !== teamShape) continue;
289
270
  if (rule.effect === 'add' && !held.has(rule.module)) held.add(rule.module);
290
- // `remove` is declared but named by no live rule since dev-box was retired
291
- // (task 1003886). Kept for the next rule that needs it, not exercised today.
271
+ // `remove` is declared but named by no live rule today. Kept for the next
272
+ // rule that needs it.
292
273
  else if (rule.effect === 'remove' && held.has(rule.module)) held.delete(rule.module);
293
274
  else continue;
294
275
  adjustments.push({ rule: rule.id, effect: rule.effect, module: rule.module, reason: rule.reason });
@@ -404,7 +385,6 @@ function effectiveModules(row) {
404
385
  module.exports = {
405
386
  ALWAYS_ON_CORE,
406
387
  HUB_ONLY_MODULES,
407
- RETIRED_MODULES,
408
388
  OPTIONAL_MODULES,
409
389
  STARTER_BUNDLES,
410
390
  TEAM_SHAPE_RULES,
@@ -2,6 +2,7 @@
2
2
  "key": "public-landing",
3
3
  "title": "The front door",
4
4
  "description": "The instance's public front door served at the APEX ROOT — the landing page (/), the projects hub (/projects, and the /create redirect into its ?view=new wizard), the three footer doors (/privacy, /terms, /contact) and every asset behind them. The third WEB-SURFACE core-domain module after status-ui (BV1.R84) and hall-ui (BV1.R85), carved in task 1003322 (ADR 0218; named in ADR 0197 §8 — the front door keeps its own key, because a customer of the ui-design capability is not part of it). default-on: an instance ships its front door like it ships its hall. Registers no port and contributes no routes — it declares a webSurface, and where hall-ui and status-ui name a Host PREFIX this one declares apexRoot:true, since the apex is whatever host is left once the subdomains are taken (ADR 0218 §2; host:\"\" is rejected, because every host string startsWith \"\"). Like the hall, the declaration is the discovery + scope-map + window.__MODULES__ record: the bytes are served by platform-server.js's dedicated landing block, which keeps the apex-only sentinel strip, the branding-token stamp and the ?v= content stamp and only re-points its root at this module's public/ dir. Disabling the module removes the front door outright — the apex then answers the game-less 404 tail. The world it renders (DESIGN.md, the token contract, the direction records) is the INSTANCE's; the method for building one stays in modules/ui-design/.",
5
+ "version": "1.0.0",
5
6
  "coreVersion": "^1.19.0",
6
7
  "default": true,
7
8
  "maintenance": { "status": "core-maintained" },
@@ -1598,7 +1598,7 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
1598
1598
  /* the six-step strip as the rail: six hairlines, a 7px dot, one lit step on the
1599
1599
  accent with its halo, the number in the display voice, the name in the label
1600
1600
  face; a step already answered (role=button) stays a way back */
1601
- #view-new .steps{display:grid;grid-template-columns:repeat(7,1fr);gap:0 10px;align-items:start;margin:0 0 40px;}
1601
+ #view-new .steps{display:grid;grid-template-columns:repeat(8,1fr);gap:0 10px;align-items:start;margin:0 0 40px;}
1602
1602
  #view-new .steps li{display:block;position:relative;border-top:1px solid var(--rule);padding:12px 0 0;gap:0;}
1603
1603
  #view-new .steps li::before{content:"";position:absolute;top:-4px;left:0;right:auto;width:7px;height:7px;margin:0;border-radius:50%;border:1px solid var(--rule);background:var(--bg);}
1604
1604
  #view-new .steps .snum{display:block;width:auto;height:auto;border:0;border-radius:0;background:none;font-family:var(--font-display);font-weight:300;font-size:22px;letter-spacing:-.02em;line-height:1.1;color:var(--ink-faint);margin-bottom:2px;}
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <!-- Server-stamped like index.html and projects.html (task 1003251): the {{…}}
7
7
  tokens are filled by landingPage() (src/platform-server.js) from the
8
- instance's own branding, and every <!--apex-only--> region is REMOVED off
8
+ instance's own branding, and every apex-only:start/end region is REMOVED off
9
9
  the hub — a claim about the platform must not ship in a child project's
10
10
  page (task 1002748). The baked values are the NEUTRAL pack's.
11
11
  Both doors here are token-stamped: a pack that names no repository loses
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <!-- Server-stamped like index.html and projects.html (task 1003251): the {{…}}
7
7
  tokens are filled by landingPage() (src/platform-server.js) from the
8
- instance's own branding, and every <!--apex-only--> region is REMOVED off
8
+ instance's own branding, and every apex-only:start/end region is REMOVED off
9
9
  the hub — a claim about the platform must not ship in a child project's
10
10
  page (task 1002748). The baked values are the NEUTRAL pack's. -->
11
11
  <title>{{productName}} — Privacy</title>
@@ -303,6 +303,20 @@ summary{min-height:24px;padding:3px 0;}
303
303
  .addrConfirm details .inner{margin-top:6px;}
304
304
  .addrOpt{display:flex;align-items:flex-start;gap:12px;margin-top:14px;font-size:14px;font-weight:400;color:var(--warn);line-height:1.5;cursor:pointer;}
305
305
  .addrOpt input{margin-top:4px;accent-color:var(--accent);}
306
+ /* the app step (task 1004351, ADR 0345): the hall line, then one row per place the app
307
+ can run. A radio per row so the choice is native; "soon" is a row that is shown but
308
+ cannot be picked yet, and says so in words rather than by colour alone. */
309
+ .appHall{font-size:14.5px;font-weight:400;color:var(--ink-soft);line-height:1.5;max-width:62ch;margin:0 0 18px;}
310
+ .appHall b{color:var(--ink);font-weight:500;}
311
+ .appOpts{border:0;padding:0;margin:0 0 14px;border-top:1px solid var(--rule);}
312
+ .appOpts legend{font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;font-weight:400;color:var(--ink-faint);padding:0;margin:0 0 10px;}
313
+ .appOpt{display:flex;align-items:flex-start;gap:12px;min-height:24px;padding:14px 0;border-bottom:1px solid var(--rule);cursor:pointer;}
314
+ .appOpt input{flex:none;width:18px;height:18px;margin:3px 0 0;accent-color:var(--accent);}
315
+ .appOpt b{display:block;font-family:var(--font-body);font-size:15px;font-weight:500;color:var(--ink);margin-bottom:2px;}
316
+ .appOpt span span{display:block;font-size:14px;font-weight:400;color:var(--ink-soft);line-height:1.5;max-width:62ch;}
317
+ .appOpt.soon{cursor:default;}
318
+ .appOpt.soon b{color:var(--ink-soft);}
319
+ .appOpt .soonTag{display:inline-block;margin-left:8px;padding:0 8px;border:1px solid var(--rule-soft);border-radius:999px;font-size:12px;font-weight:500;line-height:1.6;color:var(--ink-soft);vertical-align:1px;}
306
320
 
307
321
  /* GitHub repo picker (task 1002099): hairline rows, the chosen one marked on
308
322
  the accent; the private badge in the label face */
@@ -893,7 +907,7 @@ summary{min-height:24px;padding:3px 0;}
893
907
  <div id="mMods"><p class="finePrint">Reading the project…</p></div>
894
908
  <details class="finePrint" id="mModsWhat">
895
909
  <summary>What an extra is — and what is always on</summary>
896
- <p>Extras are the optional parts a project can run — a shared dev box, a Discord mirror, and the rest. You picked a set when you created the project, or took the suggested set by skipping that step; this is where you change your mind. Switching one on or off saves straight away and changes nothing that is already running: nothing restarts, and no work is lost either way. The parts every project runs — the platform itself, the way it tracks work, the builders’ hall — were never part of the choice, so they are not listed here and cannot be switched off.</p>
910
+ <p>Extras are the optional parts a project can run — extra AI agents, a Discord mirror, and the rest. You picked a set when you created the project, or took the suggested set by skipping that step; this is where you change your mind. Switching one on or off saves straight away and changes nothing that is already running: nothing restarts, and no work is lost either way. The parts every project runs — the platform itself, the way it tracks work, the builders’ hall — were never part of the choice, so they are not listed here and cannot be switched off.</p>
897
911
  </details>
898
912
  </div>
899
913
 
@@ -1019,7 +1033,8 @@ summary{min-height:24px;padding:3px 0;}
1019
1033
  <li data-step="4"><span class="snum">4</span><span class="slbl">Modules</span></li>
1020
1034
  <li data-step="5"><span class="snum">5</span><span class="slbl">Home</span></li>
1021
1035
  <li data-step="6"><span class="snum">6</span><span class="slbl">Address</span></li>
1022
- <li data-step="7"><span class="snum">7</span><span class="slbl">Create</span></li>
1036
+ <li data-step="7"><span class="snum">7</span><span class="slbl">App</span></li>
1037
+ <li data-step="8"><span class="snum">8</span><span class="slbl">Create</span></li>
1023
1038
  </ol>
1024
1039
 
1025
1040
  <div class="createSplit">
@@ -1301,14 +1316,44 @@ summary{min-height:24px;padding:3px 0;}
1301
1316
  </form>
1302
1317
  </section>
1303
1318
 
1304
- <!-- step 7 · review + create -->
1319
+ <!-- step 7 · where the app runs (task 1004351, ADR 0345). The hall is ours to
1320
+ host, so this step is only about the owner's APP. Render is listed but
1321
+ cannot be picked until the connect flow lands (task 1004352), which
1322
+ removes the "soon" state; "decide later" is the owner's ruling and is
1323
+ always the default, so nothing here can block a Create. -->
1324
+ <section class="panel" id="panel-app" aria-labelledby="app-h">
1325
+ <h1 id="app-h">Where your app will run</h1>
1326
+ <p class="appHall"><b>We host your Builders' hall</b> — the place where the project gets built — at the address you just chose. There is nothing for you to set up.</p>
1327
+ <p class="lede">Your app is the thing the project builds. Choose where it should run, or decide later.</p>
1328
+ <form data-next="8">
1329
+ <fieldset class="appOpts" id="appOpts">
1330
+ <legend>Where your app runs</legend>
1331
+ <label class="appOpt soon" id="appOptRender">
1332
+ <input type="radio" name="appPlatform" value="render" disabled aria-describedby="appRenderWhat">
1333
+ <span><b>Render <span class="soonTag">Coming soon</span></b>
1334
+ <span id="appRenderWhat">We set your app up on your own Render account. You lend us your Render key once, and Render bills you directly.</span></span>
1335
+ </label>
1336
+ <label class="appOpt">
1337
+ <input type="radio" name="appPlatform" value="later" checked>
1338
+ <span><b>Decide later</b>
1339
+ <span>Create the project now. You can choose where your app runs afterwards.</span></span>
1340
+ </label>
1341
+ </fieldset>
1342
+ <div class="nav">
1343
+ <button type="button" class="btn ghost" data-back="6">← Back</button>
1344
+ <button type="submit" class="btn">Next →</button>
1345
+ </div>
1346
+ </form>
1347
+ </section>
1348
+
1349
+ <!-- step 8 · review + create -->
1305
1350
  <section class="panel" id="panel-review" aria-labelledby="rev-h">
1306
1351
  <h1 id="rev-h">Ready to roll</h1>
1307
1352
  <p class="lede">One tap files the request and the platform starts standing your project up — server, database, address. Here's the beat you're about to drop:</p>
1308
1353
  <ul class="review" id="reviewList"></ul>
1309
1354
  <div class="alert" id="createAlert" role="alert"></div>
1310
1355
  <div class="nav">
1311
- <button type="button" class="btn ghost" data-back="6">← Back</button>
1356
+ <button type="button" class="btn ghost" data-back="7">← Back</button>
1312
1357
  <button type="button" class="btn big" id="doCreate">Create my project</button>
1313
1358
  </div>
1314
1359
  <p class="finePrint">This files the request; the control plane does the real standup and nothing touches servers from this page. You'll get the few steps only you can do right after.</p>
@@ -3238,7 +3283,7 @@ summary{min-height:24px;padding:3px 0;}
3238
3283
  reinterpreted — a stale step 4 meant Address under v1 and Home under v3,
3239
3284
  and replaying it would land on the wrong panel with the rail already
3240
3285
  marking the skipped ones done. Bump this key on EVERY renumbering. */
3241
- var DRAFT_KEY = 'cb-create-draft-v4';
3286
+ var DRAFT_KEY = 'cb-create-draft-v5';
3242
3287
  var CREATED_KEY = 'cb-created-instance';
3243
3288
  /* `description` + `teamShape` are the optional About step (task 1002334) —
3244
3289
  both legitimately stay empty, and empty is what the create request omits. */
@@ -3247,7 +3292,7 @@ summary{min-height:24px;padding:3px 0;}
3247
3292
  request omits the field), [] = the owner switched them all off, [...] =
3248
3293
  what they picked. Never seed it with the preselect — that would store an
3249
3294
  answer nobody gave. */
3250
- var state = { step: 0, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false };
3295
+ var state = { step: 0, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later' };
3251
3296
  try { Object.assign(state, JSON.parse(sessionStorage.getItem(DRAFT_KEY) || '{}')); } catch (e) {}
3252
3297
  var authKnown = false; /* flips true when the boot's /me settles, either way */
3253
3298
 
@@ -3261,7 +3306,7 @@ summary{min-height:24px;padding:3px 0;}
3261
3306
  state.name = handedName.trim().slice(0, 80);
3262
3307
  state.slug = deriveSlug(state.name); state.slugTouched = false;
3263
3308
  state.repo = deriveRepo(state.name); state.repoTouched = false;
3264
- state.step = state.step >= 1 && state.step <= 7 ? state.step : 1;
3309
+ state.step = state.step >= 1 && state.step <= 8 ? state.step : 1;
3265
3310
  try { sessionStorage.setItem(DRAFT_KEY, JSON.stringify(state)); } catch (e) {}
3266
3311
  }
3267
3312
  } catch (e) {}
@@ -3453,18 +3498,18 @@ summary{min-height:24px;padding:3px 0;}
3453
3498
  }
3454
3499
 
3455
3500
  /* ── step navigation ──
3456
- Eight steps since task 1002339: gate 0 · name 1 · type 2 · about 3 ·
3457
- modules 4 · home 5 · address 6 · review 7 · done 8 (the rail shows 1-7;
3458
- done marks it all). About and Modules are the two steps Next can pass with
3501
+ Nine steps since task 1004351: gate 0 · name 1 · type 2 · about 3 ·
3502
+ modules 4 · home 5 · address 6 · app 7 · review 8 · done 9 (the rail shows
3503
+ 1-8; done marks it all). About and Modules are the two steps Next can pass with
3459
3504
  nothing filled in. */
3460
- var panels = { 0: 'panel-gate', 1: 'panel-name', 2: 'panel-type', 3: 'panel-detail', 4: 'panel-modules', 5: 'panel-home', 6: 'panel-address', 7: 'panel-review', 8: 'panel-done' };
3505
+ var panels = { 0: 'panel-gate', 1: 'panel-name', 2: 'panel-type', 3: 'panel-detail', 4: 'panel-modules', 5: 'panel-home', 6: 'panel-address', 7: 'panel-app', 8: 'panel-review', 9: 'panel-done' };
3461
3506
  /* the rail at the done panel (task 1003244): "done" is the Create step
3462
3507
  still running — the marker stays on 5 until the project actually
3463
3508
  answers, and only then does the whole rail read finished. aria-current
3464
3509
  tells a screen reader the same thing. */
3465
3510
  function paintRail(step) {
3466
- var landed = step === 8 && !!(live && live.instStatus === 'active');
3467
- var cur = step === 8 ? 7 : step;
3511
+ var landed = step === 9 && !!(live && live.instStatus === 'active');
3512
+ var cur = step === 9 ? 8 : step;
3468
3513
  root.querySelectorAll('.steps li').forEach(function (li) {
3469
3514
  var n = Number(li.getAttribute('data-step'));
3470
3515
  var now = !landed && n === cur;
@@ -3475,7 +3520,7 @@ summary{min-height:24px;padding:3px 0;}
3475
3520
  the button role, the tab stop and the data-goto the delegated handler
3476
3521
  below reads. The done panel offers none — the project is filed, and
3477
3522
  there is nothing behind it to change. */
3478
- if (step < 8 && n < cur) {
3523
+ if (step < 9 && n < cur) {
3479
3524
  li.setAttribute('role', 'button');
3480
3525
  li.setAttribute('tabindex', '0');
3481
3526
  li.setAttribute('data-goto', String(n));
@@ -3494,7 +3539,7 @@ summary{min-height:24px;padding:3px 0;}
3494
3539
  paintRail(step);
3495
3540
  saveDraft();
3496
3541
  /* the done step takes the whole card — the bongo pair steps aside */
3497
- root.querySelector('.createSplit').classList.toggle('wizDone', step === 8);
3542
+ root.querySelector('.createSplit').classList.toggle('wizDone', step === 9);
3498
3543
  /* focus moves ONLY on a deliberate step (the hub rule setView already
3499
3544
  applies to this view: never on boot, never on a background settle) */
3500
3545
  if (moveFocus) {
@@ -3510,12 +3555,13 @@ summary{min-height:24px;padding:3px 0;}
3510
3555
  if (step === 5) { syncHome(); if (authKnown) ensureRepoAccess(); }
3511
3556
  /* a resumed draft can land PAST the Home step with the probe never run —
3512
3557
  Create would then file a repo it promised to make but never did */
3513
- else if (step > 5 && step < 8 && authKnown && repoAccess === null) ensureRepoAccess();
3558
+ else if (step > 5 && step < 9 && authKnown && repoAccess === null) ensureRepoAccess();
3514
3559
  /* re-check on every entry, not just on typing: a resumed draft arrives here with
3515
3560
  a handle nobody has asked the server about, and a handle free ten minutes ago
3516
3561
  may not be now (task 1002898 N10) */
3517
3562
  if (step === 6) { checkSlugAvailable(); renderAddrPanel(); }
3518
- if (step === 7) renderReview();
3563
+ if (step === 7) syncAppStep();
3564
+ if (step === 8) renderReview();
3519
3565
  }
3520
3566
 
3521
3567
  /* One delegated pair on the rail, so paintRail can add and drop data-goto
@@ -3709,7 +3755,7 @@ summary{min-height:24px;padding:3px 0;}
3709
3755
  prevent, one screen before Create. */
3710
3756
  function repaintForBundles() {
3711
3757
  if (state.step === 4) renderModules();
3712
- else if (state.step === 7) renderReview();
3758
+ else if (state.step === 8) renderReview();
3713
3759
  }
3714
3760
  /* The row for the declared type, or null before the read lands / for a type
3715
3761
  the table has no row for (including no type at all). */
@@ -3742,8 +3788,8 @@ summary{min-height:24px;padding:3px 0;}
3742
3788
 
3743
3789
  The fallback is the point (task 1003684). `adjustments` is a DELTA: a rule that
3744
3790
  fires without changing anything claims nothing (ADR 0243). So for a type whose
3745
- bundle ALREADY contains what the rule would add — game is [dev-box, discord] and
3746
- the small-team rule adds dev-box — the delta is empty and the owner was shown a
3791
+ bundle ALREADY contains what the rule would add — game is [discord] and the
3792
+ community rule adds discord — the delta is empty and the owner was shown a
3747
3793
  tailored preselect with no reason beside it at all. That is the state ADR 0237
3748
3794
  calls worse than no preselect: one the owner has to audit. Each bundle carries a
3749
3795
  curated summary authored for exactly this, served on every row, and until now
@@ -4201,6 +4247,28 @@ summary{min-height:24px;padding:3px 0;}
4201
4247
  });
4202
4248
 
4203
4249
  /* ── review ── */
4250
+ /* the app step (task 1004351): a native radio group, so the draft only mirrors it.
4251
+ An older draft has no appPlatform, and a value this page does not offer (a
4252
+ platform still marked soon, or one that was removed) reads as 'later' — the
4253
+ review must never name a platform the owner could not actually pick. */
4254
+ function appPlatformChoice() {
4255
+ var want = state.appPlatform;
4256
+ var pick = Array.prototype.filter.call(root.querySelectorAll('#appOpts input[name=appPlatform]'), function (i) {
4257
+ return i.value === want && !i.disabled;
4258
+ })[0];
4259
+ return pick ? pick.value : 'later';
4260
+ }
4261
+ function syncAppStep() {
4262
+ var pick = appPlatformChoice();
4263
+ root.querySelectorAll('#appOpts input[name=appPlatform]').forEach(function (i) { i.checked = i.value === pick; });
4264
+ }
4265
+ function appRow() {
4266
+ return appPlatformChoice() === 'render' ? 'Render, on your own account' : 'Not chosen yet — you can decide later';
4267
+ }
4268
+ var appOptsEl = root.querySelector('#appOpts');
4269
+ if (appOptsEl) appOptsEl.addEventListener('change', function (ev) {
4270
+ if (ev.target && ev.target.name === 'appPlatform' && !ev.target.disabled) { state.appPlatform = ev.target.value; saveDraft(); }
4271
+ });
4204
4272
  function renderReview() {
4205
4273
  /* every road back to this step gets a live button — the create path
4206
4274
  disables it and only the failure branch used to restore it, which
@@ -4227,9 +4295,10 @@ summary{min-height:24px;padding:3px 0;}
4227
4295
  ['Address', resolvedDomain()
4228
4296
  ? '<code>' + esc(resolvedDomain()) + '</code>'
4229
4297
  : '<em style="font-weight:600;color:var(--warn)">none — sign-in stays locked until it has one</em>'],
4230
- /* The wizard creates hosting_shape 'cloud-host' — we stand it up and run it for
4231
- them. Since task 1004182 the stored value IS the owner-facing name (ADR 0323). */
4232
- ['Shape', 'Cloud host — we stand it up and run it for you, on the platform’s current release']
4298
+ /* The wizard creates hosting_shape 'cloud-host', which since ADR 0345 means the
4299
+ HALL is hosted by us; where the owner's APP runs is its own row (task 1004351). */
4300
+ ['Builders\' hall', 'Hosted by us, on the platform’s current release'],
4301
+ ['App', appRow()]
4233
4302
  ];
4234
4303
  $('reviewList').innerHTML = rows.map(function (r) {
4235
4304
  return '<li><span class="k">' + r[0] + '</span><span class="v">' + r[1] + '</span></li>';
@@ -4362,7 +4431,7 @@ summary{min-height:24px;padding:3px 0;}
4362
4431
  sessionStorage.removeItem(DRAFT_KEY);
4363
4432
  } catch (e) {}
4364
4433
  renderDone();
4365
- show(8, true);
4434
+ show(9, true);
4366
4435
  startProgress(data.instance && data.instance.id);
4367
4436
  }).catch(function (err) {
4368
4437
  if (String(err && err.message) === 'signing in') return;
@@ -4935,7 +5004,7 @@ summary{min-height:24px;padding:3px 0;}
4935
5004
  5s tick never clobbers an open dropdown or mid-flight button) */
4936
5005
  if (inst && inst.status !== live.instStatus) {
4937
5006
  live.instStatus = inst.status; renderSteps();
4938
- if (state.step === 8) paintRail(8); /* the rail finishes only when the project answers */
5007
+ if (state.step === 9) paintRail(9); /* the rail finishes only when the project answers */
4939
5008
  }
4940
5009
  var terminal = renderProgress(inst);
4941
5010
  if (!terminal) pollTimer = setTimeout(tick, 5000);
@@ -4975,7 +5044,7 @@ summary{min-height:24px;padding:3px 0;}
4975
5044
  is three-valued and null is its "nothing said" sentinel; leaving the key out
4976
5045
  left it UNDEFINED, which is not null — so pickedModules() reached .slice()
4977
5046
  on it and the second project's Modules step threw. */
4978
- state = { step: 1, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false };
5047
+ state = { step: 1, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later' };
4979
5048
  $('newName').value = ''; $('f-owner').value = ''; $('f-repo').value = ''; $('f-slug').value = ''; $('f-domain').value = '';
4980
5049
  $('f-noaddr').checked = false; $('f-desc').value = '';
4981
5050
  /* Re-seed the owner from the signed-in account for the next project. */
@@ -5044,17 +5113,17 @@ summary{min-height:24px;padding:3px 0;}
5044
5113
  another project" the only way out.
5045
5114
 
5046
5115
  The reset fires only when there is a SECOND DRAFT to lose, and the draft's own
5047
- step is what says so. A landed create clears DRAFT_KEY — but show(8) then
5116
+ step is what says so. A landed create clears DRAFT_KEY — but show(9) then
5048
5117
  persists the done panel's own position straight back into it, so "is there a
5049
5118
  draft?" is always yes and would have skipped the reset forever, leaving the
5050
- finished project's name sitting in the fresh form. Only steps 1–7 are wizard
5119
+ finished project's name sitting in the fresh form. Only steps 1–8 are wizard
5051
5120
  steps: anything else is the done panel's bookkeeping, not a project someone
5052
5121
  is part-way through typing. */
5053
5122
  function enterCreated(created, focus) {
5054
5123
  if (focus && !resumeIntent) {
5055
5124
  var draft = null;
5056
5125
  try { draft = JSON.parse(sessionStorage.getItem(DRAFT_KEY) || 'null'); } catch (e) {}
5057
- var at = draft && draft.step >= 1 && draft.step <= 7 ? draft.step : 0;
5126
+ var at = draft && draft.step >= 1 && draft.step <= 8 ? draft.step : 0;
5058
5127
  if (!at) { resetForNewProject(); at = 1; }
5059
5128
  paintResumeOffer(created);
5060
5129
  /* step 1's own focus target is the name field, not the heading — the same
@@ -5078,7 +5147,7 @@ summary{min-height:24px;padding:3px 0;}
5078
5147
  manifestState = created.manifest_state; manifestPending = true;
5079
5148
  }
5080
5149
  renderDone();
5081
- show(8, !!focus);
5150
+ show(9, !!focus);
5082
5151
  startProgress(created.id);
5083
5152
  resumePolls();
5084
5153
  }
@@ -5095,7 +5164,7 @@ summary{min-height:24px;padding:3px 0;}
5095
5164
  /* before identity settles, never render past the name step: deeper steps
5096
5165
  carry authenticated side effects (the Home-step repo probe), and onAuth()
5097
5166
  re-enters to the real draft step the moment /me answers */
5098
- var step = authKnown && state.step >= 1 && state.step <= 7 ? state.step : 1;
5167
+ var step = authKnown && state.step >= 1 && state.step <= 8 ? state.step : 1;
5099
5168
  if (step === 1) {
5100
5169
  /* Pre-auth, step 1 is a PLACEHOLDER, not where the visitor is — but show()
5101
5170
  persists whatever step it renders, so it used to overwrite the draft's real
@@ -5104,7 +5173,7 @@ summary{min-height:24px;padding:3px 0;}
5104
5173
  step back after rendering the placeholder, in memory AND in the draft. */
5105
5174
  var resumeStep = state.step;
5106
5175
  show(1, false);
5107
- if (!authKnown && resumeStep >= 1 && resumeStep <= 7) { state.step = resumeStep; saveDraft(); }
5176
+ if (!authKnown && resumeStep >= 1 && resumeStep <= 8) { state.step = resumeStep; saveDraft(); }
5108
5177
  if (focus) $('newName').focus();
5109
5178
  } else {
5110
5179
  show(step, !!focus);
@@ -159,10 +159,10 @@
159
159
  "steps": [["wait",900],["click","[data-disc-ask]"],["wait",200],["fill","#mDiscName","old-lantern"],["wait",100],["click","[data-disc-yes]"],["wait",900]],
160
160
  "expect": {"text":[["#mDisc .addr","This project is being disconnected."],["#mName","old-lantern"]],"hidden":["#mDiscName","[data-disc-ask]"]} },
161
161
  { "name": "the wizard driver (task 1003346): name, type, about, home (fresh; the stub grants repo access, so the new repository is named from the project), address (the handle's verdict), the review as a ledger, then the filing — the done panel with the standup rail and the human steps", "auth": true, "width": 1440, "url": "/projects?view=new",
162
- "steps": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#doCreate"],["wait",1500]],
162
+ "steps": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#panel-app button[type=submit]"],["wait",400],["click","#doCreate"],["wait",1500]],
163
163
  "expect": {"visible":["#panel-done","#liveProgress .prog","#liveProgress .prog .stages li.now","#humanSteps li"],"hidden":["#panel-review","#panel-name"],"text":[["#done-h","The drums are rolling"]],"attr":[["#panel-done","class","panel on"]]} },
164
164
  { "name": "the wizard driver at 390: the rail folds to two rows of three and the walk still reaches the review", "auth": true, "width": 390, "url": "/projects?view=new",
165
- "steps": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400]],
165
+ "steps": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#panel-app button[type=submit]"],["wait",400]],
166
166
  "expect": {"visible":["#panel-review","#reviewList li","#doCreate"],"hidden":["#panel-address"],"text":[["#rev-h","Ready to roll"]]} }
167
167
  ]
168
168
  }
@@ -36,9 +36,10 @@
36
36
  "in-new-modules-search": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["fill","#modQ","discord"],["wait",200]], "expect": {"visible":["#panel-modules","#modQ"],"value":[["#modQ","discord"]],"count":[["#modCards .tpill",1],["#modCards .tpill[data-mod=\"discord\"]",1]],"text":[["#modFilterNote","Showing 1 of 3. 2 extras are switched on, including any this search is hiding."]]} },
37
37
  "in-new-home": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400]], "expect": {"visible":["#panel-home"],"hidden":["#panel-detail","#qWrap"]} },
38
38
  "in-new-address": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400]], "expect": {"visible":["#panel-address"],"hidden":["#panel-home","#qWrap"]} },
39
- "in-new-review": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400]], "expect": {"visible":["#panel-review","#reviewList li"],"hidden":["#panel-address","#qWrap"]} },
40
- "in-new-done": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#doCreate"],["wait",1500]], "expect": {"visible":["#panel-done","#liveProgress .prog","#humanSteps li"],"hidden":["#panel-review","#qWrap"]} },
41
- "in-new-resume-offer": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#doCreate"],["wait",1500],["click","#projTrig"],["wait",350],["click","#menuProjects [data-nav=\"new\"]"],["wait",500]], "expect": {"visible":["#panel-name","#wizResume","#wizResumeGo"],"hidden":["#panel-done"],"text":[["#wizResumeName","Mercury"]]} },
39
+ "in-new-app": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400]], "expect": {"visible":["#panel-app","#appOpts","#appOptRender .soonTag"],"hidden":["#panel-address","#panel-review","#qWrap"]} },
40
+ "in-new-review": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#panel-app button[type=submit]"],["wait",400]], "expect": {"visible":["#panel-review","#reviewList li"],"hidden":["#panel-address","#qWrap"]} },
41
+ "in-new-done": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#panel-app button[type=submit]"],["wait",400],["click","#doCreate"],["wait",1500]], "expect": {"visible":["#panel-done","#liveProgress .prog","#humanSteps li"],"hidden":["#panel-review","#qWrap"]} },
42
+ "in-new-resume-offer": { "auth": true, "url": "/projects?view=new", "actions": [["wait",600],["fill","#newName","Mercury"],["click","#panel-name button[type=submit]"],["wait",400],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-type button[type=submit]"],["wait",400],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#teamCards .tpill[data-team=\"small-team\"]"],["click","#panel-detail button[type=submit]"],["wait",900],["click","#panel-modules button[type=submit]"],["wait",400],["click","#panel-home button[type=submit]"],["wait",400],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#panel-address button[type=submit]"],["wait",400],["click","#panel-app button[type=submit]"],["wait",400],["click","#doCreate"],["wait",1500],["click","#projTrig"],["wait",350],["click","#menuProjects [data-nav=\"new\"]"],["wait",500]], "expect": {"visible":["#panel-name","#wizResume","#wizResumeGo"],"hidden":["#panel-done"],"text":[["#wizResumeName","Mercury"]]} },
42
43
  "out-map-projects": { "auth": false, "actions": [["click", "#projTrig"], ["wait", 350]], "expect": { "expanded": true, "hidden": ["#menuProjects [data-nav=\"mine\"]"] } },
43
44
  "card": { "auth": true, "actions": [["dispatchClick", "#orbField a.worldOrb[data-origin=\"https://example.com\"]"], ["wait", 900]], "expect": { "dialog": true, "hasClass": [["#projCard", "has-art"]], "visible": ["#cardArt", "#cardFaces", "#cardBuildersFig", "#cardShippedFig", "#cardOpen", "#cardHall"], "text": [["#cardBuilders", "11"], ["#cardShipped", "0"], ["#cardRel", "you build here"], ["#cardRuns", "example.com"], ["#cardFaces .facesMore", "+6"]], "count": [["#cardFaces img", 5]], "href": [["#cardHall", "https://builders.example.com/"]] } },
44
45
  "card-noart": { "auth": true, "actions": [["dispatchClick", "#orbField a.worldOrb[data-origin=\"https://emersonian-circles.cloudbongos.com\"]"], ["wait", 600]], "expect": { "dialog": true, "hasClass": [["#projCard", "has-art", false]], "hidden": ["#cardArt", "#cardFaces", "#cardHall"], "visible": ["#cardBuildersFig", "#cardShippedFig", "#cardOpen"], "text": [["#cardShipped", "30+"], ["#cardRel", "you build here"]] } },
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <!-- Server-stamped like index.html and projects.html (task 1003251): the {{…}}
7
7
  tokens are filled by landingPage() (src/platform-server.js) from the
8
- instance's own branding, and every <!--apex-only--> region is REMOVED off
8
+ instance's own branding, and every apex-only:start/end region is REMOVED off
9
9
  the hub — a claim about the platform must not ship in a child project's
10
10
  page (task 1002748). The baked values are the NEUTRAL pack's. -->
11
11
  <title>{{productName}} — Terms</title>
@@ -2,6 +2,7 @@
2
2
  "key": "security",
3
3
  "title": "Security (red-team · bounty)",
4
4
  "description": "The red-team / vulnerability-report intake and the bounty payout system (rank-gated Metic+): the /builder-redteam skill files a report, the Archon dashboard adjudicates (confirm/dispute/fix/link-fix), and the env-aware bounty table sets the per-severity drachmae payout. A core-domain module carved out of the GDS core in BV1.R79 (ADR 0093 §1; 02-module-map §5 — security-the-FEATURE, NOT security-the-property, which stays kernel). default-on because every instance can take red-team reports. Registers the `security` kernel PORT the core /public/bounty-table resolves for the payout schedule. Also owns the scan-before-install surface (goal 1000055): the artifact-scan engine (quarantine/manifest/mirror) and the security_tool_scans record — POST Metic+, GET every rank.",
5
+ "version": "1.0.0",
5
6
  "coreVersion": "^1.8.0",
6
7
  "default": true,
7
8
  "maintenance": { "status": "core-maintained" },
@@ -187,7 +187,7 @@ async function syncSessionDrachmaeEarnedTx(client, builderId, sessionId) {
187
187
  // safe, and lets a later, costlier ship in the same session book its increment.
188
188
  // task 1676: pass totalTokens so the reward can fall back to pricing the
189
189
  // session's real token total when modelUsage is empty/unpriceable — the
190
- // dev-box/CI agent path that historically paid $0 cost-plus (ADR 0097).
190
+ // CI agent path that historically paid $0 cost-plus (ADR 0097).
191
191
  async function awardSessionTokenRewardTx(client, { builderId, sessionId, modelUsage, totalTokens }) {
192
192
  const reward = seams.resolveOptional('reward');
193
193
  if (!reward) return { drachmae: 0, trueCostUsd: 0, awarded: false, unknownModels: [], deferred: false };
@@ -2,6 +2,7 @@
2
2
  "key": "sessions",
3
3
  "title": "Sessions & BFG (session corpus · efficiency eval)",
4
4
  "description": "The session-records corpus + its data plane (POST /sessions upload, the Archon-gated cross-builder /sessions/search + /sessions/:id deep-dive + /sessions/upload-health, the server-side signal that a builder's session uploads have silently stopped), the BFG 'read-the-room' cross-builder scorer (ADR 0026 §6B), and the session-pulse / stale-claim heartbeat helpers. A core-domain module carved out of the GDS core in BV1.R82 (ADR 0093 §1); default-on because every instance records its builders' sessions for the BFG. Like the memory module, sessions registers no port — core never calls back into it: the ship-time digest write is an HTTP POST to the module's own /sessions route, and the only outward dependency is the economy `reward` kernel PORT it resolves (session token reward + sumCreditsForTasks) at upload time.",
5
+ "version": "1.0.0",
5
6
  "coreVersion": "^1.10.0",
6
7
  "default": true,
7
8
  "maintenance": { "status": "core-maintained" },
@@ -2,6 +2,7 @@
2
2
  "key": "specialities",
3
3
  "title": "Role sub-specialities (harnesses)",
4
4
  "description": "Role SUB-SPECIALITIES — a named bundle of knowledge, skills and an interaction contract that sits UNDER a craft (task 1003855; ADR 0296). A craft says how you work (engineer / ideator / artist / ui); a speciality says what you work ON and how a subject-matter expert wants to be engaged inside it. Deliberately a thin layer over three surfaces that already exist — discipline-modes.json for craft->playbook, behavior_prefs.interaction for the per-session contract (a speciality contract rides that SAME GET /me -> Conductor path rather than adding a second one), and the ADR 0083 manifest for declared skills; the only new machinery is the knowledge bundle. Training is two-fold per the owner's 2026-09-17 ruling: documents the builder supplied, plus learnings captured from sessions worked in the speciality (pointing at existing `learnings` rows, never a second corpus). Owned per-builder OR per-project, each carrying its owner's sharing decision (private / project / public) and an explicit sellable flag — the flag records intent only, because ADR 0107 defers the marketplace and there is nothing to list on. default-on: a speciality is how an instance's expertise enters the platform, so it ships like the hall and the status page.",
5
+ "version": "1.0.0",
5
6
  "coreVersion": "^1.19.0",
6
7
  "default": true,
7
8
  "maintenance": { "status": "core-maintained" },
@@ -2,6 +2,7 @@
2
2
  "key": "status-ui",
3
3
  "title": "Status dashboard (\"The Watch\")",
4
4
  "description": "The public build-status dashboard served at status.<apex> (status.example.com) — the live up/down banner, version-progress rollups, cost summary, recent ships, leaderboard, and the ecosystem fingerprint, all polling the read-only /api/bongos/public/* surface every 60s. A WEB-SURFACE core-domain module carved out of the GDS core in BV1.R84 (ADR 0093 §1; 02-module-map §6 — a web surface is first-class). default-on: a Cloud Bongos instance ships its status page like it ships its hall. Registers no port and contributes no routes — it declares a webSurface (host prefix + static dir) the loader hands serve-internal, which serves the module's public/ dir on the matching host exactly as it served public-status/ before. The public read endpoints it renders stay SHARED core in routes/public.js (the hall + the off-box mirror read them too).",
5
+ "version": "1.0.0",
5
6
  "coreVersion": "^1.11.0",
6
7
  "default": true,
7
8
  "maintenance": { "status": "core-maintained" },
@@ -2,6 +2,7 @@
2
2
  "key": "ui-design",
3
3
  "title": "UI design (the design contract, its adapters and sync, the /design playbook, the kit, the skills, the styles)",
4
4
  "description": "The platform capability that lets any builder on any instance create and design good-looking, functional UIs in line with that instance's world (scoped with the owner 2026-08-28; task 1003324, ADR 0197). It ships METHOD and never a world: the neutral design contract of ADR 0081 with its tool adapters (Claude Design, Figma), their sync CLIs and the validator; the /design playbook for ui-discipline work; and the reserved homes for the look-before-you-ship kit (kit/), the vetted UI skills (skills/) and the style library (styles/) the sibling tasks land. The instance's world — its branding pack, config/design-tokens.*, config/design-sources.json and its DESIGN.md — stays in config/ and at the repo root as the host boundary this module reads and never owns (ADR 0062 §7). Cloud Bongos's own front door is this module's first customer, not its owner. default-on because every instance has a face. No routes, no migrations, no port: declaration-only like character-anim, so disabling it withdraws only the skills it contributes and touches no served surface.",
5
+ "version": "1.0.0",
5
6
  "coreVersion": "^1.19.0",
6
7
  "default": true,
7
8
  "maintenance": { "status": "core-maintained" },