@bongos/core 1.23.22 → 1.24.2

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 (435) hide show
  1. package/.bongos-core.json +933 -413
  2. package/.claude/skills/blocker-review/SKILL.md +9 -1
  3. package/.claude/skills/blocker-solve/SKILL.md +1 -1
  4. package/.claude/skills/builder-claim/SKILL.md +1 -1
  5. package/.claude/skills/builder-reauth/SKILL.md +1 -1
  6. package/.claude/skills/builder-redteam/SKILL.md +1 -1
  7. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  8. package/.claude/skills/builder-setup/SKILL.md +1 -1
  9. package/.claude/skills/builder-ship/SKILL.md +1 -1
  10. package/.claude/skills/collab-review/SKILL.md +5 -2
  11. package/.claude/skills/design/SKILL.md +1 -1
  12. package/.claude/skills/goal-create/SKILL.md +2 -2
  13. package/.claude/skills/grade-recover/SKILL.md +1 -1
  14. package/.claude/skills/merge-mode/SKILL.md +1 -1
  15. package/.claude/skills/owner-review/SKILL.md +1 -1
  16. package/.claude/skills/planning-session/SKILL.md +11 -11
  17. package/.claude/skills/read-session-export/SKILL.md +1 -1
  18. package/.claude/skills/recall/SKILL.md +1 -1
  19. package/.claude/skills/scan-before-install/SKILL.md +1 -1
  20. package/.claude/skills/session-handoff/SKILL.md +1 -1
  21. package/.claude/skills/strand-fix/SKILL.md +13 -0
  22. package/.claude/skills/worktree-clean/SKILL.md +1 -1
  23. package/AGENTS.md +15 -0
  24. package/GEMINI.md +5 -0
  25. package/clients/bongos-client/README.md +1 -1
  26. package/clients/bongos-client/bongos-client.global.js +96 -0
  27. package/clients/bongos-client/index.cjs +96 -0
  28. package/clients/bongos-client/index.d.ts +155 -4
  29. package/clients/bongos-client/index.mjs +96 -0
  30. package/docs/adr/0054-session-token-reward-cost-plus.md +3 -1
  31. package/docs/adr/0055-server-mediated-branch-publish.md +1 -1
  32. package/docs/adr/0385-money-lives-with-a-processor-credits-stay-a-project-meter.md +12 -1
  33. package/docs/adr/0393-a-platform-account-is-a-person-and-github-is-one-way-in.md +37 -0
  34. package/docs/adr/0394-market-watch-searches-through-the-messages-api-on-the-projects-key-and-runs-from-its-own-poller.md +102 -0
  35. package/docs/adr/0395-a-task-says-what-it-needs-and-lists-show-only-what-you-can-do.md +36 -0
  36. package/docs/adr/0396-google-sign-in-a-stand-in-login-and-a-browser-approved-cli-sign-in.md +41 -0
  37. package/docs/adr/README.md +6 -2
  38. package/docs/api/openapi.json +8651 -5833
  39. package/docs/api-reference.md +66 -10
  40. package/docs/architecture.md +37 -1
  41. package/docs/canonical-permissions.md +1 -1
  42. package/docs/copy-inventory.md +427 -339
  43. package/docs/copy-registry.json +1376 -500
  44. package/docs/file-map.md +1 -0
  45. package/docs/module-api-changelog.md +7 -0
  46. package/docs/onboarding/diagrams/03-drachmae-karma.mmd +3 -3
  47. package/docs/onboarding/diagrams/README.md +1 -1
  48. package/docs/onboarding/drachmae-and-karma.md +15 -15
  49. package/docs/onboarding/primer.md +2 -2
  50. package/docs/page-inventory.json +57 -7
  51. package/docs/page-readings.json +1210 -1027
  52. package/docs/recipes/google-sign-in.md +60 -0
  53. package/docs/recipes/ops-gotchas.md +1 -1
  54. package/migrations/core_282_builders_lower_login_idx.sql +33 -0
  55. package/migrations/core_283_claimable_ignores_page_markers.sql +53 -0
  56. package/migrations/core_283_payout_approvals.sql +183 -0
  57. package/migrations/core_284_payout_gates.sql +179 -0
  58. package/migrations/core_285_task_needs.sql +74 -0
  59. package/modules/ai-studio/billing.js +67 -0
  60. package/modules/ai-studio/context.js +29 -0
  61. package/modules/ai-studio/db.js +172 -0
  62. package/modules/ai-studio/gemini.js +75 -0
  63. package/modules/ai-studio/generate.js +119 -0
  64. package/modules/ai-studio/keys.js +73 -0
  65. package/modules/ai-studio/migrations/ai_studio_001_keys.sql +22 -0
  66. package/modules/ai-studio/migrations/ai_studio_002_ledger.sql +48 -0
  67. package/modules/ai-studio/migrations/ai_studio_003_requests.sql +55 -0
  68. package/modules/ai-studio/openrouter.js +90 -0
  69. package/modules/ai-studio/payments.js +105 -0
  70. package/modules/ai-studio/pricing.js +92 -0
  71. package/modules/ai-studio/routes/ai-studio.js +235 -5
  72. package/modules/ai-studio/studio.js +121 -0
  73. package/modules/autonomy/fence.js +64 -1
  74. package/modules/builder-settings/builder-needs.js +27 -1
  75. package/modules/copy-desk/routes/copy-desk.js +5 -0
  76. package/modules/economy/achievements.js +22 -10
  77. package/modules/economy/cost-classify.js +9 -0
  78. package/modules/economy/cost-write-guard.js +52 -0
  79. package/modules/economy/cost.js +2 -1
  80. package/modules/economy/credits.js +18 -15
  81. package/modules/economy/goal-reward.js +161 -0
  82. package/modules/economy/reward.js +4 -0
  83. package/modules/economy/routes/cost.js +33 -7
  84. package/modules/government/access-routes.js +70 -0
  85. package/modules/government/access.js +88 -0
  86. package/modules/government/asks.js +5 -2
  87. package/modules/government/catalog.js +6 -0
  88. package/modules/government/db.js +72 -0
  89. package/modules/government/docket.js +48 -2
  90. package/modules/government/migrations/government_035_payout_approve.sql +29 -0
  91. package/modules/government/migrations/government_036_access_holders.sql +33 -0
  92. package/modules/government/pollers/board-expiry.js +108 -20
  93. package/modules/government/protected-surfaces.json +1 -0
  94. package/modules/government/routes/government.js +31 -0
  95. package/modules/government/routing.js +49 -7
  96. package/modules/government/waiting.js +78 -0
  97. package/modules/hall-ui/public/ai-studio-lib.js +268 -0
  98. package/modules/hall-ui/public/ai-studio.css +193 -0
  99. package/modules/hall-ui/public/ai-studio.html +98 -0
  100. package/modules/hall-ui/public/ai-studio.js +556 -0
  101. package/modules/hall-ui/public/ai-studio.states.json +94 -0
  102. package/modules/hall-ui/public/blockers-by-person.js +158 -0
  103. package/modules/hall-ui/public/blockers-lib.js +15 -1
  104. package/modules/hall-ui/public/blockers.html +8 -0
  105. package/modules/hall-ui/public/blockers.js +1 -1
  106. package/modules/hall-ui/public/claim-action.js +3 -0
  107. package/modules/hall-ui/public/collab.html +12 -0
  108. package/modules/hall-ui/public/craft-mode.js +4 -1
  109. package/modules/hall-ui/public/criterion-uat-ui.js +4 -1
  110. package/modules/hall-ui/public/drachmae.html +1 -1
  111. package/modules/hall-ui/public/genesis/r5-life-1-primordial-sea.jpg +0 -0
  112. package/modules/hall-ui/public/genesis/r5-life-2-first-cells-cut.webp +0 -0
  113. package/modules/hall-ui/public/genesis/r5-life-2-first-cells.jpg +0 -0
  114. package/modules/hall-ui/public/genesis/r5-life-3-genome-cut.webp +0 -0
  115. package/modules/hall-ui/public/genesis/r5-life-3-genome.jpg +0 -0
  116. package/modules/hall-ui/public/genesis/r5-life-4-membrane-cut.webp +0 -0
  117. package/modules/hall-ui/public/genesis/r5-life-4-membrane.jpg +0 -0
  118. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system-cut.webp +0 -0
  119. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system.jpg +0 -0
  120. package/modules/hall-ui/public/goal-inbox.js +1 -1
  121. package/modules/hall-ui/public/goals-render.js +4 -0
  122. package/modules/hall-ui/public/goals.html +8 -0
  123. package/modules/hall-ui/public/gov-living.js +6 -2
  124. package/modules/hall-ui/public/government-access.js +108 -0
  125. package/modules/hall-ui/public/government.html +21 -0
  126. package/modules/hall-ui/public/hall-ask.css +5 -0
  127. package/modules/hall-ui/public/hall-ask.js +39 -3
  128. package/modules/hall-ui/public/notes-panel.css +20 -0
  129. package/modules/hall-ui/public/notes-panel.js +146 -0
  130. package/modules/hall-ui/public/project-settings.html +1 -1
  131. package/modules/hall-ui/public/project-settings.js +7 -5
  132. package/modules/hall-ui/public/settings-ai-keys.js +124 -0
  133. package/modules/hall-ui/public/settings.html +15 -0
  134. package/modules/hall-ui/public/street-deck.js +12 -3
  135. package/modules/hall-ui/public/studio.css +90 -8
  136. package/modules/hall-ui/public/studio.html +39 -10
  137. package/modules/hall-ui/public/studio.js +148 -18
  138. package/modules/hall-ui/public/task.html +2 -0
  139. package/modules/hall-ui/public/task.js +4 -0
  140. package/modules/hall-ui/public/tweak-editor.js +12 -3
  141. package/modules/hall-ui/public/welcome-boot.css +42 -6
  142. package/modules/hall-ui/public/welcome-boot.js +20 -6
  143. package/modules/hall-ui/public/work.js +20 -0
  144. package/modules/hall-ui/records/ai-studio.md +36 -0
  145. package/modules/hall-ui/records/blockers-people.md +38 -0
  146. package/modules/lifecycle/db-claims.js +32 -4
  147. package/modules/lifecycle/db-goals.js +18 -5
  148. package/modules/lifecycle/db-tasks.js +15 -6
  149. package/modules/lifecycle/done-when.js +23 -1
  150. package/modules/lifecycle/lifecycle.js +5 -0
  151. package/modules/lifecycle/migrations/lifecycle_017_notes.sql +46 -0
  152. package/modules/lifecycle/module.json +2 -1
  153. package/modules/lifecycle/notes.js +219 -0
  154. package/modules/lifecycle/page-notice.js +124 -0
  155. package/modules/lifecycle/page-tweak-artist.js +18 -1
  156. package/modules/lifecycle/publish-reconciler.js +67 -20
  157. package/modules/lifecycle/routes/claims.js +5 -2
  158. package/modules/lifecycle/routes/goals.js +3 -1
  159. package/modules/lifecycle/routes/notes.js +91 -0
  160. package/modules/lifecycle/routes/project-settings.js +43 -35
  161. package/modules/lifecycle/routes/task-route-helpers.js +21 -0
  162. package/modules/lifecycle/routes/task-write-routes.js +21 -3
  163. package/modules/lifecycle/routes/tasks.js +12 -12
  164. package/modules/lifecycle/task-needs-gate.js +70 -0
  165. package/modules/market-watch/CLAUDE.md +15 -0
  166. package/modules/market-watch/db.js +340 -0
  167. package/modules/market-watch/key.js +58 -0
  168. package/modules/market-watch/migrations/market_watch_001_tables.sql +249 -0
  169. package/modules/market-watch/migrations/market_watch_002_run.sql +46 -0
  170. package/modules/market-watch/module.json +26 -0
  171. package/modules/market-watch/pollers/hub-seed.js +54 -0
  172. package/modules/market-watch/pollers/weekly-run.js +100 -0
  173. package/modules/market-watch/research.js +350 -0
  174. package/modules/market-watch/run.js +245 -0
  175. package/modules/market-watch/seed/market-data.json +38 -0
  176. package/modules/market-watch/seed/partners-data.json +497 -0
  177. package/modules/market-watch/seed.js +252 -0
  178. package/modules/market-watch/store.js +230 -0
  179. package/modules/memory/routes/memory.js +14 -2
  180. package/modules/memory/routes/search.js +8 -2
  181. package/modules/platform-identity/account-logins.js +192 -0
  182. package/modules/platform-identity/migrations/platform_identity_034_account_logins.sql +96 -0
  183. package/modules/platform-identity/platform-identity.js +5 -4
  184. package/modules/platform-identity/routes/my-projects.js +6 -0
  185. package/modules/platform-identity/routes/profile.js +18 -0
  186. package/modules/platform-identity/routes/public-profile.js +10 -1
  187. package/modules/platform-identity/routes/sso.js +26 -1
  188. package/modules/platform-identity/tests/platform-identity.mjs +2 -1
  189. package/modules/provisioning/credential-preflight.js +13 -3
  190. package/modules/provisioning/pollers/app-liveness.js +25 -5
  191. package/modules/provisioning/routes/provisioning.js +1 -1
  192. package/modules/provisioning/starter-bundles.js +6 -2
  193. package/modules/public-landing/public/account.html +10 -2
  194. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg +0 -0
  195. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
  196. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
  197. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +1 -1
  198. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp +0 -0
  199. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp.json +1 -1
  200. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg +0 -0
  201. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
  202. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
  203. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +1 -1
  204. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg +0 -0
  205. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
  206. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
  207. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +1 -1
  208. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp +0 -0
  209. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp.json +1 -1
  210. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp +0 -0
  211. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp.json +1 -1
  212. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp +0 -0
  213. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp.json +1 -1
  214. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp +0 -0
  215. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp.json +1 -1
  216. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp +0 -0
  217. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp.json +1 -1
  218. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp +0 -0
  219. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp.json +1 -1
  220. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg +0 -0
  221. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg.json +1 -1
  222. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg +0 -0
  223. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg.json +1 -1
  224. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg +0 -0
  225. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg.json +1 -1
  226. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg +0 -0
  227. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg.json +1 -1
  228. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp +0 -0
  229. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp.json +1 -1
  230. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg +0 -0
  231. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg.json +1 -1
  232. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp +0 -0
  233. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp.json +1 -1
  234. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg +0 -0
  235. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg.json +1 -1
  236. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp +0 -0
  237. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp.json +1 -1
  238. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg +0 -0
  239. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg.json +1 -1
  240. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp +0 -0
  241. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp.json +1 -1
  242. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg +0 -0
  243. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg.json +1 -1
  244. package/modules/public-landing/public/community.html +1 -1
  245. package/modules/public-landing/public/connections.html +2 -2
  246. package/modules/public-landing/public/guild.html +1 -1
  247. package/modules/public-landing/public/invitations.html +2 -2
  248. package/modules/public-landing/public/projects.html +5 -5
  249. package/modules/raise/views/nda.html +2 -0
  250. package/modules/specialities/db.js +32 -1
  251. package/modules/specialities/routes/specialities.js +10 -6
  252. package/modules/status-ui/public/index.html +1 -1
  253. package/package-lock.json +2 -2
  254. package/package.json +1 -1
  255. package/release-notes.json +230 -0
  256. package/scripts/bongos/autobongos-tweak-lane.js +46 -1
  257. package/scripts/bongos/backfill-subagent-rewards.js +2 -2
  258. package/scripts/bongos/claim.js +22 -1
  259. package/scripts/bongos/db-backup-nightly.sh +29 -0
  260. package/scripts/bongos/deploy-divergence.js +7 -0
  261. package/scripts/bongos/doc-cli-guard.js +6 -0
  262. package/scripts/bongos/fitness.js +3 -2
  263. package/scripts/bongos/gen-diagrams.js +3 -3
  264. package/scripts/bongos/government-walk.js +3 -0
  265. package/scripts/bongos/lib.sh +4 -5
  266. package/scripts/bongos/migration-namespace.js +13 -1
  267. package/scripts/bongos/plain-cards.js +4 -0
  268. package/scripts/bongos/provision-github-setup.js +3 -1
  269. package/scripts/bongos/provision-units.js +6 -1
  270. package/scripts/bongos/publish-manifest.js +3 -0
  271. package/scripts/bongos/release.js +2 -0
  272. package/scripts/bongos/run-unit-tests.js +268 -82
  273. package/scripts/bongos/seed-tasks.example.json +56 -0
  274. package/scripts/bongos/seed-tasks.js +222 -0
  275. package/scripts/bongos/seed-verify-criteria.js +1 -2
  276. package/scripts/bongos/ship-finish.js +2 -0
  277. package/scripts/bongos/ship-resume.js +2 -0
  278. package/scripts/bongos/strand-lease.js +250 -0
  279. package/scripts/bongos/strand-watch.js +26 -5
  280. package/scripts/bongos/version-literal-guard.js +2 -2
  281. package/scripts/discord/post.js +4 -3
  282. package/scripts/gds/seed-tasks.js +7 -0
  283. package/scripts/gds/{build-bongos.js → strand-lease.js} +3 -3
  284. package/scripts/hall-preview/server.js +21 -0
  285. package/src/bongos/auth-config.js +29 -1
  286. package/src/bongos/auth-discord.js +3 -3
  287. package/src/bongos/auth-github.js +3 -6
  288. package/src/bongos/auth-google.js +217 -0
  289. package/src/bongos/device-approval.js +140 -0
  290. package/src/bongos/llm-pricing.js +17 -1
  291. package/src/bongos/metrics.js +48 -2
  292. package/src/bongos/middleware/rate-limit.js +30 -11
  293. package/src/bongos/module-scope-map.js +12 -1
  294. package/src/bongos/optimizer.js +15 -1
  295. package/src/bongos/payout-approvals.js +342 -0
  296. package/src/bongos/payout-gates.js +364 -0
  297. package/src/bongos/prelaunch-gate.js +7 -9
  298. package/src/bongos/prelaunch-switch.js +20 -0
  299. package/src/bongos/route-rank-check.js +7 -0
  300. package/src/bongos/routes/auth-google.js +246 -0
  301. package/src/bongos/routes/auth.js +38 -1
  302. package/src/bongos/routes/backup.js +33 -9
  303. package/src/bongos/routes/builders.js +57 -30
  304. package/src/bongos/routes/github.js +9 -0
  305. package/src/bongos/routes/me.js +18 -0
  306. package/src/bongos/routes/my-payouts.js +133 -0
  307. package/src/bongos/routes/payout-approvals.js +312 -0
  308. package/src/bongos/routes/payout-gates.js +179 -0
  309. package/src/bongos/routes.js +15 -1
  310. package/src/bongos/secret-box.js +18 -3
  311. package/src/bongos/serve-internal.js +47 -19
  312. package/src/bongos/sign-in-pages.js +138 -0
  313. package/src/bongos/task-needs.js +146 -0
  314. package/src/bongos-downloads.js +18 -1
  315. package/src/instance-config.js +28 -0
  316. package/src/module-api.js +14 -1
  317. package/tests/access_holders.mjs +214 -0
  318. package/tests/account_logins.mjs +326 -0
  319. package/tests/account_logins_db.mjs +161 -0
  320. package/tests/ai_studio_billing.mjs +253 -0
  321. package/tests/ai_studio_generate.mjs +282 -0
  322. package/tests/ai_studio_keys.mjs +159 -0
  323. package/tests/ai_studio_requests.mjs +319 -0
  324. package/tests/auth_backchannel_logout_route.mjs +201 -0
  325. package/tests/auto_satisfy_criteria.mjs +10 -1
  326. package/tests/autobongos_tweak_lane.mjs +144 -0
  327. package/tests/autobongos_tweak_pin_identity.mjs +137 -0
  328. package/tests/backfill_subagent_rewards.mjs +17 -1
  329. package/tests/backup_trigger_lock.mjs +119 -0
  330. package/tests/blockers_people.mjs +198 -0
  331. package/tests/bounded_rate_maps.mjs +184 -0
  332. package/tests/claimable_blocker_status.mjs +1 -1
  333. package/tests/claims_batch_routes.mjs +421 -0
  334. package/tests/config_read_cache.mjs +171 -0
  335. package/tests/copy_desk_page_editor.mjs +12 -0
  336. package/tests/cost_write_guard.mjs +200 -0
  337. package/tests/craft_achievements.mjs +33 -10
  338. package/tests/criterion_goal_attach.mjs +1 -1
  339. package/tests/db_backup_nightly.mjs +73 -1
  340. package/tests/deploy_divergence_line.mjs +7 -0
  341. package/tests/effective_visibility_predicate.mjs +12 -0
  342. package/tests/fitness.mjs +19 -0
  343. package/tests/fixtures/seed-tasks/bongos-v1-idea-routing.json +256 -0
  344. package/tests/fixtures/seed-tasks/bv1-profiles.json +592 -0
  345. package/tests/fixtures/seed-tasks/bv2-ideator-surface.json +373 -0
  346. package/tests/fixtures/seed-tasks/fake-api.mjs +80 -0
  347. package/tests/github_one_trip.mjs +34 -0
  348. package/tests/github_repo_visibility.mjs +20 -0
  349. package/tests/goal_achievement.mjs +30 -1
  350. package/tests/goal_achievement_reward.mjs +205 -0
  351. package/tests/goal_sort_staleness.mjs +2 -1
  352. package/tests/goal_tier.mjs +11 -1
  353. package/tests/google_fonts_nonblocking.mjs +84 -0
  354. package/tests/google_sign_in.mjs +401 -0
  355. package/tests/government_board_expiry.mjs +94 -0
  356. package/tests/government_board_membership.mjs +4 -1
  357. package/tests/government_protected_surfaces.mjs +1 -1
  358. package/tests/government_routes.mjs +1 -1
  359. package/tests/government_seed.mjs +1 -0
  360. package/tests/hall_ai_studio.mjs +347 -0
  361. package/tests/hall_page_gate_map.mjs +3 -0
  362. package/tests/hall_studio_home.mjs +61 -2
  363. package/tests/home_attention_cards.mjs +1 -1
  364. package/tests/human_signal.mjs +141 -0
  365. package/tests/install_script_reader.mjs +51 -0
  366. package/tests/integration_fixture_ids.mjs +82 -0
  367. package/tests/invite_expiry_db.mjs +13 -1
  368. package/tests/lib_sh_resolution.mjs +0 -4
  369. package/tests/market_watch_data.mjs +244 -0
  370. package/tests/market_watch_data_db.mjs +308 -0
  371. package/tests/market_watch_module.mjs +114 -0
  372. package/tests/market_watch_run.mjs +503 -0
  373. package/tests/metrics.mjs +124 -0
  374. package/tests/migration_namespace.mjs +14 -0
  375. package/tests/module_api.mjs +2 -0
  376. package/tests/module_loader.mjs +1 -1
  377. package/tests/notes.mjs +182 -0
  378. package/tests/own_scope_guard.mjs +5 -0
  379. package/tests/page_tweak_marker_sql.mjs +76 -0
  380. package/tests/page_tweak_no_block.mjs +135 -0
  381. package/tests/page_tweak_notice.mjs +103 -0
  382. package/tests/payout_approvals.mjs +253 -0
  383. package/tests/payout_approvals_db.mjs +106 -0
  384. package/tests/payout_gates.mjs +322 -0
  385. package/tests/payout_gates_db.mjs +113 -0
  386. package/tests/planning_session_skill.mjs +13 -3
  387. package/tests/project_settings_page.mjs +29 -5
  388. package/tests/project_settings_spend_cap_route.mjs +235 -0
  389. package/tests/promotion_sweep.mjs +29 -1
  390. package/tests/provision.mjs +3 -2
  391. package/tests/provisioning_app_status.mjs +18 -0
  392. package/tests/provisioning_credential_preflight.mjs +53 -0
  393. package/tests/provisioning_env_manifest_edit_delete.mjs +223 -0
  394. package/tests/publish_reconciler_overlap.mjs +60 -0
  395. package/tests/rank_change_broadcast_port.mjs +151 -0
  396. package/tests/seed_tasks.mjs +176 -0
  397. package/tests/seed_verify_criteria.mjs +2 -6
  398. package/tests/site_classified_once.mjs +142 -0
  399. package/tests/speciality_db_shape.mjs +23 -0
  400. package/tests/speciality_session_skills.mjs +48 -2
  401. package/tests/strand_lease.mjs +249 -0
  402. package/tests/strand_watch.mjs +10 -0
  403. package/tests/task_criteria_routes.mjs +275 -0
  404. package/tests/task_criteria_unlink_db.mjs +123 -0
  405. package/tests/task_needs.mjs +233 -0
  406. package/tests/task_needs_db.mjs +110 -0
  407. package/tests/unit_runner_serial.mjs +266 -43
  408. package/tests/version_literals.mjs +5 -7
  409. package/tests/welcome_boot.mjs +16 -5
  410. package/tests/welcome_boot_browser.mjs +36 -4
  411. package/docs/recipes/bongos-cli-release.md +0 -66
  412. package/scripts/bongos/backfill-disciplines.js +0 -144
  413. package/scripts/bongos/backfill-session-earnings.js +0 -123
  414. package/scripts/bongos/backfill-session-types.js +0 -87
  415. package/scripts/bongos/build-bongos.js +0 -94
  416. package/scripts/bongos/cleanup-orphans.js +0 -74
  417. package/scripts/bongos/seed-bongos-v1-idea-routing-tasks.js +0 -152
  418. package/scripts/bongos/seed-bv1-profiles-tasks.js +0 -135
  419. package/scripts/bongos/seed-bv2-ideator-surface-tasks.js +0 -390
  420. package/scripts/bongos/smoke-batch-claim.sh +0 -238
  421. package/scripts/bongos/smoke-batch-release.sh +0 -316
  422. package/scripts/bongos/smoke-claim-consistency.sh +0 -222
  423. package/scripts/bongos/smoke-dependencies.sh +0 -143
  424. package/scripts/gds/backfill-disciplines.js +0 -7
  425. package/scripts/gds/backfill-session-earnings.js +0 -7
  426. package/scripts/gds/backfill-session-types.js +0 -7
  427. package/scripts/gds/cleanup-orphans.js +0 -7
  428. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +0 -6
  429. package/scripts/gds/seed-bv1-profiles-tasks.js +0 -6
  430. package/scripts/gds/seed-bv2-ideator-surface-tasks.js +0 -6
  431. package/scripts/gds/smoke-batch-claim.sh +0 -8
  432. package/scripts/gds/smoke-batch-release.sh +0 -8
  433. package/scripts/gds/smoke-claim-consistency.sh +0 -8
  434. package/scripts/gds/smoke-dependencies.sh +0 -8
  435. package/tests/smoke_dependencies_witness.mjs +0 -46
@@ -1,316 +0,0 @@
1
- #!/usr/bin/env bash
2
- # GDS batch-release + dry-run-validate smoke test (task 1758).
3
- #
4
- # Exercises POST /api/bongos/claims/batch/release:
5
- # Case A: 2 own active claims → 200, both in released[], both tasks 'ready'.
6
- # Case B: 1 own active claim + 1 bogus claim id → 200 (NOT all-or-nothing —
7
- # the batch has no cross-claim invariant), the good one released,
8
- # the bad one enumerated in failures[] with CLAIM_NOT_FOUND.
9
- #
10
- # Exercises POST /api/bongos/claims/batch/validate:
11
- # Case C: 2 ready tasks, disjoint touches → parallel_safe:true, both valid.
12
- # Case D: 2 ready tasks, OVERLAPPING touches → parallel_safe:false, both
13
- # marked invalid (BATCH_TOUCHES_CONFLICT) — and, since this is a
14
- # dry run, neither task actually gets claimed (still 'ready' after).
15
- # Case E: 1 ready + 1 already-active task → the active one is marked
16
- # invalid (TASK_NOT_READY), the ready one stays valid.
17
- #
18
- # Creates synthetic '__smoke__' tasks that are filtered from the public surfaces.
19
- # Cleans up by releasing/abandoning every claim it creates and marking tasks
20
- # 'abandoned' so they don't linger.
21
- #
22
- # Usage: bash scripts/bongos/smoke-batch-release.sh
23
- # Env: GDS_API_BASE / PMS_API_BASE override host (default: this instance's own,
24
- # resolved from the session + branding pack — see lib.sh)
25
-
26
- set -euo pipefail
27
-
28
- # shellcheck source=scripts/bongos/lib.sh
29
- source "$(dirname "$0")/lib.sh"
30
-
31
- API="$(gds_api_base)"
32
- TOKEN="$(gds_resolve_token)" || exit $?
33
-
34
- # task 1003166 (G02): resolve the version at RUNTIME rather than naming one. A
35
- # literal works until that version ships, then `version_closed` refuses every
36
- # create and the smoke fails as if the code broke (idea 1000823).
37
- VERSION_ID=$(node "$(dirname "$0")/version-select.js") || {
38
- echo "FAIL: could not resolve a building version — see version-select.js" >&2
39
- exit 1
40
- }
41
-
42
- ts=$(date +%Y%m%d-%H%M%S)
43
-
44
- # Wrapper: METHOD PATH [BODY] → echoes "PAYLOAD\nHTTP_CODE". Never exits.
45
- call() {
46
- local method="$1" path="$2" body="${3:-}"
47
- local args=(-sS -X "${method}" -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -w "\n%{http_code}")
48
- if [[ -n "${body}" ]]; then args+=(-d "${body}"); fi
49
- curl "${args[@]}" "${API}${path}"
50
- }
51
-
52
- parse_call() {
53
- local out="$1"
54
- CODE="${out##*$'\n'}"
55
- PAYLOAD="${out%$'\n'*}"
56
- }
57
-
58
- mk_task() {
59
- # mk_task <suffix> <touches-csv> → echoes new task id
60
- local suffix="$1" touches_csv="$2"
61
- local body
62
- body=$(python3 -c "
63
- import json,sys
64
- t = '${touches_csv}'.split(',')
65
- print(json.dumps({
66
- 'version_id': '${VERSION_ID}',
67
- 'title': '__smoke__ batch-release ${ts}-${suffix}',
68
- 'description': 'smoke',
69
- 'status': 'ready',
70
- 'touches': t,
71
- 'est_minutes': 1,
72
- 'manual_degree': 1,
73
- 'priority': 5,
74
- 'automation_tag': 'overnight-safe',
75
- 'credits_reward': 0,
76
- 'source': 'smoke',
77
- 'source_ref': '${ts}-${suffix}'
78
- }))")
79
- parse_call "$(call POST /api/bongos/tasks "${body}")"
80
- python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['task']['id'])"
81
- }
82
-
83
- claim_task() {
84
- # claim_task <task_id> → echoes new claim id.
85
- # Uses /claims/batch with bind_session:false (task 1795) rather than the
86
- # plain single-claim path — this CLI token IS a real bound session, and the
87
- # plain single-claim path caps a session to ONE active claim at a time
88
- # (gateOneActiveClaimPerSession, task 1642). bind_session:false stores
89
- # creator_session_id NULL instead of the caller's session, so this session
90
- # can hold as many of these as it needs for fixture setup (NULL sessions are
91
- # explicitly excluded from the uniq_active_claim_per_session index).
92
- local tid="$1"
93
- parse_call "$(call POST /api/bongos/claims/batch "{\"task_ids\":[${tid}],\"bind_session\":false}")"
94
- python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['claims'][0]['id'])"
95
- }
96
-
97
- # Track created tasks + claims for cleanup. Claims released in Case A/B are
98
- # dropped from CREATED_CLAIMS as they resolve so cleanup doesn't double-resolve.
99
- CREATED_TASKS=()
100
- CREATED_CLAIMS=()
101
- cleanup() {
102
- local leaked=()
103
- echo
104
- echo "--- cleanup ---"
105
- for cid in "${CREATED_CLAIMS[@]:-}"; do
106
- [[ -z "${cid}" ]] && continue
107
- call POST "/api/bongos/claims/${cid}/resolve" \
108
- '{"outcome":"abandoned","notes_md":"smoke cleanup"}' >/dev/null || true
109
- done
110
- for tid in "${CREATED_TASKS[@]:-}"; do
111
- [[ -z "${tid}" ]] && continue
112
- # task 1002856: same bug as smoke-batch-claim.sh — /tasks/:id/promote is the
113
- # backlog->ready transition and ignores a status field, so this never
114
- # abandoned anything and the redirect swallowed the failure.
115
- if ! call POST "/api/bongos/tasks/${tid}/abandon" \
116
- '{"reason":"smoke cleanup (scripts/bongos/smoke-batch-release.sh)"}' >/dev/null 2>&1; then
117
- leaked+=("${tid}")
118
- fi
119
- done
120
- if [[ ${#leaked[@]} -gt 0 ]]; then
121
- echo "WARN: could not abandon ${#leaked[@]} smoke task(s): ${leaked[*]}"
122
- echo "WARN: clear them with: node scripts/bongos/api.js POST /tasks/<id>/abandon --body '{\"reason\":\"smoke residue\"}'"
123
- fi
124
- echo "cleanup done"
125
- }
126
- trap cleanup EXIT
127
-
128
- fail=0
129
- ok() { echo "PASS $*"; }
130
- bad() { echo "FAIL $*"; fail=1; }
131
-
132
- echo "=== GDS batch-release + validate smoke ==="
133
- echo "API: ${API}"
134
- echo
135
-
136
- # ---- Case A: 2 own active claims → 200, both released ------------------
137
- # Each id is registered for cleanup IMMEDIATELY after it's created/claimed
138
- # (not batched after both calls) — so if the second call in a pair fails,
139
- # the first one's already-registered and still gets cleaned up on exit.
140
- echo "--- A: release 2 own claims (expect 200, both released) ---"
141
- TA1=$(mk_task A1 "__smoke__/batch-release/${ts}/a1"); CREATED_TASKS+=("${TA1}")
142
- TA2=$(mk_task A2 "__smoke__/batch-release/${ts}/a2"); CREATED_TASKS+=("${TA2}")
143
- CA1=$(claim_task "${TA1}"); CREATED_CLAIMS+=("${CA1}")
144
- CA2=$(claim_task "${TA2}"); CREATED_CLAIMS+=("${CA2}")
145
- echo " claimed #${TA1}→claim ${CA1}, #${TA2}→claim ${CA2}"
146
-
147
- BODY_A=$(python3 -c "import json; print(json.dumps({'claim_ids':[${CA1},${CA2}]}))")
148
- parse_call "$(call POST /api/bongos/claims/batch/release "${BODY_A}")"
149
- if [[ "${CODE}" == "200" ]]; then
150
- N=$(python3 -c "import json,sys; print(len(json.loads('''${PAYLOAD}''')['released']))")
151
- NF=$(python3 -c "import json,sys; print(len(json.loads('''${PAYLOAD}''')['failures']))")
152
- if [[ "${N}" == "2" && "${NF}" == "0" ]]; then
153
- ok "A: 200 with 2 released, 0 failures"
154
- CREATED_CLAIMS=("${CREATED_CLAIMS[@]/${CA1}/}" ); CREATED_CLAIMS=("${CREATED_CLAIMS[@]/${CA2}/}")
155
- else
156
- bad "A: expected 2 released/0 failures, got ${N}/${NF} → ${PAYLOAD}"
157
- fi
158
- else
159
- bad "A: expected 200, got ${CODE} → ${PAYLOAD}"
160
- fi
161
- for tid in "${TA1}" "${TA2}"; do
162
- parse_call "$(call GET "/api/bongos/tasks/${tid}")"
163
- S=$(python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['task']['status'])")
164
- if [[ "${S}" == "ready" ]]; then
165
- ok "A: task #${tid} back to 'ready'"
166
- else
167
- bad "A: task #${tid} status = ${S} (expected ready)"
168
- fi
169
- done
170
-
171
- # ---- Case B: 1 own claim + 1 bogus id → 200, partial success -----------
172
- echo
173
- echo "--- B: 1 own claim + 1 bogus claim id (expect 200, partial) ---"
174
- TB1=$(mk_task B1 "__smoke__/batch-release/${ts}/b1")
175
- CREATED_TASKS+=("${TB1}")
176
- CB1=$(claim_task "${TB1}")
177
- CREATED_CLAIMS+=("${CB1}")
178
- BOGUS_CLAIM_ID=999999999
179
- echo " claimed #${TB1}→claim ${CB1}; bogus id ${BOGUS_CLAIM_ID}"
180
-
181
- BODY_B=$(python3 -c "import json; print(json.dumps({'claim_ids':[${CB1},${BOGUS_CLAIM_ID}]}))")
182
- parse_call "$(call POST /api/bongos/claims/batch/release "${BODY_B}")"
183
- if [[ "${CODE}" == "200" ]]; then
184
- RELEASED_IDS=$(python3 -c "
185
- import json,sys
186
- d = json.loads('''${PAYLOAD}''')
187
- print(','.join(str(r['claim_id']) for r in d['released']))
188
- ")
189
- FAIL_REASONS=$(python3 -c "
190
- import json,sys
191
- d = json.loads('''${PAYLOAD}''')
192
- fs = d['failures']
193
- print(','.join(f\"{f['claim_id']}:{f['reason']}\" for f in fs))
194
- ")
195
- if [[ "${RELEASED_IDS}" == *"${CB1}"* ]]; then
196
- ok "B: good claim #${CB1} released (released: ${RELEASED_IDS})"
197
- CREATED_CLAIMS=("${CREATED_CLAIMS[@]/${CB1}/}")
198
- else
199
- bad "B: good claim #${CB1} NOT released (released: ${RELEASED_IDS})"
200
- fi
201
- if [[ "${FAIL_REASONS}" == *"${BOGUS_CLAIM_ID}:CLAIM_NOT_FOUND"* ]]; then
202
- ok "B: bogus id enumerated as CLAIM_NOT_FOUND (failures: ${FAIL_REASONS})"
203
- else
204
- bad "B: bogus id not enumerated as CLAIM_NOT_FOUND (failures: ${FAIL_REASONS})"
205
- fi
206
- else
207
- bad "B: expected 200, got ${CODE} → ${PAYLOAD}"
208
- fi
209
-
210
- # ---- Case C: validate, disjoint touches → parallel_safe:true -----------
211
- echo
212
- echo "--- C: validate 2 ready disjoint-touches tasks (expect parallel_safe:true) ---"
213
- TC1=$(mk_task C1 "__smoke__/batch-release/${ts}/c1"); CREATED_TASKS+=("${TC1}")
214
- TC2=$(mk_task C2 "__smoke__/batch-release/${ts}/c2"); CREATED_TASKS+=("${TC2}")
215
-
216
- BODY_C=$(python3 -c "import json; print(json.dumps({'task_ids':[${TC1},${TC2}]}))")
217
- parse_call "$(call POST /api/bongos/claims/batch/validate "${BODY_C}")"
218
- if [[ "${CODE}" == "200" ]]; then
219
- PS=$(python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['parallel_safe'])")
220
- if [[ "${PS}" == "True" ]]; then
221
- ok "C: parallel_safe:true for disjoint touches"
222
- else
223
- bad "C: expected parallel_safe:true, got ${PS} → ${PAYLOAD}"
224
- fi
225
- else
226
- bad "C: expected 200, got ${CODE} → ${PAYLOAD}"
227
- fi
228
- # Dry run — confirm NOTHING got claimed.
229
- for tid in "${TC1}" "${TC2}"; do
230
- parse_call "$(call GET "/api/bongos/tasks/${tid}")"
231
- S=$(python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['task']['status'])")
232
- if [[ "${S}" == "ready" ]]; then
233
- ok "C: task #${tid} still 'ready' (validate did not claim)"
234
- else
235
- bad "C: task #${tid} status = ${S} (validate must never claim)"
236
- fi
237
- done
238
-
239
- # ---- Case D: validate, overlapping touches → parallel_safe:false -------
240
- echo
241
- echo "--- D: validate 2 ready overlapping-touches tasks (expect parallel_safe:false) ---"
242
- TD1=$(mk_task D1 "__smoke__/batch-release/${ts}/shared"); CREATED_TASKS+=("${TD1}")
243
- TD2=$(mk_task D2 "__smoke__/batch-release/${ts}/shared"); CREATED_TASKS+=("${TD2}")
244
- echo " created tasks ${TD1}, ${TD2} (both touch __smoke__/batch-release/${ts}/shared)"
245
-
246
- BODY_D=$(python3 -c "import json; print(json.dumps({'task_ids':[${TD1},${TD2}]}))")
247
- parse_call "$(call POST /api/bongos/claims/batch/validate "${BODY_D}")"
248
- if [[ "${CODE}" == "200" ]]; then
249
- PS=$(python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['parallel_safe'])")
250
- REASONS=$(python3 -c "
251
- import json,sys
252
- d = json.loads('''${PAYLOAD}''')
253
- rs = set()
254
- for r in d['results']:
255
- for reason in r['reasons']:
256
- rs.add(reason['reason'])
257
- print(','.join(sorted(rs)))
258
- ")
259
- if [[ "${PS}" == "False" && "${REASONS}" == *"BATCH_TOUCHES_CONFLICT"* ]]; then
260
- ok "D: parallel_safe:false with BATCH_TOUCHES_CONFLICT (reasons: ${REASONS})"
261
- else
262
- bad "D: expected parallel_safe:false + BATCH_TOUCHES_CONFLICT, got ${PS}/${REASONS} → ${PAYLOAD}"
263
- fi
264
- else
265
- bad "D: expected 200, got ${CODE} → ${PAYLOAD}"
266
- fi
267
- for tid in "${TD1}" "${TD2}"; do
268
- parse_call "$(call GET "/api/bongos/tasks/${tid}")"
269
- S=$(python3 -c "import json,sys; print(json.loads('''${PAYLOAD}''')['task']['status'])")
270
- if [[ "${S}" == "ready" ]]; then
271
- ok "D: task #${tid} still 'ready' (validate did not claim)"
272
- else
273
- bad "D: task #${tid} status = ${S} (validate must never claim)"
274
- fi
275
- done
276
-
277
- # ---- Case E: validate, 1 ready + 1 already-active → the active one invalid
278
- echo
279
- echo "--- E: validate 1 ready + 1 already-active (expect the active one invalid) ---"
280
- TE1=$(mk_task E1 "__smoke__/batch-release/${ts}/e1"); CREATED_TASKS+=("${TE1}")
281
- TE2=$(mk_task E2 "__smoke__/batch-release/${ts}/e2"); CREATED_TASKS+=("${TE2}")
282
- CE1=$(claim_task "${TE1}"); CREATED_CLAIMS+=("${CE1}")
283
- echo " #${TE1} pre-claimed (claim ${CE1}, now 'active'); #${TE2} stays 'ready'"
284
-
285
- BODY_E=$(python3 -c "import json; print(json.dumps({'task_ids':[${TE1},${TE2}]}))")
286
- parse_call "$(call POST /api/bongos/claims/batch/validate "${BODY_E}")"
287
- if [[ "${CODE}" == "200" ]]; then
288
- VALID_E1=$(python3 -c "
289
- import json,sys
290
- d = json.loads('''${PAYLOAD}''')
291
- for r in d['results']:
292
- if r['task_id'] == ${TE1}: print(r['valid'])
293
- ")
294
- VALID_E2=$(python3 -c "
295
- import json,sys
296
- d = json.loads('''${PAYLOAD}''')
297
- for r in d['results']:
298
- if r['task_id'] == ${TE2}: print(r['valid'])
299
- ")
300
- if [[ "${VALID_E1}" == "False" && "${VALID_E2}" == "True" ]]; then
301
- ok "E: active task #${TE1} invalid, ready task #${TE2} valid"
302
- else
303
- bad "E: expected #${TE1}=invalid/#${TE2}=valid, got ${VALID_E1}/${VALID_E2} → ${PAYLOAD}"
304
- fi
305
- else
306
- bad "E: expected 200, got ${CODE} → ${PAYLOAD}"
307
- fi
308
-
309
- echo
310
- echo "--- summary ---"
311
- if [[ "${fail}" -eq 0 ]]; then
312
- echo "OK: batch-release + validate smoke passed"
313
- else
314
- echo "FAIL: one or more checks failed"
315
- fi
316
- exit "${fail}"
@@ -1,222 +0,0 @@
1
- #!/usr/bin/env bash
2
- # GDS claim-consistency smoke test (production). Renamed from PMS in V3.R01.
3
- #
4
- # Enforces criterion 7 of pms-v2.md: every surface that lists "your active
5
- # claims" must read from the canonical helper (src/bongos/active-claims.js)
6
- # and therefore return identical claim sets in identical order.
7
- #
8
- # Strategy:
9
- # 1. Create 2 disjoint __smoke__ tasks
10
- # 2. Claim both as the same builder
11
- # 3. Hit every consumer surface that currently exists:
12
- # - GET /api/bongos/me (always present)
13
- # - GET /api/bongos/builders/me (PMS-V2 P6) (capability-gated)
14
- # The /builder-start and /builder-session CLIs render server data;
15
- # they do not constitute independent surfaces in the sense of
16
- # criterion 7 (they consume /api/bongos/* responses). We assert at the
17
- # API boundary, which is where the bug class lives.
18
- # 4. Extract the ordered (task_id) sequence from each surface
19
- # 5. Assert all surfaces return identical sequences
20
- # 6. Release both claims, surfaces are cleaned up by the task lifecycle
21
- #
22
- # Surfaces that 404 are AUTO-SKIPPED so the smoke test passes against
23
- # current production even before PMS-V2 P6 lands. A summary line records
24
- # which surfaces were checked vs skipped.
25
- #
26
- # TODO: once PMS-V2 P6 (#48 — /builders web profile) ships, the
27
- # /api/bongos/builders/me surface will start returning 200 and this smoke
28
- # will automatically include it. No edits needed here.
29
- #
30
- # Usage:
31
- # bash scripts/bongos/smoke-claim-consistency.sh
32
- # Optional env:
33
- # GDS_API_BASE / PMS_API_BASE override the API host (default: this instance's own,
34
- # resolved from the session + branding pack — see lib.sh)
35
-
36
- set -euo pipefail
37
-
38
- # shellcheck source=scripts/bongos/lib.sh
39
- source "$(dirname "$0")/lib.sh"
40
-
41
- API="$(gds_api_base)"
42
- TOKEN="$(gds_resolve_token)" || exit $?
43
-
44
- ts=$(date +%Y%m%d-%H%M%S)
45
- SMOKE_TITLE_A="__smoke__ claim-consistency-A ${ts}"
46
- SMOKE_TITLE_B="__smoke__ claim-consistency-B ${ts}"
47
-
48
- call() {
49
- local method="$1" path="$2" body="${3:-}"
50
- local args=(-sS -X "${method}" -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -w "\n%{http_code}")
51
- if [[ -n "${body}" ]]; then args+=(-d "${body}"); fi
52
- local out
53
- out=$(curl "${args[@]}" "${API}${path}")
54
- local code="${out##*$'\n'}"
55
- local payload="${out%$'\n'*}"
56
- echo "${payload}"
57
- if [[ "${code}" -ge 300 ]]; then
58
- echo "FAIL: ${method} ${path} -> HTTP ${code}" >&2
59
- return 1
60
- fi
61
- }
62
-
63
- # Returns the HTTP status code for a GET to PATH. Used for capability gating.
64
- probe_status() {
65
- local path="$1"
66
- curl -sS -o /dev/null -w "%{http_code}" \
67
- -H "Authorization: Bearer ${TOKEN}" \
68
- "${API}${path}"
69
- }
70
-
71
- # Extract sorted task_id list from a JSON payload at a given JSON path.
72
- # Args: <payload> <python-extract-expr-returning-list-of-ints>
73
- extract_ids() {
74
- local payload="$1" expr="$2"
75
- echo "${payload}" | python3 -c "
76
- import json, sys
77
- data = json.load(sys.stdin)
78
- ids = ${expr}
79
- print(','.join(str(x) for x in ids))
80
- "
81
- }
82
-
83
- create_task() {
84
- local title="$1" suffix="$2"
85
- local body
86
- body=$(python3 -c "
87
- import json
88
- print(json.dumps({
89
- 'version_id': '${VERSION_ID}',
90
- 'title': '${title}',
91
- 'description': 'Synthetic smoke task. Auto-cleaned by smoke-claim-consistency.sh.',
92
- 'status': 'ready',
93
- 'touches': ['__smoke__/claim-consistency/${ts}/${suffix}'],
94
- 'est_minutes': 1,
95
- 'manual_degree': 1,
96
- 'priority': 5,
97
- 'automation_tag': 'overnight-safe',
98
- 'credits_reward': 0,
99
- 'source': 'smoke',
100
- 'source_ref': 'consistency-${ts}-${suffix}'
101
- }))
102
- ")
103
- local out
104
- out=$(call POST /api/bongos/tasks "${body}")
105
- echo "${out}" | python3 -c "import json,sys; print(json.load(sys.stdin)['task']['id'])"
106
- }
107
-
108
- claim_task() {
109
- local task_id="$1"
110
- local body
111
- body=$(python3 -c "import json; print(json.dumps({'task_id': ${task_id}, 'worktree_name': '__smoke__'}))")
112
- local out
113
- out=$(call POST /api/bongos/claims "${body}")
114
- echo "${out}" | python3 -c "import json,sys; print(json.load(sys.stdin)['claim']['id'])"
115
- }
116
-
117
- release_claim() {
118
- local claim_id="$1"
119
- call POST "/api/bongos/claims/${claim_id}/resolve" '{"outcome":"abandoned","notes_md":"smoke cleanup"}' >/dev/null || true
120
- }
121
-
122
- echo "=== GDS claim-consistency smoke test ==="
123
- echo "API: ${API}"
124
- echo "Titles: ${SMOKE_TITLE_A} | ${SMOKE_TITLE_B}"
125
- echo
126
-
127
- # task 1003166 (G02): resolve the version at RUNTIME. This file used to hardcode
128
- # one; that version shipped, `version_closed` refused every create, and the smoke
129
- # could not pass while /merge-mode still advertised it green (idea 1000823).
130
- VERSION_ID=$(node "$(dirname "$0")/version-select.js") || {
131
- echo "FAIL: could not resolve a building version — see version-select.js" >&2
132
- exit 1
133
- }
134
- echo "Version: ${VERSION_ID}"
135
-
136
- echo "--- 1. create 2 smoke tasks ---"
137
- TASK_A=$(create_task "${SMOKE_TITLE_A}" "A")
138
- TASK_B=$(create_task "${SMOKE_TITLE_B}" "B")
139
- echo "task A=#${TASK_A} task B=#${TASK_B}"
140
-
141
- # Always clean up on exit, even if assertions fail.
142
- CLAIM_A=""
143
- CLAIM_B=""
144
- cleanup() {
145
- local rc=$?
146
- echo
147
- echo "--- cleanup ---"
148
- [[ -n "${CLAIM_A}" ]] && release_claim "${CLAIM_A}" && echo "released claim ${CLAIM_A}"
149
- [[ -n "${CLAIM_B}" ]] && release_claim "${CLAIM_B}" && echo "released claim ${CLAIM_B}"
150
- exit "${rc}"
151
- }
152
- trap cleanup EXIT
153
-
154
- echo
155
- echo "--- 2. claim both as same builder (A first, then B) ---"
156
- CLAIM_A=$(claim_task "${TASK_A}")
157
- # Tiny pause so claimed_at differs and ordering is unambiguous.
158
- sleep 1
159
- CLAIM_B=$(claim_task "${TASK_B}")
160
- echo "claim A=#${CLAIM_A} claim B=#${CLAIM_B}"
161
-
162
- EXPECTED="${TASK_A},${TASK_B}"
163
- echo "expected ordered task_ids: ${EXPECTED}"
164
-
165
- echo
166
- echo "--- 3. probe each surface, extract ordered task_id sequence ---"
167
- checked=0
168
- skipped=0
169
- fail=0
170
-
171
- # Surface 1: /api/bongos/me — always present.
172
- ME_PAYLOAD=$(call GET /api/bongos/me)
173
- ME_IDS=$(extract_ids "${ME_PAYLOAD}" "[c['task_id'] for c in data.get('active_claims', [])]")
174
- # Filter to just our 2 smoke task_ids in case the builder has other live claims.
175
- ME_FILTERED=$(python3 -c "
176
- ids = '${ME_IDS}'.split(',') if '${ME_IDS}' else []
177
- keep = [x for x in ids if x in ('${TASK_A}', '${TASK_B}')]
178
- print(','.join(keep))
179
- ")
180
- echo "/api/bongos/me -> ${ME_FILTERED}"
181
- if [[ "${ME_FILTERED}" == "${EXPECTED}" ]]; then
182
- echo " PASS /api/bongos/me ordering matches"
183
- checked=$((checked+1))
184
- else
185
- echo " FAIL /api/bongos/me ordering mismatch (expected ${EXPECTED}, got ${ME_FILTERED})"
186
- fail=1
187
- fi
188
-
189
- # Surface 2: /api/bongos/builders/me — PMS-V2 P6, capability-gated.
190
- BUILDERS_ME_CODE=$(probe_status /api/bongos/builders/me)
191
- if [[ "${BUILDERS_ME_CODE}" == "200" ]]; then
192
- BME_PAYLOAD=$(call GET /api/bongos/builders/me)
193
- # Try both common shapes: top-level active_claims, or nested under builder/profile.
194
- BME_IDS=$(extract_ids "${BME_PAYLOAD}" "[c['task_id'] for c in (data.get('active_claims') or data.get('builder', {}).get('active_claims') or data.get('profile', {}).get('active_claims') or [])]")
195
- BME_FILTERED=$(python3 -c "
196
- ids = '${BME_IDS}'.split(',') if '${BME_IDS}' else []
197
- keep = [x for x in ids if x in ('${TASK_A}', '${TASK_B}')]
198
- print(','.join(keep))
199
- ")
200
- echo "/api/bongos/builders/me -> ${BME_FILTERED}"
201
- if [[ "${BME_FILTERED}" == "${EXPECTED}" ]]; then
202
- echo " PASS /api/bongos/builders/me ordering matches /api/bongos/me"
203
- checked=$((checked+1))
204
- else
205
- echo " FAIL /api/bongos/builders/me ordering mismatch (expected ${EXPECTED}, got ${BME_FILTERED})"
206
- fail=1
207
- fi
208
- else
209
- echo "/api/bongos/builders/me -> HTTP ${BUILDERS_ME_CODE} (SKIP — PMS-V2 P6 not live yet)"
210
- skipped=$((skipped+1))
211
- fi
212
-
213
- echo
214
- echo "--- summary ---"
215
- echo "surfaces checked: ${checked}"
216
- echo "surfaces skipped: ${skipped}"
217
- if [[ "${fail}" -eq 0 ]]; then
218
- echo "OK: claim-consistency smoke passed (task A=#${TASK_A}, task B=#${TASK_B})"
219
- else
220
- echo "FAIL: one or more surfaces disagreed on active-claims ordering"
221
- fi
222
- exit "${fail}"