@bongos/core 1.23.21 → 1.24.1

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 (457) hide show
  1. package/.bongos-core.json +983 -428
  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 +6 -3
  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 +94 -0
  27. package/clients/bongos-client/index.cjs +94 -0
  28. package/clients/bongos-client/index.d.ts +154 -4
  29. package/clients/bongos-client/index.mjs +94 -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 +87 -0
  33. package/docs/adr/0386-the-funding-wall-is-a-per-project-rule-claim-time-hold-by-default.md +37 -0
  34. package/docs/adr/0387-two-ledgers-credits-measure-work-money-stays-with-the-processor.md +39 -0
  35. package/docs/adr/0388-a-module-sale-is-split-by-the-project-the-buyer-pays-the-platform-fee.md +42 -0
  36. package/docs/adr/0392-ai-generation-runs-on-a-processor-held-balance-and-the-builders-own-keys.md +33 -0
  37. package/docs/adr/0393-a-platform-account-is-a-person-and-github-is-one-way-in.md +37 -0
  38. package/docs/adr/0394-market-watch-searches-through-the-messages-api-on-the-projects-key-and-runs-from-its-own-poller.md +102 -0
  39. package/docs/adr/0395-a-task-says-what-it-needs-and-lists-show-only-what-you-can-do.md +36 -0
  40. package/docs/adr/0396-google-sign-in-a-stand-in-login-and-a-browser-approved-cli-sign-in.md +41 -0
  41. package/docs/adr/README.md +10 -1
  42. package/docs/api/openapi.json +8619 -5885
  43. package/docs/api-reference.md +68 -9
  44. package/docs/architecture.md +37 -1
  45. package/docs/canonical-permissions.md +1 -1
  46. package/docs/copy-inventory.md +420 -337
  47. package/docs/copy-registry.json +1321 -500
  48. package/docs/file-map.md +4 -0
  49. package/docs/module-api-changelog.md +7 -0
  50. package/docs/onboarding/diagrams/03-drachmae-karma.mmd +3 -3
  51. package/docs/onboarding/diagrams/README.md +1 -1
  52. package/docs/onboarding/drachmae-and-karma.md +15 -15
  53. package/docs/onboarding/primer.md +2 -2
  54. package/docs/page-inventory.json +55 -6
  55. package/docs/page-readings.json +1185 -1011
  56. package/docs/recipes/google-sign-in.md +60 -0
  57. package/docs/recipes/ops-gotchas.md +1 -1
  58. package/migrations/core_282_builders_lower_login_idx.sql +33 -0
  59. package/migrations/core_283_claimable_ignores_page_markers.sql +53 -0
  60. package/migrations/core_283_payout_approvals.sql +183 -0
  61. package/migrations/core_284_payout_gates.sql +179 -0
  62. package/migrations/core_285_task_needs.sql +74 -0
  63. package/modules/ai-studio/CLAUDE.md +15 -0
  64. package/modules/ai-studio/billing.js +67 -0
  65. package/modules/ai-studio/context.js +29 -0
  66. package/modules/ai-studio/db.js +172 -0
  67. package/modules/ai-studio/gemini.js +75 -0
  68. package/modules/ai-studio/generate.js +119 -0
  69. package/modules/ai-studio/keys.js +73 -0
  70. package/modules/ai-studio/migrations/ai_studio_001_keys.sql +22 -0
  71. package/modules/ai-studio/migrations/ai_studio_002_ledger.sql +48 -0
  72. package/modules/ai-studio/migrations/ai_studio_003_requests.sql +55 -0
  73. package/modules/ai-studio/module.json +26 -0
  74. package/modules/ai-studio/openrouter.js +90 -0
  75. package/modules/ai-studio/payments.js +105 -0
  76. package/modules/ai-studio/pricing.js +92 -0
  77. package/modules/ai-studio/routes/ai-studio.js +252 -0
  78. package/modules/ai-studio/studio.js +121 -0
  79. package/modules/autonomy/fence.js +64 -1
  80. package/modules/builder-settings/builder-needs.js +27 -1
  81. package/modules/copy-desk/routes/copy-desk.js +5 -0
  82. package/modules/economy/achievements.js +22 -10
  83. package/modules/economy/cost-classify.js +9 -0
  84. package/modules/economy/cost-write-guard.js +52 -0
  85. package/modules/economy/cost.js +2 -1
  86. package/modules/economy/credits.js +18 -15
  87. package/modules/economy/goal-reward.js +161 -0
  88. package/modules/economy/reward.js +4 -0
  89. package/modules/economy/routes/cost.js +33 -7
  90. package/modules/government/catalog.js +6 -0
  91. package/modules/government/db.js +108 -0
  92. package/modules/government/docket.js +36 -0
  93. package/modules/government/migrations/government_035_payout_approve.sql +29 -0
  94. package/modules/government/pollers/board-expiry.js +108 -20
  95. package/modules/government/protected-surfaces.json +1 -0
  96. package/modules/government/routes/government.js +50 -18
  97. package/modules/government/routing.js +39 -5
  98. package/modules/government/waiting.js +74 -0
  99. package/modules/grading/grader-subagent.js +30 -11
  100. package/modules/hall-ui/public/ai-studio-lib.js +268 -0
  101. package/modules/hall-ui/public/ai-studio.css +193 -0
  102. package/modules/hall-ui/public/ai-studio.html +98 -0
  103. package/modules/hall-ui/public/ai-studio.js +556 -0
  104. package/modules/hall-ui/public/ai-studio.states.json +94 -0
  105. package/modules/hall-ui/public/blockers-by-person.js +156 -0
  106. package/modules/hall-ui/public/blockers-lib.js +15 -1
  107. package/modules/hall-ui/public/blockers.html +8 -0
  108. package/modules/hall-ui/public/blockers.js +1 -1
  109. package/modules/hall-ui/public/city.html +15 -15
  110. package/modules/hall-ui/public/claim-action.js +3 -0
  111. package/modules/hall-ui/public/collab.html +12 -0
  112. package/modules/hall-ui/public/craft-mode.js +4 -1
  113. package/modules/hall-ui/public/criterion-uat-ui.js +4 -1
  114. package/modules/hall-ui/public/drachmae.html +1 -1
  115. package/modules/hall-ui/public/genesis/r5-life-1-primordial-sea.jpg +0 -0
  116. package/modules/hall-ui/public/genesis/r5-life-2-first-cells-cut.webp +0 -0
  117. package/modules/hall-ui/public/genesis/r5-life-2-first-cells.jpg +0 -0
  118. package/modules/hall-ui/public/genesis/r5-life-3-genome-cut.webp +0 -0
  119. package/modules/hall-ui/public/genesis/r5-life-3-genome.jpg +0 -0
  120. package/modules/hall-ui/public/genesis/r5-life-4-membrane-cut.webp +0 -0
  121. package/modules/hall-ui/public/genesis/r5-life-4-membrane.jpg +0 -0
  122. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system-cut.webp +0 -0
  123. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system.jpg +0 -0
  124. package/modules/hall-ui/public/goal-inbox.js +1 -1
  125. package/modules/hall-ui/public/goals-render.js +4 -0
  126. package/modules/hall-ui/public/goals.html +8 -0
  127. package/modules/hall-ui/public/gov-living.js +6 -2
  128. package/modules/hall-ui/public/hall-ask.css +5 -0
  129. package/modules/hall-ui/public/hall-ask.js +39 -3
  130. package/modules/hall-ui/public/notes-panel.css +20 -0
  131. package/modules/hall-ui/public/notes-panel.js +146 -0
  132. package/modules/hall-ui/public/project-settings.html +1 -1
  133. package/modules/hall-ui/public/project-settings.js +7 -5
  134. package/modules/hall-ui/public/settings-ai-keys.js +124 -0
  135. package/modules/hall-ui/public/settings.html +15 -0
  136. package/modules/hall-ui/public/street-deck.js +12 -3
  137. package/modules/hall-ui/public/studio.css +90 -8
  138. package/modules/hall-ui/public/studio.html +39 -10
  139. package/modules/hall-ui/public/studio.js +148 -18
  140. package/modules/hall-ui/public/task.html +2 -0
  141. package/modules/hall-ui/public/task.js +4 -0
  142. package/modules/hall-ui/public/tweak-editor.js +12 -3
  143. package/modules/hall-ui/public/welcome-boot.css +42 -6
  144. package/modules/hall-ui/public/welcome-boot.js +20 -6
  145. package/modules/hall-ui/public/work.js +20 -0
  146. package/modules/hall-ui/records/ai-studio.md +36 -0
  147. package/modules/hall-ui/records/blockers-people.md +24 -0
  148. package/modules/lifecycle/db-analytics.js +10 -3
  149. package/modules/lifecycle/db-claims.js +32 -4
  150. package/modules/lifecycle/db-goals.js +48 -18
  151. package/modules/lifecycle/db-shared.js +9 -0
  152. package/modules/lifecycle/db-tasks.js +15 -6
  153. package/modules/lifecycle/db-versions.js +21 -8
  154. package/modules/lifecycle/done-when.js +23 -1
  155. package/modules/lifecycle/lifecycle.js +5 -0
  156. package/modules/lifecycle/migrations/lifecycle_017_notes.sql +46 -0
  157. package/modules/lifecycle/module.json +2 -1
  158. package/modules/lifecycle/notes.js +219 -0
  159. package/modules/lifecycle/page-notice.js +124 -0
  160. package/modules/lifecycle/page-tweak-artist.js +18 -1
  161. package/modules/lifecycle/publish-reconciler.js +67 -20
  162. package/modules/lifecycle/routes/claims.js +5 -2
  163. package/modules/lifecycle/routes/goals.js +3 -1
  164. package/modules/lifecycle/routes/notes.js +91 -0
  165. package/modules/lifecycle/routes/project-settings.js +43 -35
  166. package/modules/lifecycle/routes/task-route-helpers.js +21 -0
  167. package/modules/lifecycle/routes/task-write-routes.js +21 -3
  168. package/modules/lifecycle/routes/tasks.js +12 -12
  169. package/modules/lifecycle/ship-assurance.js +4 -1
  170. package/modules/lifecycle/ship-card.js +8 -2
  171. package/modules/lifecycle/task-needs-gate.js +70 -0
  172. package/modules/market-watch/CLAUDE.md +15 -0
  173. package/modules/market-watch/db.js +340 -0
  174. package/modules/market-watch/key.js +58 -0
  175. package/modules/market-watch/migrations/market_watch_001_tables.sql +249 -0
  176. package/modules/market-watch/migrations/market_watch_002_run.sql +46 -0
  177. package/modules/market-watch/module.json +26 -0
  178. package/modules/market-watch/pollers/hub-seed.js +54 -0
  179. package/modules/market-watch/pollers/weekly-run.js +100 -0
  180. package/modules/market-watch/research.js +350 -0
  181. package/modules/market-watch/run.js +245 -0
  182. package/modules/market-watch/seed/market-data.json +38 -0
  183. package/modules/market-watch/seed/partners-data.json +497 -0
  184. package/modules/market-watch/seed.js +252 -0
  185. package/modules/market-watch/store.js +230 -0
  186. package/modules/memory/routes/memory.js +14 -2
  187. package/modules/memory/routes/search.js +8 -2
  188. package/modules/onboarding/howto-moments.js +8 -1
  189. package/modules/platform-identity/account-logins.js +192 -0
  190. package/modules/platform-identity/migrations/platform_identity_034_account_logins.sql +96 -0
  191. package/modules/platform-identity/platform-identity.js +5 -4
  192. package/modules/platform-identity/routes/my-projects.js +6 -0
  193. package/modules/platform-identity/routes/profile.js +18 -0
  194. package/modules/platform-identity/routes/public-profile.js +10 -1
  195. package/modules/platform-identity/routes/sso.js +26 -1
  196. package/modules/platform-identity/tests/platform-identity.mjs +2 -1
  197. package/modules/provisioning/credential-preflight.js +13 -3
  198. package/modules/provisioning/pollers/app-liveness.js +25 -5
  199. package/modules/provisioning/routes/provisioning.js +1 -1
  200. package/modules/provisioning/starter-bundles.js +8 -2
  201. package/modules/public-landing/public/account.html +10 -2
  202. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg +0 -0
  203. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
  204. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
  205. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +1 -1
  206. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp +0 -0
  207. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp.json +1 -1
  208. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg +0 -0
  209. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
  210. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
  211. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +1 -1
  212. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg +0 -0
  213. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
  214. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
  215. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +1 -1
  216. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp +0 -0
  217. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp.json +1 -1
  218. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp +0 -0
  219. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp.json +1 -1
  220. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp +0 -0
  221. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp.json +1 -1
  222. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp +0 -0
  223. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp.json +1 -1
  224. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp +0 -0
  225. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp.json +1 -1
  226. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp +0 -0
  227. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp.json +1 -1
  228. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg +0 -0
  229. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg.json +1 -1
  230. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg +0 -0
  231. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg.json +1 -1
  232. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg +0 -0
  233. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg.json +1 -1
  234. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg +0 -0
  235. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg.json +1 -1
  236. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp +0 -0
  237. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp.json +1 -1
  238. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg +0 -0
  239. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg.json +1 -1
  240. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp +0 -0
  241. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp.json +1 -1
  242. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg +0 -0
  243. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg.json +1 -1
  244. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp +0 -0
  245. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp.json +1 -1
  246. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg +0 -0
  247. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg.json +1 -1
  248. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp +0 -0
  249. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp.json +1 -1
  250. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg +0 -0
  251. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg.json +1 -1
  252. package/modules/public-landing/public/community.html +1 -1
  253. package/modules/public-landing/public/connections.html +2 -2
  254. package/modules/public-landing/public/guild.html +1 -1
  255. package/modules/public-landing/public/invitations.html +2 -2
  256. package/modules/public-landing/public/projects.html +5 -5
  257. package/modules/raise/views/nda.html +2 -0
  258. package/modules/specialities/db.js +32 -1
  259. package/modules/specialities/routes/specialities.js +10 -6
  260. package/modules/status-ui/public/index.html +1 -1
  261. package/package-lock.json +2 -2
  262. package/package.json +1 -1
  263. package/release-notes.json +286 -0
  264. package/scripts/bongos/autobongos-tweak-lane.js +46 -1
  265. package/scripts/bongos/backfill-subagent-rewards.js +2 -2
  266. package/scripts/bongos/claim.js +22 -1
  267. package/scripts/bongos/db-backup-nightly.sh +29 -0
  268. package/scripts/bongos/deploy-divergence.js +7 -0
  269. package/scripts/bongos/doc-cli-guard.js +6 -0
  270. package/scripts/bongos/fitness.js +3 -2
  271. package/scripts/bongos/gen-diagrams.js +3 -3
  272. package/scripts/bongos/lib.sh +4 -5
  273. package/scripts/bongos/migration-namespace.js +13 -1
  274. package/scripts/bongos/plain-cards.js +4 -0
  275. package/scripts/bongos/provision-github-setup.js +3 -1
  276. package/scripts/bongos/provision-units.js +6 -1
  277. package/scripts/bongos/publish-manifest.js +4 -0
  278. package/scripts/bongos/release.js +2 -0
  279. package/scripts/bongos/run-unit-tests.js +268 -82
  280. package/scripts/bongos/seed-tasks.example.json +56 -0
  281. package/scripts/bongos/seed-tasks.js +222 -0
  282. package/scripts/bongos/seed-verify-criteria.js +1 -2
  283. package/scripts/bongos/ship-finish.js +2 -0
  284. package/scripts/bongos/ship-resume.js +2 -0
  285. package/scripts/bongos/strand-lease.js +250 -0
  286. package/scripts/bongos/strand-watch.js +129 -12
  287. package/scripts/bongos/version-literal-guard.js +2 -2
  288. package/scripts/discord/post.js +4 -3
  289. package/scripts/gds/seed-tasks.js +7 -0
  290. package/scripts/gds/{build-bongos.js → strand-lease.js} +3 -3
  291. package/scripts/hall-preview/server.js +21 -0
  292. package/src/bongos/auth-config.js +29 -1
  293. package/src/bongos/auth-discord.js +3 -3
  294. package/src/bongos/auth-github.js +3 -6
  295. package/src/bongos/auth-google.js +217 -0
  296. package/src/bongos/device-approval.js +140 -0
  297. package/src/bongos/llm-pricing.js +17 -1
  298. package/src/bongos/metrics.js +48 -2
  299. package/src/bongos/middleware/rate-limit.js +30 -11
  300. package/src/bongos/module-scope-map.js +16 -1
  301. package/src/bongos/optimizer.js +15 -1
  302. package/src/bongos/payout-approvals.js +342 -0
  303. package/src/bongos/payout-gates.js +364 -0
  304. package/src/bongos/prelaunch-gate.js +7 -9
  305. package/src/bongos/prelaunch-switch.js +20 -0
  306. package/src/bongos/route-rank-check.js +3 -0
  307. package/src/bongos/routes/auth-google.js +246 -0
  308. package/src/bongos/routes/auth.js +38 -1
  309. package/src/bongos/routes/backup.js +33 -9
  310. package/src/bongos/routes/builders.js +57 -30
  311. package/src/bongos/routes/github.js +9 -0
  312. package/src/bongos/routes/me.js +18 -0
  313. package/src/bongos/routes/my-payouts.js +133 -0
  314. package/src/bongos/routes/payout-approvals.js +312 -0
  315. package/src/bongos/routes/payout-gates.js +179 -0
  316. package/src/bongos/routes.js +15 -1
  317. package/src/bongos/secret-box.js +18 -3
  318. package/src/bongos/serve-internal.js +47 -19
  319. package/src/bongos/sign-in-pages.js +138 -0
  320. package/src/bongos/task-needs.js +146 -0
  321. package/src/bongos-downloads.js +18 -1
  322. package/src/instance-config.js +28 -0
  323. package/src/module-api.js +14 -1
  324. package/src/platform-server.js +27 -1
  325. package/tests/account_logins.mjs +326 -0
  326. package/tests/account_logins_db.mjs +161 -0
  327. package/tests/ai_studio_billing.mjs +253 -0
  328. package/tests/ai_studio_generate.mjs +282 -0
  329. package/tests/ai_studio_keys.mjs +159 -0
  330. package/tests/ai_studio_requests.mjs +319 -0
  331. package/tests/auth_backchannel_logout_route.mjs +201 -0
  332. package/tests/auto_satisfy_criteria.mjs +10 -1
  333. package/tests/autobongos_tweak_lane.mjs +144 -0
  334. package/tests/autobongos_tweak_pin_identity.mjs +137 -0
  335. package/tests/backfill_subagent_rewards.mjs +17 -1
  336. package/tests/backup_trigger_lock.mjs +119 -0
  337. package/tests/batched_writes_parity.mjs +340 -0
  338. package/tests/blockers_people.mjs +198 -0
  339. package/tests/bounded_rate_maps.mjs +184 -0
  340. package/tests/claimable_blocker_status.mjs +1 -1
  341. package/tests/claims_batch_routes.mjs +421 -0
  342. package/tests/conductor_main_e2e.mjs +4 -0
  343. package/tests/config_read_cache.mjs +171 -0
  344. package/tests/copy_desk_page_editor.mjs +12 -0
  345. package/tests/cost_write_guard.mjs +200 -0
  346. package/tests/craft_achievements.mjs +33 -10
  347. package/tests/criterion_goal_attach.mjs +1 -1
  348. package/tests/db_backup_nightly.mjs +73 -1
  349. package/tests/deploy_divergence_line.mjs +7 -0
  350. package/tests/effective_visibility_predicate.mjs +12 -0
  351. package/tests/fitness.mjs +19 -0
  352. package/tests/fixtures/per-row-loops-legacy.cjs +245 -0
  353. package/tests/fixtures/seed-tasks/bongos-v1-idea-routing.json +256 -0
  354. package/tests/fixtures/seed-tasks/bv1-profiles.json +592 -0
  355. package/tests/fixtures/seed-tasks/bv2-ideator-surface.json +373 -0
  356. package/tests/fixtures/seed-tasks/fake-api.mjs +80 -0
  357. package/tests/github_one_trip.mjs +34 -0
  358. package/tests/github_repo_visibility.mjs +20 -0
  359. package/tests/goal_achievement.mjs +30 -1
  360. package/tests/goal_achievement_reward.mjs +205 -0
  361. package/tests/goal_archive_disposition.mjs +5 -5
  362. package/tests/goal_sort_staleness.mjs +2 -1
  363. package/tests/goal_tier.mjs +11 -1
  364. package/tests/google_fonts_nonblocking.mjs +84 -0
  365. package/tests/google_sign_in.mjs +401 -0
  366. package/tests/government_board_expiry.mjs +94 -0
  367. package/tests/government_protected_surfaces.mjs +1 -1
  368. package/tests/government_routes.mjs +146 -23
  369. package/tests/grader.mjs +31 -0
  370. package/tests/hall_ai_studio.mjs +347 -0
  371. package/tests/hall_city.mjs +8 -0
  372. package/tests/hall_page_gate_map.mjs +3 -0
  373. package/tests/hall_studio_home.mjs +61 -2
  374. package/tests/home_attention_cards.mjs +1 -1
  375. package/tests/hook_shell_tools.mjs +8 -0
  376. package/tests/hooks_drain.mjs +1 -1
  377. package/tests/host_topology_skips.mjs +2 -0
  378. package/tests/howto_moments.mjs +17 -0
  379. package/tests/human_signal.mjs +141 -0
  380. package/tests/install_script_reader.mjs +51 -0
  381. package/tests/integration_fixture_ids.mjs +82 -0
  382. package/tests/invite_expiry_db.mjs +13 -1
  383. package/tests/lib_sh_resolution.mjs +0 -4
  384. package/tests/market_watch_data.mjs +244 -0
  385. package/tests/market_watch_data_db.mjs +308 -0
  386. package/tests/market_watch_module.mjs +114 -0
  387. package/tests/market_watch_run.mjs +503 -0
  388. package/tests/metrics.mjs +124 -0
  389. package/tests/migration_namespace.mjs +14 -0
  390. package/tests/module_api.mjs +2 -0
  391. package/tests/module_loader.mjs +1 -1
  392. package/tests/module_skills_hook.mjs +69 -0
  393. package/tests/notes.mjs +182 -0
  394. package/tests/own_scope_guard.mjs +5 -0
  395. package/tests/page_tweak_marker_sql.mjs +76 -0
  396. package/tests/page_tweak_no_block.mjs +135 -0
  397. package/tests/page_tweak_notice.mjs +103 -0
  398. package/tests/payout_approvals.mjs +253 -0
  399. package/tests/payout_approvals_db.mjs +106 -0
  400. package/tests/payout_gates.mjs +322 -0
  401. package/tests/payout_gates_db.mjs +113 -0
  402. package/tests/planning_session_skill.mjs +13 -3
  403. package/tests/project_settings_page.mjs +29 -5
  404. package/tests/project_settings_spend_cap_route.mjs +235 -0
  405. package/tests/promotion_sweep.mjs +29 -1
  406. package/tests/provision.mjs +3 -2
  407. package/tests/provisioning_app_status.mjs +18 -0
  408. package/tests/provisioning_credential_preflight.mjs +53 -0
  409. package/tests/provisioning_env_manifest_edit_delete.mjs +223 -0
  410. package/tests/public_landing_projects.mjs +37 -0
  411. package/tests/publish_reconciler_overlap.mjs +60 -0
  412. package/tests/rank_change_broadcast_port.mjs +151 -0
  413. package/tests/seed_tasks.mjs +176 -0
  414. package/tests/seed_verify_criteria.mjs +2 -6
  415. package/tests/session_start_freshness.mjs +66 -1
  416. package/tests/shell_hooks.mjs +209 -0
  417. package/tests/ship_assurance.mjs +28 -0
  418. package/tests/ship_card.mjs +20 -5
  419. package/tests/site_classified_once.mjs +142 -0
  420. package/tests/speciality_db_shape.mjs +23 -0
  421. package/tests/speciality_session_skills.mjs +48 -2
  422. package/tests/strand_lease.mjs +249 -0
  423. package/tests/strand_watch.mjs +58 -0
  424. package/tests/task_criteria_routes.mjs +275 -0
  425. package/tests/task_criteria_unlink_db.mjs +123 -0
  426. package/tests/task_needs.mjs +233 -0
  427. package/tests/task_needs_db.mjs +110 -0
  428. package/tests/unit_runner_serial.mjs +266 -43
  429. package/tests/version_close_route.mjs +1 -1
  430. package/tests/version_literals.mjs +5 -7
  431. package/tests/welcome_boot.mjs +16 -5
  432. package/tests/welcome_boot_browser.mjs +36 -4
  433. package/docs/recipes/bongos-cli-release.md +0 -66
  434. package/scripts/bongos/backfill-disciplines.js +0 -144
  435. package/scripts/bongos/backfill-session-earnings.js +0 -123
  436. package/scripts/bongos/backfill-session-types.js +0 -87
  437. package/scripts/bongos/build-bongos.js +0 -94
  438. package/scripts/bongos/cleanup-orphans.js +0 -74
  439. package/scripts/bongos/seed-bongos-v1-idea-routing-tasks.js +0 -152
  440. package/scripts/bongos/seed-bv1-profiles-tasks.js +0 -135
  441. package/scripts/bongos/seed-bv2-ideator-surface-tasks.js +0 -390
  442. package/scripts/bongos/smoke-batch-claim.sh +0 -238
  443. package/scripts/bongos/smoke-batch-release.sh +0 -316
  444. package/scripts/bongos/smoke-claim-consistency.sh +0 -222
  445. package/scripts/bongos/smoke-dependencies.sh +0 -143
  446. package/scripts/gds/backfill-disciplines.js +0 -7
  447. package/scripts/gds/backfill-session-earnings.js +0 -7
  448. package/scripts/gds/backfill-session-types.js +0 -7
  449. package/scripts/gds/cleanup-orphans.js +0 -7
  450. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +0 -6
  451. package/scripts/gds/seed-bv1-profiles-tasks.js +0 -6
  452. package/scripts/gds/seed-bv2-ideator-surface-tasks.js +0 -6
  453. package/scripts/gds/smoke-batch-claim.sh +0 -8
  454. package/scripts/gds/smoke-batch-release.sh +0 -8
  455. package/scripts/gds/smoke-claim-consistency.sh +0 -8
  456. package/scripts/gds/smoke-dependencies.sh +0 -8
  457. package/tests/smoke_dependencies_witness.mjs +0 -46
@@ -0,0 +1,60 @@
1
+ # Turning on Google sign-in (the hub)
2
+
3
+ Google sign-in ([task 1004993](https://cloudbongos.com/builders#/task/1004993), [ADR 0396](../adr/0396-google-sign-in-a-stand-in-login-and-a-browser-approved-cli-sign-in.md)) ships **switched off**. Until the two keys below are on the server, the site behaves exactly as before: GitHub only, no chooser page, and the command line still uses GitHub's code page. Adding the keys is what turns it on, so it is also the "go live" step.
4
+
5
+ It needs a Google sign-in app. The app is **free** and takes about ten minutes to create. Only the owner should create it, signed in with the Google account that should own it.
6
+
7
+ > **Never paste the client secret into a chat, a task, a commit or Discord.** It goes straight from Google's page into the server's settings file.
8
+
9
+ ## 1. Create the Google sign-in app
10
+
11
+ 1. Open <https://console.cloud.google.com/> and sign in.
12
+ 2. In the top bar, click the project picker, then **New project**. Name it `Cloud Bongos sign-in` and click **Create**. When it is ready, make sure it is the selected project in the top bar.
13
+ 3. In the left menu open **APIs & Services → OAuth consent screen**. Google may call this **Google Auth Platform**. Click **Get started**.
14
+ - **App name:** `Cloud Bongos`. **User support email:** your address.
15
+ - **Audience:** **External**.
16
+ - **Contact information:** your address. Tick the agreement and click **Create**.
17
+ 4. Open **Branding** and fill in:
18
+ - **Application home page:** `https://cloudbongos.com`
19
+ - **Privacy policy:** `https://cloudbongos.com/privacy`
20
+ - **Terms of service:** `https://cloudbongos.com/terms`
21
+ - **Authorised domains:** `cloudbongos.com`
22
+
23
+ Click **Save**. Leave the logo empty: adding one sends the app to Google for a review.
24
+ 5. Open **Data access**. Do not add anything. The three basic scopes (name, email address, profile picture) are all Bongos asks for, and they need no review.
25
+ 6. Open **Audience** and click **Publish app**, then **Confirm**. Until you do this, only email addresses you list as test users can sign in.
26
+ 7. Open **Clients**, click **Create client**, and fill in:
27
+ - **Application type:** **Web application**
28
+ - **Name:** `Cloud Bongos web`
29
+ - **Authorised redirect URIs:** click **Add URI** and enter exactly `https://cloudbongos.com/api/bongos/auth/google/callback`
30
+ - Leave **Authorised JavaScript origins** empty.
31
+
32
+ Click **Create**.
33
+ 8. Google shows a **Client ID** and a **Client secret**. Click **Download JSON** and keep the file somewhere private. You need both values in the next step.
34
+
35
+ ## 2. Put the two values on the server
36
+
37
+ The server keeps its sign-in keys in its settings file, the same file that already holds `…_GITHUB_CLIENT_ID` (on cloudbongos.com: `/etc/cloudbongos/web.env`). Add two lines next to the GitHub ones. Use **the same first word** those lines start with, so that if they read `CLOUDBONGOS_GITHUB_CLIENT_ID`, yours read:
38
+
39
+ ```
40
+ CLOUDBONGOS_GOOGLE_CLIENT_ID=<the Client ID>
41
+ CLOUDBONGOS_GOOGLE_CLIENT_SECRET=<the Client secret>
42
+ ```
43
+
44
+ Then restart the web service, the same way as after any other change to that file. If you would rather not edit the file yourself, ask in a session for help doing it on the server, but still type the secret there yourself.
45
+
46
+ ## 3. Check it
47
+
48
+ 1. Open <https://cloudbongos.com> in a private window and click **Sign in**. You should see **Continue with GitHub** and **Continue with Google**.
49
+ 2. Click **Continue with Google** and pick an account. A first sign-in creates an account and lands on the account page so the person can choose their handle.
50
+ 3. In a terminal, run the Bongos sign-in. The browser opens a cloudbongos.com page showing the same code as the terminal. Press **Approve**, and the terminal finishes by itself.
51
+
52
+ ## What a Google-only person can and cannot do yet
53
+
54
+ - **Can:** sign up and sign in on cloudbongos.com and its hall, use the command line, and edit their account.
55
+ - **Cannot yet:** join another project's hall ([task 1004994](https://cloudbongos.com/builders#/task/1004994)) or link GitHub and Google together ([task 1004995](https://cloudbongos.com/builders#/task/1004995)). They are told so in plain words.
56
+ - Until they link GitHub, the hall shows them as `~<their handle>`. The `~` means "no GitHub account".
57
+
58
+ ## Turning it off again
59
+
60
+ Remove the two lines and restart. Accounts created with Google stay. Their owners cannot sign in again until the lines are back, and their data is not lost.
@@ -171,7 +171,7 @@ Inside the namespace the file lists as `---------- 1 root root 0`. The runner un
171
171
 
172
172
  - **Symptom:** on a fresh instance every `/builder-ship` parks at `confirmed`; `GET /tasks/:id/publish-status` answers 503 `push_unconfigured`; the archon has to merge PRs and `POST /tasks/:id/ship` by hand. Silent — work just piles up (gap-list W7, proven live on Spike Harbor task 1).
173
173
  - **Root cause:** the ADR 0133 manifest used to request **zero** repo permissions and the conversion's App private key (`pem`) was discarded, so no publish credential (ADR 0055) ever existed on a wizard-born instance. Fixed for newly minted Apps (task 1003049): the manifest now requests `contents: write` + `pull_requests: write` + `actions: read`, `placeManifestCreds` writes `GITHUB_APP_ID` + `GITHUB_APP_PRIVATE_KEY` into web.env, and the server discovers the installation id at runtime — the one human step left is **installing the App on the repo** (the onboarding `app-install` step).
174
- - **Fix for pre-existing instances:** in the App's GitHub settings — (1) **Permissions & events**: grant Contents read/write, Pull requests read/write, Actions read-only; (2) **General → Private keys**: generate a key; (3) put `GITHUB_APP_ID=<id>` and `GITHUB_APP_PRIVATE_KEY=<pem as one line with literal \n>` in `/etc/<slug>/web.env` and restart the unit; (4) **Install App** → pick the project repo (owners must re-approve the new permissions on an already-installed App). Alternative: a fine-grained `GITHUB_PUSH_TOKEN` PAT with the same three scopes (ADR 0055).
174
+ - **Fix for pre-existing instances:** in the App's GitHub settings — (1) **Permissions & events**: grant Contents read/write, Pull requests read/write, Actions read-only; (2) **General → Private keys**: generate a key; (3) put `GITHUB_APP_ID=<id>` and `GITHUB_APP_PRIVATE_KEY="<pem as one line with literal \n>"` in `/etc/<slug>/web.env` — **double-quoted**: systemd drops an unquoted backslash, so the server gets `n` for every line break and fails with `ERR_OSSL_UNSUPPORTED` (task 1005009) — and restart the unit; (4) **Install App** → pick the project repo (owners must re-approve the new permissions on an already-installed App). Alternative: a fine-grained `GITHUB_PUSH_TOKEN` PAT with the same three scopes (ADR 0055).
175
175
  - **How you know it worked:** `publish-status` stops 503ing, and the publish-reconciler log line `WARN … not installed` (if the App wasn't installed yet) goes quiet after the install.
176
176
 
177
177
  ---
@@ -0,0 +1,33 @@
1
+ -- =========================================================================
2
+ -- core_282 — index builders by lower(github_login) (task 1004923, from the DB
3
+ -- performance audit)
4
+ --
5
+ -- builders has NO index on github_login at all: 003_pms declares github_id
6
+ -- UNIQUE and leaves github_login bare, and no later migration indexes it. Yet
7
+ -- the admission paths look a builder up by login, case-insensitively:
8
+ --
9
+ -- the onboarding routes "is this login already a member?" before an
10
+ -- invite, an approval and the public POST
11
+ -- (SELECT 1 FROM builders WHERE lower(github_login) = lower($1))
12
+ -- the access-request a correlated is-member probe PER access_requests row
13
+ -- lists (EXISTS ... WHERE lower(b.github_login) = lower(ar.github_login))
14
+ --
15
+ -- A plain index on github_login could not serve any of them — they compare
16
+ -- lower(), so only an index on the expression can. Each was a sequential scan
17
+ -- of builders, and the list probes paid it once per row.
18
+ --
19
+ -- Not UNIQUE on purpose: logins can be renamed on GitHub and github_id is the
20
+ -- stable key, so two rows may legitimately have held the same login over time.
21
+ --
22
+ -- Additive and idempotent: an index only, no column, constraint or data. Safe to
23
+ -- run forward against a live database; an older release just has an unused
24
+ -- index. Rollback is DROP INDEX.
25
+
26
+ CREATE INDEX IF NOT EXISTS idx_builders_lower_login
27
+ ON builders (lower(github_login));
28
+
29
+ COMMENT ON INDEX idx_builders_lower_login IS
30
+ 'Case-insensitive builder-by-login lookups on the admission paths (modules/onboarding/routes/access-requests.js). github_login had no index of any kind before this (task 1004923).';
31
+
32
+ INSERT INTO schema_migrations (version) VALUES ('core_282_builders_lower_login_idx')
33
+ ON CONFLICT DO NOTHING;
@@ -0,0 +1,53 @@
1
+ -- core_282 — claimable_tasks ignores an artist's page claim (task 1004947).
2
+ --
3
+ -- An artist claiming a page holds a web claim (no worktree, no session) on a
4
+ -- page-tweak task whose touches list the page's files. It is a MARKER: it says
5
+ -- "this page is being updated" and nothing more. The touches-overlap guard below
6
+ -- hid every ready engineering task on those files while the marker stood. The
7
+ -- two inlined copies (CLAIMABLE_SQL in modules/lifecycle/db-tasks.js and
8
+ -- src/bongos/optimizer.js) carry the same exclusion, and
9
+ -- tests/claimable_blocker_status.mjs pins all three. COALESCE keeps a claim on a
10
+ -- source-less task counted (a NULL source must not make the NOT evaluate to NULL).
11
+ --
12
+ -- Everything else is core_264's definition, byte for byte: DROP VIEW IF EXISTS +
13
+ -- CREATE, the t.* wildcard, the blocker and dependency clauses unchanged.
14
+
15
+ BEGIN;
16
+
17
+ DROP VIEW IF EXISTS claimable_tasks;
18
+ CREATE VIEW claimable_tasks AS
19
+ SELECT t.*,
20
+ pms_calibrated_minutes(t.est_minutes, t.kind) AS est_minutes_calibrated
21
+ FROM tasks t
22
+ WHERE t.status = 'ready'
23
+ AND t.title NOT LIKE '\_\_smoke\_\_%' ESCAPE '\'
24
+ AND NOT EXISTS (
25
+ SELECT 1
26
+ FROM task_blockers tb
27
+ LEFT JOIN blockers b ON b.id = tb.blocker_id
28
+ WHERE tb.task_id = t.id
29
+ AND (b.id IS NULL OR b.status = 'open')
30
+ )
31
+ AND NOT EXISTS (
32
+ SELECT 1
33
+ FROM dependencies d
34
+ WHERE ((d.from_kind = 'task' AND d.from_id = t.id)
35
+ OR (d.from_kind = 'goal' AND d.from_id = t.goal_id)
36
+ OR (d.from_kind = 'criterion' AND d.from_id IN (
37
+ SELECT tc.criterion_id FROM task_criteria tc WHERE tc.task_id = t.id)))
38
+ AND ((d.to_kind = 'task' AND EXISTS (SELECT 1 FROM tasks x WHERE x.id = d.to_id AND x.status <> 'shipped'))
39
+ OR (d.to_kind = 'criterion' AND EXISTS (SELECT 1 FROM done_when_criteria x WHERE x.id = d.to_id AND x.satisfied = false))
40
+ OR (d.to_kind = 'goal' AND EXISTS (SELECT 1 FROM goals x WHERE x.id = d.to_id AND x.status <> 'achieved')))
41
+ )
42
+ AND NOT EXISTS (
43
+ SELECT 1 FROM claims c
44
+ JOIN tasks t2 ON t2.id = c.task_id
45
+ WHERE c.released_at IS NULL
46
+ AND NOT (COALESCE(t2.source, '') = 'page-tweak' AND c.worktree_name IS NULL AND c.creator_session_id IS NULL)
47
+ AND t2.touches && t.touches
48
+ );
49
+
50
+ COMMIT;
51
+
52
+ INSERT INTO schema_migrations (version) VALUES ('core_283_claimable_ignores_page_markers')
53
+ ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,183 @@
1
+ -- core_283_payout_approvals.sql — every payout needs a logged, personal approval,
2
+ -- and the approvals are an unchangeable log (task 1004913, goal 1000092 N9;
3
+ -- ADR 0385 decisions 4 and 8, ADR 0387 decision 3).
4
+ --
5
+ -- WHY. The owner's legal framework (Art. I, cited by Article only) says a payout,
6
+ -- equity grant or contract is never executed by the platform or an AI on its own:
7
+ -- each needs a distinct step by the project's authorised person, kept in an
8
+ -- append-only log of who approved what and when. If we cannot prove the person
9
+ -- pressed the button, we were the actor. ADR 0385 decision 4 lets a project sign a
10
+ -- STANDING payout rule once (caps, formula, schedule, a pause window before each
11
+ -- run) instead of approving every payout; equity grants and contracts keep one
12
+ -- signature each; an AI may never create or widen a rule.
13
+ --
14
+ -- SHAPE. One table, one row per event, never edited:
15
+ --
16
+ -- rule_signed a person signs a standing payout rule. Its row id IS the
17
+ -- rule id; terms holds caps, formula, schedule, pause_hours.
18
+ -- rule_narrowed a person tightens a signed rule. The trigger refuses any
19
+ -- term that would widen it (a higher cap, a shorter pause, a
20
+ -- different formula, schedule or currency). Widening is
21
+ -- therefore only possible by signing a NEW rule.
22
+ -- rule_revoked a person ends a rule. Nothing may follow it.
23
+ -- run_noticed a run under a rule is announced (who gets what). It is the
24
+ -- one kind that is not a signature: the runner may file it.
25
+ -- It may not pay before the rule's pause window has passed.
26
+ -- run_held a person stops a noticed run inside its pause window.
27
+ -- payout_approved a person approves ONE payout (recipient, cents, currency).
28
+ -- grant_signed a person signs ONE equity grant.
29
+ -- contract_signed a person signs ONE contract.
30
+ --
31
+ -- WHAT THE DATABASE ENFORCES (not only the code that writes here; ADR 0387 D2):
32
+ -- * append-only: UPDATE and DELETE are refused row by row and TRUNCATE by
33
+ -- statement, by trigger, and the privileges are revoked from PUBLIC;
34
+ -- * personal: every kind except run_noticed must name the web session that
35
+ -- pressed it (session_source = 'web'), and the actor must be a human
36
+ -- builder: a machine principal (builders.system_role set) is refused;
37
+ -- * a narrowing never widens, and nothing follows a revocation.
38
+ -- Who may write at all (the payout.approve permission, rank fresh per request,
39
+ -- ADR 0016) is checked by the server before the insert.
40
+ --
41
+ -- Nothing here moves money. A processor does that (ADR 0385); this records the
42
+ -- authority a transfer must cite. Additive and idempotent.
43
+
44
+ BEGIN;
45
+
46
+ CREATE TABLE IF NOT EXISTS payout_approvals (
47
+ id bigserial PRIMARY KEY,
48
+ kind text NOT NULL CHECK (kind IN (
49
+ 'rule_signed', 'rule_narrowed', 'rule_revoked',
50
+ 'run_noticed', 'run_held',
51
+ 'payout_approved', 'grant_signed', 'contract_signed')),
52
+ rule_id bigint REFERENCES payout_approvals(id) ON DELETE RESTRICT,
53
+ run_key text CHECK (run_key IS NULL OR run_key ~ '^[A-Za-z0-9._:-]{1,80}$'),
54
+ actor_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
55
+ actor_rank text,
56
+ session_id bigint,
57
+ session_source text,
58
+ recipient_id bigint REFERENCES builders(id) ON DELETE RESTRICT,
59
+ amount_cents bigint CHECK (amount_cents IS NULL OR amount_cents > 0),
60
+ currency text CHECK (currency IS NULL OR currency ~ '^[A-Z]{3}$'),
61
+ terms jsonb NOT NULL DEFAULT '{}'::jsonb,
62
+ note text CHECK (note IS NULL OR length(note) <= 500),
63
+ created_at timestamptz NOT NULL DEFAULT now(),
64
+
65
+ -- A signature names the web session that pressed it.
66
+ CONSTRAINT payout_approvals_personal CHECK (
67
+ kind = 'run_noticed' OR (session_source = 'web' AND session_id IS NOT NULL)
68
+ ),
69
+ -- Each kind carries exactly what it needs.
70
+ CONSTRAINT payout_approvals_shape CHECK (
71
+ (kind = 'rule_signed' AND rule_id IS NULL AND run_key IS NULL AND recipient_id IS NULL AND amount_cents IS NULL AND terms <> '{}'::jsonb) OR
72
+ (kind = 'rule_narrowed' AND rule_id IS NOT NULL AND run_key IS NULL AND recipient_id IS NULL AND amount_cents IS NULL AND terms <> '{}'::jsonb) OR
73
+ (kind = 'rule_revoked' AND rule_id IS NOT NULL AND run_key IS NULL AND recipient_id IS NULL AND amount_cents IS NULL) OR
74
+ (kind = 'run_noticed' AND rule_id IS NOT NULL AND run_key IS NOT NULL AND amount_cents IS NOT NULL AND currency IS NOT NULL) OR
75
+ (kind = 'run_held' AND rule_id IS NOT NULL AND run_key IS NOT NULL AND amount_cents IS NULL) OR
76
+ (kind = 'payout_approved' AND rule_id IS NULL AND recipient_id IS NOT NULL AND amount_cents IS NOT NULL AND currency IS NOT NULL) OR
77
+ (kind IN ('grant_signed', 'contract_signed') AND rule_id IS NULL AND recipient_id IS NOT NULL AND terms <> '{}'::jsonb)
78
+ )
79
+ );
80
+
81
+ CREATE INDEX IF NOT EXISTS payout_approvals_rule_idx ON payout_approvals (rule_id, id) WHERE rule_id IS NOT NULL;
82
+ CREATE UNIQUE INDEX IF NOT EXISTS payout_approvals_run_once_idx ON payout_approvals (rule_id, run_key, kind) WHERE run_key IS NOT NULL;
83
+ -- The rules list reads only the three rule kinds; every payout and run row lives
84
+ -- in this same ever-growing table, so the list gets its own small index.
85
+ CREATE INDEX IF NOT EXISTS payout_approvals_rules_idx ON payout_approvals (id)
86
+ WHERE kind IN ('rule_signed', 'rule_narrowed', 'rule_revoked');
87
+
88
+ -- Append-only, by the database.
89
+ CREATE OR REPLACE FUNCTION payout_approvals_refuse_change() RETURNS trigger
90
+ LANGUAGE plpgsql AS $$
91
+ BEGIN
92
+ RAISE EXCEPTION 'payout_approvals is append-only: % refused (a correction is a new row)', TG_OP
93
+ USING ERRCODE = 'insufficient_privilege';
94
+ END;
95
+ $$;
96
+
97
+ DROP TRIGGER IF EXISTS payout_approvals_no_update_delete ON payout_approvals;
98
+ CREATE TRIGGER payout_approvals_no_update_delete
99
+ BEFORE UPDATE OR DELETE ON payout_approvals
100
+ FOR EACH ROW EXECUTE FUNCTION payout_approvals_refuse_change();
101
+
102
+ DROP TRIGGER IF EXISTS payout_approvals_no_truncate ON payout_approvals;
103
+ CREATE TRIGGER payout_approvals_no_truncate
104
+ BEFORE TRUNCATE ON payout_approvals
105
+ FOR EACH STATEMENT EXECUTE FUNCTION payout_approvals_refuse_change();
106
+
107
+ REVOKE UPDATE, DELETE, TRUNCATE ON payout_approvals FROM PUBLIC;
108
+
109
+ -- Personal, never widened, nothing after a revocation.
110
+ CREATE OR REPLACE FUNCTION payout_approvals_check_insert() RETURNS trigger
111
+ LANGUAGE plpgsql AS $$
112
+ DECLARE
113
+ machine text;
114
+ rule_kind text;
115
+ cur jsonb;
116
+ oldv bigint;
117
+ newv bigint;
118
+ cap text;
119
+ BEGIN
120
+ IF NEW.kind <> 'run_noticed' THEN
121
+ SELECT system_role INTO machine FROM builders WHERE id = NEW.actor_id;
122
+ IF machine IS NOT NULL THEN
123
+ RAISE EXCEPTION 'payout_approvals: % must be a person''s own act; machine principal % refused', NEW.kind, machine
124
+ USING ERRCODE = 'insufficient_privilege';
125
+ END IF;
126
+ END IF;
127
+
128
+ IF NEW.rule_id IS NULL THEN
129
+ RETURN NEW;
130
+ END IF;
131
+
132
+ SELECT kind INTO rule_kind FROM payout_approvals WHERE id = NEW.rule_id;
133
+ IF rule_kind IS DISTINCT FROM 'rule_signed' THEN
134
+ RAISE EXCEPTION 'payout_approvals: rule % is not a signed rule', NEW.rule_id
135
+ USING ERRCODE = 'check_violation';
136
+ END IF;
137
+ IF EXISTS (SELECT 1 FROM payout_approvals WHERE rule_id = NEW.rule_id AND kind = 'rule_revoked') THEN
138
+ RAISE EXCEPTION 'payout_approvals: rule % is revoked; nothing may follow it', NEW.rule_id
139
+ USING ERRCODE = 'check_violation';
140
+ END IF;
141
+
142
+ IF NEW.kind = 'rule_narrowed' THEN
143
+ SELECT terms INTO cur FROM payout_approvals
144
+ WHERE (id = NEW.rule_id OR (rule_id = NEW.rule_id AND kind = 'rule_narrowed'))
145
+ ORDER BY id DESC LIMIT 1;
146
+ IF (NEW.terms -> 'formula') IS DISTINCT FROM (cur -> 'formula')
147
+ OR (NEW.terms -> 'schedule') IS DISTINCT FROM (cur -> 'schedule')
148
+ OR (NEW.terms ->> 'currency') IS DISTINCT FROM (cur ->> 'currency') THEN
149
+ RAISE EXCEPTION 'payout_approvals: a narrowing may not change the formula, schedule or currency; sign a new rule'
150
+ USING ERRCODE = 'check_violation';
151
+ END IF;
152
+ IF (NEW.terms ->> 'pause_hours') IS NULL
153
+ OR (NEW.terms ->> 'pause_hours')::bigint < (cur ->> 'pause_hours')::bigint THEN
154
+ RAISE EXCEPTION 'payout_approvals: a narrowing may not shorten the pause window'
155
+ USING ERRCODE = 'check_violation';
156
+ END IF;
157
+ FOREACH cap IN ARRAY ARRAY['per_payout_cents', 'per_run_cents', 'per_month_cents'] LOOP
158
+ oldv := (cur -> 'caps' ->> cap)::bigint;
159
+ newv := (NEW.terms -> 'caps' ->> cap)::bigint;
160
+ IF oldv IS NOT NULL AND (newv IS NULL OR newv > oldv) THEN
161
+ RAISE EXCEPTION 'payout_approvals: a narrowing may not raise or remove the % cap', cap
162
+ USING ERRCODE = 'check_violation';
163
+ END IF;
164
+ END LOOP;
165
+ END IF;
166
+
167
+ IF NEW.kind = 'run_held' AND NOT EXISTS (
168
+ SELECT 1 FROM payout_approvals WHERE rule_id = NEW.rule_id AND run_key = NEW.run_key AND kind = 'run_noticed'
169
+ ) THEN
170
+ RAISE EXCEPTION 'payout_approvals: run % was never noticed', NEW.run_key
171
+ USING ERRCODE = 'check_violation';
172
+ END IF;
173
+
174
+ RETURN NEW;
175
+ END;
176
+ $$;
177
+
178
+ DROP TRIGGER IF EXISTS payout_approvals_insert_rules ON payout_approvals;
179
+ CREATE TRIGGER payout_approvals_insert_rules
180
+ BEFORE INSERT ON payout_approvals
181
+ FOR EACH ROW EXECUTE FUNCTION payout_approvals_check_insert();
182
+
183
+ COMMIT;
@@ -0,0 +1,179 @@
1
+ -- core_284_payout_gates.sql — who may be paid at all: age tier, sanctions
2
+ -- screening, and a freeze that tells the person (task 1004914, goal 1000092 N10;
3
+ -- ADR 0385 decision 8).
4
+ --
5
+ -- WHY. The owner's legal framework (cited by Article only) puts two gates in front
6
+ -- of every payout. Art. VII, age: under 13 no account takes part in pay at all; 13
7
+ -- to 15 no money; 16 and 17 only with a guardian's co-signature, paid into an
8
+ -- account the guardian controls. Art. X, sanctions: the recipient is screened, and
9
+ -- a match stops the payout. And a stop that touches money someone is owed must
10
+ -- tell them and offer an appeal: pay is never withheld silently.
11
+ --
12
+ -- SHAPE. Six tables, all append-only (a correction is a new row; the latest row
13
+ -- wins), enforced by one shared trigger:
14
+ --
15
+ -- payout_age_records a builder's age tier as recorded, by whom, on what basis.
16
+ -- No date of birth is stored: the tier is all a gate needs.
17
+ -- payout_guardians a guardian link for a 16-17 builder: the guardian (a
18
+ -- builder), the guardian-controlled processor account, and
19
+ -- whether the link stands (a later row with active=false
20
+ -- ends it).
21
+ -- payout_screenings one sanctions screening result per recipient per check:
22
+ -- clear | match | error, who screened (the processor once
23
+ -- N2 chooses one, or a person), and until when a clear
24
+ -- result counts.
25
+ -- payout_freezes one stop on a person's payouts: the reason in words, the
26
+ -- notice they were shown, and the appeal route. A freeze is
27
+ -- NOTIFIED by construction: notice_text and appeal_route
28
+ -- are NOT NULL, so a silent freeze cannot be stored.
29
+ -- payout_freeze_events what happened to a freeze since: appealed, upheld, lifted.
30
+ -- payout_guardian_cosigns a guardian's own co-signature on one payout to a
31
+ -- 16-17 builder, from their own web session.
32
+ --
33
+ -- The gate itself is server code (src/bongos/payout-gates.js), run on every money
34
+ -- route; this file is what it reads and writes.
35
+
36
+ BEGIN;
37
+
38
+ CREATE TABLE IF NOT EXISTS payout_age_records (
39
+ id bigserial PRIMARY KEY,
40
+ builder_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
41
+ tier text NOT NULL CHECK (tier IN ('under_13', '13_15', '16_17', 'adult')),
42
+ basis text NOT NULL CHECK (basis IN ('self_declared', 'verified_by_processor', 'verified_by_person')),
43
+ recorded_by bigint REFERENCES builders(id) ON DELETE RESTRICT,
44
+ recorded_at timestamptz NOT NULL DEFAULT now()
45
+ );
46
+ CREATE INDEX IF NOT EXISTS payout_age_records_builder_idx ON payout_age_records (builder_id, id DESC);
47
+
48
+ CREATE TABLE IF NOT EXISTS payout_guardians (
49
+ id bigserial PRIMARY KEY,
50
+ builder_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
51
+ guardian_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
52
+ guardian_account text CHECK (guardian_account IS NULL OR length(guardian_account) BETWEEN 3 AND 200),
53
+ active boolean NOT NULL,
54
+ recorded_by bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
55
+ recorded_at timestamptz NOT NULL DEFAULT now(),
56
+ CONSTRAINT payout_guardians_not_self CHECK (guardian_id <> builder_id),
57
+ CONSTRAINT payout_guardians_account CHECK (active = false OR guardian_account IS NOT NULL)
58
+ );
59
+ CREATE INDEX IF NOT EXISTS payout_guardians_builder_idx ON payout_guardians (builder_id, id DESC);
60
+
61
+ CREATE TABLE IF NOT EXISTS payout_screenings (
62
+ id bigserial PRIMARY KEY,
63
+ builder_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
64
+ result text NOT NULL CHECK (result IN ('clear', 'match', 'error')),
65
+ screened_by text NOT NULL CHECK (screened_by ~ '^(processor|person):[A-Za-z0-9._-]{1,60}$'),
66
+ reference text CHECK (reference IS NULL OR length(reference) <= 200),
67
+ valid_until timestamptz,
68
+ recorded_by bigint REFERENCES builders(id) ON DELETE RESTRICT,
69
+ screened_at timestamptz NOT NULL DEFAULT now(),
70
+ CONSTRAINT payout_screenings_clear_expires CHECK (result <> 'clear' OR valid_until IS NOT NULL)
71
+ );
72
+ CREATE INDEX IF NOT EXISTS payout_screenings_builder_idx ON payout_screenings (builder_id, id DESC);
73
+
74
+ CREATE TABLE IF NOT EXISTS payout_freezes (
75
+ id bigserial PRIMARY KEY,
76
+ builder_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
77
+ reason text NOT NULL CHECK (reason IN ('sanctions_match', 'sanctions_unscreened', 'age_no_money', 'age_needs_guardian', 'age_unknown', 'manual')),
78
+ notice_text text NOT NULL CHECK (length(notice_text) BETWEEN 20 AND 1000),
79
+ appeal_route text NOT NULL CHECK (length(appeal_route) BETWEEN 1 AND 300),
80
+ owed_cents bigint CHECK (owed_cents IS NULL OR owed_cents > 0),
81
+ frozen_by bigint REFERENCES builders(id) ON DELETE RESTRICT,
82
+ frozen_at timestamptz NOT NULL DEFAULT now()
83
+ );
84
+ CREATE INDEX IF NOT EXISTS payout_freezes_builder_idx ON payout_freezes (builder_id, id DESC);
85
+
86
+ CREATE TABLE IF NOT EXISTS payout_freeze_events (
87
+ id bigserial PRIMARY KEY,
88
+ freeze_id bigint NOT NULL REFERENCES payout_freezes(id) ON DELETE RESTRICT,
89
+ kind text NOT NULL CHECK (kind IN ('appealed', 'upheld', 'lifted')),
90
+ actor_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
91
+ statement text NOT NULL CHECK (length(statement) BETWEEN 1 AND 2000),
92
+ created_at timestamptz NOT NULL DEFAULT now()
93
+ );
94
+ CREATE INDEX IF NOT EXISTS payout_freeze_events_freeze_idx ON payout_freeze_events (freeze_id, id);
95
+
96
+ -- A guardian's own co-signature on one payout to a 16-17 builder: either a
97
+ -- one-off approval or one recipient's line in a run. Their own web session only.
98
+ CREATE TABLE IF NOT EXISTS payout_guardian_cosigns (
99
+ id bigserial PRIMARY KEY,
100
+ builder_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
101
+ guardian_id bigint NOT NULL REFERENCES builders(id) ON DELETE RESTRICT,
102
+ approval_id bigint REFERENCES payout_approvals(id) ON DELETE RESTRICT,
103
+ rule_id bigint REFERENCES payout_approvals(id) ON DELETE RESTRICT,
104
+ run_key text,
105
+ session_id bigint NOT NULL,
106
+ session_source text NOT NULL CHECK (session_source = 'web'),
107
+ created_at timestamptz NOT NULL DEFAULT now(),
108
+ CONSTRAINT payout_guardian_cosigns_target CHECK (
109
+ (approval_id IS NOT NULL AND rule_id IS NULL AND run_key IS NULL) OR
110
+ (approval_id IS NULL AND rule_id IS NOT NULL AND run_key IS NOT NULL))
111
+ );
112
+ CREATE UNIQUE INDEX IF NOT EXISTS payout_guardian_cosigns_once_idx
113
+ ON payout_guardian_cosigns (builder_id, COALESCE(approval_id, 0), COALESCE(rule_id, 0), COALESCE(run_key, ''));
114
+
115
+ -- Only the builder's guardian, in a link that stands now, may co-sign.
116
+ CREATE OR REPLACE FUNCTION payout_guardian_cosigns_check() RETURNS trigger
117
+ LANGUAGE plpgsql AS $$
118
+ DECLARE g record;
119
+ BEGIN
120
+ SELECT guardian_id, active INTO g FROM payout_guardians WHERE builder_id = NEW.builder_id ORDER BY id DESC LIMIT 1;
121
+ IF g IS NULL OR NOT g.active OR g.guardian_id <> NEW.guardian_id THEN
122
+ RAISE EXCEPTION 'only the builder''s current guardian may co-sign their payout' USING ERRCODE = 'check_violation';
123
+ END IF;
124
+ RETURN NEW;
125
+ END;
126
+ $$;
127
+
128
+ DROP TRIGGER IF EXISTS payout_guardian_cosigns_rules ON payout_guardian_cosigns;
129
+ CREATE TRIGGER payout_guardian_cosigns_rules
130
+ BEFORE INSERT ON payout_guardian_cosigns
131
+ FOR EACH ROW EXECUTE FUNCTION payout_guardian_cosigns_check();
132
+
133
+ CREATE OR REPLACE FUNCTION payout_gates_refuse_change() RETURNS trigger
134
+ LANGUAGE plpgsql AS $$
135
+ BEGIN
136
+ RAISE EXCEPTION '% is append-only: % refused (a correction is a new row)', TG_TABLE_NAME, TG_OP
137
+ USING ERRCODE = 'insufficient_privilege';
138
+ END;
139
+ $$;
140
+
141
+ DO $$
142
+ DECLARE t text;
143
+ BEGIN
144
+ FOREACH t IN ARRAY ARRAY['payout_age_records', 'payout_guardians', 'payout_screenings', 'payout_freezes', 'payout_freeze_events', 'payout_guardian_cosigns'] LOOP
145
+ EXECUTE format('DROP TRIGGER IF EXISTS %I ON %I', t || '_no_update_delete', t);
146
+ EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE OR DELETE ON %I FOR EACH ROW EXECUTE FUNCTION payout_gates_refuse_change()', t || '_no_update_delete', t);
147
+ EXECUTE format('DROP TRIGGER IF EXISTS %I ON %I', t || '_no_truncate', t);
148
+ EXECUTE format('CREATE TRIGGER %I BEFORE TRUNCATE ON %I FOR EACH STATEMENT EXECUTE FUNCTION payout_gates_refuse_change()', t || '_no_truncate', t);
149
+ EXECUTE format('REVOKE UPDATE, DELETE, TRUNCATE ON %I FROM PUBLIC', t);
150
+ END LOOP;
151
+ END;
152
+ $$;
153
+
154
+ -- An appeal is the frozen person's own; upheld/lifted come after an appeal or
155
+ -- straight from whoever reviews it, and nothing follows a lift.
156
+ CREATE OR REPLACE FUNCTION payout_freeze_events_check() RETURNS trigger
157
+ LANGUAGE plpgsql AS $$
158
+ DECLARE owner_id bigint;
159
+ BEGIN
160
+ SELECT builder_id INTO owner_id FROM payout_freezes WHERE id = NEW.freeze_id;
161
+ IF EXISTS (SELECT 1 FROM payout_freeze_events WHERE freeze_id = NEW.freeze_id AND kind = 'lifted') THEN
162
+ RAISE EXCEPTION 'payout freeze % is already lifted', NEW.freeze_id USING ERRCODE = 'check_violation';
163
+ END IF;
164
+ IF NEW.kind = 'appealed' AND NEW.actor_id IS DISTINCT FROM owner_id THEN
165
+ RAISE EXCEPTION 'only the person whose pay is frozen may appeal it' USING ERRCODE = 'check_violation';
166
+ END IF;
167
+ IF NEW.kind IN ('upheld', 'lifted') AND NEW.actor_id = owner_id THEN
168
+ RAISE EXCEPTION 'a person may not decide the appeal on their own freeze' USING ERRCODE = 'check_violation';
169
+ END IF;
170
+ RETURN NEW;
171
+ END;
172
+ $$;
173
+
174
+ DROP TRIGGER IF EXISTS payout_freeze_events_rules ON payout_freeze_events;
175
+ CREATE TRIGGER payout_freeze_events_rules
176
+ BEFORE INSERT ON payout_freeze_events
177
+ FOR EACH ROW EXECUTE FUNCTION payout_freeze_events_check();
178
+
179
+ COMMIT;
@@ -0,0 +1,74 @@
1
+ -- core_285 — a task says what it NEEDS; a builder holds CAPABILITY grants
2
+ -- (task 1004950, ADR 0395).
3
+ --
4
+ -- tasks.needs: what a task needs beyond the ordinary build loop — 'owner' (a
5
+ -- decision, account or permission only the project owner holds) and/or 'server'
6
+ -- (hands on the live host). Empty for most tasks. Its own column on purpose, not a
7
+ -- value of automation_tag (that one says whether work can run unattended).
8
+ --
9
+ -- builders.capability_grants: the capabilities the owner has granted a builder by
10
+ -- hand. Only 'server' today; 'owner' is the seat itself and is never stored here.
11
+ -- Default off.
12
+ --
13
+ -- Both are additive with a default, so a rolled-back release that never names the
14
+ -- columns keeps working.
15
+ --
16
+ -- The claimable_tasks VIEW is re-created with core_283's body byte for byte: a
17
+ -- view freezes `t.*` at CREATE time, so without this it would not carry `needs`.
18
+ -- The two inlined copies (CLAIMABLE_SQL in modules/lifecycle/db-tasks.js and
19
+ -- src/bongos/optimizer.js) read `t.*` at query time and need no change for that;
20
+ -- the viewer filter itself is per-request and lives in those queries, because a
21
+ -- view cannot know who is asking.
22
+
23
+ BEGIN;
24
+
25
+ ALTER TABLE tasks ADD COLUMN IF NOT EXISTS needs text[] NOT NULL DEFAULT '{}'::text[];
26
+ ALTER TABLE tasks DROP CONSTRAINT IF EXISTS tasks_needs_known;
27
+ ALTER TABLE tasks ADD CONSTRAINT tasks_needs_known
28
+ CHECK (needs <@ ARRAY['owner', 'server']::text[]);
29
+ -- The board's need filter asks needs @> ARRAY[$1]; most rows need nothing, so a
30
+ -- partial GIN index keeps it small.
31
+ CREATE INDEX IF NOT EXISTS tasks_needs_idx ON tasks USING gin (needs) WHERE cardinality(needs) > 0;
32
+
33
+ ALTER TABLE builders ADD COLUMN IF NOT EXISTS capability_grants text[] NOT NULL DEFAULT '{}'::text[];
34
+ ALTER TABLE builders DROP CONSTRAINT IF EXISTS builders_capability_grants_known;
35
+ ALTER TABLE builders ADD CONSTRAINT builders_capability_grants_known
36
+ CHECK (capability_grants <@ ARRAY['server']::text[]);
37
+
38
+ DROP VIEW IF EXISTS claimable_tasks;
39
+ CREATE VIEW claimable_tasks AS
40
+ SELECT t.*,
41
+ pms_calibrated_minutes(t.est_minutes, t.kind) AS est_minutes_calibrated
42
+ FROM tasks t
43
+ WHERE t.status = 'ready'
44
+ AND t.title NOT LIKE '\_\_smoke\_\_%' ESCAPE '\'
45
+ AND NOT EXISTS (
46
+ SELECT 1
47
+ FROM task_blockers tb
48
+ LEFT JOIN blockers b ON b.id = tb.blocker_id
49
+ WHERE tb.task_id = t.id
50
+ AND (b.id IS NULL OR b.status = 'open')
51
+ )
52
+ AND NOT EXISTS (
53
+ SELECT 1
54
+ FROM dependencies d
55
+ WHERE ((d.from_kind = 'task' AND d.from_id = t.id)
56
+ OR (d.from_kind = 'goal' AND d.from_id = t.goal_id)
57
+ OR (d.from_kind = 'criterion' AND d.from_id IN (
58
+ SELECT tc.criterion_id FROM task_criteria tc WHERE tc.task_id = t.id)))
59
+ AND ((d.to_kind = 'task' AND EXISTS (SELECT 1 FROM tasks x WHERE x.id = d.to_id AND x.status <> 'shipped'))
60
+ OR (d.to_kind = 'criterion' AND EXISTS (SELECT 1 FROM done_when_criteria x WHERE x.id = d.to_id AND x.satisfied = false))
61
+ OR (d.to_kind = 'goal' AND EXISTS (SELECT 1 FROM goals x WHERE x.id = d.to_id AND x.status <> 'achieved')))
62
+ )
63
+ AND NOT EXISTS (
64
+ SELECT 1 FROM claims c
65
+ JOIN tasks t2 ON t2.id = c.task_id
66
+ WHERE c.released_at IS NULL
67
+ AND NOT (COALESCE(t2.source, '') = 'page-tweak' AND c.worktree_name IS NULL AND c.creator_session_id IS NULL)
68
+ AND t2.touches && t.touches
69
+ );
70
+
71
+ COMMIT;
72
+
73
+ INSERT INTO schema_migrations (version) VALUES ('core_285_task_needs')
74
+ ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,15 @@
1
+ # @bongos/core — installed platform dependency (not your project's CLAUDE.md)
2
+
3
+ This file is a placeholder shipped inside the **@bongos/core** package. The core's own
4
+ internal agent notes are intentionally omitted from the published artifact so they cannot
5
+ load into your instance's context.
6
+
7
+ **It does not govern this repository.** Your own root `CLAUDE.md`, your `.claude/`
8
+ directory, and the live Bongos database are the source of truth for how work happens here
9
+ and who may do what.
10
+
11
+ You are seeing this only because an agent opened a file under `node_modules/@bongos/core/`.
12
+ Nothing in here needs to be read to use the platform — run `bongos help` for commands.
13
+
14
+ _To work ON the platform core itself, use the standalone @bongos/core source repository,
15
+ not this vendored copy._