@bongos/core 1.18.0 → 1.18.18

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 (553) hide show
  1. package/.bongos-core.json +1740 -640
  2. package/.claude/skills/builder-box/SKILL.md +6 -0
  3. package/.claude/skills/builder-sequence/SKILL.md +97 -0
  4. package/.claude/skills/builder-ship/SKILL.md +8 -2
  5. package/.claude/skills/builder-start/SKILL.md +11 -0
  6. package/.claude/skills/builder-sync/SKILL.md +41 -0
  7. package/.claude/skills/fix-task/SKILL.md +64 -0
  8. package/.claude/skills/goal-create/SKILL.md +158 -0
  9. package/.claude/skills/goal-review/SKILL.md +3 -1
  10. package/.claude/skills/idea-triage/SKILL.md +14 -8
  11. package/.claude/skills/merge-mode/SKILL.md +2 -2
  12. package/.claude/skills/new-project/SKILL.md +1 -0
  13. package/.claude/skills/planning-session/SKILL.md +45 -18
  14. package/.env.local.example +4 -3
  15. package/README.md +5 -3
  16. package/bin/bongos.js +1 -0
  17. package/clients/bongos-client/README.md +2 -2
  18. package/clients/bongos-client/bongos-client.global.js +82 -18
  19. package/clients/bongos-client/index.cjs +82 -18
  20. package/clients/bongos-client/index.d.ts +131 -29
  21. package/clients/bongos-client/index.mjs +82 -18
  22. package/config/branding.neutral.json +11 -2
  23. package/config/governance.neutral.json +21 -0
  24. package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
  25. package/docs/adr/0090-metic-task-authoring.md +1 -1
  26. package/docs/adr/0142-project-context-is-prose-only.md +41 -0
  27. package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
  28. package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
  29. package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
  30. package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
  31. package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
  32. package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
  33. package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
  34. package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
  35. package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
  36. package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
  37. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
  38. package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
  39. package/docs/adr/0152-metic-task-abandonment.md +67 -0
  40. package/docs/adr/0153-sequential-chain-runner.md +51 -0
  41. package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
  42. package/docs/adr/README.md +15 -2
  43. package/docs/api/openapi.json +2648 -483
  44. package/docs/api-reference.md +73 -13
  45. package/docs/architecture.md +4 -2
  46. package/docs/branding-contract.md +3 -1
  47. package/docs/canonical-permissions.md +21 -8
  48. package/docs/file-map.md +15 -7
  49. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
  50. package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
  51. package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
  52. package/docs/onboarding/diagrams/assertions.json +4 -7
  53. package/docs/onboarding/drachmae-and-karma.md +3 -3
  54. package/docs/onboarding/primer.md +17 -16
  55. package/docs/onboarding/slash-commands.md +124 -0
  56. package/docs/recipes/builder-box-lifecycle.md +23 -0
  57. package/docs/recipes/devbox-app-release.md +14 -4
  58. package/docs/recipes/instance-first-run.md +16 -0
  59. package/docs/recipes/local-dev.md +81 -0
  60. package/docs/recipes/ops-gotchas.md +19 -1
  61. package/docs/recipes/overnight-builder.md +1 -1
  62. package/docs/recipes/packaging-the-core.md +13 -0
  63. package/docs/recipes/parallel-goal-waves.md +174 -0
  64. package/docs/recipes/ship-and-regrade.md +2 -2
  65. package/docs/recipes/standalone-live-docs.md +48 -0
  66. package/docs/recipes/upgrading-the-core.md +5 -2
  67. package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
  68. package/migrations/003_pms.sql +6 -7
  69. package/migrations/006_pms_v2.sql +3 -31
  70. package/migrations/039_newcomer_friendly_column.sql +5 -0
  71. package/migrations/102_remove_box_first_provision_approval.sql +4 -0
  72. package/migrations/core_192_github_oauth_tokens.sql +33 -0
  73. package/migrations/core_193_task_needs_rebase.sql +28 -0
  74. package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
  75. package/migrations/core_195_idea_triage_provenance.sql +57 -0
  76. package/migrations/core_196_session_reward_topup.sql +69 -0
  77. package/modules/autonomy/pollers/routine-timers.js +9 -8
  78. package/modules/builder-settings/wandering-prefs.js +61 -18
  79. package/modules/dev-box/app/README.md +73 -0
  80. package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
  81. package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
  82. package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
  83. package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
  84. package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
  85. package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
  86. package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
  87. package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
  88. package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
  89. package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
  90. package/modules/dev-box/app/assets/tray/win-off.png +0 -0
  91. package/modules/dev-box/app/assets/tray/win-on.png +0 -0
  92. package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
  93. package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
  94. package/modules/dev-box/app/build-resources/icon.png +0 -0
  95. package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
  96. package/modules/dev-box/app/electron-builder.yml +95 -0
  97. package/modules/dev-box/app/package-lock.json +5291 -0
  98. package/modules/dev-box/app/package.json +30 -0
  99. package/modules/dev-box/app/renderer/app.js +319 -0
  100. package/modules/dev-box/app/renderer/index.html +45 -0
  101. package/modules/dev-box/app/renderer/styles.css +246 -0
  102. package/modules/dev-box/app/renderer/theme.generated.css +16 -0
  103. package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
  104. package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
  105. package/modules/dev-box/app/scripts/gen-brand.js +138 -0
  106. package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
  107. package/modules/dev-box/app/scripts/gen-icons.js +286 -0
  108. package/modules/dev-box/app/scripts/vendor-client.js +23 -0
  109. package/modules/dev-box/app/src/box-controller.js +287 -0
  110. package/modules/dev-box/app/src/brand.generated.json +13 -0
  111. package/modules/dev-box/app/src/brand.js +16 -0
  112. package/modules/dev-box/app/src/config.js +19 -0
  113. package/modules/dev-box/app/src/gds-client.js +90 -0
  114. package/modules/dev-box/app/src/main.js +610 -0
  115. package/modules/dev-box/app/src/pairing.js +57 -0
  116. package/modules/dev-box/app/src/preload.js +29 -0
  117. package/modules/dev-box/app/src/session-store.js +58 -0
  118. package/modules/dev-box/app/src/ssh-setup.js +569 -0
  119. package/modules/dev-box/app/src/task-picker.js +70 -0
  120. package/modules/dev-box/app/src/tray.js +99 -0
  121. package/modules/dev-box/app/src/updater.js +55 -0
  122. package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
  123. package/modules/dev-box/app/test/unit.mjs +526 -0
  124. package/modules/dev-box/box-access.js +121 -4
  125. package/modules/dev-box/boxes.js +20 -0
  126. package/modules/dev-box/module.json +1 -1
  127. package/modules/dev-box/routes/box.js +87 -3
  128. package/modules/economy/credits.js +116 -25
  129. package/modules/economy/reward.js +8 -0
  130. package/modules/economy/streak.js +2 -1
  131. package/modules/governance/CLAUDE.md +15 -0
  132. package/modules/governance/catalog.js +419 -0
  133. package/modules/governance/config.js +174 -0
  134. package/modules/governance/db.js +125 -0
  135. package/modules/governance/migrations/governance_001_tables.sql +81 -0
  136. package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
  137. package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
  138. package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
  139. package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
  140. package/modules/governance/module.json +10 -0
  141. package/modules/governance/protected-surfaces.js +88 -0
  142. package/modules/governance/protected-surfaces.json +80 -0
  143. package/modules/governance/rank-roles.js +83 -0
  144. package/modules/governance/resolver.js +221 -0
  145. package/modules/governance/routes/governance.js +89 -0
  146. package/modules/governance/routes/role-sync.js +49 -0
  147. package/modules/governance/session-scopes.js +127 -0
  148. package/modules/governance/session-scopes.json +38 -0
  149. package/modules/hall-ui/public/atlas.css +117 -0
  150. package/modules/hall-ui/public/atlas.html +3 -114
  151. package/modules/hall-ui/public/brand-apply.js +34 -6
  152. package/modules/hall-ui/public/builders.js +187 -219
  153. package/modules/hall-ui/public/diagrams.html +2 -0
  154. package/modules/hall-ui/public/dom-utils.js +27 -0
  155. package/modules/hall-ui/public/drachmae.html +2 -0
  156. package/modules/hall-ui/public/drachmae.js +54 -1
  157. package/modules/hall-ui/public/gate.css +98 -0
  158. package/modules/hall-ui/public/gate.html +3 -95
  159. package/modules/hall-ui/public/goal-inbox.js +4 -1
  160. package/modules/hall-ui/public/goals-page.js +626 -114
  161. package/modules/hall-ui/public/goals.css +79 -1
  162. package/modules/hall-ui/public/goals.html +38 -11
  163. package/modules/hall-ui/public/hall-widgets.js +62 -52
  164. package/modules/hall-ui/public/harbor.css +123 -0
  165. package/modules/hall-ui/public/harbor.html +3 -120
  166. package/modules/hall-ui/public/index.html +11 -4
  167. package/modules/hall-ui/public/instances-panel.js +4 -1
  168. package/modules/hall-ui/public/modules.css +63 -0
  169. package/modules/hall-ui/public/modules.html +3 -60
  170. package/modules/hall-ui/public/my-projects.html +78 -0
  171. package/modules/hall-ui/public/my-projects.js +142 -0
  172. package/modules/hall-ui/public/new-project-wizard.js +7 -3
  173. package/modules/hall-ui/public/not-ready.html +2 -0
  174. package/modules/hall-ui/public/pair.css +73 -0
  175. package/modules/hall-ui/public/pair.html +3 -70
  176. package/modules/hall-ui/public/palette.js +302 -0
  177. package/modules/hall-ui/public/primer.css +13 -0
  178. package/modules/hall-ui/public/primer.html +2 -0
  179. package/modules/hall-ui/public/profile.html +2 -0
  180. package/modules/hall-ui/public/ranks.html +2 -0
  181. package/modules/hall-ui/public/roadmap.css +179 -0
  182. package/modules/hall-ui/public/roadmap.html +9 -172
  183. package/modules/hall-ui/public/roadmap.js +329 -316
  184. package/modules/hall-ui/public/scouting.html +45 -0
  185. package/modules/hall-ui/public/scouting.js +73 -0
  186. package/modules/hall-ui/public/sessions.css +16 -0
  187. package/modules/hall-ui/public/sessions.html +3 -13
  188. package/modules/hall-ui/public/settings.html +2 -0
  189. package/modules/hall-ui/public/settings.js +4 -4
  190. package/modules/hall-ui/public/shell.js +143 -18
  191. package/modules/hall-ui/public/style.css +231 -39
  192. package/modules/hall-ui/public/task-detail.js +347 -26
  193. package/modules/hall-ui/public/task.html +6 -1
  194. package/modules/hall-ui/public/watch.html +2 -0
  195. package/modules/hall-ui/public/work.html +8 -6
  196. package/modules/hall-ui/public/work.js +1 -1
  197. package/modules/ideas/inbox.js +61 -11
  198. package/modules/ideas/routes/inbox.js +23 -0
  199. package/modules/lifecycle/claim-eligibility.js +72 -0
  200. package/modules/lifecycle/db.js +519 -139
  201. package/modules/lifecycle/done-when.js +18 -3
  202. package/modules/lifecycle/github-push.js +19 -2
  203. package/modules/lifecycle/goal-advisory.js +114 -0
  204. package/modules/lifecycle/goal-authz.js +62 -0
  205. package/modules/lifecycle/lifecycle.js +9 -0
  206. package/modules/lifecycle/publish-reconciler.js +109 -6
  207. package/modules/lifecycle/routes/claims.js +68 -23
  208. package/modules/lifecycle/routes/done-when.js +110 -15
  209. package/modules/lifecycle/routes/goals.js +8 -38
  210. package/modules/lifecycle/routes/tasks.js +38 -6
  211. package/modules/lifecycle/ship-card.js +6 -0
  212. package/modules/onboarding/onboarding-state.js +1 -1
  213. package/modules/platform-identity/CLAUDE.md +15 -0
  214. package/modules/platform-identity/hub-device.js +147 -0
  215. package/modules/platform-identity/hub-keys.js +151 -0
  216. package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
  217. package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
  218. package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
  219. package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
  220. package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
  221. package/modules/platform-identity/module.json +18 -0
  222. package/modules/platform-identity/platform-identity.js +531 -0
  223. package/modules/platform-identity/pollers/code-sweep.js +43 -0
  224. package/modules/platform-identity/routes/my-projects.js +140 -0
  225. package/modules/platform-identity/routes/projects.js +107 -0
  226. package/modules/platform-identity/routes/scouting.js +35 -0
  227. package/modules/platform-identity/routes/sso.js +402 -0
  228. package/modules/platform-identity/tests/platform-identity.mjs +388 -0
  229. package/modules/platform-identity/ui/.gitkeep +0 -0
  230. package/modules/security/routes/reports.js +10 -0
  231. package/modules/sessions/db.js +166 -21
  232. package/modules/sessions/module.json +1 -1
  233. package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
  234. package/modules/sessions/routes/sessions.js +33 -0
  235. package/modules/status-ui/public/explore.html +54 -0
  236. package/modules/status-ui/public/explore.js +67 -0
  237. package/package-lock.json +2 -2
  238. package/package.json +1 -1
  239. package/public-landing/assets/anim/idle/frame_00.webp +0 -0
  240. package/public-landing/assets/anim/idle/frame_01.webp +0 -0
  241. package/public-landing/assets/anim/idle/frame_02.webp +0 -0
  242. package/public-landing/assets/anim/idle/frame_03.webp +0 -0
  243. package/public-landing/assets/anim/idle/frame_04.webp +0 -0
  244. package/public-landing/assets/anim/idle/frame_05.webp +0 -0
  245. package/public-landing/assets/anim/idle/frame_06.webp +0 -0
  246. package/public-landing/assets/anim/idle/frame_07.webp +0 -0
  247. package/public-landing/assets/anim/idle/frame_08.webp +0 -0
  248. package/public-landing/assets/anim/idle/frame_09.webp +0 -0
  249. package/public-landing/assets/anim/idle/frame_10.webp +0 -0
  250. package/public-landing/assets/anim/idle/frame_11.webp +0 -0
  251. package/public-landing/assets/anim/idle/frame_12.webp +0 -0
  252. package/public-landing/assets/anim/idle/frame_13.webp +0 -0
  253. package/public-landing/assets/anim/idle/frame_14.webp +0 -0
  254. package/public-landing/assets/anim/idle/frame_15.webp +0 -0
  255. package/public-landing/assets/anim/idle/frame_16.webp +0 -0
  256. package/public-landing/assets/anim/idle/frame_17.webp +0 -0
  257. package/public-landing/assets/anim/idle/frame_18.webp +0 -0
  258. package/public-landing/assets/anim/idle/frame_19.webp +0 -0
  259. package/public-landing/assets/anim/idle/frame_20.webp +0 -0
  260. package/public-landing/assets/anim/idle/frame_21.webp +0 -0
  261. package/public-landing/assets/anim/idle/frame_22.webp +0 -0
  262. package/public-landing/assets/anim/idle/frame_23.webp +0 -0
  263. package/public-landing/assets/anim/idle/frame_24.webp +0 -0
  264. package/public-landing/assets/anim/idle/frame_25.webp +0 -0
  265. package/public-landing/assets/anim/idle/frame_26.webp +0 -0
  266. package/public-landing/assets/anim/idle/frame_27.webp +0 -0
  267. package/public-landing/assets/anim/idle/frame_28.webp +0 -0
  268. package/public-landing/assets/anim/idle/frame_29.webp +0 -0
  269. package/public-landing/assets/anim/idle/frame_30.webp +0 -0
  270. package/public-landing/assets/anim/idle/frame_31.webp +0 -0
  271. package/public-landing/assets/anim/idle/frame_32.webp +0 -0
  272. package/public-landing/assets/anim/idle/frame_33.webp +0 -0
  273. package/public-landing/assets/anim/idle/frame_34.webp +0 -0
  274. package/public-landing/assets/anim/idle/frame_35.webp +0 -0
  275. package/public-landing/assets/anim/idle/frame_36.webp +0 -0
  276. package/public-landing/assets/anim/idle/frame_37.webp +0 -0
  277. package/public-landing/assets/anim/idle/frame_38.webp +0 -0
  278. package/public-landing/assets/anim/idle/frame_39.webp +0 -0
  279. package/public-landing/assets/anim/idle/frame_40.webp +0 -0
  280. package/public-landing/assets/anim/idle/frame_41.webp +0 -0
  281. package/public-landing/assets/anim/idle/frame_42.webp +0 -0
  282. package/public-landing/assets/anim/idle/frame_43.webp +0 -0
  283. package/public-landing/create.html +252 -62
  284. package/public-landing/gate/README.md +137 -0
  285. package/public-landing/gate/dispmaps/bar.png +0 -0
  286. package/public-landing/gate/dispmaps/flat.png +0 -0
  287. package/public-landing/gate/dispmaps/key.png +0 -0
  288. package/public-landing/gate/index.html +587 -0
  289. package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
  290. package/public-landing/gate/previews/off-the-boats.jpg +0 -0
  291. package/public-landing/gate/space.css +799 -0
  292. package/public-landing/gate/space.js +1826 -0
  293. package/public-landing/gate/sprites/enter.png +0 -0
  294. package/public-landing/gate/sprites/search.png +0 -0
  295. package/public-landing/gate/sprites/terminal-blank.png +0 -0
  296. package/public-landing/gate/sprites/tile.png +0 -0
  297. package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
  298. package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
  299. package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
  300. package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
  301. package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
  302. package/public-landing/world/assets/plates/scene-establishing.png +0 -0
  303. package/scripts/gds/abandon.js +6 -4
  304. package/scripts/gds/api.js +10 -5
  305. package/scripts/gds/api.ps1 +26 -0
  306. package/scripts/gds/api.sh +6 -0
  307. package/scripts/gds/audit-ships.js +7 -1
  308. package/scripts/gds/backfill-sessions.js +78 -18
  309. package/scripts/gds/backup.js +23 -1
  310. package/scripts/gds/box-connect-lib.js +124 -31
  311. package/scripts/gds/box-sync.js +66 -0
  312. package/scripts/gds/box.js +225 -53
  313. package/scripts/gds/cf-tunnel.js +145 -6
  314. package/scripts/gds/claim.js +34 -3
  315. package/scripts/gds/cli-lib.js +161 -21
  316. package/scripts/gds/code.js +6 -2
  317. package/scripts/gds/deploy-divergence.js +209 -0
  318. package/scripts/gds/dev-lib.js +309 -0
  319. package/scripts/gds/dev.js +322 -0
  320. package/scripts/gds/doctor.js +90 -61
  321. package/scripts/gds/fetch-art-key.js +1 -1
  322. package/scripts/gds/fetch-sound-prefs.js +2 -2
  323. package/scripts/gds/fitness.js +228 -12
  324. package/scripts/gds/gds-db-backup.service +16 -1
  325. package/scripts/gds/gds-db-offsite.service +9 -1
  326. package/scripts/gds/gen-api-client.js +1 -1
  327. package/scripts/gds/gen-api-docs.js +36 -14
  328. package/scripts/gds/gen-diagrams.js +45 -28
  329. package/scripts/gds/gen-file-map.js +2 -1
  330. package/scripts/gds/gen-freshness.js +32 -0
  331. package/scripts/gds/gen-repo-map.js +3 -2
  332. package/scripts/gds/gen-session-index.js +14 -5
  333. package/scripts/gds/hooks/pre-push.js +2 -2
  334. package/scripts/gds/init.js +60 -3
  335. package/scripts/gds/install-git-hooks.js +1 -1
  336. package/scripts/gds/key-card.js +15 -6
  337. package/scripts/gds/key-status.js +1 -1
  338. package/scripts/gds/linkify-refs.js +35 -9
  339. package/scripts/gds/lint-migrations.js +102 -0
  340. package/scripts/gds/login.js +58 -11
  341. package/scripts/gds/mirror-redact.js +5 -0
  342. package/scripts/gds/package-core.js +263 -4
  343. package/scripts/gds/paste-token.js +7 -1
  344. package/scripts/gds/preflight.js +126 -0
  345. package/scripts/gds/provision.js +268 -19
  346. package/scripts/gds/publish-manifest.js +22 -1
  347. package/scripts/gds/reauth.js +7 -3
  348. package/scripts/gds/regen-instance-docs.js +47 -0
  349. package/scripts/gds/run-unit-tests.js +42 -16
  350. package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
  351. package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
  352. package/scripts/gds/sequence.js +425 -0
  353. package/scripts/gds/session-cost.js +10 -1
  354. package/scripts/gds/setup.js +72 -5
  355. package/scripts/gds/shell.js +5 -3
  356. package/scripts/gds/ship.js +433 -59
  357. package/scripts/gds/smoke-gds.js +139 -8
  358. package/scripts/gds/start.js +171 -22
  359. package/scripts/gds/status.js +1 -1
  360. package/scripts/gds/triage.js +10 -9
  361. package/scripts/gds/upgrade.js +271 -7
  362. package/scripts/migrate.sh +10 -0
  363. package/scripts/status-mirror-sync.js +114 -84
  364. package/src/bongos/api-errors.js +1 -0
  365. package/src/bongos/auth.js +809 -107
  366. package/src/bongos/db-kernel.js +27 -0
  367. package/src/bongos/db.js +105 -0
  368. package/src/bongos/github-repos.js +93 -0
  369. package/src/bongos/module-scope-map.js +27 -1
  370. package/src/bongos/permission-path-check.js +136 -102
  371. package/src/bongos/repo-info.js +47 -11
  372. package/src/bongos/route-rank-check.js +429 -46
  373. package/src/bongos/routes/_helpers.js +12 -1
  374. package/src/bongos/routes/auth.js +312 -13
  375. package/src/bongos/routes/backup.js +58 -2
  376. package/src/bongos/routes/github.js +90 -0
  377. package/src/bongos/routes/instance.js +15 -3
  378. package/src/bongos/routes/me.js +35 -1
  379. package/src/bongos/routes.js +2 -0
  380. package/src/bongos/serve-internal.js +84 -15
  381. package/src/branding.js +49 -2
  382. package/src/instance-config.js +46 -0
  383. package/src/module-api.js +140 -1
  384. package/src/platform-server.js +86 -9
  385. package/tests/abandon_task.mjs +59 -3
  386. package/tests/api_cli_flags.mjs +53 -0
  387. package/tests/auth_page_gate.mjs +13 -0
  388. package/tests/backfill_sessions.mjs +127 -1
  389. package/tests/backup_cli.mjs +54 -0
  390. package/tests/bongos_box_connect.mjs +77 -0
  391. package/tests/box_access.mjs +130 -1
  392. package/tests/box_credential.mjs +125 -0
  393. package/tests/box_host_keys.mjs +24 -0
  394. package/tests/box_infra_resolve.mjs +149 -0
  395. package/tests/box_scope_session.mjs +6 -2
  396. package/tests/box_sync.mjs +55 -0
  397. package/tests/box_task_scope.mjs +99 -0
  398. package/tests/branding.mjs +41 -23
  399. package/tests/cf_ruleset_preflight.mjs +142 -0
  400. package/tests/cf_tunnel.mjs +37 -0
  401. package/tests/claim_gate_rebase.mjs +98 -0
  402. package/tests/clawback_confirmed_backlog.mjs +103 -0
  403. package/tests/cli_lib_formatters.mjs +20 -0
  404. package/tests/confirm_attribution.mjs +30 -46
  405. package/tests/credit_grant.mjs +198 -10
  406. package/tests/criterion_authoring_gate.mjs +272 -0
  407. package/tests/criterion_progress.mjs +33 -1
  408. package/tests/dev_lib.mjs +253 -0
  409. package/tests/devbox_artifact_gate.mjs +75 -0
  410. package/tests/devbox_dmg_backdrop.mjs +137 -0
  411. package/tests/devbox_icons.mjs +304 -0
  412. package/tests/devbox_installer_brand.mjs +232 -0
  413. package/tests/devbox_key_register.mjs +234 -0
  414. package/tests/docs_openapi_route.mjs +110 -0
  415. package/tests/doctor_hooks.mjs +141 -0
  416. package/tests/extract_json.mjs +140 -0
  417. package/tests/fitness.mjs +89 -0
  418. package/tests/gen_freshness.mjs +96 -0
  419. package/tests/github_repos_helpers.mjs +91 -0
  420. package/tests/github_token_store.mjs +121 -0
  421. package/tests/goal_advisory.mjs +251 -0
  422. package/tests/goal_criterion_confirm_ui.mjs +269 -0
  423. package/tests/goal_routes.mjs +59 -4
  424. package/tests/goal_tier.mjs +12 -3
  425. package/tests/governance_catalog.mjs +129 -0
  426. package/tests/governance_claim_eligibility.mjs +262 -0
  427. package/tests/governance_config.mjs +187 -0
  428. package/tests/governance_ownership_scope.mjs +410 -0
  429. package/tests/governance_page_gates.mjs +324 -0
  430. package/tests/governance_parity.mjs +336 -0
  431. package/tests/governance_principals.mjs +232 -0
  432. package/tests/governance_protected_surfaces.mjs +208 -0
  433. package/tests/governance_require_permission.mjs +223 -0
  434. package/tests/governance_resolver.mjs +84 -0
  435. package/tests/governance_role_sync.mjs +231 -0
  436. package/tests/governance_seed.mjs +127 -0
  437. package/tests/governance_session_scope.mjs +434 -0
  438. package/tests/governance_vanilla_boot.mjs +203 -0
  439. package/tests/grade_attribution.mjs +7 -7
  440. package/tests/hall_audit.mjs +223 -0
  441. package/tests/hall_nav.mjs +191 -0
  442. package/tests/hall_palette.mjs +206 -0
  443. package/tests/hall_signout.mjs +124 -0
  444. package/tests/hook_user_agents.mjs +10 -0
  445. package/tests/idea_triage.mjs +162 -0
  446. package/tests/idp_device_exchange.mjs +198 -0
  447. package/tests/idp_federation.mjs +100 -0
  448. package/tests/init.mjs +51 -0
  449. package/tests/instance_config.mjs +65 -0
  450. package/tests/instance_mismatch_guard.mjs +23 -6
  451. package/tests/instance_release_config.mjs +104 -0
  452. package/tests/linkify_refs.mjs +15 -2
  453. package/tests/migrations_forward_safe.mjs +86 -0
  454. package/tests/module_api.mjs +1 -1
  455. package/tests/module_contributions.mjs +55 -0
  456. package/tests/module_loader.mjs +10 -5
  457. package/tests/module_scope_active_claims.mjs +94 -0
  458. package/tests/needs_rebase.mjs +92 -0
  459. package/tests/one_active_claim_per_session.mjs +76 -0
  460. package/tests/override_attribution.mjs +10 -8
  461. package/tests/override_request_ownership.mjs +8 -4
  462. package/tests/package_core.mjs +246 -1
  463. package/tests/parse_cookie_decode.mjs +42 -0
  464. package/tests/pay_on_land.mjs +129 -0
  465. package/tests/platform_boot.mjs +100 -1
  466. package/tests/post_login_landing.mjs +42 -0
  467. package/tests/preflight_checks.mjs +72 -0
  468. package/tests/provision.mjs +289 -7
  469. package/tests/pruned_lockfile_integrity.mjs +79 -0
  470. package/tests/publish_branch_route.mjs +53 -0
  471. package/tests/publish_reconciler.mjs +187 -2
  472. package/tests/repo_info_binding.mjs +248 -0
  473. package/tests/reward_gate.mjs +11 -2
  474. package/tests/reward_mode_cost_plus_only.mjs +116 -0
  475. package/tests/reward_mode_surfacing.mjs +168 -0
  476. package/tests/route_permission_check.mjs +301 -0
  477. package/tests/route_rank_check.mjs +254 -12
  478. package/tests/route_validation.mjs +30 -0
  479. package/tests/sequence.mjs +267 -0
  480. package/tests/session_digest.mjs +44 -0
  481. package/tests/session_index.mjs +18 -6
  482. package/tests/session_records.mjs +39 -1
  483. package/tests/session_reward_on_land.mjs +381 -0
  484. package/tests/session_reward_reconcile.mjs +229 -0
  485. package/tests/ship_api_client_pathspec.mjs +100 -0
  486. package/tests/ship_base_flag.mjs +93 -0
  487. package/tests/ship_ci_deploy.mjs +140 -3
  488. package/tests/ship_upstream_deletion.mjs +57 -0
  489. package/tests/smoke_target.mjs +233 -0
  490. package/tests/start_env_guard.mjs +87 -0
  491. package/tests/start_rebase_warning.mjs +103 -0
  492. package/tests/status_mirror_sync.mjs +122 -0
  493. package/tests/stop_refcheck.mjs +19 -1
  494. package/tests/task_goal_link.mjs +15 -6
  495. package/tests/upgrade.mjs +393 -5
  496. package/tests/web_admission_status.mjs +162 -0
  497. package/tests/write_validation_gaps.mjs +110 -0
  498. package/.gitignore +0 -91
  499. package/docs/adr/0139-platform-history-migration-to-cloudbongos.md +0 -94
  500. package/docs/adr/0140-cloudbongos-standalone-reprovision.md +0 -43
  501. package/scripts/hall-preview/fixtures/access-requests.json +0 -20
  502. package/scripts/hall-preview/fixtures/achievements.json +0 -76
  503. package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
  504. package/scripts/hall-preview/fixtures/audit-log.json +0 -68
  505. package/scripts/hall-preview/fixtures/blockers__detail.json +0 -12
  506. package/scripts/hall-preview/fixtures/box__me.json +0 -5
  507. package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -69
  508. package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
  509. package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
  510. package/scripts/hall-preview/fixtures/builders__roster.json +0 -48
  511. package/scripts/hall-preview/fixtures/goals.json +0 -502
  512. package/scripts/hall-preview/fixtures/goals__25.json +0 -96
  513. package/scripts/hall-preview/fixtures/goals__26.json +0 -67
  514. package/scripts/hall-preview/fixtures/goals__3.json +0 -103
  515. package/scripts/hall-preview/fixtures/goals__35.json +0 -49
  516. package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
  517. package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
  518. package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
  519. package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
  520. package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -32
  521. package/scripts/hall-preview/fixtures/inbox.json +0 -330
  522. package/scripts/hall-preview/fixtures/inbox__detail.json +0 -15
  523. package/scripts/hall-preview/fixtures/instance.json +0 -124
  524. package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
  525. package/scripts/hall-preview/fixtures/me.json +0 -476
  526. package/scripts/hall-preview/fixtures/me__art-key__own.json +0 -6
  527. package/scripts/hall-preview/fixtures/me__event-sound-prefs.json +0 -209
  528. package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
  529. package/scripts/hall-preview/fixtures/me__render.json +0 -5
  530. package/scripts/hall-preview/fixtures/me__skill-prefs.json +0 -143
  531. package/scripts/hall-preview/fixtures/me__sound-prefs.json +0 -67
  532. package/scripts/hall-preview/fixtures/me__wandering.json +0 -43
  533. package/scripts/hall-preview/fixtures/override-requests.json +0 -15
  534. package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
  535. package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
  536. package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
  537. package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
  538. package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
  539. package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
  540. package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
  541. package/scripts/hall-preview/fixtures/public__grades.json +0 -50
  542. package/scripts/hall-preview/fixtures/public__progress.json +0 -124
  543. package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
  544. package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
  545. package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
  546. package/scripts/hall-preview/fixtures/security__docs.json +0 -10
  547. package/scripts/hall-preview/fixtures/security__reports.json +0 -31
  548. package/scripts/hall-preview/fixtures/sessions__search.json +0 -9
  549. package/scripts/hall-preview/fixtures/tasks.json +0 -2420
  550. package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
  551. package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
  552. package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
  553. package/scripts/hall-preview/fixtures/versions.json +0 -89
@@ -83,7 +83,7 @@ module.exports = function buildMeRouter() {
83
83
  const [
84
84
  builder, activeClaims, estVsActual, unlocked, lockedWithProgress, streakInfo,
85
85
  recentGrades, builderAvg, onboardingRow, shipCount, recentKarma, karma30d, discordLink, boxConnected, cliAuthed,
86
- behaviorPrefs, geminiKeyRow,
86
+ behaviorPrefs, geminiKeyRow, needsRebaseTasks,
87
87
  ] = await Promise.all([
88
88
  db.getBuilderById(req.builder.id),
89
89
  lc().getActiveClaimsForBuilder(req.builder.id),
@@ -136,6 +136,14 @@ module.exports = function buildMeRouter() {
136
136
  // Own Gemini-key status via the art-pipeline port (ADR 0102) — the storage
137
137
  // is art-pipeline domain now; degrades to a no-key shape on a vanilla instance.
138
138
  seams.resolveOptional('art.getBuilderGeminiKeyRow', async () => ({ enc: null, last4: null, set_at: null }))(req.builder.id),
139
+ // ADR 0120 part 5: the confirmed tasks this builder owes a rebase on —
140
+ // un-landed confirmed work the publish-reconciler flagged needs_rebase
141
+ // (part 2). It GATES new claims (part 3: claimTask refuses REBASE_REQUIRED)
142
+ // and its per-task reward now lands only on ship (part 1), so the CLI
143
+ // (/builder-start) + the hall surface an owed-rebase warning from this
144
+ // without a follow-up call. Through the `lifecycle` port; [] on a
145
+ // lifecycle-less instance (guarded — the port is resolveOptional).
146
+ lc() ? lc().needsRebaseTasksForBuilder(req.builder.id) : [],
139
147
  ]);
140
148
  // V3.R84 (#302), criterion C3: the builder's month-to-date spend vs their
141
149
  // monthly budget. Surfaced here so the CLI (session-start ping) and the hall
@@ -148,6 +156,18 @@ module.exports = function buildMeRouter() {
148
156
  } catch (err) {
149
157
  console.error('[gds] GET /me cost status', err);
150
158
  }
159
+ // Best-effort read of the resolved reward policy (see the payload note).
160
+ // Never break the profile over a display concern — null degrades the CLI to
161
+ // its own paying default rather than a wrong "not paid" claim.
162
+ const rewardPolicySafe = () => {
163
+ try {
164
+ const p = typeof reward.rewardConfig === 'function' ? reward.rewardConfig() : null;
165
+ return p && typeof p.mode === 'string' ? { mode: p.mode, perTaskCredit: p.perTaskCredit !== false } : null;
166
+ } catch (err) {
167
+ console.error('[gds] GET /me reward policy', err);
168
+ return null;
169
+ }
170
+ };
151
171
  // For each active claim, compute the streak preview (cheap; pool query).
152
172
  // Lets the CLI render "shipping this would extend streak to N days" hints.
153
173
  const activeClaimsWithPreview = await Promise.all(
@@ -161,6 +181,20 @@ module.exports = function buildMeRouter() {
161
181
  active_claims: activeClaimsWithPreview,
162
182
  // Legacy field — first claim only. Prefer active_claims (plural).
163
183
  active_claim: activeClaimsWithPreview[0] ?? null,
184
+ // ADR 0120 part 5: un-landed confirmed tasks this builder owes a rebase on.
185
+ // Each row: { id, title, needs_rebase_reason, needs_rebase_at }, oldest
186
+ // first. Empty when none owed (or on a lifecycle-less instance). These GATE
187
+ // new claims (part 3) and their reward is pending until they land on ship
188
+ // (part 1); the CLI + hall render a warning off this array.
189
+ needs_rebase_tasks: needsRebaseTasks,
190
+ // ADR 0146 / task 1002469: the instance's RESOLVED reward policy, so the
191
+ // CLI can label a task's advertised `credits_reward` honestly. On a
192
+ // `cost-plus-only` instance that estimate is never paid, and a builder who
193
+ // isn't told reads a correct `+0` at ship as a broken payout. It must come
194
+ // from the SERVER — the instance's branding.json is not in the builder's
195
+ // checkout, so a laptop reading local config always sees the default.
196
+ // Resolved by economy (never re-derived); null if economy is disabled.
197
+ reward: rewardPolicySafe(),
164
198
  est_vs_actual: estVsActual,
165
199
  unlocked,
166
200
  locked_with_progress: lockedWithProgress,
@@ -20,6 +20,7 @@ const express = require('express');
20
20
  const buildHealthzRouter = require('./routes/healthz');
21
21
  const buildInstanceRouter = require('./routes/instance');
22
22
  const buildAuthRouter = require('./routes/auth');
23
+ const buildGithubRouter = require('./routes/github');
23
24
  const buildMeRouter = require('./routes/me');
24
25
  const buildBuildersRouter = require('./routes/builders');
25
26
  // The LIFECYCLE routes (tasks · claims · versions · done-when · goals ·
@@ -116,6 +117,7 @@ function buildGdsRouter() {
116
117
  router.use(buildHealthzRouter());
117
118
  router.use(buildInstanceRouter());
118
119
  router.use(buildAuthRouter());
120
+ router.use(buildGithubRouter());
119
121
  router.use(buildMeRouter());
120
122
  router.use(buildBuildersRouter());
121
123
  // tasks · claims · versions · done-when · goals · dependencies · analytics now
@@ -47,7 +47,7 @@ const { buildBongosDownloads } = require('../bongos-downloads');
47
47
  const { clientBranding, branding } = require('../branding');
48
48
  const { clientModules, isModuleEnabled } = require('../modules');
49
49
  const { hallWidgetScripts, moduleWebSurfaces } = require('../module-loader/loader');
50
- const { resolveCoreRoot } = require('../instance-config');
50
+ const { resolveCoreRoot, resolveDocsRoot, resolveInstanceRoot } = require('../instance-config');
51
51
  const { API_PREFIX, LEGACY_API_PREFIXES, API_VERSION, VERSIONED_API_PREFIX, ALL_API_PREFIXES } = require('./api-prefix');
52
52
 
53
53
  // ADR 0108 §1: every use of ROOT below (infra/ installers, modules/, docs/) is
@@ -56,15 +56,28 @@ const { API_PREFIX, LEGACY_API_PREFIXES, API_VERSION, VERSIONED_API_PREFIX, ALL_
56
56
  const ROOT = resolveCoreRoot();
57
57
 
58
58
  // Instance-only RELEASE config (config/devbox-app.json, config/bongos-cli.json) is
59
- // boundary-excluded from the portable core (publish-manifest INSTANCE_EXCLUDE), so a
60
- // vanilla self-host boot ships without it. Requiring it hard used to CRASH the boot
61
- // (task 1824). Guard the require so an absent config makes its download surface simply
62
- // not mount (fail-to-vanilla, like branding/modules) rather than take the server down.
63
- // A malformed config (JSON parse error, etc.) still throws — only a MISSING file is
64
- // tolerated. A branded instance that ships the config gets the routes exactly as before.
65
- function tryRequireConfig(relPath) {
66
- try { return require(relPath); }
67
- catch (e) { if (e && e.code === 'MODULE_NOT_FOUND') return null; throw e; }
59
+ // boundary-excluded from the portable core (publish-manifest INSTANCE_EXCLUDE), so it is
60
+ // HOST content: it lives at the INSTANCE root, which on a vendored instance is NOT the
61
+ // package dir this file sits under. A core-relative require therefore looked in
62
+ // node_modules/@bongos/core/config/ and never found it, so /downloads/* silently failed
63
+ // to mount (task 1002371 — same class as ADR 0144's vendored infra/ path bug; ADR 0145's
64
+ // copy-the-config-into-node_modules workaround is lost on the next `npm ci`). So resolve
65
+ // the instance root FIRST — the branding/modules resolution (src/branding.js INSTANCE_PATH)
66
+ // — then the core package dir, which keeps a single checkout (and that copied-in
67
+ // workaround) byte-identical.
68
+ //
69
+ // Fail-soft is preserved verbatim: an ABSENT config makes its download surface simply not
70
+ // mount (fail-to-vanilla, like branding/modules) rather than crash the boot as the original
71
+ // hard require did (task 1824); a MALFORMED config still throws — only a MISSING file is
72
+ // tolerated. `roots` is injected so the ladder is unit-testable with zero ambient state.
73
+ function tryLoadInstanceConfig(name, roots = [resolveInstanceRoot(), ROOT]) {
74
+ for (const root of new Set(roots)) {
75
+ let raw;
76
+ try { raw = fs.readFileSync(path.join(root, 'config', name), 'utf8'); }
77
+ catch (e) { if (e.code === 'ENOENT') continue; throw e; }
78
+ return JSON.parse(raw);
79
+ }
80
+ return null;
68
81
  }
69
82
 
70
83
  // Map the pack's camelCase theme color keys → the kebab-case CSS custom
@@ -193,6 +206,60 @@ function docsIndexHtml() {
193
206
  return _docsHtml;
194
207
  }
195
208
 
209
+ // The OpenAPI 3.1 spec served at /docs/openapi.json — SELF-HEALING (task 1002200).
210
+ // The Redoc page (public-docs/) ships as static assets, but the SPEC is a generated
211
+ // artifact whose on-disk copy is NOT guaranteed at every deploy topology, so a bare
212
+ // res.sendFile(one fixed path) 404s exactly when the file is missing:
213
+ // • Standalone instance (ADR 0108/0140): the route resolves from the CORE package
214
+ // (resolveCoreRoot → node_modules/@bongos/core) while the generator writes the
215
+ // INSTANCE's own spec to resolveDocsRoot (the instance repo) — a path mismatch.
216
+ // • A pinned @bongos/core that predates the spec's packaging ships NO copy at all
217
+ // (the observed cloudbongos.com 404: public-docs/ shipped, docs/api/ didn't).
218
+ // • A fresh instance, before its first generate, has neither.
219
+ // So resolve the spec in tiers: (1) the committed spec at resolveDocsRoot() (the
220
+ // instance's own — carries its module routes), then (2) at resolveCoreRoot() (the
221
+ // core-package copy), then (3) GENERATE it in-process from the live route source.
222
+ // gen-api-docs.build() reads routes from resolveCoreRoot() (always present — it IS
223
+ // the running code), is DB-free + express-free (a pure line+regex extractor that
224
+ // never executes a route or opens a connection), and yields the identical spec.
225
+ // resolveOpenapiJson is the pure, injectable core so the fallback ladder is unit-
226
+ // testable (tests/docs_openapi_route.mjs).
227
+ function resolveOpenapiJson({ candidates = [], generate } = {}) {
228
+ for (const p of candidates) {
229
+ let raw;
230
+ try { raw = fs.readFileSync(p, 'utf8'); } catch { continue; } // absent → next tier
231
+ try { JSON.parse(raw); } catch { continue; } // corrupt → next tier
232
+ return raw;
233
+ }
234
+ if (typeof generate === 'function') {
235
+ try {
236
+ const out = generate();
237
+ if (out) return out;
238
+ } catch (e) {
239
+ console.error('[docs] in-process OpenAPI generation failed:', e && e.message);
240
+ }
241
+ }
242
+ return '';
243
+ }
244
+
245
+ // Memoized like docsIndexHtml: one resolve per process; a redeploy restarts and
246
+ // re-resolves. '' (→ the route falls through to 404) only if every tier fails.
247
+ let _openapiJson;
248
+ function openapiJson() {
249
+ if (_openapiJson !== undefined) return _openapiJson;
250
+ const roots = [...new Set([resolveDocsRoot(), ROOT])]; // instance repo first, then core pkg
251
+ _openapiJson = resolveOpenapiJson({
252
+ candidates: roots.map((r) => path.join(r, 'docs/api/openapi.json')),
253
+ generate() {
254
+ // Lazy require: boot never pays for it, and a generator hiccup is contained
255
+ // to this one endpoint rather than taking down server start.
256
+ const gen = require('../../scripts/gds/gen-api-docs.js');
257
+ return JSON.stringify(gen.build().spec, null, 2) + '\n';
258
+ },
259
+ });
260
+ return _openapiJson;
261
+ }
262
+
196
263
  // The browser-global build of the generated typed client (task 1996 / R09),
197
264
  // served at /lib/bongos-client.js so classic <script> web pages can consume the
198
265
  // same generated client the CLI uses (window.BongosClient). Read once at boot
@@ -408,7 +475,7 @@ function mountInternalSurfaces(app) {
408
475
  // builders.<apex> (the builders rewrite shim below only prefixes non-/api
409
476
  // paths, so without this placement /downloads/* would be rewritten to
410
477
  // /builders/downloads/* and 404).
411
- const devboxCfg = tryRequireConfig('../../config/devbox-app.json');
478
+ const devboxCfg = tryLoadInstanceConfig('devbox-app.json');
412
479
  if (devboxCfg) {
413
480
  const devboxDownloads = buildDevboxDownloads(devboxCfg);
414
481
  app.get('/downloads/devbox/latest.json', (_req, res) => {
@@ -439,7 +506,7 @@ function mountInternalSurfaces(app) {
439
506
  // every user-facing URL on the apex. The installer scripts are served with the
440
507
  // server's PINNED origin substituted for __GDS_API_BASE__ — never a request
441
508
  // header, so a spoofed Host can't redirect a `curl | sh` (the box-connect.sh rule).
442
- const bongosCfg = tryRequireConfig('../../config/bongos-cli.json');
509
+ const bongosCfg = tryLoadInstanceConfig('bongos-cli.json');
443
510
  if (bongosCfg) {
444
511
  const bongosDownloads = buildBongosDownloads(bongosCfg);
445
512
  // Pinned public origin for the served installer scripts (never a request header —
@@ -847,7 +914,7 @@ function mountInternalSurfaces(app) {
847
914
  // external fetch (matches the /vendor/* self-hosting convention; CSP-safe).
848
915
  // GET /docs → the Redoc host page (branding-injected)
849
916
  // GET /docs/redoc.standalone.js → the vendored renderer (long-cached)
850
- // GET /docs/openapi.json → the generated spec (CORS-open so Postman/Swagger/AI can fetch it)
917
+ // GET /docs/openapi.json → the spec, SELF-HEALING (committed → generated), CORS-open so Postman/Swagger/AI can fetch it; see openapiJson()
851
918
  app.get('/docs', (req, res, next) => {
852
919
  if (isModuleSurfaceHost(req)) return next();
853
920
  const html = docsIndexHtml();
@@ -864,10 +931,12 @@ function mountInternalSurfaces(app) {
864
931
  });
865
932
  app.get('/docs/openapi.json', (req, res, next) => {
866
933
  if (isModuleSurfaceHost(req)) return next();
934
+ const json = openapiJson();
935
+ if (!json) return next(); // no committed spec + generation failed → fall through to 404
867
936
  res.set('Access-Control-Allow-Origin', '*'); // read-only spec — tools fetch it cross-origin
868
937
  res.set('Cache-Control', 'public, max-age=60');
869
938
  res.type('application/json');
870
- res.sendFile(path.join(ROOT, 'docs/api/openapi.json'));
939
+ res.send(json);
871
940
  });
872
941
 
873
942
  app.use((req, res, next) => {
@@ -895,4 +964,4 @@ function mountInternalSurfaces(app) {
895
964
  return app;
896
965
  }
897
966
 
898
- module.exports = { mountInternalSurfaces, isStatusHost, isBuildersHost, injectBrandingGlobal, injectBrandingInto, injectModuleHallWidgets, themeMarkup, applyBrandTokens };
967
+ module.exports = { mountInternalSurfaces, isStatusHost, isBuildersHost, injectBrandingGlobal, injectBrandingInto, injectModuleHallWidgets, themeMarkup, applyBrandTokens, resolveOpenapiJson, openapiJson, tryLoadInstanceConfig };
package/src/branding.js CHANGED
@@ -44,6 +44,16 @@ const ENV_OVERRIDES = [
44
44
  ['OAUTH_ORIGIN', ['domains', 'oauthOrigin']],
45
45
  ['PROVISIONING_ORIGIN', ['domains', 'provisioningOrigin']],
46
46
  ['COOKIE_DOMAIN', ['domains', 'cookieDomain']],
47
+ // Cross-site identity federation flip (ADR 0141 §4). Provisioning sets
48
+ // <PREFIX>_AUTH_IDP=true per hosted instance (config/branding.neutral.json ships
49
+ // idp:false), so a co-tenant instance sharing the neutral pack still federates
50
+ // individually. 'bool'-coerced below — auth.js idpEnabled() reads it as strict === true.
51
+ ['AUTH_IDP', ['auth', 'idp'], 'bool'],
52
+ // Post-sign-in landing when no ?return=/Referer was carried (auth.js
53
+ // postLoginLanding). Env-overridable so a platform-home instance can flip its
54
+ // front door with one env var and no instance branding.json — cloudbongos.com
55
+ // sets <PREFIX>_POST_LOGIN_LANDING=/gate/ (the orbs). Task 1002240.
56
+ ['POST_LOGIN_LANDING', ['landing', 'postLogin']],
47
57
  ];
48
58
 
49
59
  const isObj = (v) => v && typeof v === 'object' && !Array.isArray(v);
@@ -69,6 +79,12 @@ function deepFreeze(o) {
69
79
  return o;
70
80
  }
71
81
 
82
+ // This is the ONE structured host-identity contract. Project context (vision/world/visual-style
83
+ // prose in docs/project-context.md) is deliberately PROSE-ONLY — there is no parallel resolver for
84
+ // it, because nothing in the platform reads project context as data; it is written for agents to
85
+ // read. If a host value must be CODE-READ, add it HERE (branding), not a new project-context
86
+ // resolver. Decided in ADR 0142 (audit H11 / task 1002224).
87
+ //
72
88
  // Pure resolver — all inputs injected, so tests drive it with zero I/O.
73
89
  function resolveBranding({ neutral = {}, instance = {}, env = {} } = {}) {
74
90
  // structuredClone so the merged result shares no nested references with the
@@ -76,9 +92,13 @@ function resolveBranding({ neutral = {}, instance = {}, env = {} } = {}) {
76
92
  // the caller's input objects (deepMerge shallow-copies only the top level).
77
93
  const resolved = structuredClone(deepMerge(neutral, instance));
78
94
  const prefix = resolved.envPrefix || 'CLOUDBONGOS';
79
- for (const [suffix, p] of ENV_OVERRIDES) {
95
+ for (const [suffix, p, coerce] of ENV_OVERRIDES) {
80
96
  const v = env[`${prefix}_${suffix}`];
81
- if (v !== undefined && v !== '') setPath(resolved, p, v);
97
+ if (v === undefined || v === '') continue;
98
+ // Most overrides are string-valued (origins, cookie domain) and set verbatim. A
99
+ // 'bool'-tagged override (auth.idp) coerces the env string to a real boolean —
100
+ // idpEnabled() checks `=== true`, so an uncoerced "true" would never federate.
101
+ setPath(resolved, p, coerce === 'bool' ? /^(1|true|yes|on)$/i.test(String(v)) : v);
82
102
  }
83
103
  const missing = REQUIRED.filter((p) => {
84
104
  const v = getPath(resolved, p);
@@ -177,7 +197,34 @@ function clientBranding(b = branding()) {
177
197
  notFound: b.copy?.notFound || 'Page not found.',
178
198
  },
179
199
  rankLabels: b.rankLabels || {},
200
+ reward: clientReward(),
180
201
  };
181
202
  }
182
203
 
204
+ // The RESOLVED reward policy, projected client-safe (ADR 0146 follow-up, task
205
+ // 1002469). Display surfaces need to know which streams this instance actually
206
+ // pays — on a `cost-plus-only` instance the per-task "Est." is a guide, never a
207
+ // payout, and a builder who is not told that reads a correct `+0` as a bug.
208
+ //
209
+ // Resolved through the economy module's `reward` port, NOT re-derived here: the
210
+ // mode→perTaskCredit mapping is economy's to own (ADR 0146 put the knob inside
211
+ // the module deliberately). `module-seams` is a dependency-free leaf, so this
212
+ // adds no boot-order coupling to the config layer.
213
+ //
214
+ // Fail-safe: an instance with economy disabled, or a resolve that throws, falls
215
+ // back to the ADR 0146 DEFAULT (pay both streams) — the same direction the pure
216
+ // resolver takes an unknown mode, so a hiccup can never silently tell builders
217
+ // their per-task reward is withheld.
218
+ function clientReward() {
219
+ const fallback = { mode: 'cost-plus-and-estimate', perTaskCredit: true };
220
+ try {
221
+ const reward = require('./module-seams').resolveOptional('reward');
222
+ const p = reward && typeof reward.rewardConfig === 'function' ? reward.rewardConfig() : null;
223
+ if (!p || typeof p.mode !== 'string') return fallback;
224
+ return { mode: p.mode, perTaskCredit: p.perTaskCredit !== false };
225
+ } catch (_) {
226
+ return fallback;
227
+ }
228
+ }
229
+
183
230
  module.exports = { resolveBranding, loadBranding, deepMerge, branding, clientBranding, userAgent, NEUTRAL_PATH, INSTANCE_PATH };
@@ -50,6 +50,50 @@ function envPrefix(b = safeBrand()) {
50
50
  return b.envPrefix || FALLBACK_ENV_PREFIX;
51
51
  }
52
52
 
53
+ // The default API base the CLI targets when there is no <PREFIX>_API_BASE env
54
+ // override AND no logged-in session api_base — i.e. the last-resort fallback.
55
+ // Resolves to THIS instance's own publicOrigin from the branding pack (OTB →
56
+ // https://amazonprimea.com, vanilla → http://localhost:3000), so the portable
57
+ // core never hard-codes another instance's URL (task 1002201 — pre-ADR-0139 the
58
+ // literal 'https://amazonprimea.com' was baked into cli-lib, sending every
59
+ // unconfigured consumer at the founder's game box). Single source of truth: every
60
+ // CLI base resolution routes through here. Last-resort http://localhost:3000 when
61
+ // branding can't be read at all — a local dev origin, never a foreign prod, so an
62
+ // unconfigured raw CLI fails safe rather than acting against someone else's DB.
63
+ function defaultApiBase(b = safeBrand()) {
64
+ const origin = b && b.domains && b.domains.publicOrigin;
65
+ return (typeof origin === 'string' && origin.trim()) || 'http://localhost:3000';
66
+ }
67
+
68
+ // The API base a CLI command should actually talk to:
69
+ // <PREFIX>_API_BASE (env) → the PERSISTED session's api_base → defaultApiBase()
70
+ // The session beats the branding default because a builder authenticated against
71
+ // instance A must keep hitting A even when this checkout's own branding names B —
72
+ // which is exactly what broke re-auth (task 1002427). cliClient() had this order
73
+ // right; paste-token.js hardcoded the founder host and reauth.js used the bare
74
+ // branding default, so a token minted by one instance was verified against
75
+ // another and rejected 401. Every base resolution routes through here so the
76
+ // three cannot drift again.
77
+ //
78
+ // `session` is injected by callers that already loaded it (cliClient) and read
79
+ // from the session file otherwise; pass null to mean "no session" without a disk
80
+ // read. Never returns empty — an unusable api_base falls back to the default.
81
+ function resolveApiBase({ session, env = process.env, b = safeBrand() } = {}) {
82
+ const fromEnv = resolveEnv('API_BASE', { env, prefix: envPrefix(b) });
83
+ if (fromEnv) return fromEnv;
84
+ let s = session;
85
+ if (s === undefined) {
86
+ try {
87
+ const raw = readConfigFileSync('gds-session.json', { b });
88
+ s = raw ? JSON.parse(raw) : null;
89
+ } catch (_) {
90
+ s = null; // unreadable/corrupt session must never break base resolution
91
+ }
92
+ }
93
+ const fromSession = s && typeof s.api_base === 'string' && s.api_base.trim();
94
+ return fromSession || defaultApiBase(b);
95
+ }
96
+
53
97
  // Absolute path to the instance config dir — the WRITE target and first read.
54
98
  function configHome(b = safeBrand()) {
55
99
  return path.join(os.homedir(), '.config', configDirName(b));
@@ -186,6 +230,8 @@ module.exports = {
186
230
  LEGACY_ENV_PREFIXES,
187
231
  configDirName,
188
232
  envPrefix,
233
+ defaultApiBase,
234
+ resolveApiBase,
189
235
  configHome,
190
236
  configReadDirs,
191
237
  configPath,
package/src/module-api.js CHANGED
@@ -218,8 +218,138 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
218
218
  // post-dates the published 1.17.3 tarball — a new user-facing feature set with no
219
219
  // doorway export removal, so semver MINOR. NOT yet published to npm (that is the
220
220
  // follow-on release task); amazonprimea still runs the vendored 1.17.3.
221
+ // 1.18.1 — go-live cut deployed to cloudbongos.com (owner-directed, 2026-07-14). Rolling
222
+ // 1.18.0 content PLUS the onboarding GitHub repo picker + auto-create (task 1002099,
223
+ // ADR 0143 — core auth: opt-in public_repo scope, encrypted short-TTL token store,
224
+ // GET/POST /github/repos) and the goal 1000041 cross-project hub features
225
+ // (platform-identity module, ADR 0141). Adds no doorway export → semver PATCH.
226
+ // 1.18.2 — go-live cut for cloudbongos.com (owner-directed, 2026-07-14). Rolling 1.18.1
227
+ // content PLUS the /create onboarding repo-picker rendering fix (task 1002228):
228
+ // the Home step's `hidden` attribute was defeated by author display rules
229
+ // (.field/.row2), so the adopt-picker / fresh-name / manual sub-panels all showed
230
+ // at once, and #ghConnect never appeared (toggled via `hidden` instead of its .on
231
+ // class). A CSS/markup-only fix in public-landing/create.html. No doorway export
232
+ // change → semver PATCH.
233
+ // 1.18.3 — package-core .gitignore pin fix (task 1002229, idea 1000543). `npm install` never
234
+ // materializes .gitignore/.npmignore/.npmrc into an installed package, but package-core
235
+ // pinned a tracked .gitignore in tree_sha256 → every vendored `bongos upgrade` pin-verify
236
+ // failed with `missing installed file: .gitignore` and auto-rolled-back (the workaround
237
+ // was --skip-pin-verify, which the unattended auto-upgrade subscription cannot pass).
238
+ // package-core now drops npm-stripped files from the manifest + pin so it describes exactly
239
+ // what npm installs. Build-tool fix, no doorway export change → semver PATCH.
240
+ // 1.18.4 — ship the platform-identity hub module in the core package (task 1002235, goal 1000041).
241
+ // The module (ADR 0141: /sso/*, projects catalog, my-projects, scouting + its migrations) was
242
+ // built but never added to publish-manifest PUBLISH_ALLOWLIST, so it did not ship in
243
+ // @bongos/core — the hub's enabledModules() threw "unknown module platform-identity" and
244
+ // provision.js's federation load MODULE_NOT_FOUNDed. Reclassified IN (sibling of provisioning);
245
+ // default:false → shipped ≠ enabled, dormant on every instance until the hub turns it on. PATCH.
246
+ // 1.18.5 — configurable post-login landing (task 1002240, goal 1000041). A successful web sign-in
247
+ // that carried no explicit ?return= / same-apex Referer now lands on branding.landing.postLogin
248
+ // (auth.js postLoginLanding) instead of a hardcoded /builders. Portable default stays
249
+ // '/builders' (the hall always exists); env-overridable per instance via
250
+ // <PREFIX>_POST_LOGIN_LANDING. cloudbongos.com sets it to /gate/ so a visitor who signs in
251
+ // from the orbs returns to the orbs, never auto-redirected into the builders' hall. The value
252
+ // is validated through the open-redirect allowlist. Additive config read, no doorway change → PATCH.
253
+ // 1.18.6 — post-login ?return= fix (task 1002241). parseCookie() now URL-DECODES the cookie
254
+ // value, symmetric with Express res.cookie's percent-ENCODING. Before this, a return
255
+ // target like "/create" was stored as "%2Fcreate"; safeReturnTo() rejected the encoded
256
+ // form and every explicit ?return= fell through to the post-login landing (on
257
+ // cloudbongos.com, /gate/) — most visibly the onboarding "Connect GitHub" button, which
258
+ // bounced to the orbs instead of back to the wizard. Also un-breaks the #726 subdomain
259
+ // return. A bug fix in a shared route helper, no doorway change → PATCH.
260
+ // 1.18.7 — federated single-logout (task 1002238, goal 1000041, ADR 0144). Signing out of the hub now
261
+ // signs you out of every federated project too. Core gains: a `builder.logout` seam event
262
+ // (emitted by POST /auth/logout), a POST /auth/backchannel-logout endpoint (dormant unless the
263
+ // instance federates — idp set), and auth.js verifyHubLogoutToken. The hub (platform-identity)
264
+ // listens for builder.logout and fans a hub-signed EdDSA logout token out to each federated
265
+ // instance the builder entered, which verifies it (aud-scoped, purpose-tagged, ~120s TTL) and
266
+ // revokes that builder's local sessions. Identity/trust boundary intact (the token carries only
267
+ // a subject + purpose, never a rank). Additive event + route, no doorway change → PATCH.
268
+ // 1.18.8 — hall sign-out works on every page (task 1002245). The real sign-out (POST /auth/logout:
269
+ // revoke session + clear cookies + emit the `builder.logout` federated single-logout) was wired
270
+ // ONLY in the index script (builders.js); shell.js draws the sign-out control on EVERY hall page
271
+ // as a bare GET anchor to the POST-only endpoint, so on non-index pages the click 404'd — the
272
+ // session was never revoked and the hub never notified (the 1.18.7 SLO was bypassed). Centralized
273
+ // in shell.js (doLogout + a delegated click listener), with tests/hall_signout.mjs proving it.
274
+ // Also carries minor /create wizard polish (tasks 1002246/1002247). Client + shared-surface fix,
275
+ // no doorway change → PATCH.
276
+ // 1.18.9 — /create onboarding: the wizard's own "Sign in with GitHub" now requests repo scope up front
277
+ // (read:user + public_repo via &repos=1), so a visitor who signs in THROUGH the create flow grants
278
+ // everything in one GitHub screen and never hits the separate "Connect GitHub" step at Home —
279
+ // ensureRepoAccess()'s probe finds the stored token and shows the picker/creator directly. Also
280
+ // reworks the residual need-connect copy + button ("Allow repo access") so a user already signed
281
+ // in with identity-only scope isn't asked to "connect" as if signing in twice. Hall + CLI sign-in
282
+ // stay identity-only (ADR 0143 least-privilege default). Client-only (public-landing/create.html),
283
+ // no doorway change → PATCH. (task 1002259)
284
+ // 1.18.10 — reward-mode go-live: the configurable per-instance branding.reward.mode knob (economy;
285
+ // ADR 0146) lands together with the goal-1000037 pay-on-land migrations. Cloud Bongos selects
286
+ // "cost-plus-only" (instance config), so a shipped task pays only the cost-plus session reward,
287
+ // not the per-task author estimate; the estimate still rides the row for display + the no-zero
288
+ // claim gate. This deploy applies core_193 (tasks.needs_rebase columns) + core_194 (the one-time
289
+ // confirmed-backlog clawback). Default stays "cost-plus-and-estimate" → every other instance is
290
+ // unchanged; economy-only, no doorway change → PATCH. (task 1002270 + goal 1000037 go-live 1002273)
291
+ // 1.18.12 — Docs-surface correctness (task 1002374). User-facing "GDS"/"Game Development System" →
292
+ // "Bongos" (primer, OpenAPI spec title/description + reference header, the two CLI session
293
+ // messages the primer quotes). 04-architecture diagram REDRAWN for the standalone model —
294
+ // own repo + auto-pull deploy (ADR 0129) + vendored @bongos/core (ADR 0108), product-neutral;
295
+ // it had hardcoded the reference game monorepo (amazonprimea.com / GitHub-Actions deploy-prod.yml
296
+ // / "the live game"). Docs/prose + diagram generator only, no schema/doorway change → PATCH.
297
+ // 1.18.11 — Standalone instances get live-updating docs (ADR 0147, task 1002314). gen-session-index.js
298
+ // now resolves the INSTANCE root (was hardcoded to the core, so a standalone box indexed
299
+ // node_modules/@bongos/core instead of its own sessions); adds upgrade.regenerateNavDocs() +
300
+ // a regen-instance-docs.js CLI wired into init/upgrade/provision-deploy; INSTANCE_GITIGNORE
301
+ // ignores the whole-file nav docs. Docs-pipeline only, no schema/doorway change → PATCH.
302
+ // (go-live 1002318)
303
+ // 1.18.12 — docs-surface correctness: GDS→Bongos rename + standalone architecture redraw
304
+ // (task 1002374). Docs/prose + diagram generator only, no schema/doorway change → PATCH.
305
+ // 1.18.13 — `bongos dev`: one-command LOCAL launcher for a standalone instance (task 1002397,
306
+ // ADR 0149). New CLI verb + scripts/gds/dev.js + dev-lib.js so a freshly-created,
307
+ // localhost-configured project stands up locally in one step. No schema/doorway change → PATCH.
308
+ // 1.18.14 — module pollers actually start on a standalone instance (task 1002419). The loader's
309
+ // startModulePollers had ZERO callers once the game entrypoint server.js was retired, so
310
+ // EVERY module poller was dead — most visibly lifecycle/publish-reconciler, which is what
311
+ // drives confirmed→shipped, leaving merged tasks stranded at 'confirmed' indefinitely
312
+ // (12 rows, oldest 6.2 days). src/platform-server.js now starts them at boot behind the
313
+ // same isEnabled gate mountModuleRoutes uses, and stops them on SIGTERM/SIGINT. Wiring
314
+ // only — no schema/doorway change → PATCH. Any instance on ≤1.18.13 lands nothing until
315
+ // it takes this bump.
316
+ // 1.18.15 — re-release of the 1.18.14 module-poller fix (task 1002419) under a fresh number.
317
+ // A SEPARATE release had already published 1.18.14 for the task-scoped dev-box go-live
318
+ // (goal 1000051), so the poller-fix 1.18.14 could never reach an instance already pinned to
319
+ // the dev-box 1.18.14 (same version = npm no-op; the pull-deploy loop skips npm ci when the
320
+ // lockfile is unchanged). This bump carries the identical src/platform-server.js poller
321
+ // wiring forward on a number no instance has taken yet, so the pin can actually move. No
322
+ // code delta vs the 1.18.14 already on main — version constant only → PATCH. (task 1002421)
323
+ // 1.18.16 — go-live carrier for the hall version-UI work already merged to main since 1.18.15:
324
+ // the Roadmap "Command deck" redesign (task 1002426) and the sidebar reorg — nav order
325
+ // Roadmap→Goals→Tasks, the "Work" board relabelled "Tasks", goal-detail task parity
326
+ // (task 1002425, PR #17). Both landed on main with NO version bump, so no vendored-tarball
327
+ // instance could take them (the pull-deploy pin only moves on a fresh number). No new code
328
+ // delta beyond this constant → PATCH. (go-live task 1002431)
329
+ // 1.18.17 — Goals page reorganised into a task-readiness rollup (grouped
330
+ // Active/Blocked/Achieved; each goal rolls its tasks into ready/in-progress/
331
+ // blocked + a next claimable task) and the task-list API gained an opt-in
332
+ // `?include=deps` that enriches each task with blocked_by[]/blocks so the
333
+ // hall can paint readiness without an N+1 (db.attachTaskDepSummaries). New
334
+ // export is additive; the enrichment is opt-in → PATCH. (task 1002439)
335
+ // 1.18.18 — go-live carrier for 171 commits that landed on main between 2026-07-24
336
+ // and 2026-08-03 with no bump behind them, so no vendored-tarball instance
337
+ // could take any of them. Headline: the governance permission system
338
+ // (BV1.R95–R109 — resolver + kernel port, first-class principals, session
339
+ // scopes, requirePermission(), ownership-scoped grants, config/governance.json)
340
+ // and the route-rank/validation hardening that followed it; the ship.js
341
+ // Windows project-path fix so Windows sessions actually get paid (89f291c);
342
+ // the sequential chain runner (task 1002484); Metic task abandon/un-abandon
343
+ // (ADR 0152); goal-authored criteria + the orphan-task goal_advisory (ADR
344
+ // 0154); the nightly-backup 203/EXEC fix (task 1002479); and a broad hall
345
+ // pass (jump palette, sidebar regroup, browser-side idea triage, mobile
346
+ // overflow). This bump also carries the /version-vs-CORE_VERSION divergence
347
+ // check added under task 1002521 — the gap above went unnoticed for ten days
348
+ // precisely because nothing compared live against main. The doorway surface
349
+ // is byte-identical to 1.18.17 (governance is reached through the kernel
350
+ // port, not a new export), so despite the size this is → PATCH. (task 1002521)
221
351
  // ---------------------------------------------------------------------------
222
- const CORE_VERSION = '1.18.0'; // see the changelog above — 1.18.0 is the first cut from the cloud-bongos authoritative source (re-seed task 2190); includes the builders'-hall UI redesign beyond published 1.17.3
352
+ const CORE_VERSION = '1.18.18'; // go-live carrier for 171 unreleased commits + the deploy-divergence check (task 1002521); see changelog above
223
353
 
224
354
  // A namespaced logger so a module's log lines are attributable + consistent.
225
355
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -245,6 +375,15 @@ module.exports = {
245
375
  // tokens. A module's own bootstrap routes flag themselves; everything else
246
376
  // stays closed to box tokens (the ADR 0016 trust boundary).
247
377
  allowBoxScope: auth.allowBoxScope,
378
+ // resolveSession(req) — resolve the request to a live session row (or null)
379
+ // WITHOUT the 401-or-pass behaviour of requireBuilder. A module route that
380
+ // must make its own auth decision — e.g. a browser page that REDIRECTS to
381
+ // sign-in on a missing session rather than returning JSON 401 (the
382
+ // platform-identity /sso/authorize leg, ADR 0141) — needs the raw resolve.
383
+ // Returns the same shape lookupSession does (builder_id, github_id,
384
+ // github_login, display_name, avatar_url, rank, source, status); rank is
385
+ // still never an authority a module should trust for cross-instance identity.
386
+ resolveSession: (...a) => auth.resolveSession(...a),
248
387
 
249
388
  // --- data — the shared Postgres pool. A module owns its namespaced tables
250
389
  // (<key>_*) via its own migrations (BV1.R46); it reaches them through this.