@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
@@ -0,0 +1,174 @@
1
+ # Running a goal as parallel worktree waves
2
+
3
+ How to take a goal with ~20 tasks and ship it with several agents building at once, one worktree per claim.
4
+
5
+ Written from the 2026-07-30 session that shipped 14 tasks off goal 1000030 (Governance — configurable roles & permissions). **This records what actually worked, which differed from the plan we started with.** The differences are the point.
6
+
7
+ ---
8
+
9
+ ## The one-paragraph version
10
+
11
+ Dependencies tell you what must **ship** first. They tell you nothing about what can be **edited** at the same time. Work out the file-conflict graph yourself, run the disjoint set in parallel worktrees, and serialise anything that touches the same file. Claim the parallel set with `POST /claims/batch` (`claim.js` can only hold one claim per machine). Expect the plan's own dependency edges to be wrong somewhere, and expect one shared doc file to become the merge-conflict tax.
12
+
13
+ ---
14
+
15
+ ## 1. Read the DAG, then don't trust it
16
+
17
+ Start by pulling the real graph — status, `dependencies[]`, `dependents[]`, and `requires_rank` for every task on the goal:
18
+
19
+ ```
20
+ node scripts/gds/api.js GET "/api/gds/tasks?goal_id=<goal>&limit=100"
21
+ node scripts/gds/api.js GET "/api/gds/tasks/<id>" # includes dependencies + dependents
22
+ ```
23
+
24
+ > **Gotcha (cost us ~40 minutes).** The generated API client wraps responses as `{status, ok, data:{...}}`. Reading `res.tasks` gives `undefined` and every dependency array silently looks empty — which reads as "this goal has no dependencies at all". Unwrap `.data` first. An empty dependency graph should make you suspicious, not relieved.
25
+
26
+ Then **audit the edges for direction errors before scheduling anything**. Two of goal 1000030's edges were backwards, and each cost a full task cycle:
27
+
28
+ - **The checker recorded as depending on the thing it checks.** R109 (teach the CI fitness gate to understand the new gate form) was recorded as depending on R104 (migrate the gates). But migrating gates without teaching the checker made every migrated route classify as `any-builder` — a silent downgrade that tripped exact-rank pins. R104 could not pass its grade until R109 shipped, and R109 could not be claimed until R104 shipped. **Deadlock.** Fix: `PUT /tasks/:id/dependencies` to reverse it. The heuristic — *if task B validates task A's output, B is usually A's prerequisite, not its dependent.*
29
+ - **A migration racing ahead of a missing writer.** The plan migrated ~80 authority gates onto a new resolver, but nothing ever wrote the table the resolver reads outside a one-shot backfill. Any account created or re-ranked afterwards would have resolved to zero permissions — and a demoted account would have kept its old powers. Found only because one task's agent reported it instead of coding around it. Fix: file the missing work as a task, then `PUT /tasks/:id/dependencies` to gate the migration tasks behind it.
30
+
31
+ **Do not let a wrong edge stand because fixing it feels like process work.** A backwards edge deadlocks a whole chain, and the deadlock presents as an unexplained grade failure several hours later.
32
+
33
+ ---
34
+
35
+ ## 2. Build the file-conflict graph — this is the real gate
36
+
37
+ `dependencies[]` is a *ship* ordering. Parallel safety is a *file* question, and `touches[]` is advisory and frequently empty. So derive it yourself: read each task's description and predict the files it will edit.
38
+
39
+ Then group:
40
+
41
+ - **Parallel-safe** — no file overlap with anything else in the wave.
42
+ - **Serialised** — two tasks edit the same file, so they run back-to-back regardless of what the DAG says.
43
+
44
+ Worked example from goal 1000030:
45
+
46
+ | Wave | Ran in parallel | Why the rest was held |
47
+ |---|---|---|
48
+ | 0 | resolver + kernel port ‖ config loader | disjoint: new module files vs `config/*.json` |
49
+ | A | the gate primitive ‖ the protected-surface registry | both touched different core files; three others all edited `catalog.js`+`resolver.js` and were serialised behind them |
50
+ | B | a proof test ‖ the core-route migration | test files collide with nothing |
51
+ | C | module-route migration alone | it owns every `modules/*/routes/*.js`, so nothing else in that tree could move |
52
+
53
+ **Heuristics that held up:**
54
+ - A task whose whole output is a new test file is parallel-safe with everything. Schedule these freely.
55
+ - A task that "migrates all X" owns its entire tree for the duration. Run the narrow, specific tasks in that tree **first**, then let the sweep absorb the remainder and rebase onto them. Running the sweep first forces every narrow task to conflict with it.
56
+ - Two tasks extending the same registry/catalog file always serialise, even when their subject matter is unrelated.
57
+
58
+ ---
59
+
60
+ ## 3. Claiming a parallel set
61
+
62
+ `claim.js` **cannot hold concurrent claims from one machine.** The app-layer guard permits one claim per *worktree*, but `uniq_active_claim_per_session` (`migrations/180`) is keyed on `creator_session_id` alone — worktree-blind — and the stricter of the two wins. Every worktree on a box shares one CLI session token, so the second `claim.js` fails.
63
+
64
+ Worse, it fails with a **misleading** message: `claimTask` maps any Postgres `23505` to `ALREADY_CLAIMED`, so you are told *"Task #N was just claimed by another session"* when nothing is claimed and no retry will ever succeed. Two separate agents burned a full investigation each on this before the cause was found. (Filed as idea 1000617.)
65
+
66
+ **Use the batch endpoint**, which was built for exactly this:
67
+
68
+ ```
69
+ node scripts/gds/api.js POST /api/gds/claims/batch \
70
+ --body-file batch.json # {"task_ids":[111,222,333],"bind_session":false}
71
+ ```
72
+
73
+ `bind_session:false` stores each claim with a NULL session, which is the supported web-claim mode; many NULLs coexist. The safety property that matters — one task per worktree, one branch per ship, no commingled commits — is preserved, because you still give each task its own worktree.
74
+
75
+ ```bash
76
+ git worktree add .claude/worktrees/task-<id> -b worktree-task-<id> origin/main
77
+ ```
78
+
79
+ Always branch from a **freshly fetched `origin/main`**, not from local `main`.
80
+
81
+ ---
82
+
83
+ ## 4. Briefing an agent per worktree
84
+
85
+ Each agent gets one task, one worktree, and an explicit **do-not-touch list** naming the files its siblings own. That list is what makes parallelism safe, so keep it accurate as the wave progresses.
86
+
87
+ Include in every brief:
88
+
89
+ - the absolute worktree path, and "never edit the main checkout, never `git push origin main`, never merge to main yourself"
90
+ - the claim is **already held** — tell them not to run `claim.js` (it will fail, per §3)
91
+ - the **known-red test baseline**, by name. If the suite is red on `main` for environmental reasons, an agent that doesn't know will either chase ghosts or quietly assume its own regressions are pre-existing. Give them the exact list and the technique: `git stash push -u`, re-run the suspect test on the clean tree, compare.
92
+ - **report findings, don't fix them.** An agent that patches a defect in a sibling's file creates a conflict and hides a bug. Several of this session's most valuable findings came from agents that stopped and reported.
93
+ - **mutation-test your own tests.** The highest-value defect class here is a test that passes while proving nothing — one agent shipped a first draft where both sides of the comparison read the same field, so mutating it moved both sides together and nothing went red. Require: break the thing deliberately, confirm red, revert, report that you did it.
94
+
95
+ ---
96
+
97
+ ## 5. The merge-conflict tax
98
+
99
+ One file will become the contention point. Here it was the module's nested `CLAUDE.md`: four agents each appended to the same "build plan" line, and the resulting conflicts stalled two ships and needed manual recovery.
100
+
101
+ **Mitigations, best first:**
102
+
103
+ 1. **Don't share the file.** The task that avoided the problem entirely needed a new kernel port, and registered it from a **new** file rather than editing the contended one. Prefer adding a file over editing a shared one.
104
+ 2. **Assign disjoint regions.** If several agents must edit one doc, give each a *specific* slot ("one bullet appended at the end of the Gotchas list", "one paragraph immediately after the R95 block") and forbid reflowing anything else. Different regions usually auto-merge.
105
+ 3. **Accept and recover.** A conflict is a bail, not a corruption — the task parks at `confirmed` and nothing is lost.
106
+
107
+ **Generated files: always resolve by regenerating, never by picking a side.**
108
+
109
+ ```bash
110
+ git checkout --theirs <file>
111
+ node scripts/gds/gen-repo-map.js # or gen-api-docs.js, gen-diagrams.js
112
+ git add <file> && git commit --no-edit
113
+ ```
114
+
115
+ Picking a side leaves the artefact inconsistent with source, and the freshness fitness check fails on the *next* task instead of yours. The generated symbol blocks and the OpenAPI spec both bit us this way.
116
+
117
+ > If `ship.js` says *"auto-merge: bailed; task stays at confirmed"*, don't reach for `/merge-mode` first. Merge `origin/main` into the **task's own branch**, resolve there, re-run `fitness.js`, then re-run `ship.js <id>` — it resumes from `confirmed`. `/merge-mode` is an operator procedure that mutates the main worktree and assumes a bash/SSH environment.
118
+
119
+ ---
120
+
121
+ ## 6. Treat the ship grade as a noisy signal
122
+
123
+ The subagent grader gates on **forwarded confidence**, not just scores. A worker that times out returns no vote, which collapses confidence and fails work that has **no defect finding against it**.
124
+
125
+ Observed in one session: two tasks failed on a worker `SUBAGENT_TIMEOUT` and passed on retry **with zero code change**; another failed three times at 8.5–9.5/10 against a threshold of 6 with 4 of 5 workers passing every time.
126
+
127
+ Practical rules:
128
+
129
+ - **Capture the full grader output.** Do not pipe `ship.js` through `tail` — you will lose the finding and have to pay for another run. Redirect to a file.
130
+ - **Read the per-worker table before reacting.** "4/5 PASS, verdict CONCERNS, confidence 0.3" is an infrastructure failure. "1 worker FAIL" is a real defect.
131
+ - **A re-grade is the right first response** to a timeout-shaped failure. It is also not free — budget for it.
132
+ - **A pass is not evidence either.** A gate this noisy can wave things through. Run a separate adversarial review over the finished work.
133
+ - When the grader repeatedly flags a deliberate architecture decision, that is a signal to **record the decision** (an ADR or a triaged idea) rather than to keep re-litigating it per task — each re-grade costs real money.
134
+
135
+ ---
136
+
137
+ ## 7. Run an adversarial review at the end
138
+
139
+ Fan reviewers out over surfaces, then have **every finding attacked by an independent skeptic prompted to refute by default**. On this goal that pass killed 6 of the top 8 findings — including three that were confidently written and wrong. Two survived, both reproduced end-to-end against the live module, and both were real.
140
+
141
+ What made it work:
142
+
143
+ - Tell reviewers explicitly **not to inherit the ship grades' verdicts**, and to re-derive security claims from the code.
144
+ - Give the skeptics the failure modes to check: is the path actually reachable? is there a compensating control? is this a documented deliberate decision?
145
+ - Name the highest-value defect class up front. Here it was tests whose expectation derives from the same code under test.
146
+ - Findings that are never adversarially verified should be **recorded as unverified**, not reported as defects. With a 6-of-8 refutation rate, an unverified finding is more likely wrong than right.
147
+
148
+ ---
149
+
150
+ ## Checklist
151
+
152
+ ```
153
+ [ ] Pull the real DAG; unwrap .data; be suspicious of an empty dependency graph
154
+ [ ] Audit edge DIRECTION — does anything validate its own prerequisite?
155
+ [ ] Predict files per task; build the conflict graph; group parallel vs serialised
156
+ [ ] Narrow tasks in a tree BEFORE the sweep that owns that tree
157
+ [ ] git worktree per task, branched from a fresh origin/main
158
+ [ ] POST /claims/batch with bind_session:false (NOT claim.js)
159
+ [ ] Brief each agent: worktree path, do-not-touch list, known-red baseline,
160
+ report-don't-fix, mutation-test your tests
161
+ [ ] Assign disjoint regions in any shared doc; prefer a new file
162
+ [ ] Regenerate generated files on conflict; never pick a side
163
+ [ ] Capture full grader output to a file; read the per-worker table
164
+ [ ] Adversarial review at the end; record unverified findings as unverified
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Provenance
170
+
171
+ Goal 1000030 (Governance — configurable roles & permissions), 2026-07-30. 14 tasks shipped; 5 defects found that were outside any task's scope, the most serious being that a demoted builder retained their previous powers because nothing kept role assignments in sync with rank.
172
+
173
+ Related ideas: 1000617 (session-claim guard vs index), 1000618 (legacy ranks resolve to zero permissions), 1000624 (uncached per-request resolve — ADR 0016 tension), 1000625 (`guards` prose has no oracle), 1000626 (unverified review backlog).
174
+ Related tasks: 1002550, 1002551, 1002552, 1002553, 1002554.
@@ -11,8 +11,8 @@
11
11
  `/builder-ship` runs three transitions ([Phase 5](../session-logs/<redacted>.md)):
12
12
 
13
13
  1. **`completed`** — the claim resolves once local verification (smoke) passes. **The claim is consumed here.**
14
- 2. **`confirmed`** — the v2 subagent quality grader (the 4-worker panel: Narc · Quality · Hacker · Efficiency Monger) passes. **Credits land here.**
15
- 3. **`shipped`** — branch auto-merged to `main` + deployed; the Discord `#ship-news` broadcast fires.
14
+ 2. **`confirmed`** — the v2 subagent quality grader (the 4-worker panel: Narc · Quality · Hacker · Efficiency Monger) passes. **Verified, but not yet paid.**
15
+ 3. **`shipped`** — branch auto-merged to `main` + deployed; the Discord `#ship-news` broadcast fires. **Credits land here** ([ADR 0120](../adr/<redacted>.md) pays on land, not on confirm) — so a task stranded at `confirmed` is unpaid until it lands.
16
16
 
17
17
  The grader reads **committed history** (`merge-base origin/main HEAD`…`HEAD`), independent of touches[] — so the diff it judges is whatever you've committed on the branch, not your working tree.
18
18
 
@@ -0,0 +1,48 @@
1
+ # Recipe — live-updating docs on a STANDALONE instance
2
+
3
+ **Read before:** standing up / debugging a standalone instance whose `docs/` is empty or stale.
4
+ **Decision of record:** [ADR 0147](../adr/<redacted>.md) (builds on [ADR 0110](../adr/<redacted>.md) / [ADR 0108](../adr/<redacted>.md)).
5
+
6
+ ## The mental model — which doc refreshes where
7
+
8
+ A standalone instance (its own repo + `@bongos/core` vendored in `node_modules`) has several *generated* docs. They do **not** all refresh the same way:
9
+
10
+ | Doc | Kind | Refreshes | Committed? |
11
+ |---|---|---|---|
12
+ | `docs/session-log-index.md` | whole-file, instance content | **deploy** (`regen-instance-docs.js`) + `bongos upgrade` + init seed | **gitignored** |
13
+ | `docs/api/openapi.json`, `docs/api-reference.md`, `docs/routes-permissions.md` | generated from routes | `bongos init` + `bongos upgrade` | tracked/committed |
14
+ | `docs/file-map.md` | hybrid (prose + generated sections) | ship-time | tracked/committed |
15
+ | `docs/repo-map.md` | CORE symbol map | shipped with `@bongos/core` (core-scoped) | gitignored |
16
+ | onboarding diagrams (`.svg`/`.png`) | rendered | package/CI time (headless browser) | gitignored renders, tracked `.mmd` |
17
+
18
+ Only `session-log-index.md` is regenerated **on deploy** — it's the one whole-file doc whose content (the instance's own session logs) changes as work ships. Everything else is committed-at-ship, shipped-with-core, or rendered-at-package.
19
+
20
+ ## Wiring a standalone deploy to keep docs live
21
+
22
+ The one-liner every standalone deploy script must run **after** `git reset --hard origin/main` + migrate:
23
+
24
+ ```bash
25
+ node node_modules/@bongos/core/scripts/gds/regen-instance-docs.js
26
+ ```
27
+
28
+ Run it with `cwd` = the instance repo root (or set `CLOUDBONGOS_INSTANCE_ROOT=<instance-dir>`). It resolves the instance root, regenerates `docs/session-log-index.md` there, is **best-effort** (always exits 0), and is **LOUD** on failure (`::ERROR::` → journald). A stale nav doc is tolerable; a failed deploy is not (ADR 0110 §2 "accepted staleness").
29
+
30
+ `provision.js` already runs this on its standalone deploy path, and `bongos init` / `bongos upgrade` run it at standup / on a core bump. You only wire it by hand into a **bespoke** pull-deploy script (e.g. cloudbongos.com's `/home/lars/deploy.sh`).
31
+
32
+ ## `.gitignore` requirement
33
+
34
+ The instance repo must gitignore the whole-file docs so `git reset --hard` never wipes the regenerated copy and no branch can diff it:
35
+
36
+ ```
37
+ docs/session-log-index.md
38
+ docs/repo-map.md
39
+ ```
40
+
41
+ `provision.js`'s `INSTANCE_GITIGNORE` seeds these for new instances; an older instance (pre-ADR-0147) needs them added by hand.
42
+
43
+ ## Debugging "my instance's docs are empty / stale"
44
+
45
+ 1. **Empty `docs/` (only the 3 API files)?** The nav-doc seed never ran. Run `regen-instance-docs.js` once, and confirm the deploy script calls it (above).
46
+ 2. **`session-log-index.md` indexes the *core's* sessions, not the instance's?** You're on a core older than the ADR 0147 fix (`gen-session-index.js` hardcoded the core root). `bongos upgrade` to a fixed core.
47
+ 3. **The file keeps disappearing after deploy?** It isn't gitignored — `git reset --hard` wipes it. Add the `.gitignore` lines above.
48
+ 4. **`::ERROR:: regen-instance-docs` in journald?** A generator threw — the deploy still succeeded, but the doc is stale. Check the generator output; the instance must have `docs/session-logs/` and a resolvable instance root.
@@ -9,11 +9,12 @@
9
9
  1. **pre-flight** — module-compat vs the target core + a clean git tree (skip with `--force`).
10
10
  2. **bump the pin** — vendor the new `bongos-core-<version>.tgz` and rewrite the `"@bongos/core": "file:vendor/…"` dependency.
11
11
  3. **`npm install`** — `node_modules/@bongos/core` becomes the new version.
12
+ 3b. **verify the integrity pin** (task [#1002216](https://example.com/builders#/task/1002216)) — recompute `tree_sha256` over the installed core and check the vendored `.tgz` bytes against `tarball.sha256`, comparing to the trusted reference manifest (the committed `vendor/…manifest.json`; the installed inner manifest for `--registry`). Runs **before** migrate so a corrupted core never touches the DB. A **mismatch is fatal → rollback**; a missing reference warns (fatal with `--require-pin`); opt out with `--skip-pin-verify`.
12
13
  4. **`npm run migrate`** — the core's `migrate.sh` applies additive `core_*` migrations (merged three-root: core + instance + modules).
13
14
  5. **materialize `.claude/`** — refresh skills/settings/hooks from the new core (`materializeClaude`), rewriting invocations to the `bongos` bin.
14
15
  6. **restart** — `--service <unit>` or `--restart-cmd "<cmd>"`.
15
- 7. **verify** — installed version == target (+ optional `--health-url`).
16
- 8. **auto-rollback on failure** (task [#2149](https://example.com/builders#/task/2149), default ON) — if `npm install`/`migrate` fails or the step-7 health check fails, revert the pin → reinstall the previous core → restart → re-verify → write a `rolled_back:` ledger row. Opt out with `--no-rollback-on-failure`. See the section below.
16
+ 7. **verify** — installed version == target + the **mandatory post-restart health check** (task [#1002222](https://example.com/builders#/task/1002222)): a bump that restarts the service **requires `--health-url <url>`** (it can't report success without confirming the new core serves). Opt out explicitly with `--no-health-check`; a bump with no managed restart needs no URL (it reports the new core installed-but-unconfirmed). A still-failing health poll fails the bump (auto-rollback).
17
+ 8. **auto-rollback on failure** (task [#2149](https://example.com/builders#/task/2149), default ON) — if `npm install`/pin-verify/`migrate` fails or the step-7 health check fails, revert the pin → reinstall the previous core → restart → re-verify → write a `rolled_back:` ledger row. Opt out with `--no-rollback-on-failure`. See the section below.
17
18
 
18
19
  Run bare (`bongos upgrade`, no `--to`) it stays the module-compat **pre-check** only.
19
20
 
@@ -63,6 +64,8 @@ By default (`--rollback-on-failure`, ON unless `--no-rollback-on-failure`) the c
63
64
 
64
65
  **The DB is NOT rolled back — only the code pin.** Core migrations are additive + forward-safe (the core migration rule), so an already-applied migration is left in place; a *failed* migration is never recorded in `schema_migrations`, so a retry re-runs it cleanly. The reversal is recorded via the always-present `note` column (not a new `outcome` column) so it lands even in the failed-migrate path — where a newer column wouldn't yet exist on that instance.
65
66
 
67
+ > **The forward-safe rule is now enforced, not just documented** (task [#1002223](https://example.com/builders#/task/1002223), audit H10). A core migration that DROPs/RENAMEs/retypes existing state (which would strand the rolled-back old code on the new schema) fails the [`tests/migrations_forward_safe.mjs`](../../tests/migrations_forward_safe.mjs) unit gate unless it carries an explicit `-- forward-unsafe: <reason>` acknowledgement pragma. `migrate.sh` also prints a non-fatal notice at apply time (via [`scripts/gds/lint-migrations.js`](../../scripts/gds/lint-migrations.js)). Additive migrations (the norm) need no annotation.
68
+
66
69
  **Proven live on demo.cloudbongos.com** (task [#2157](https://example.com/builders#/task/2157)): demo, on rollback-capable 1.17.3, was upgraded to a canary carrying a deliberately-failing migration. Migrate raised → the channel auto-reverted the pin to 1.17.3, reinstalled + restarted it, `/healthz` stayed 200 (**zero downtime** — the failure was at migrate, before the restart), and a `rolled_back` ledger row was written. This is the safety gate the unattended patch-only auto-upgrade subscription (task [#2150](https://example.com/builders#/task/2150)) depends on.
67
70
 
68
71
  ## Subscribing to updates — unattended patch-only auto-upgrade (task 2150 / ADR 0136)
@@ -0,0 +1,108 @@
1
+ # Work on a task from your dev box
2
+
3
+ > Your dev box is **task-scoped**: claim a task and the box pulls **only the code
4
+ > that task needs** — the module(s) its work touches, on top of a small base
5
+ > instance — never the whole repo. Your GitHub token never leaves the server; the
6
+ > box fetches its slice through the control plane. See
7
+ > [ADR 0148](../adr/<redacted>.md) (the scope model) and
8
+ > [ADR 0150](../adr/<redacted>.md) (how the box
9
+ > comes up).
10
+
11
+ ## TL;DR
12
+
13
+ In your dev box's terminal:
14
+
15
+ ```bash
16
+ /builder-start # see what you can claim
17
+ /builder-claim <N> # claim task N (locks it to your session)
18
+ /builder-sync # pull task N's code onto the box now (re-scopes in place)
19
+ # …work in /workspace…
20
+ /builder-ship # smoke + review, then land + deploy — awards credits
21
+ ```
22
+
23
+ That's the whole loop. `/builder-sync` is the new step: it materializes the claimed
24
+ task's code within seconds instead of waiting for the box's ~10-minute refresh.
25
+
26
+ ## The model — what's on your box
27
+
28
+ A task-scoped box carries two layers:
29
+
30
+ 1. **The base instance** — always present, whatever you've claimed: the methodology
31
+ (`CLAUDE.md`, `.claude/`), the build tooling (`scripts/`, `src/bongos/`),
32
+ `docs/`, `infra/`, and the **test suite** (`tests/`). Enough for Claude to hold
33
+ context and run the `/builder-*` CLI, and to run your module's tests.
34
+ 2. **Your claimed task's code** — the module directories the task's goal scopes
35
+ (`goals.scope_modules` → globs, [ADR 0086](../adr/<redacted>.md)). Claim a `dev-box` task → you get
36
+ `modules/dev-box/`; claim a `game` task → you get the game world too. Nothing
37
+ else.
38
+
39
+ What you do **not** get: other builders' modules, the product/game runtime (unless
40
+ your task is game-scoped), and — the point — **no GitHub credential on the box**.
41
+ The box asks the control plane (`GET /box/source-access`) for its slice on each
42
+ fetch; the server holds the token and returns a scoped, cone-mode sparse-checkout
43
+ spec. Lose the claim or a rank, and the next fetch is cut off at the server.
44
+
45
+ ## Step by step
46
+
47
+ ### 1. Connect to your box
48
+
49
+ If you haven't yet, run **`/builder-connect`** (or follow the
50
+ [dev-box lifecycle recipe](builder-box-lifecycle.md)) to raise and connect to your
51
+ box, then **`/builder-setup`** once on the box to sign the GDS CLI in. The browser
52
+ terminal drops you into `/workspace` — the one working folder.
53
+
54
+ > **`bongos shell` / `bongos code` re-scope on connect (BV1.R101).** Connecting with
55
+ > either verb runs the sync for you first, so you land in `/workspace` already scoped
56
+ > to your active claim — no manual `/builder-sync` needed just to arrive. (The browser
57
+ > terminal drops you straight into `/workspace`; run `/builder-sync` there if you
58
+ > claimed or switched since your last sync.)
59
+
60
+ ### 2. See what you can claim — `/builder-start`
61
+
62
+ Lists the tasks that are `ready` and parallel-safe against everyone else's active
63
+ claims. Pick one.
64
+
65
+ ### 3. Claim it — `/builder-claim <N>`
66
+
67
+ Locks task N to your session. **This is what drives your box's scope:** source
68
+ access is computed from your **active claim** — its task → goal → `scope_modules`.
69
+
70
+ ### 4. Pull the code now — `/builder-sync`
71
+
72
+ Re-runs the box's source-fetch immediately, so `/workspace` re-scopes to task N's
73
+ modules within seconds. (A ~10-minute cron does this on its own as a backstop — you
74
+ just don't want to wait for it.) Off a box there's nothing to sync — your source is
75
+ your local checkout — and the command tells you so.
76
+
77
+ ### 5. Work — in `/workspace`
78
+
79
+ `/workspace` now holds the base instance **plus** task N's module code. One folder:
80
+ when you switch tasks it **re-scopes in place**, so there are no per-task folders to
81
+ manage.
82
+
83
+ ### 6. Ship — `/builder-ship`
84
+
85
+ Runs the smoke tests and the review gate, then lands + deploys and awards credits.
86
+
87
+ ## Switching tasks
88
+
89
+ One box, one working folder, one active claim at a time (the server enforces
90
+ one-claim-per-session). To move to a different task:
91
+
92
+ 1. `/builder-ship` (or `/builder-release`) the current claim.
93
+ 2. `/builder-claim <M>` the new one.
94
+ 3. `/builder-sync` — the box re-scopes to task M in place.
95
+
96
+ ## Notes + gotchas
97
+
98
+ - **`tests/` is always in the base** — so a module's tests run on the box (they
99
+ live in the top-level `tests/`, not inside `modules/<key>/`).
100
+ - **Idle boxes rest.** A box with no activity is reclaimed after ~10–15 min; the
101
+ next connect re-provisions a fresh one and re-fetches your scope. **Uncommitted
102
+ work on a reaped box is lost** — ship or commit before you step away.
103
+ - **`/builder-sync` is idempotent** — safe to re-run; it just does, on demand, what
104
+ the cron does on its schedule.
105
+ - **A fresh box comes up with the base already cloned.** If a box ever comes up
106
+ *bare* (no code, no terminal), that's the packaging bug
107
+ [ADR 0150](../adr/<redacted>.md) fixed on the
108
+ control plane — flag it rather than working around it.
@@ -223,17 +223,16 @@ CREATE INDEX IF NOT EXISTS idx_session_logs_builder ON session_logs (builder_id)
223
223
  CREATE INDEX IF NOT EXISTS idx_session_logs_ended ON session_logs (ended_at);
224
224
 
225
225
  -- =========================================================================
226
- -- Seed: the two known versions
226
+ -- Seed: the platform PMS-V1 version
227
227
  -- =========================================================================
228
- -- Instance-seed guard (task 1704 / ADR 0105): these are OTB product versions —
229
- -- scope-truth that must NOT seed onto a vanilla / non-owning DB. scripts/migrate.sh
230
- -- sets app.seed_instance_data='off' on such a boot; unset (direct psql / OTB) = seed.
228
+ -- Instance-seed guard (task 1704 / ADR 0105): OTB platform scope-truth that must
229
+ -- NOT seed onto a vanilla / non-owning DB. scripts/migrate.sh sets
230
+ -- app.seed_instance_data='off' on such a boot; unset (direct psql / OTB) = seed.
231
+ -- (Game V1 was product/primea scope; relocated to the amazonprimea instance's
232
+ -- migrations/instance/ per task 1002423 — the neutral core carries no game seed.)
231
233
  DO $seed$ BEGIN IF current_setting('app.seed_instance_data', true) IS DISTINCT FROM 'off' THEN
232
234
  INSERT INTO versions (id, name, track, status, scope_doc_path, started_at, done_when)
233
235
  VALUES
234
- ('V1', 'Game V1 — first playable purchase loop', 'product', 'building',
235
- 'limitations/current-version.md', '2026-05-08'::timestamptz,
236
- 'A visitor can land in the world, walk to the vendor, buy a real item, and Hermeslines fulfills it.'),
237
236
  ('PMS-V1', 'PMS V1 — project management system, parallel internal track', 'internal', 'building',
238
237
  'limitations/pms-v1.md', '2026-05-09'::timestamptz,
239
238
  'Builders auth via GitHub. Slash commands claim/ship tasks atomically. Backlog migrated. Public status page live.')
@@ -337,38 +337,10 @@ ON CONFLICT (version_id, criterion_id) DO UPDATE
337
337
  END IF; END $seed$;
338
338
 
339
339
  -- =========================================================================
340
- -- 6. Seeds: V1 done-when criteria (mirrors limitations/current-version.md)
340
+ -- (Game V1 done-when criteria removed — product/primea scope, not core.)
341
+ -- Relocated to the amazonprimea instance's migrations/instance/ per task
342
+ -- 1002423; the neutral core seeds no game scope-truth.
341
343
  -- =========================================================================
342
- -- The V1 done-when (CLAUDE.md §9): "the experience supports the full
343
- -- purchase loop: land in the world → walk to the vendor → buy a real
344
- -- item → Hermeslines fulfills it." Decomposed into checkable criteria.
345
-
346
- -- Instance-seed guard (task 1704 / ADR 0105): OTB V1 game scope-truth. FK-references
347
- -- the V1 version guarded above, so this must skip on a vanilla DB too.
348
- DO $seed$ BEGIN IF current_setting('app.seed_instance_data', true) IS DISTINCT FROM 'off' THEN
349
- INSERT INTO done_when_criteria (version_id, criterion_id, criterion_md, sort_order) VALUES
350
- ('V1', 'world-land',
351
- 'Visitor lands in the persistent world from amazonprimea.com',
352
- 10),
353
- ('V1', 'walk-to-vendor',
354
- 'Visitor can walk to Hyperion at the shipping container with WASD',
355
- 20),
356
- ('V1', 'auth-magic-link',
357
- 'Visitor authenticates via Stripe-tied magic link before purchase',
358
- 30),
359
- ('V1', 'vendor-purchase',
360
- 'Vendor dialog supports real-product purchase via Stripe',
361
- 40),
362
- ('V1', 'hermeslines-fulfill',
363
- 'Order intake reaches Hermeslines fulfillment system (whatever the format)',
364
- 50),
365
- ('V1', 'order-confirmation',
366
- 'Visitor receives order confirmation in-world',
367
- 60)
368
- ON CONFLICT (version_id, criterion_id) DO UPDATE
369
- SET criterion_md = EXCLUDED.criterion_md,
370
- sort_order = EXCLUDED.sort_order;
371
- END IF; END $seed$;
372
344
 
373
345
  -- =========================================================================
374
346
  -- 7. Migration record
@@ -1,6 +1,11 @@
1
1
  -- 039_newcomer_friendly_column.sql — V3.R15: tasks.newcomer_friendly column +
2
2
  -- view-level filter + Xenos claim-policy error code.
3
3
  --
4
+ -- forward-unsafe: rename-column (RENAME tasks.xenos_claimable → newcomer_friendly). Historical
5
+ -- (V3.R15, 2026), already applied on every instance long before `bongos upgrade`'s code-only
6
+ -- rollback existed — no core version a current rollback could revert to reads the old column
7
+ -- name. Acknowledged per audit H10 / task 1002223 (scripts/gds/lint-migrations.js).
8
+ --
4
9
  -- Context: V3.R15 (#239) was planned as the row-level "newcomer-friendly task"
5
10
  -- gate for the Xenos rank. In parallel, #360 / ADR 0018 (migration 029) shipped
6
11
  -- the same idea under the name `xenos_claimable`. Now V3.R15 closes by:
@@ -1,6 +1,10 @@
1
1
  -- 102_remove_box_first_provision_approval.sql — ADR 0059 (task 1141): REMOVE the
2
2
  -- dev-box "first-box Archon approval" gate. Reverts migration 071.
3
3
  --
4
+ -- forward-unsafe: drop-column (box_intents.approved_by / approved_at). Historical (ADR 0059, task
5
+ -- 1141); the code that read those columns was removed in the SAME change, and it predates
6
+ -- `bongos upgrade`'s code-only rollback. Acknowledged per audit H10 / task 1002223.
7
+ --
4
8
  -- Context
5
9
  -- -------
6
10
  -- Migration 071 (#717, ADR 0035 Decision 2) added a 'pending_approval' state to
@@ -0,0 +1,33 @@
1
+ -- core_192_github_oauth_tokens.sql — short-lived, encrypted GitHub repo tokens for
2
+ -- the onboarding wizard (task 1002099, ADR 0143).
3
+ --
4
+ -- The wizard (public-landing/create.html) opts into `public_repo` at GitHub sign-in
5
+ -- so it can LIST the signed-in user's repos (adopt) and CREATE an empty repo (fresh)
6
+ -- — things `read:user` cannot do. That user-to-server GitHub token is held here
7
+ -- BRIEFLY: one row per builder, the token encrypted with secret-box (master key in
8
+ -- server env only — a DB dump alone decrypts nothing), with a short expires_at (one
9
+ -- wizard sitting). It is read back by the repo picker/creator over the next few
10
+ -- minutes and deleted on use; getGithubToken lazily sweeps an expired row so the
11
+ -- table self-cleans without a cron. ON DELETE CASCADE ties a token to its builder.
12
+ --
13
+ -- This is the AUTH system's OWN handshake token (not a feature's third-party API
14
+ -- key like the art module's Gemini key, ADR 0102), so it lives in core. When
15
+ -- secret-box is unconfigured no row is ever written and the wizard falls back to
16
+ -- manual repo entry (ADR 0143).
17
+ --
18
+ -- Idempotent: safe to re-run.
19
+
20
+ CREATE TABLE IF NOT EXISTS github_oauth_tokens (
21
+ builder_id bigint PRIMARY KEY REFERENCES builders(id) ON DELETE CASCADE,
22
+ token_enc text NOT NULL,
23
+ scope text,
24
+ created_at timestamptz NOT NULL DEFAULT now(),
25
+ expires_at timestamptz NOT NULL
26
+ );
27
+
28
+ -- The read/sweep hot path filters on expiry.
29
+ CREATE INDEX IF NOT EXISTS idx_github_oauth_tokens_expires
30
+ ON github_oauth_tokens (expires_at);
31
+
32
+ INSERT INTO schema_migrations (version) VALUES ('core_192_github_oauth_tokens')
33
+ ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,28 @@
1
+ -- core_193_task_needs_rebase.sql — ADR 0120 part 2: the `needs_rebase` flag.
2
+ --
3
+ -- A confirmed task whose land the publish-reconciler cannot complete after the
4
+ -- normal auto-land grace (its retries + the ADR 0082 generated-file self-heal)
5
+ -- is flagged needs_rebase=true. It is a SIGNAL, not a status change: the task
6
+ -- stays 'confirmed' (its work is done) — it is simply marked as awaiting *its
7
+ -- builder's* rebase. Attribution to the builder who did the work is derived from
8
+ -- tasks.shipped_by (confirmTask/applyGrade/decideOverrideRequest all COALESCE it
9
+ -- to the claim holder), so no separate owner column is needed.
10
+ --
11
+ -- The claim gate (core claimTask, ADR 0120 part 3) refuses that builder's NEW
12
+ -- claims while any of their tasks is needs_rebase; landing the task (shipTask)
13
+ -- or releasing it clears the flag. This is a CORE migration (not a lifecycle
14
+ -- module migration) because it ALTERs the core `tasks` table — the module
15
+ -- migration namespacing rule forbids a module migration touching non-namespaced
16
+ -- core objects (the discord precedent).
17
+ --
18
+ -- Safe DDL: ADD COLUMN ... NOT NULL DEFAULT <constant> does not rewrite the
19
+ -- table on Postgres 11+ (the default is stored in the catalog).
20
+
21
+ ALTER TABLE tasks ADD COLUMN IF NOT EXISTS needs_rebase boolean NOT NULL DEFAULT false;
22
+ ALTER TABLE tasks ADD COLUMN IF NOT EXISTS needs_rebase_reason text;
23
+ ALTER TABLE tasks ADD COLUMN IF NOT EXISTS needs_rebase_at timestamptz;
24
+
25
+ -- The claim gate + hall/CLI ask "does builder B own any needs_rebase task?",
26
+ -- keyed on shipped_by. Partial index keeps that lookup cheap (only the handful
27
+ -- of flagged rows are indexed).
28
+ CREATE INDEX IF NOT EXISTS idx_tasks_needs_rebase ON tasks (shipped_by) WHERE needs_rebase;
@@ -0,0 +1,63 @@
1
+ -- core_194_confirmed_backlog_clawback.sql — ADR 0120 part 4: one-time clawback
2
+ -- + re-gate of the confirmed backlog that accrued under the OLD pay-on-confirm
3
+ -- rule (parts 1-3 moved BOTH the pay and the queue gate to the LAND).
4
+ --
5
+ -- For every task still at status='confirmed' (verified but NOT yet merged to
6
+ -- main) this migration:
7
+ -- 1. Reverses its task.confirmed per-task credit — a compensating NEGATIVE
8
+ -- credit_log row (reason='task.confirmed_reversal') per (task, builder), so
9
+ -- the builders.total_credits trigger nets it back to 0. The reward is fully
10
+ -- RE-EARNABLE: when the task finally lands, part 1a books a fresh
11
+ -- 'task.shipped' credit. Achievements already unlocked are LEFT INTACT
12
+ -- (reversing gamification is punitive + messy — ADR 0120 §Consequences).
13
+ -- 2. Flags the task needs_rebase=true (reason 'clawback:confirmed_backlog') so
14
+ -- the part-3 claim gate applies the new incentive to the work that stranded
15
+ -- under the old rule, rather than grandfathering it.
16
+ --
17
+ -- Idempotent: a task already carrying a task.confirmed_reversal row is skipped,
18
+ -- and needs_rebase is only set where still false — a re-run is a no-op. It runs
19
+ -- ONCE per DB (schema_migrations), at the deploy that first carries it; that is
20
+ -- WHERE the retroactive sting lands, so it hits real builders (the owner
21
+ -- included) only when this version is actually deployed.
22
+ --
23
+ -- Deliberately NOT reversed: the idea-promotion bonus and the net-negative
24
+ -- bonus. The ADR names only the 'task.confirmed' delta; the idea bonus stays
25
+ -- with its capturer (it is not double-paid on re-land — maybeAwardIdeaPromotion
26
+ -- Bonus guards on the existing 'idea_promotion_bonus' row), and the net-negative
27
+ -- bonus derives from grade-time signals that never moved off confirm.
28
+ --
29
+ -- DML only (no schema change): safe to run inside one transaction.
30
+
31
+ BEGIN;
32
+
33
+ -- 1. Compensating reversal of the task.confirmed credit for still-confirmed tasks.
34
+ INSERT INTO credit_log (builder_id, task_id, delta, reason, description)
35
+ SELECT cl.builder_id,
36
+ cl.task_id,
37
+ -SUM(cl.delta),
38
+ 'task.confirmed_reversal',
39
+ 'ADR 0120 clawback: reverse premature task.confirmed credit for still-confirmed (unlanded) task ' || cl.task_id
40
+ FROM credit_log cl
41
+ JOIN tasks t ON t.id = cl.task_id
42
+ WHERE t.status = 'confirmed'
43
+ AND cl.reason = 'task.confirmed'
44
+ AND NOT EXISTS (
45
+ SELECT 1 FROM credit_log r
46
+ WHERE r.task_id = cl.task_id
47
+ AND r.builder_id = cl.builder_id
48
+ AND r.reason = 'task.confirmed_reversal'
49
+ )
50
+ GROUP BY cl.builder_id, cl.task_id
51
+ HAVING SUM(cl.delta) <> 0;
52
+
53
+ -- 2. Re-gate: flag every still-confirmed task needs_rebase for its builder
54
+ -- (attribution via tasks.shipped_by), so the claim gate (part 3) bites.
55
+ UPDATE tasks
56
+ SET needs_rebase = true,
57
+ needs_rebase_reason = 'clawback:confirmed_backlog',
58
+ needs_rebase_at = COALESCE(needs_rebase_at, now()),
59
+ updated_at = now()
60
+ WHERE status = 'confirmed'
61
+ AND needs_rebase = false;
62
+
63
+ COMMIT;