@bongos/core 1.17.0

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 (1142) hide show
  1. package/.bongos-core.json +5727 -0
  2. package/.claude/skills/blocker-review/SKILL.md +91 -0
  3. package/.claude/skills/blocker-solve/SKILL.md +96 -0
  4. package/.claude/skills/builder-backup/SKILL.md +54 -0
  5. package/.claude/skills/builder-box/SKILL.md +45 -0
  6. package/.claude/skills/builder-claim/SKILL.md +76 -0
  7. package/.claude/skills/builder-connect/SKILL.md +59 -0
  8. package/.claude/skills/builder-cost/SKILL.md +47 -0
  9. package/.claude/skills/builder-end/SKILL.md +81 -0
  10. package/.claude/skills/builder-exit/SKILL.md +88 -0
  11. package/.claude/skills/builder-key/SKILL.md +40 -0
  12. package/.claude/skills/builder-reauth/SKILL.md +50 -0
  13. package/.claude/skills/builder-redteam/SKILL.md +109 -0
  14. package/.claude/skills/builder-release/SKILL.md +41 -0
  15. package/.claude/skills/builder-setup/SKILL.md +62 -0
  16. package/.claude/skills/builder-ship/SKILL.md +79 -0
  17. package/.claude/skills/builder-stage/SKILL.md +51 -0
  18. package/.claude/skills/builder-start/SKILL.md +46 -0
  19. package/.claude/skills/close-box/SKILL.md +43 -0
  20. package/.claude/skills/design-sync/SKILL.md +69 -0
  21. package/.claude/skills/dev/SKILL.md +49 -0
  22. package/.claude/skills/feedback/SKILL.md +32 -0
  23. package/.claude/skills/figma-design-sync/SKILL.md +74 -0
  24. package/.claude/skills/goal-review/SKILL.md +89 -0
  25. package/.claude/skills/idea-triage/SKILL.md +144 -0
  26. package/.claude/skills/ideate/SKILL.md +82 -0
  27. package/.claude/skills/merge-mode/SKILL.md +169 -0
  28. package/.claude/skills/new-project/SKILL.md +108 -0
  29. package/.claude/skills/otb-character-review/SKILL.md +71 -0
  30. package/.claude/skills/otb-design-review/SKILL.md +47 -0
  31. package/.claude/skills/otb-feedback-capture/SKILL.md +45 -0
  32. package/.claude/skills/otb-figma-sync/SKILL.md +54 -0
  33. package/.claude/skills/otb-tile-generate/SKILL.md +45 -0
  34. package/.claude/skills/paint/SKILL.md +70 -0
  35. package/.claude/skills/planning-session/SKILL.md +299 -0
  36. package/.claude/skills/priority-session/SKILL.md +134 -0
  37. package/.claude/skills/read-session-export/SKILL.md +58 -0
  38. package/.claude/skills/recall/SKILL.md +52 -0
  39. package/.claude/skills/session-handoff/SKILL.md +46 -0
  40. package/.claude/skills/status/SKILL.md +33 -0
  41. package/.devcontainer/Dockerfile +69 -0
  42. package/.devcontainer/README.md +73 -0
  43. package/.devcontainer/devcontainer-lock.json +19 -0
  44. package/.devcontainer/devcontainer.json +93 -0
  45. package/.devcontainer/healthcheck.sh +84 -0
  46. package/.devcontainer/init-firewall.sh +198 -0
  47. package/.devcontainer/post-create.sh +153 -0
  48. package/.dockerignore +36 -0
  49. package/.env.local.example +32 -0
  50. package/.gitattributes +83 -0
  51. package/.gitignore +91 -0
  52. package/CLAUDE.md +242 -0
  53. package/CODE_OF_CONDUCT.md +46 -0
  54. package/CONTRIBUTING.md +51 -0
  55. package/Dockerfile +46 -0
  56. package/GOVERNANCE.md +44 -0
  57. package/LICENSE +661 -0
  58. package/README.md +88 -0
  59. package/bin/bongos.js +222 -0
  60. package/clients/bongos-client/README.md +48 -0
  61. package/clients/bongos-client/bongos-client.global.js +617 -0
  62. package/clients/bongos-client/examples/hello-world.mjs +62 -0
  63. package/clients/bongos-client/index.cjs +619 -0
  64. package/clients/bongos-client/index.d.ts +793 -0
  65. package/clients/bongos-client/index.mjs +614 -0
  66. package/clients/bongos-client/package.json +32 -0
  67. package/config/branding.neutral.json +60 -0
  68. package/config/design-tokens.neutral.json +51 -0
  69. package/config/design-tokens.schema.json +96 -0
  70. package/config/modules.neutral.json +9 -0
  71. package/docker-compose.yml +52 -0
  72. package/docker-entrypoint.sh +30 -0
  73. package/docs/adr/0001-stack-choice-single-vps.md +45 -0
  74. package/docs/adr/0002-digitalocean-over-hetzner.md +27 -0
  75. package/docs/adr/0003-cloudflare-origin-cert-over-letsencrypt.md +35 -0
  76. package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +45 -0
  77. package/docs/adr/0005-invisible-other-players-in-v1.md +37 -0
  78. package/docs/adr/0006-singleton-worldroom-plus-queueroom.md +30 -0
  79. package/docs/adr/0007-persistent-identity-via-localstorage-uuid.md +31 -0
  80. package/docs/adr/0008-family-based-tile-generation.md +86 -0
  81. package/docs/adr/0008-google-chat-oauth-user-auth.md +37 -0
  82. package/docs/adr/0009-autotile-architecture.md +181 -0
  83. package/docs/adr/0010-pms-architecture.md +70 -0
  84. package/docs/adr/0011-terrain-id-rendering-model.md +174 -0
  85. package/docs/adr/0012-ground-object-cell-split.md +208 -0
  86. package/docs/adr/0013-paths-as-object-overlays-with-autotile-dispatch.md +158 -0
  87. package/docs/adr/0014-families-canonical-over-vocabulary.md +103 -0
  88. package/docs/adr/0015-task-dependencies-and-auto-promotion.md +125 -0
  89. package/docs/adr/0016-trust-boundary-server-enforced-permissions.md +132 -0
  90. package/docs/adr/0017-code-simplification-and-repo-cleanliness.md +74 -0
  91. package/docs/adr/0018-three-rank-model-goes-live.md +97 -0
  92. package/docs/adr/0019-red-team-bounty-payout-table.md +52 -0
  93. package/docs/adr/0020-security-model-public-stub.md +70 -0
  94. package/docs/adr/0021-per-builder-skill-model-preferences.md +99 -0
  95. package/docs/adr/0022-secrets-policy.md +124 -0
  96. package/docs/adr/0023-kind-multipliers-and-idea-bonus.md +118 -0
  97. package/docs/adr/0024-cloneable-repo-local-first-memory.md +277 -0
  98. package/docs/adr/0024-multi-agent-system-architecture.md +125 -0
  99. package/docs/adr/0025-offsite-backup-vendor-digitalocean-spaces.md +59 -0
  100. package/docs/adr/0025-structured-criterion-task-link.md +44 -0
  101. package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +117 -0
  102. package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +170 -0
  103. package/docs/adr/0028-honest-llm-spend-accounting.md +109 -0
  104. package/docs/adr/0029-status-page-outage-resilience.md +59 -0
  105. package/docs/adr/0030-builders-hall-live-updates.md +59 -0
  106. package/docs/adr/0031-cloud-dev-environments-for-builders.md +222 -0
  107. package/docs/adr/0032-discord-mirror-of-gds.md +50 -0
  108. package/docs/adr/0033-discord-bot-service-principal.md +82 -0
  109. package/docs/adr/0034-thetes-graduated-newcomer-rank.md +53 -0
  110. package/docs/adr/0035-builder-onboarding-three-paths.md +128 -0
  111. package/docs/adr/0036-builders-subdomain-and-ui-reorg.md +40 -0
  112. package/docs/adr/0037-discord-channel-management.md +51 -0
  113. package/docs/adr/0038-chromebook-ttyd-cloudflare-tunnel.md +111 -0
  114. package/docs/adr/0039-setup-first-onboarding-ux.md +49 -0
  115. package/docs/adr/0040-remote-control-default-browser-onramp.md +47 -0
  116. package/docs/adr/0041-temporary-grader-bypass-killswitch.md +40 -0
  117. package/docs/adr/0042-builder-self-deploy-ci-auto-merge.md +82 -0
  118. package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +74 -0
  119. package/docs/adr/0044-mediterranean-palette-replacement.md +73 -0
  120. package/docs/adr/0044-per-box-live-game-preview.md +57 -0
  121. package/docs/adr/0045-devbox-desktop-app.md +133 -0
  122. package/docs/adr/0046-sandbox-first-review-gate.md +72 -0
  123. package/docs/adr/0047-discord-bugs-intake-anti-abuse.md +36 -0
  124. package/docs/adr/0048-works-in-progress-ia-split.md +32 -0
  125. package/docs/adr/0049-split-parallel-safety-contract.md +46 -0
  126. package/docs/adr/0050-device-flow-admission-invite-gated-by-default.md +43 -0
  127. package/docs/adr/0051-full-session-transcript-corpus.md +57 -0
  128. package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +70 -0
  129. package/docs/adr/0053-scoped-dev-box-session.md +55 -0
  130. package/docs/adr/0054-session-token-reward-cost-plus.md +63 -0
  131. package/docs/adr/0055-server-mediated-branch-publish.md +47 -0
  132. package/docs/adr/0056-prod-deploy-script-mirror-and-healthcheck-retry.md +62 -0
  133. package/docs/adr/0057-container-cost-ledger.md +28 -0
  134. package/docs/adr/0057-discord-archon-approval-channels.md +64 -0
  135. package/docs/adr/0058-automatic-gate-surface-gatekeeper.md +64 -0
  136. package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +37 -0
  137. package/docs/adr/0060-gds-retrieval-layer.md +97 -0
  138. package/docs/adr/0061-context-layer-decomposition.md +61 -0
  139. package/docs/adr/0062-medusa-instance-model-decoupling.md +107 -0
  140. package/docs/adr/0063-generated-repo-map-symbol-skeleton.md +44 -0
  141. package/docs/adr/0064-rename-medusa-to-cloud-bongos.md +49 -0
  142. package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +69 -0
  143. package/docs/adr/0066-generated-file-map-sections.md +51 -0
  144. package/docs/adr/0067-session-start-fast-forward-pull.md +43 -0
  145. package/docs/adr/0068-shared-art-key-for-newcomers.md +38 -0
  146. package/docs/adr/0069-hall-live-channel-sse-decouple.md +35 -0
  147. package/docs/adr/0070-deterministic-session-card-delivery.md +44 -0
  148. package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +59 -0
  149. package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +35 -0
  150. package/docs/adr/0072-dev-box-code-staleness-visibility.md +39 -0
  151. package/docs/adr/0073-builder-needs-signal-and-byok-gemini-key.md +64 -0
  152. package/docs/adr/0073-secrets-scan-exclude-uri-detector.md +37 -0
  153. package/docs/adr/0074-memory-map-stays-light.md +32 -0
  154. package/docs/adr/0075-per-system-cost-attribution.md +37 -0
  155. package/docs/adr/0076-in-session-deterministic-compaction.md +58 -0
  156. package/docs/adr/0077-content-addressed-llm-cache.md +32 -0
  157. package/docs/adr/0078-deterministic-first-cron.md +48 -0
  158. package/docs/adr/0079-value-gated-autonomous-engagement.md +39 -0
  159. package/docs/adr/0080-llm-cache-api-transport-and-trust-model.md +46 -0
  160. package/docs/adr/0081-tool-agnostic-design-layer.md +62 -0
  161. package/docs/adr/0082-productized-key-storage-provisioning.md +32 -0
  162. package/docs/adr/0082-server-side-merge-conflict-auto-resolution.md +55 -0
  163. package/docs/adr/0083-modular-architecture-strangler-build-plan.md +143 -0
  164. package/docs/adr/0084-auto-derived-per-task-rank-floor.md +86 -0
  165. package/docs/adr/0085-remove-default-per-builder-spend-cap.md +39 -0
  166. package/docs/adr/0086-goal-scoped-work-hierarchy.md +123 -0
  167. package/docs/adr/0087-bongos-app-architecture-and-handoff-contract.md +49 -0
  168. package/docs/adr/0087-compete-on-governance-not-tooling-cursor.md +65 -0
  169. package/docs/adr/0088-consistent-character-generative-animation.md +169 -0
  170. package/docs/adr/0089-modular-multi-model-adversarial-grader.md +179 -0
  171. package/docs/adr/0090-metic-task-authoring.md +73 -0
  172. package/docs/adr/0091-bounding-the-kernel-and-db-carve.md +106 -0
  173. package/docs/adr/0092-hosting-module-and-on-prem-target.md +117 -0
  174. package/docs/adr/0093-tranche-2-core-carve-sequence.md +72 -0
  175. package/docs/adr/0094-repo-atlas-self-drawing-codebase-map.md +49 -0
  176. package/docs/adr/0095-borrowed-memory-and-retrieval-concepts.md +65 -0
  177. package/docs/adr/0095-cross-agent-context-management.md +58 -0
  178. package/docs/adr/0096-require-reward-before-workable.md +209 -0
  179. package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +46 -0
  180. package/docs/adr/0097-retroactive-reward-backfill.md +124 -0
  181. package/docs/adr/0098-public-mirror-publish-manifest.md +92 -0
  182. package/docs/adr/0099-delayed-redacted-mirror-export.md +55 -0
  183. package/docs/adr/0100-two-repo-instance-model.md +60 -0
  184. package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +90 -0
  185. package/docs/adr/0102-finish-bounding-the-kernel.md +36 -0
  186. package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +70 -0
  187. package/docs/adr/0103-gdsv4-bongos-consolidation.md +28 -0
  188. package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +42 -0
  189. package/docs/adr/0105-instance-seed-migrations-out-of-core.md +47 -0
  190. package/docs/adr/0106-goal-owner-manager-authority.md +84 -0
  191. package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +83 -0
  192. package/docs/adr/0108-instance-composition-configurable-root.md +87 -0
  193. package/docs/adr/0109-self-describing-openapi-and-hosted-docs.md +44 -0
  194. package/docs/adr/0110-untrack-whole-file-generated-nav-docs.md +49 -0
  195. package/docs/adr/0111-instance-hosting-provisioning-module.md +135 -0
  196. package/docs/adr/0112-private-goals-invitations-join-requests.md +72 -0
  197. package/docs/adr/0113-sandbox-studio-descope-superseded-by-0044-0052.md +41 -0
  198. package/docs/adr/0114-instance-docs-discovery-contract.md +32 -0
  199. package/docs/adr/0115-scheduled-routines-portability.md +31 -0
  200. package/docs/adr/0116-api-error-envelope-and-code-taxonomy.md +62 -0
  201. package/docs/adr/0117-api-versioning-and-deprecation-policy.md +50 -0
  202. package/docs/adr/0118-api-contract-source-of-truth-code-first.md +47 -0
  203. package/docs/adr/0119-api-pagination-contract.md +34 -0
  204. package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +108 -0
  205. package/docs/adr/0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md +97 -0
  206. package/docs/adr/0122-onboarding-diagram-renders-deploy-rendered-off-git.md +43 -0
  207. package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +36 -0
  208. package/docs/adr/0124-typed-api-response-bodies.md +37 -0
  209. package/docs/adr/0125-control-plane-scaffolds-standalone-instance-repo.md +36 -0
  210. package/docs/adr/0126-dedicated-cloudbongos-control-plane-droplet.md +30 -0
  211. package/docs/adr/0127-cross-box-fleet-observability.md +64 -0
  212. package/docs/adr/0128-provisioning-runner-privilege-and-db-auth-model.md +46 -0
  213. package/docs/adr/0129-cloudbongos-control-plane-pull-deploy.md +34 -0
  214. package/docs/adr/0130-provision-remote-exec-over-ssh.md +61 -0
  215. package/docs/adr/0131-rank-scoped-skill-visibility.md +47 -0
  216. package/docs/adr/0132-cohost-fleet-control-plane-migration.md +54 -0
  217. package/docs/adr/0133-github-app-manifest-onboarding-signin.md +42 -0
  218. package/docs/adr/0134-private-first-npm-distribution.md +38 -0
  219. package/docs/adr/README.md +208 -0
  220. package/docs/api/openapi.json +13720 -0
  221. package/docs/api-reference.md +437 -0
  222. package/docs/architecture.md +244 -0
  223. package/docs/branding-contract.md +66 -0
  224. package/docs/branding-fill-prompt.md +25 -0
  225. package/docs/canonical-permissions.md +241 -0
  226. package/docs/design/container-exterior-tiles.md +49 -0
  227. package/docs/design/container-exterior.md +81 -0
  228. package/docs/design/container-interior.md +77 -0
  229. package/docs/design/modular-architecture/00-research-report.md +107 -0
  230. package/docs/design/modular-architecture/01-architecture.md +125 -0
  231. package/docs/design/modular-architecture/02-module-map.md +116 -0
  232. package/docs/design/modular-architecture/03-builder-flows.md +104 -0
  233. package/docs/design/modular-architecture/04-module-lifecycle.md +62 -0
  234. package/docs/design/modular-architecture/README.md +27 -0
  235. package/docs/design/vanilla-hall-ui-redesign-scope.md +284 -0
  236. package/docs/design/world-map-scroll.md +41 -0
  237. package/docs/design-contract.md +320 -0
  238. package/docs/file-map.md +418 -0
  239. package/docs/handoff-template.md +92 -0
  240. package/docs/modules-contract.md +293 -0
  241. package/docs/onboarding/browser-terminal-guide.md +73 -0
  242. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +28 -0
  243. package/docs/onboarding/diagrams/02-rank-ladder.mmd +54 -0
  244. package/docs/onboarding/diagrams/03-drachmae-karma.mmd +37 -0
  245. package/docs/onboarding/diagrams/04-architecture.mmd +51 -0
  246. package/docs/onboarding/diagrams/05-versioning.mmd +29 -0
  247. package/docs/onboarding/diagrams/README.md +94 -0
  248. package/docs/onboarding/diagrams/assertions.json +170 -0
  249. package/docs/onboarding/diagrams/puppeteer-config.json +1 -0
  250. package/docs/onboarding/diagrams/render-config.json +9 -0
  251. package/docs/onboarding/drachmae-and-karma.md +178 -0
  252. package/docs/onboarding/primer.md +202 -0
  253. package/docs/project-context.template.md +67 -0
  254. package/docs/recipes/README.md +35 -0
  255. package/docs/recipes/audit-replay.md +100 -0
  256. package/docs/recipes/bongos-cli-release.md +66 -0
  257. package/docs/recipes/builder-box-lifecycle.md +152 -0
  258. package/docs/recipes/claude-design-loop.md +143 -0
  259. package/docs/recipes/claude-gemini-bongos-doors.md +155 -0
  260. package/docs/recipes/cloudbongos-staging-gate.md +139 -0
  261. package/docs/recipes/cloudbongos-standup.md +111 -0
  262. package/docs/recipes/devbox-app-release.md +93 -0
  263. package/docs/recipes/devbox-app-windows-test.md +128 -0
  264. package/docs/recipes/failed-ship-recovery-proof.md +102 -0
  265. package/docs/recipes/figma-design-loop.md +129 -0
  266. package/docs/recipes/gds-db-backup.md +255 -0
  267. package/docs/recipes/instance-deploy.md +37 -0
  268. package/docs/recipes/managed-settings-remote-control.md +416 -0
  269. package/docs/recipes/memory-backup.md +71 -0
  270. package/docs/recipes/memory-sync-conflicts.md +98 -0
  271. package/docs/recipes/multi-builder-merge.md +78 -0
  272. package/docs/recipes/ops-gotchas.md +212 -0
  273. package/docs/recipes/overnight-builder.md +53 -0
  274. package/docs/recipes/packaging-the-core.md +49 -0
  275. package/docs/recipes/parallel-load-results-2026-05-30.md +63 -0
  276. package/docs/recipes/parallel-load-test.md +32 -0
  277. package/docs/recipes/pixel-art-pipeline.md +411 -0
  278. package/docs/recipes/private-npm-distribution.md +79 -0
  279. package/docs/recipes/search-index-ingestion.md +67 -0
  280. package/docs/recipes/self-host.md +60 -0
  281. package/docs/recipes/ship-and-regrade.md +72 -0
  282. package/docs/recipes/staging-data.md +50 -0
  283. package/docs/recipes/staging-environment.md +215 -0
  284. package/docs/recipes/upgrading-the-core.md +58 -0
  285. package/docs/research/cursor-competitive-analysis.md +255 -0
  286. package/docs/research/llm-model-agnostic-and-cheaper-grader.md +227 -0
  287. package/migrations/003_pms.sql +284 -0
  288. package/migrations/004_pms_cost_idempotency.sql +13 -0
  289. package/migrations/005_pms_smoke_filter.sql +44 -0
  290. package/migrations/006_pms_v2.sql +378 -0
  291. package/migrations/007_pms_v2_hierarchy_trigger.sql +59 -0
  292. package/migrations/008_pms_v2_migration_allocator.sql +27 -0
  293. package/migrations/009_pms_v2_blockers_table.sql +68 -0
  294. package/migrations/010_uptime.sql +29 -0
  295. package/migrations/011_backfill_v2_v3_done_when.sql +20 -0
  296. package/migrations/012_pms_v2_task_lifecycle_states.sql +82 -0
  297. package/migrations/013_claim_locking.sql +22 -0
  298. package/migrations/014_pms_task_discipline.sql +86 -0
  299. package/migrations/015_pms_estimation_calibration.sql +140 -0
  300. package/migrations/016_pms_task_grades.sql +60 -0
  301. package/migrations/017_version_progress_exclude_abandoned.sql +49 -0
  302. package/migrations/019_rename_pms_v3_to_gds_v3.sql +65 -0
  303. package/migrations/020_task_dependencies.sql +99 -0
  304. package/migrations/021_v3_renumber_and_deps.sql +224 -0
  305. package/migrations/022_v3_reconcile_dep_gated_status.sql +41 -0
  306. package/migrations/023_pms_rank.sql +30 -0
  307. package/migrations/025_builder_exit_status.sql +15 -0
  308. package/migrations/027_builders_preferred_disciplines.sql +46 -0
  309. package/migrations/028_tasks_parallel_safe.sql +71 -0
  310. package/migrations/029_rank_three_live.sql +32 -0
  311. package/migrations/030_vulnerability_reports.sql +61 -0
  312. package/migrations/031_reward_simplification.sql +57 -0
  313. package/migrations/032_repo_health_snapshots.sql +56 -0
  314. package/migrations/033_audit_log.sql +64 -0
  315. package/migrations/034_lifecycle_breakdown_leaf_only.sql +62 -0
  316. package/migrations/035_auth_token_hygiene.sql +66 -0
  317. package/migrations/037_builder_skill_model_prefs.sql +44 -0
  318. package/migrations/038_task_override_requests.sql +51 -0
  319. package/migrations/039_newcomer_friendly_column.sql +124 -0
  320. package/migrations/040_builder_karma.sql +58 -0
  321. package/migrations/041_kind_multipliers_and_idea_bonus.sql +42 -0
  322. package/migrations/042_criterion_proposal_workflow.sql +78 -0
  323. package/migrations/043_builder_onboarding_observability.sql +66 -0
  324. package/migrations/044_tasks_requires_rank.sql +97 -0
  325. package/migrations/045_builder_onboarding_state.sql +147 -0
  326. package/migrations/046_cost_log_builder_attribution.sql +42 -0
  327. package/migrations/054_builder_memory.sql +108 -0
  328. package/migrations/055_task_criteria.sql +90 -0
  329. package/migrations/058_peer_votes.sql +41 -0
  330. package/migrations/059_onboarding_pick_disciplines.sql +59 -0
  331. package/migrations/060_access_requests.sql +46 -0
  332. package/migrations/061_backfill_override_ship_attribution.sql +29 -0
  333. package/migrations/062_session_records.sql +34 -0
  334. package/migrations/063_session_records_tool_errors_idx.sql +11 -0
  335. package/migrations/064_grade_attempts.sql +18 -0
  336. package/migrations/065_bfg_principal.sql +58 -0
  337. package/migrations/066_live_notify_triggers.sql +69 -0
  338. package/migrations/067_builder_boxes.sql +117 -0
  339. package/migrations/067_discord_bot_foundation.sql +69 -0
  340. package/migrations/068_thetes_requires_rank.sql +27 -0
  341. package/migrations/069_builder_ssh_keys.sql +66 -0
  342. package/migrations/070_box_intents.sql +101 -0
  343. package/migrations/071_box_first_provision_approval.sql +46 -0
  344. package/migrations/072_onboarding_ship_three_remove_primer.sql +80 -0
  345. package/migrations/073_box_terminal_access.sql +46 -0
  346. package/migrations/075_builder_sound_prefs.sql +28 -0
  347. package/migrations/078_box_claude_active.sql +22 -0
  348. package/migrations/079_box_first_connected_at.sql +20 -0
  349. package/migrations/081_tasks_needs_migration.sql +34 -0
  350. package/migrations/084_tasks_security_sensitive.sql +24 -0
  351. package/migrations/085_security_engagement_docs.sql +34 -0
  352. package/migrations/086_rename_disciplines.sql +125 -0
  353. package/migrations/088_builders_anthropic_link.sql +28 -0
  354. package/migrations/089_builders_monthly_budget.sql +19 -0
  355. package/migrations/090_box_scoped_sessions.sql +38 -0
  356. package/migrations/091_session_token_reward.sql +44 -0
  357. package/migrations/093_tasks_sandbox_review.sql +22 -0
  358. package/migrations/102_remove_box_first_provision_approval.sql +58 -0
  359. package/migrations/103_search_chunks.sql +90 -0
  360. package/migrations/104_builder_box_blocked.sql +34 -0
  361. package/migrations/105_box_host_keys.sql +35 -0
  362. package/migrations/111_medusa_customer0_framing.sql +35 -0
  363. package/migrations/112_drop_track_check.sql +25 -0
  364. package/migrations/113_merge_lease.sql +16 -0
  365. package/migrations/114_cloudbongos_rename_live_strings.sql +32 -0
  366. package/migrations/118_currency_label_decoupling.sql +23 -0
  367. package/migrations/119_builder_behavior_prefs.sql +31 -0
  368. package/migrations/121_box_code_version.sql +37 -0
  369. package/migrations/122_builder_gemini_key.sql +30 -0
  370. package/migrations/123_cost_log_tiers.sql +33 -0
  371. package/migrations/124_cost_baseline.sql +45 -0
  372. package/migrations/125_llm_cache.sql +54 -0
  373. package/migrations/126_autonomy_runs.sql +33 -0
  374. package/migrations/143_cost_calibration.sql +63 -0
  375. package/migrations/145_backfill_task_requires_rank.sql +84 -0
  376. package/migrations/160_goal_tier.sql +88 -0
  377. package/migrations/163_polymorphic_dependencies.sql +187 -0
  378. package/migrations/164_event_sound_prefs.sql +20 -0
  379. package/migrations/165_task_module_key.sql +15 -0
  380. package/migrations/171_claims_published_head_sha.sql +24 -0
  381. package/migrations/174_close_orphaned_claims_on_terminal_tasks.sql +30 -0
  382. package/migrations/175_task_grades_diff_hash.sql +9 -0
  383. package/migrations/176_promotion_respects_open_blockers.sql +58 -0
  384. package/migrations/176_ui_discipline.sql +40 -0
  385. package/migrations/177_require_reward_before_workable.sql +76 -0
  386. package/migrations/178_reward_gate_auto_assign_revert_autopromote.sql +61 -0
  387. package/migrations/179_search_chunk_usefulness.sql +33 -0
  388. package/migrations/180_one_active_claim_per_session.sql +54 -0
  389. package/migrations/181_cost_log_skill_name.sql +33 -0
  390. package/migrations/184_claim_release_requested.sql +25 -0
  391. package/migrations/185_module_upstreaming_goal_wiring.sql +59 -0
  392. package/migrations/187_goal_sort_order.sql +30 -0
  393. package/migrations/187_tasks_kind_check_add_verify.sql +21 -0
  394. package/migrations/README.md +88 -0
  395. package/migrations/core_188_goal_visibility_and_membership_requests.sql +71 -0
  396. package/migrations/core_189_core_upgrades_ledger.sql +37 -0
  397. package/migrations/core_189_credit_log_task_id_index.sql +19 -0
  398. package/migrations/core_190_rebuild_claimable_task_views.sql +71 -0
  399. package/migrations/instance/018_pms_v3_planning_seed.sql +131 -0
  400. package/migrations/instance/080_gds_v4_planning_seed.sql +75 -0
  401. package/migrations/instance/110_medusa_planning_seed.sql +70 -0
  402. package/migrations/instance/120_bongos_v1_planning_seed.sql +69 -0
  403. package/migrations/instance/144_bongos_v1_module_system_criterion.sql +26 -0
  404. package/migrations/instance/159_bongos_v1_goal_hierarchy_criterion.sql +29 -0
  405. package/migrations/instance/172_v2_world_planning_seed.sql +163 -0
  406. package/migrations/instance/173_bongos_v1_c7_core_modularized.sql +33 -0
  407. package/migrations/instance/182_gdsv4_bongos_consolidation.sql +132 -0
  408. package/migrations/instance/183_gdsv4_carryover_themed_goals.sql +116 -0
  409. package/migrations/instance/186_bongos_v1_governance_planning_seed.sql +69 -0
  410. package/modules/autonomy/CLAUDE.md +49 -0
  411. package/modules/autonomy/db.js +50 -0
  412. package/modules/autonomy/module.json +13 -0
  413. package/modules/autonomy/pollers/routine-timers.js +146 -0
  414. package/modules/autonomy/routes/autonomy.js +37 -0
  415. package/modules/builder-settings/CLAUDE.md +58 -0
  416. package/modules/builder-settings/builder-needs.js +115 -0
  417. package/modules/builder-settings/db.js +168 -0
  418. package/modules/builder-settings/display-name.js +84 -0
  419. package/modules/builder-settings/event-sound-prefs.js +169 -0
  420. package/modules/builder-settings/interaction-prefs.js +201 -0
  421. package/modules/builder-settings/model-alloc-prefs.js +147 -0
  422. package/modules/builder-settings/module.json +10 -0
  423. package/modules/builder-settings/render-prefs.js +103 -0
  424. package/modules/builder-settings/routes/settings.js +417 -0
  425. package/modules/builder-settings/settings.js +52 -0
  426. package/modules/builder-settings/skill-prefs.js +196 -0
  427. package/modules/builder-settings/sound-prefs.js +178 -0
  428. package/modules/builder-settings/wandering-prefs.js +282 -0
  429. package/modules/dev-box/CLAUDE.md +38 -0
  430. package/modules/dev-box/box-access.js +275 -0
  431. package/modules/dev-box/box-credential.js +94 -0
  432. package/modules/dev-box/box-onboard.js +486 -0
  433. package/modules/dev-box/boxes.js +842 -0
  434. package/modules/dev-box/db.js +39 -0
  435. package/modules/dev-box/module.json +14 -0
  436. package/modules/dev-box/routes/box.js +977 -0
  437. package/modules/discord/CLAUDE.md +50 -0
  438. package/modules/discord/auth.js +54 -0
  439. package/modules/discord/bug-attachments.js +210 -0
  440. package/modules/discord/db.js +96 -0
  441. package/modules/discord/discord-approvals.js +145 -0
  442. package/modules/discord/discord-audit.js +29 -0
  443. package/modules/discord/discord-bot.js +545 -0
  444. package/modules/discord/discord-bugs.js +257 -0
  445. package/modules/discord/discord-channels.js +412 -0
  446. package/modules/discord/discord-inbound.js +147 -0
  447. package/modules/discord/discord-message-buffer.js +54 -0
  448. package/modules/discord/discord-reaction.js +186 -0
  449. package/modules/discord/discord-role-sync.js +318 -0
  450. package/modules/discord/module.json +14 -0
  451. package/modules/discord/pollers/discord-bot.js +19 -0
  452. package/modules/discord/routes/bug-attachments.js +44 -0
  453. package/modules/discord/routes/discord.js +102 -0
  454. package/modules/discord/ship-broadcast.js +78 -0
  455. package/modules/discord/webhook.js +74 -0
  456. package/modules/economy/CLAUDE.md +48 -0
  457. package/modules/economy/achievements.js +594 -0
  458. package/modules/economy/cost-classify.js +331 -0
  459. package/modules/economy/cost-summary-shape.js +90 -0
  460. package/modules/economy/cost.js +438 -0
  461. package/modules/economy/credits.js +430 -0
  462. package/modules/economy/migrations/economy_001_fix_gds_shipper_description.sql +91 -0
  463. package/modules/economy/module.json +10 -0
  464. package/modules/economy/reward.js +61 -0
  465. package/modules/economy/routes/cost.js +97 -0
  466. package/modules/economy/routes/leaderboard.js +26 -0
  467. package/modules/economy/routes/reward.js +42 -0
  468. package/modules/economy/streak.js +285 -0
  469. package/modules/grading/CLAUDE.md +42 -0
  470. package/modules/grading/db.js +39 -0
  471. package/modules/grading/grader-rubric.json +151 -0
  472. package/modules/grading/grader-workers/efficiency.js +213 -0
  473. package/modules/grading/grader-workers/extract-json.js +80 -0
  474. package/modules/grading/grader-workers/fence.js +100 -0
  475. package/modules/grading/grader-workers/hacker.js +239 -0
  476. package/modules/grading/grader-workers/index.js +183 -0
  477. package/modules/grading/grader-workers/narc.js +207 -0
  478. package/modules/grading/grader-workers/quality.js +198 -0
  479. package/modules/grading/grader-workers/rubric.js +20 -0
  480. package/modules/grading/grader-workers/worker-prompt.js +89 -0
  481. package/modules/grading/grader-workers/worker-verdict.js +50 -0
  482. package/modules/grading/grader.js +1790 -0
  483. package/modules/grading/module.json +12 -0
  484. package/modules/grading/routes/grade.js +51 -0
  485. package/modules/hall-ui/CLAUDE.md +61 -0
  486. package/modules/hall-ui/module.json +14 -0
  487. package/modules/hall-ui/public/atlas.html +180 -0
  488. package/modules/hall-ui/public/atlas.js +336 -0
  489. package/modules/hall-ui/public/box-panel.js +423 -0
  490. package/modules/hall-ui/public/brand-apply.js +117 -0
  491. package/modules/hall-ui/public/builders.js +3028 -0
  492. package/modules/hall-ui/public/chime.wav +0 -0
  493. package/modules/hall-ui/public/copy-on-click.js +174 -0
  494. package/modules/hall-ui/public/cursors/arrow.png +0 -0
  495. package/modules/hall-ui/public/cursors/hand-pointer.png +0 -0
  496. package/modules/hall-ui/public/cursors/magnifier-out.png +0 -0
  497. package/modules/hall-ui/public/cursors/magnifier.png +0 -0
  498. package/modules/hall-ui/public/diagram-viewer.css +125 -0
  499. package/modules/hall-ui/public/diagram-viewer.js +330 -0
  500. package/modules/hall-ui/public/diagrams.html +113 -0
  501. package/modules/hall-ui/public/dom-utils.js +212 -0
  502. package/modules/hall-ui/public/drachmae.html +68 -0
  503. package/modules/hall-ui/public/drachmae.js +136 -0
  504. package/modules/hall-ui/public/gate.html +143 -0
  505. package/modules/hall-ui/public/gate.js +228 -0
  506. package/modules/hall-ui/public/goals-page.js +1297 -0
  507. package/modules/hall-ui/public/goals.html +376 -0
  508. package/modules/hall-ui/public/goals.js +119 -0
  509. package/modules/hall-ui/public/hall-widgets.js +189 -0
  510. package/modules/hall-ui/public/harbor.html +167 -0
  511. package/modules/hall-ui/public/harbor.js +335 -0
  512. package/modules/hall-ui/public/index.html +116 -0
  513. package/modules/hall-ui/public/instances-panel.js +172 -0
  514. package/modules/hall-ui/public/md-reader.js +234 -0
  515. package/modules/hall-ui/public/modules.html +119 -0
  516. package/modules/hall-ui/public/modules.js +154 -0
  517. package/modules/hall-ui/public/new-project-wizard.js +186 -0
  518. package/modules/hall-ui/public/not-ready.html +48 -0
  519. package/modules/hall-ui/public/pair.html +119 -0
  520. package/modules/hall-ui/public/pair.js +132 -0
  521. package/modules/hall-ui/public/primer.css +404 -0
  522. package/modules/hall-ui/public/primer.html +85 -0
  523. package/modules/hall-ui/public/primer.js +641 -0
  524. package/modules/hall-ui/public/profile.html +85 -0
  525. package/modules/hall-ui/public/profile.js +236 -0
  526. package/modules/hall-ui/public/ranks.html +69 -0
  527. package/modules/hall-ui/public/ranks.js +206 -0
  528. package/modules/hall-ui/public/roadmap.html +209 -0
  529. package/modules/hall-ui/public/roadmap.js +375 -0
  530. package/modules/hall-ui/public/sessions.html +92 -0
  531. package/modules/hall-ui/public/sessions.js +222 -0
  532. package/modules/hall-ui/public/settings.html +640 -0
  533. package/modules/hall-ui/public/settings.js +1219 -0
  534. package/modules/hall-ui/public/shell.js +495 -0
  535. package/modules/hall-ui/public/style.css +1748 -0
  536. package/modules/hall-ui/public/task-detail.js +253 -0
  537. package/modules/hall-ui/public/task.html +83 -0
  538. package/modules/hall-ui/public/task.js +326 -0
  539. package/modules/hall-ui/public/watch.html +333 -0
  540. package/modules/hall-ui/public/watch.js +859 -0
  541. package/modules/hall-ui/public/work.html +469 -0
  542. package/modules/hall-ui/public/work.js +1292 -0
  543. package/modules/ideas/CLAUDE.md +37 -0
  544. package/modules/ideas/blockers.js +100 -0
  545. package/modules/ideas/inbox.js +459 -0
  546. package/modules/ideas/module.json +10 -0
  547. package/modules/ideas/routes/blockers.js +120 -0
  548. package/modules/ideas/routes/inbox.js +230 -0
  549. package/modules/lifecycle/CLAUDE.md +63 -0
  550. package/modules/lifecycle/conflict-resolve.js +436 -0
  551. package/modules/lifecycle/db.js +4970 -0
  552. package/modules/lifecycle/done-when.js +355 -0
  553. package/modules/lifecycle/github-push.js +969 -0
  554. package/modules/lifecycle/goal-conflicts.js +133 -0
  555. package/modules/lifecycle/hierarchy.js +104 -0
  556. package/modules/lifecycle/lifecycle.js +58 -0
  557. package/modules/lifecycle/merge-lock.js +261 -0
  558. package/modules/lifecycle/migrations/lifecycle_001_goal_first_leads.sql +28 -0
  559. package/modules/lifecycle/migrations/lifecycle_002_backfill_orphan_task_goals.sql +36 -0
  560. package/modules/lifecycle/module.json +13 -0
  561. package/modules/lifecycle/pollers/publish-reconciler.js +20 -0
  562. package/modules/lifecycle/publish-reconciler.js +418 -0
  563. package/modules/lifecycle/routes/analytics.js +63 -0
  564. package/modules/lifecycle/routes/claims.js +506 -0
  565. package/modules/lifecycle/routes/dependencies.js +82 -0
  566. package/modules/lifecycle/routes/done-when.js +136 -0
  567. package/modules/lifecycle/routes/gate-approvals.js +197 -0
  568. package/modules/lifecycle/routes/goals.js +1419 -0
  569. package/modules/lifecycle/routes/lifecycle.js +43 -0
  570. package/modules/lifecycle/routes/tasks.js +1703 -0
  571. package/modules/lifecycle/routes/versions.js +128 -0
  572. package/modules/lifecycle/ship-card.js +505 -0
  573. package/modules/lifecycle/ship-preflight.js +225 -0
  574. package/modules/lifecycle/task-classifier.js +512 -0
  575. package/modules/lifecycle/version-close.js +106 -0
  576. package/modules/memory/CLAUDE.md +40 -0
  577. package/modules/memory/learnings.js +275 -0
  578. package/modules/memory/memory.js +572 -0
  579. package/modules/memory/module.json +12 -0
  580. package/modules/memory/routes/learnings.js +90 -0
  581. package/modules/memory/routes/memory.js +916 -0
  582. package/modules/memory/routes/search.js +188 -0
  583. package/modules/memory/search-chunker.js +252 -0
  584. package/modules/memory/search.js +320 -0
  585. package/modules/onboarding/CLAUDE.md +55 -0
  586. package/modules/onboarding/approval-broadcast.js +59 -0
  587. package/modules/onboarding/db.js +54 -0
  588. package/modules/onboarding/module.json +10 -0
  589. package/modules/onboarding/newcomer-restock.js +212 -0
  590. package/modules/onboarding/onboarding-state.js +532 -0
  591. package/modules/onboarding/onboarding.js +508 -0
  592. package/modules/onboarding/port.js +63 -0
  593. package/modules/onboarding/routes/access-requests.js +208 -0
  594. package/modules/onboarding/routes/onboarding.js +54 -0
  595. package/modules/security/CLAUDE.md +44 -0
  596. package/modules/security/module.json +10 -0
  597. package/modules/security/routes/reports.js +251 -0
  598. package/modules/security/secret-scrub.js +201 -0
  599. package/modules/security/security.js +294 -0
  600. package/modules/sessions/CLAUDE.md +39 -0
  601. package/modules/sessions/bfg.js +357 -0
  602. package/modules/sessions/db.js +326 -0
  603. package/modules/sessions/module.json +10 -0
  604. package/modules/sessions/pulse.js +149 -0
  605. package/modules/sessions/routes/sessions.js +331 -0
  606. package/modules/status-ui/CLAUDE.md +47 -0
  607. package/modules/status-ui/module.json +14 -0
  608. package/modules/status-ui/public/README.md +29 -0
  609. package/modules/status-ui/public/cursors/arrow.png +0 -0
  610. package/modules/status-ui/public/cursors/hand-pointer.png +0 -0
  611. package/modules/status-ui/public/index.html +363 -0
  612. package/modules/status-ui/public/snapshots/.gitkeep +0 -0
  613. package/modules/status-ui/public/status.js +1375 -0
  614. package/modules/status-ui/public/style.css +1342 -0
  615. package/package-lock.json +975 -0
  616. package/package.json +28 -0
  617. package/public-docs/index.html +35 -0
  618. package/public-docs/redoc.standalone.js +1838 -0
  619. package/public-docs/redoc.standalone.js.LICENSE.txt +102 -0
  620. package/public-landing/buddha.png +0 -0
  621. package/public-landing/create.html +868 -0
  622. package/public-landing/index.html +168 -0
  623. package/scripts/bongos-mcp.js +28 -0
  624. package/scripts/cron/style_guide_audit.sh +134 -0
  625. package/scripts/discord/README.md +52 -0
  626. package/scripts/discord/lib.js +80 -0
  627. package/scripts/discord/post.js +51 -0
  628. package/scripts/gds/CLAUDE.md +144 -0
  629. package/scripts/gds/abandon.js +58 -0
  630. package/scripts/gds/adopt-detect.js +123 -0
  631. package/scripts/gds/adopt-import.js +111 -0
  632. package/scripts/gds/adopt-preflight.js +121 -0
  633. package/scripts/gds/api.js +78 -0
  634. package/scripts/gds/architect-audit.js +288 -0
  635. package/scripts/gds/art-stage.js +152 -0
  636. package/scripts/gds/audit-authorship.sh +243 -0
  637. package/scripts/gds/audit-deps.js +121 -0
  638. package/scripts/gds/audit-exports.js +128 -0
  639. package/scripts/gds/audit-replay.sh +161 -0
  640. package/scripts/gds/audit-ships.js +251 -0
  641. package/scripts/gds/autonomy-gate.js +135 -0
  642. package/scripts/gds/backfill-cost.js +165 -0
  643. package/scripts/gds/backfill-sessions.js +351 -0
  644. package/scripts/gds/backfill-task-rewards.js +408 -0
  645. package/scripts/gds/backup.js +94 -0
  646. package/scripts/gds/bfg-principal-token.js +65 -0
  647. package/scripts/gds/box-auth-check.js +160 -0
  648. package/scripts/gds/box-connect-lib.js +453 -0
  649. package/scripts/gds/box.js +1258 -0
  650. package/scripts/gds/build-bongos.js +94 -0
  651. package/scripts/gds/capture.js +123 -0
  652. package/scripts/gds/cf-tunnel.js +419 -0
  653. package/scripts/gds/ci-grade.js +82 -0
  654. package/scripts/gds/claim-recall.js +112 -0
  655. package/scripts/gds/claim.js +333 -0
  656. package/scripts/gds/classify-discipline.js +153 -0
  657. package/scripts/gds/claude-materialize.js +176 -0
  658. package/scripts/gds/cleanup-orphans.js +74 -0
  659. package/scripts/gds/cli-lib.js +518 -0
  660. package/scripts/gds/code.js +101 -0
  661. package/scripts/gds/codemod-rename-src-gds.js +145 -0
  662. package/scripts/gds/conductor-dispatch.js +426 -0
  663. package/scripts/gds/context-pack.js +228 -0
  664. package/scripts/gds/coreB-carve-proof.sh +716 -0
  665. package/scripts/gds/cost.js +47 -0
  666. package/scripts/gds/db-backup-nightly.sh +160 -0
  667. package/scripts/gds/db-backup-offsite.sh +152 -0
  668. package/scripts/gds/demote.js +40 -0
  669. package/scripts/gds/design-sync.js +62 -0
  670. package/scripts/gds/diagnose-achievements.js +118 -0
  671. package/scripts/gds/diagram-facts.js +319 -0
  672. package/scripts/gds/discipline-modes.json +25 -0
  673. package/scripts/gds/discord-channels.js +66 -0
  674. package/scripts/gds/do-api.js +176 -0
  675. package/scripts/gds/docs-entropy.js +403 -0
  676. package/scripts/gds/doctor.js +389 -0
  677. package/scripts/gds/feedback-latest.js +94 -0
  678. package/scripts/gds/fetch-art-key.js +106 -0
  679. package/scripts/gds/fetch-sound-prefs.js +88 -0
  680. package/scripts/gds/figma-design-sync.js +61 -0
  681. package/scripts/gds/fitness.js +1446 -0
  682. package/scripts/gds/gate-review.js +322 -0
  683. package/scripts/gds/gating.js +325 -0
  684. package/scripts/gds/gds-db-backup.service +24 -0
  685. package/scripts/gds/gds-db-backup.timer +20 -0
  686. package/scripts/gds/gds-db-offsite.service +29 -0
  687. package/scripts/gds/gds-db-offsite.timer +18 -0
  688. package/scripts/gds/gen-api-client.js +508 -0
  689. package/scripts/gds/gen-api-docs.js +1037 -0
  690. package/scripts/gds/gen-atlas.js +366 -0
  691. package/scripts/gds/gen-diagrams.js +608 -0
  692. package/scripts/gds/gen-file-map.js +196 -0
  693. package/scripts/gds/gen-repo-map.js +519 -0
  694. package/scripts/gds/gen-session-index.js +210 -0
  695. package/scripts/gds/git-merge-regen.js +147 -0
  696. package/scripts/gds/grade-smoke.js +205 -0
  697. package/scripts/gds/hooks/pre-push.js +169 -0
  698. package/scripts/gds/http-api-client.js +88 -0
  699. package/scripts/gds/init.js +903 -0
  700. package/scripts/gds/install-git-hooks.js +114 -0
  701. package/scripts/gds/key-card.js +213 -0
  702. package/scripts/gds/key-status.js +126 -0
  703. package/scripts/gds/land-watch.js +168 -0
  704. package/scripts/gds/learning-capture.js +145 -0
  705. package/scripts/gds/lib.sh +44 -0
  706. package/scripts/gds/linkify-refs.js +473 -0
  707. package/scripts/gds/local-preview-lib.js +159 -0
  708. package/scripts/gds/local-preview.js +95 -0
  709. package/scripts/gds/login.js +225 -0
  710. package/scripts/gds/main-audit.js +279 -0
  711. package/scripts/gds/me.js +88 -0
  712. package/scripts/gds/memory-map.js +174 -0
  713. package/scripts/gds/merge-lock.js +71 -0
  714. package/scripts/gds/migration-namespace.js +200 -0
  715. package/scripts/gds/mirror-lineage-check.js +319 -0
  716. package/scripts/gds/mirror-redact.js +305 -0
  717. package/scripts/gds/module.js +482 -0
  718. package/scripts/gds/newcomer-floor.config.json +13 -0
  719. package/scripts/gds/newcomer-floor.js +415 -0
  720. package/scripts/gds/newcomer-floor.templates.json +86 -0
  721. package/scripts/gds/newcomer-floor.test.js +235 -0
  722. package/scripts/gds/next-number.js +163 -0
  723. package/scripts/gds/oauth-secret.js +197 -0
  724. package/scripts/gds/onboard.js +217 -0
  725. package/scripts/gds/onboarding-analyze.js +226 -0
  726. package/scripts/gds/onboarding-config.js +178 -0
  727. package/scripts/gds/onboarding-ship.js +92 -0
  728. package/scripts/gds/package-core.js +684 -0
  729. package/scripts/gds/paste-token.js +131 -0
  730. package/scripts/gds/portability-smoke-art.sh +85 -0
  731. package/scripts/gds/portability-smoke-memory.sh +147 -0
  732. package/scripts/gds/provision.js +1324 -0
  733. package/scripts/gds/publish-manifest.js +307 -0
  734. package/scripts/gds/pulse.js +309 -0
  735. package/scripts/gds/push-main.js +45 -0
  736. package/scripts/gds/read-session-export.js +359 -0
  737. package/scripts/gds/reauth.js +149 -0
  738. package/scripts/gds/recall.js +135 -0
  739. package/scripts/gds/release.js +71 -0
  740. package/scripts/gds/render-ideas.js +173 -0
  741. package/scripts/gds/repo-metrics.js +363 -0
  742. package/scripts/gds/resolve-skill-model.js +57 -0
  743. package/scripts/gds/run-routine.js +197 -0
  744. package/scripts/gds/run-unit-tests.js +178 -0
  745. package/scripts/gds/sandbox-stage.js +653 -0
  746. package/scripts/gds/search-ingest-db.js +209 -0
  747. package/scripts/gds/search-ingest-md.js +225 -0
  748. package/scripts/gds/security-baseline-check.sh +180 -0
  749. package/scripts/gds/seed-adopt-tasks.js +75 -0
  750. package/scripts/gds/seed-api-contract-goal-tasks.js +141 -0
  751. package/scripts/gds/seed-bongos-app-tasks.js +294 -0
  752. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +81 -0
  753. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +100 -0
  754. package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +307 -0
  755. package/scripts/gds/seed-bongos-module-system-tasks.js +346 -0
  756. package/scripts/gds/seed-bongos-tasks.js +214 -0
  757. package/scripts/gds/seed-gds-v4-tasks.js +624 -0
  758. package/scripts/gds/seed-governance-tasks.js +340 -0
  759. package/scripts/gds/seed-medusa-tasks.js +440 -0
  760. package/scripts/gds/seed-module-upstreaming.js +219 -0
  761. package/scripts/gds/seed-productization-tasks.js +235 -0
  762. package/scripts/gds/seed-provisioning-tasks.js +83 -0
  763. package/scripts/gds/seed-staging.sh +104 -0
  764. package/scripts/gds/seed-v2-world-tasks.js +283 -0
  765. package/scripts/gds/seed-v3-tasks.js +1981 -0
  766. package/scripts/gds/session-cost.js +393 -0
  767. package/scripts/gds/session-digest.js +179 -0
  768. package/scripts/gds/session-eval.js +576 -0
  769. package/scripts/gds/session.js +404 -0
  770. package/scripts/gds/setup.js +504 -0
  771. package/scripts/gds/shell.js +100 -0
  772. package/scripts/gds/ship.js +3618 -0
  773. package/scripts/gds/smoke-batch-claim.sh +213 -0
  774. package/scripts/gds/smoke-batch-release.sh +296 -0
  775. package/scripts/gds/smoke-box.sh +150 -0
  776. package/scripts/gds/smoke-claim-consistency.sh +212 -0
  777. package/scripts/gds/smoke-dependencies.sh +84 -0
  778. package/scripts/gds/smoke-gds.js +125 -0
  779. package/scripts/gds/smoke-write.sh +168 -0
  780. package/scripts/gds/start.js +782 -0
  781. package/scripts/gds/status.js +365 -0
  782. package/scripts/gds/triage.js +366 -0
  783. package/scripts/gds/upgrade.js +421 -0
  784. package/scripts/gds/validate-design.js +254 -0
  785. package/scripts/gds/version-close.js +549 -0
  786. package/scripts/migrate.sh +183 -0
  787. package/scripts/migrate_cost_ledger.sh +178 -0
  788. package/scripts/public-mirror-export.js +291 -0
  789. package/scripts/render-diagrams.sh +88 -0
  790. package/scripts/security/dep-audit.js +276 -0
  791. package/scripts/setup-builder.js +274 -0
  792. package/scripts/setup-builder.sh +28 -0
  793. package/scripts/snapshots/backfill-history.mjs +292 -0
  794. package/scripts/snapshots/maybe-render-on-deploy.sh +66 -0
  795. package/scripts/snapshots/render-pre-art-eras.mjs +329 -0
  796. package/scripts/snapshots/render-world.mjs +322 -0
  797. package/scripts/status-mirror-sync.js +192 -0
  798. package/scripts/status-probe.mjs +185 -0
  799. package/server.js +212 -0
  800. package/src/asset-version.js +71 -0
  801. package/src/bongos/CLAUDE.md +64 -0
  802. package/src/bongos/api-errors.js +281 -0
  803. package/src/bongos/api-path-404.js +67 -0
  804. package/src/bongos/api-prefix.js +38 -0
  805. package/src/bongos/app-pair.js +172 -0
  806. package/src/bongos/auth.js +979 -0
  807. package/src/bongos/cascade-dispatch.js +123 -0
  808. package/src/bongos/db-kernel.js +252 -0
  809. package/src/bongos/db.js +911 -0
  810. package/src/bongos/goal-scope-check.js +120 -0
  811. package/src/bongos/hierarchy-config.js +189 -0
  812. package/src/bongos/live-channel.js +145 -0
  813. package/src/bongos/llm-cache.js +260 -0
  814. package/src/bongos/llm-pricing.js +220 -0
  815. package/src/bongos/metrics.js +286 -0
  816. package/src/bongos/middleware/audit.js +274 -0
  817. package/src/bongos/middleware/error-envelope.js +93 -0
  818. package/src/bongos/middleware/rate-limit.js +195 -0
  819. package/src/bongos/module-scope-map.js +271 -0
  820. package/src/bongos/optimizer.js +166 -0
  821. package/src/bongos/path-match.js +47 -0
  822. package/src/bongos/permission-path-check.js +248 -0
  823. package/src/bongos/pool.js +55 -0
  824. package/src/bongos/repo-info.js +91 -0
  825. package/src/bongos/route-rank-check.js +420 -0
  826. package/src/bongos/routes/CLAUDE.md +43 -0
  827. package/src/bongos/routes/_helpers.js +369 -0
  828. package/src/bongos/routes/audit-log.js +59 -0
  829. package/src/bongos/routes/auth.js +755 -0
  830. package/src/bongos/routes/backup.js +104 -0
  831. package/src/bongos/routes/builders.js +526 -0
  832. package/src/bongos/routes/healthz.js +16 -0
  833. package/src/bongos/routes/instance.js +129 -0
  834. package/src/bongos/routes/live.js +125 -0
  835. package/src/bongos/routes/llm-cache.js +119 -0
  836. package/src/bongos/routes/me.js +380 -0
  837. package/src/bongos/routes/modules.js +131 -0
  838. package/src/bongos/routes/optimizer.js +54 -0
  839. package/src/bongos/routes/public.js +476 -0
  840. package/src/bongos/routes/security.js +207 -0
  841. package/src/bongos/routes.js +166 -0
  842. package/src/bongos/secret-box.js +177 -0
  843. package/src/bongos/sensitive-surfaces.js +30 -0
  844. package/src/bongos/serve-internal.js +889 -0
  845. package/src/bongos/uptime-poller.js +90 -0
  846. package/src/bongos-downloads.js +70 -0
  847. package/src/branding.js +182 -0
  848. package/src/build-info.js +77 -0
  849. package/src/devbox-downloads.js +67 -0
  850. package/src/instance-config.js +200 -0
  851. package/src/module-api.js +366 -0
  852. package/src/module-loader/loader.js +268 -0
  853. package/src/module-loader/manifest-schema.js +140 -0
  854. package/src/module-loader/provenance.js +28 -0
  855. package/src/module-loader/semver.js +100 -0
  856. package/src/module-seams.js +291 -0
  857. package/src/modules.js +254 -0
  858. package/src/platform-server.js +135 -0
  859. package/src/ui/adapters/claude-design/index.js +333 -0
  860. package/src/ui/adapters/figma/index.js +328 -0
  861. package/tests/abandon_task.mjs +138 -0
  862. package/tests/achievements_reconcile.mjs +167 -0
  863. package/tests/adopt_detect.mjs +141 -0
  864. package/tests/adopt_import.mjs +132 -0
  865. package/tests/adopt_preflight.mjs +105 -0
  866. package/tests/anti_grid.mjs +89 -0
  867. package/tests/api_client.mjs +231 -0
  868. package/tests/api_docs.mjs +283 -0
  869. package/tests/api_error_envelope_buildcheck.mjs +56 -0
  870. package/tests/api_error_envelope_middleware.mjs +99 -0
  871. package/tests/api_error_registry.mjs +108 -0
  872. package/tests/api_pagination_contract.mjs +51 -0
  873. package/tests/api_path_404.mjs +96 -0
  874. package/tests/app_pair.mjs +168 -0
  875. package/tests/architect.mjs +140 -0
  876. package/tests/art_key.mjs +121 -0
  877. package/tests/art_stage.mjs +121 -0
  878. package/tests/asset_version.mjs +94 -0
  879. package/tests/atlas.mjs +69 -0
  880. package/tests/audit_deps.mjs +74 -0
  881. package/tests/audit_middleware.mjs +385 -0
  882. package/tests/auth_admission_gate.mjs +164 -0
  883. package/tests/auth_anthropic_identity.mjs +95 -0
  884. package/tests/auth_duplicate_cookie.mjs +56 -0
  885. package/tests/auth_error_brand.mjs +77 -0
  886. package/tests/auth_flow_slice1.mjs +223 -0
  887. package/tests/auth_inactive_builder.mjs +94 -0
  888. package/tests/auth_page_gate.mjs +92 -0
  889. package/tests/auth_session_ttl.mjs +155 -0
  890. package/tests/autonomous_fit_protected_paths.mjs +115 -0
  891. package/tests/autonomy_gate.mjs +85 -0
  892. package/tests/autotile_variants.mjs +256 -0
  893. package/tests/autotile_xverify.mjs +133 -0
  894. package/tests/backfill_sessions.mjs +101 -0
  895. package/tests/backfill_task_rewards.mjs +152 -0
  896. package/tests/backup_cli.mjs +104 -0
  897. package/tests/bfg.mjs +327 -0
  898. package/tests/bfg_write.mjs +423 -0
  899. package/tests/bongos_box_connect.mjs +89 -0
  900. package/tests/bongos_dispatch.mjs +74 -0
  901. package/tests/bongos_downloads.mjs +118 -0
  902. package/tests/bongos_login.mjs +34 -0
  903. package/tests/box_access.mjs +186 -0
  904. package/tests/box_auth_check.mjs +114 -0
  905. package/tests/box_code_staleness.mjs +116 -0
  906. package/tests/box_connect_e2e.mjs +196 -0
  907. package/tests/box_cost.mjs +70 -0
  908. package/tests/box_dns_repoint.mjs +151 -0
  909. package/tests/box_host_keys.mjs +102 -0
  910. package/tests/box_onboard.mjs +317 -0
  911. package/tests/box_scope_session.mjs +115 -0
  912. package/tests/box_ship_permissions.mjs +71 -0
  913. package/tests/box_terminal_ssrf.mjs +90 -0
  914. package/tests/boxes.mjs +1255 -0
  915. package/tests/branding.mjs +88 -0
  916. package/tests/bug_attachments.mjs +189 -0
  917. package/tests/build_info.mjs +88 -0
  918. package/tests/builder_needs.mjs +99 -0
  919. package/tests/cap_newcomer_tasks.mjs +114 -0
  920. package/tests/cascade-dispatch.mjs +95 -0
  921. package/tests/cf_tunnel.mjs +459 -0
  922. package/tests/claim_recall.mjs +150 -0
  923. package/tests/claims_bind_session.mjs +47 -0
  924. package/tests/claude_materialize.mjs +148 -0
  925. package/tests/cli_box_scope.mjs +52 -0
  926. package/tests/cli_lib_formatters.mjs +87 -0
  927. package/tests/cli_token_reissue.mjs +147 -0
  928. package/tests/client_bundle_route.mjs +47 -0
  929. package/tests/cloud_bongos_pack.mjs +85 -0
  930. package/tests/conductor.mjs +496 -0
  931. package/tests/confirm_attribution.mjs +156 -0
  932. package/tests/conflict_resolve.mjs +462 -0
  933. package/tests/context_pack.mjs +240 -0
  934. package/tests/cost.mjs +94 -0
  935. package/tests/cost_audit.mjs +122 -0
  936. package/tests/cost_budget_status.mjs +78 -0
  937. package/tests/cost_reconcile.mjs +102 -0
  938. package/tests/cost_summary_shape.mjs +94 -0
  939. package/tests/credit_grant.mjs +376 -0
  940. package/tests/criterion_progress.mjs +220 -0
  941. package/tests/criterion_proposal.mjs +109 -0
  942. package/tests/criterion_ref_parse.mjs +53 -0
  943. package/tests/currency_label.mjs +119 -0
  944. package/tests/day_cycle.mjs +197 -0
  945. package/tests/dependencies_migration.mjs +77 -0
  946. package/tests/dependencies_polymorphic.mjs +212 -0
  947. package/tests/deploy_instance.mjs +78 -0
  948. package/tests/devbox_downloads.mjs +122 -0
  949. package/tests/diff_derived_signals.mjs +115 -0
  950. package/tests/discord_approvals.mjs +174 -0
  951. package/tests/discord_autojoin.mjs +158 -0
  952. package/tests/discord_bot.mjs +94 -0
  953. package/tests/discord_bugs.mjs +297 -0
  954. package/tests/discord_channels.mjs +337 -0
  955. package/tests/discord_foundation.mjs +76 -0
  956. package/tests/discord_inbound.mjs +190 -0
  957. package/tests/discord_message_buffer.mjs +87 -0
  958. package/tests/discord_oauth.mjs +55 -0
  959. package/tests/discord_reaction.mjs +170 -0
  960. package/tests/discord_role_sync.mjs +151 -0
  961. package/tests/display_name.mjs +123 -0
  962. package/tests/dns_preflight.mjs +74 -0
  963. package/tests/event_sound_prefs.mjs +194 -0
  964. package/tests/eviction_policy.mjs +279 -0
  965. package/tests/figma_adapter.mjs +199 -0
  966. package/tests/file_map.mjs +91 -0
  967. package/tests/first_admin_bootstrap.mjs +40 -0
  968. package/tests/fitness.mjs +435 -0
  969. package/tests/fitness_two_root.mjs +104 -0
  970. package/tests/fixtures/session-506-digest.json +34 -0
  971. package/tests/gate_approvals.mjs +451 -0
  972. package/tests/gate_review.mjs +152 -0
  973. package/tests/git_merge_regen.mjs +151 -0
  974. package/tests/github_push_ancestry.mjs +119 -0
  975. package/tests/github_push_land_proof.mjs +127 -0
  976. package/tests/github_push_merge_driver.mjs +175 -0
  977. package/tests/goal_abuse_matrix.mjs +187 -0
  978. package/tests/goal_achievement.mjs +146 -0
  979. package/tests/goal_conflicts.mjs +305 -0
  980. package/tests/goal_dependencies_read.mjs +73 -0
  981. package/tests/goal_member_roles.mjs +420 -0
  982. package/tests/goal_membership_requests.mjs +332 -0
  983. package/tests/goal_routes.mjs +203 -0
  984. package/tests/goal_scope_check.mjs +167 -0
  985. package/tests/goal_tier.mjs +312 -0
  986. package/tests/goal_wall_proof.mjs +112 -0
  987. package/tests/grade_attempts.mjs +73 -0
  988. package/tests/grade_attribution.mjs +117 -0
  989. package/tests/grade_diff_hash.mjs +191 -0
  990. package/tests/grade_server_authoritative.mjs +305 -0
  991. package/tests/grade_unavailable_display.mjs +66 -0
  992. package/tests/grader.mjs +1960 -0
  993. package/tests/grader_bypass.mjs +57 -0
  994. package/tests/grader_panel.mjs +252 -0
  995. package/tests/grader_prompt_fencing.mjs +192 -0
  996. package/tests/helpers.mjs +52 -0
  997. package/tests/hierarchy-config.mjs +81 -0
  998. package/tests/init.mjs +463 -0
  999. package/tests/instance_config.mjs +76 -0
  1000. package/tests/instance_manifest.mjs +110 -0
  1001. package/tests/interaction_prefs.mjs +72 -0
  1002. package/tests/key-card.mjs +110 -0
  1003. package/tests/key-status.mjs +45 -0
  1004. package/tests/land_watch.mjs +115 -0
  1005. package/tests/lifecycle-card.mjs +145 -0
  1006. package/tests/lifecycle_breakdown_view.mjs +236 -0
  1007. package/tests/linkify_refs.mjs +264 -0
  1008. package/tests/live_channel.mjs +128 -0
  1009. package/tests/live_sse.mjs +122 -0
  1010. package/tests/llm-cache-route.mjs +110 -0
  1011. package/tests/llm-cache.mjs +140 -0
  1012. package/tests/llm-pricing.mjs +152 -0
  1013. package/tests/local_preview.mjs +136 -0
  1014. package/tests/main_audit.mjs +137 -0
  1015. package/tests/memory_isolation.mjs +431 -0
  1016. package/tests/memory_map.mjs +107 -0
  1017. package/tests/memory_pull.mjs +429 -0
  1018. package/tests/merge_lease.mjs +100 -0
  1019. package/tests/merge_lock.mjs +312 -0
  1020. package/tests/metrics.mjs +147 -0
  1021. package/tests/migration_allocation.mjs +146 -0
  1022. package/tests/migration_namespace.mjs +185 -0
  1023. package/tests/migrations_fresh_replay_guard.mjs +38 -0
  1024. package/tests/mirror_lineage_fulltree.mjs +45 -0
  1025. package/tests/mirror_lineage_proof.mjs +72 -0
  1026. package/tests/mirror_redact.mjs +193 -0
  1027. package/tests/model_alloc_prefs.mjs +63 -0
  1028. package/tests/module-scope-map.mjs +88 -0
  1029. package/tests/module_api.mjs +110 -0
  1030. package/tests/module_cli.mjs +292 -0
  1031. package/tests/module_contributions.mjs +148 -0
  1032. package/tests/module_loader.mjs +286 -0
  1033. package/tests/module_manifest.mjs +194 -0
  1034. package/tests/module_owned_tests.mjs +105 -0
  1035. package/tests/module_provenance.mjs +34 -0
  1036. package/tests/module_route_rank.mjs +147 -0
  1037. package/tests/module_seams.mjs +68 -0
  1038. package/tests/modules.mjs +156 -0
  1039. package/tests/modules_route.mjs +38 -0
  1040. package/tests/newcomer_floor.mjs +17 -0
  1041. package/tests/newcomer_restock.mjs +80 -0
  1042. package/tests/next_number.mjs +154 -0
  1043. package/tests/oauth_secret.mjs +60 -0
  1044. package/tests/onboard.mjs +70 -0
  1045. package/tests/onboarding_gate.mjs +267 -0
  1046. package/tests/onboarding_observability.mjs +344 -0
  1047. package/tests/onboarding_route_signals.mjs +175 -0
  1048. package/tests/onboarding_state.mjs +346 -0
  1049. package/tests/one_active_claim_per_session.mjs +111 -0
  1050. package/tests/orphaned_claim_ship.mjs +135 -0
  1051. package/tests/override_attribution.mjs +142 -0
  1052. package/tests/override_request_ownership.mjs +235 -0
  1053. package/tests/package_core.mjs +435 -0
  1054. package/tests/parallel-load.mjs +402 -0
  1055. package/tests/path_match.mjs +62 -0
  1056. package/tests/permission_path.mjs +151 -0
  1057. package/tests/platform_boot.mjs +167 -0
  1058. package/tests/pre_compact.mjs +60 -0
  1059. package/tests/preview_server.mjs +127 -0
  1060. package/tests/profile_route.mjs +197 -0
  1061. package/tests/provision.mjs +805 -0
  1062. package/tests/provisioning_github_app_routes.mjs +98 -0
  1063. package/tests/public_mirror_export.mjs +124 -0
  1064. package/tests/public_task_resolver.mjs +112 -0
  1065. package/tests/publish_branch_route.mjs +422 -0
  1066. package/tests/publish_manifest.mjs +184 -0
  1067. package/tests/publish_reconciler.mjs +728 -0
  1068. package/tests/rank_gate.mjs +463 -0
  1069. package/tests/rate_limit_public.mjs +217 -0
  1070. package/tests/read_session_export.mjs +89 -0
  1071. package/tests/recall_cli.mjs +82 -0
  1072. package/tests/recall_hints.mjs +119 -0
  1073. package/tests/recent_shipped_window.mjs +80 -0
  1074. package/tests/regrade_eligibility.mjs +202 -0
  1075. package/tests/render_prefs.mjs +122 -0
  1076. package/tests/repo_map.mjs +92 -0
  1077. package/tests/reward_gate.mjs +284 -0
  1078. package/tests/route_rank_check.mjs +243 -0
  1079. package/tests/route_validation.mjs +490 -0
  1080. package/tests/routine_timers.mjs +72 -0
  1081. package/tests/rubric_fixtures.mjs +140 -0
  1082. package/tests/run_routine.mjs +69 -0
  1083. package/tests/sandbox_stage.mjs +582 -0
  1084. package/tests/scrubber_corpus.mjs +257 -0
  1085. package/tests/search_chunker.mjs +209 -0
  1086. package/tests/search_ingest.mjs +96 -0
  1087. package/tests/search_ingest_db.mjs +88 -0
  1088. package/tests/search_isolation.mjs +204 -0
  1089. package/tests/search_route.mjs +95 -0
  1090. package/tests/secret_box.mjs +189 -0
  1091. package/tests/security_docs.mjs +186 -0
  1092. package/tests/security_route.mjs +108 -0
  1093. package/tests/served_paths_shipped.mjs +118 -0
  1094. package/tests/session-cards.mjs +142 -0
  1095. package/tests/session_506_regression.mjs +69 -0
  1096. package/tests/session_caps.mjs +238 -0
  1097. package/tests/session_cost.mjs +133 -0
  1098. package/tests/session_digest.mjs +73 -0
  1099. package/tests/session_eval.mjs +386 -0
  1100. package/tests/session_index.mjs +105 -0
  1101. package/tests/session_records.mjs +369 -0
  1102. package/tests/session_search.mjs +78 -0
  1103. package/tests/session_start_freshness.mjs +123 -0
  1104. package/tests/setup_smoke.mjs +154 -0
  1105. package/tests/ship_autolinkify.mjs +60 -0
  1106. package/tests/ship_automerge_injection.mjs +174 -0
  1107. package/tests/ship_broadcast_routing.mjs +125 -0
  1108. package/tests/ship_broadcast_server.mjs +175 -0
  1109. package/tests/ship_card.mjs +280 -0
  1110. package/tests/ship_ci_deploy.mjs +374 -0
  1111. package/tests/ship_preflight.mjs +368 -0
  1112. package/tests/ship_premerge.mjs +75 -0
  1113. package/tests/ship_resume.mjs +129 -0
  1114. package/tests/ship_upload_skip.mjs +89 -0
  1115. package/tests/ship_zero_commit.mjs +60 -0
  1116. package/tests/single_host_hall.mjs +98 -0
  1117. package/tests/skill_prefs.mjs +150 -0
  1118. package/tests/smoke_preflight.mjs +66 -0
  1119. package/tests/snapshot_picker.mjs +233 -0
  1120. package/tests/sound_prefs.mjs +198 -0
  1121. package/tests/sprite_facing.mjs +35 -0
  1122. package/tests/status-probe.mjs +89 -0
  1123. package/tests/status_backfill.mjs +94 -0
  1124. package/tests/stop_refcheck.mjs +127 -0
  1125. package/tests/streak.mjs +175 -0
  1126. package/tests/subdomain_auth.mjs +58 -0
  1127. package/tests/task_classifier_vocab.mjs +41 -0
  1128. package/tests/task_create_idempotency.mjs +96 -0
  1129. package/tests/task_goal_link.mjs +93 -0
  1130. package/tests/task_ownership_gate.mjs +125 -0
  1131. package/tests/terrain_picker.mjs +298 -0
  1132. package/tests/touches_overlap.mjs +75 -0
  1133. package/tests/triage_development.mjs +140 -0
  1134. package/tests/turn_in_place.mjs +280 -0
  1135. package/tests/upgrade.mjs +357 -0
  1136. package/tests/verify_task_guard.mjs +64 -0
  1137. package/tests/version_close.mjs +76 -0
  1138. package/tests/versions_route.mjs +93 -0
  1139. package/tests/walkability.mjs +188 -0
  1140. package/tests/wandering_prefs.mjs +176 -0
  1141. package/tests/worktree_disambiguation.mjs +105 -0
  1142. package/tests/worktree_guard.mjs +90 -0
@@ -0,0 +1,48 @@
1
+ # `economy` module — credits, cost ledger, streaks, achievements, leaderboard + the `reward` kernel port
2
+
3
+ > The **third CORE-domain** carved into a module (BV1.R77, [ADR 0093](../../docs/adr/<redacted>.md) §1-2) — after memory (R72) and grading (R73). Like grading, it follows ADR 0091 §4's load-bearing pattern: **keep the lifecycle state machine whole, extract the capability it invokes behind a kernel seam.** The lifecycle no longer imports the credit/achievement code directly; it resolves a `reward` PORT this module registers.
4
+
5
+ Owns the **builder economy**: the cost-plus + kind-multiplier credit-allocation model (the real-money credit ledger), the idea-promotion bonus, the flat session-token reward, the net-negative (simplification) ship bonus, the cost ledger + dashboard rollups, builder streaks, achievements/gamification, and the leaderboard. `default: true` in `module.json` — every instance rewards its own builders, so it mounts unconditionally unless explicitly disabled.
6
+
7
+ ## The boundary (the one rule)
8
+
9
+ This module reaches core **only** through the published doorway `../../src/module-api.js` (`coreVersion ^1.7.0` — it needs the R77 doorway addition: `llmPricing`, the shared token→USD pricing lib). It must **never** `require()` a core internal directly, and never another module. Core, in turn, must never `require()` a file in here — it reaches economy only through the `reward` port (below). Both directions are enforced by the BV1.R44/R45 fitness checks; R70's `kernel-imports-no-domain` check keeps the kernel from reaching back in.
10
+
11
+ ## The `reward` kernel PORT (ADR 0093 §1-2 — the headline of this carve)
12
+
13
+ - **Provides — port `reward`** → the economy module's reward surface (`modules/economy/reward.js`). Registered in `routes/reward.js`'s factory (the loader runs it at boot, and again whenever a test rebuilds the GDS router — `hasProvider`-guarded so re-instantiation never trips the single-provider duplicate guard).
14
+ - **It is a TRANSACTION-PARTICIPANT port** (unlike the stateless `grade` port): the credit-allocation methods (`insertMultipliedConfirmCredit`, `maybeAwardIdeaPromotionBonus`, `awardNetNegativeBonus`, `awardSessionTokenReward`) and the claim/ship gamification hooks (`evaluateAfterClaim/Ship/CreditAward`) take the **caller's tx `client` as the first arg**. The core lifecycle opens the `withTx`, runs the state-machine SQL (FOR UPDATE, `task_grades` upsert, `UPDATE tasks status`, claim-holder lookup, `logGradeAttempt`) itself, and calls `reward.*(client, …)` inside that same transaction — so the credit write commits atomically with the status flip. Extract the capability; keep the state machine (ADR 0091 §4).
15
+ - **Core consumes it WITHOUT importing this module:**
16
+ - the LIFECYCLE — `db.applyGrade` / `db.confirmTask` / `db.decideOverrideRequest` / `db.claimTask` / `db.upsertSessionRecordWithReward` resolve it via `seams.resolveOptional('reward')` and call the credit/achievement methods inside their own `withTx`.
17
+ - the READ routes — `routes/me.js` (achievement getters + streak preview + `getBuilderCostStatus`), `routes/public.js` (`costSummary` + `getLeaderboardWithAchievements`), `routes/builders.js` (`setBuilderMonthlyBudget`), `routes/sessions.js` (`sumCreditsForTasks`), and `publish-reconciler.js` (`reconcileSessionCosts`) resolve the same port and call its read surface. economy registers ONE port; its provider exposes both the lifecycle methods and the read surface (the grading precedent registers the whole module surface on its single port too).
18
+ - This replaced the former `const achievements = require('./achievements')` / `cost` / `cost-summary-shape` core→domain requires in `db.js`, the `db.leaderboard`/`db.logCost`/etc. monolith helpers, and the `require('../streak')` core-route imports.
19
+
20
+ ## Files
21
+
22
+ | File | What |
23
+ |---|---|
24
+ | `credits.js` | the credit-allocation model: `KIND_MULTIPLIERS`/`IDEA_BONUS_FRACTION`/`REWARD_MARGIN_PCT`, `applyKindMultiplier`, `computeSessionTokenReward`, `insertMultipliedConfirmCredit`, `maybeAwardIdeaPromotionBonus`, `awardSessionTokenReward`, `awardNetNegativeBonus` (+ `NET_NEGATIVE_BONUS`/`SUBTRACTOR_THRESHOLD`/`netNegativeBonusAmount`), the `leaderboard`, and `sumCreditsForTasks`. Writes `credit_log`. |
25
+ | `cost.js` | the cost ledger: `logCost` (the one `cost_log` writer), `reconcileSessionCosts`, `costSummary`/`costCalibrationSummary`, `getBuilderCostStatus`, `setBuilderMonthlyBudget`, `autonomousApiSpendMtd`. |
26
+ | `cost-classify.js` | pure cost-attribution audit + budget classification (`classifyCostStatus`, `auditCostAttribution`, `formatAuditReport`, `OWNERLESS_CATEGORIES`, `SOFT_CAP_FRACTION`). Moved from `src/bongos/cost.js` (renamed to avoid colliding with `cost.js`). |
27
+ | `cost-summary-shape.js` | pure cost-summary dimension shapers (`shapeBySource`/`shapeByTier`/`shapeSavings`/`shapeCostCalibration`). |
28
+ | `streak.js` | streak math + anti-gaming guards (`computeStreak`, `wouldExtendStreak`, …). Reaches the shared pool through the doorway. |
29
+ | `achievements.js` | the achievement evaluators (`evaluateAfterClaim/Ship/CreditAward`, `alreadyUnlocked`, `unlockAchievement`, `filesForBadges`) PLUS the getter slice moved from `db.js` (`listAchievements`, `getBuilderAchievements`, `getLeaderboardWithAchievements`, `getLockedAchievementsProgress`, `renderProgressText`). `require('./streak')` is an intra-module sibling. |
30
+ | `reward.js` | the `reward` port provider surface — DELEGATES (does not spread) to `credits`/`achievements`/`cost`/`streak` so test stubs bite at call time. |
31
+ | `routes/reward.js` | registers the `reward` port (above); no HTTP endpoint. |
32
+ | `routes/cost.js` | `POST /cost` — log a cost row (idempotent). Reaches auth/validators via the doorway; the writer via `../cost`. |
33
+ | `routes/leaderboard.js` | `GET /leaderboard` — public drachmae-ordered leaderboard, via `../credits`. |
34
+
35
+ ## NOT in this module (deliberately left in core)
36
+
37
+ - **`llm-pricing.js`** — the shared token→USD pricing lib stays core shared LLM-cost infra (consumed by BOTH this module's reward/cost paths AND core cost scripts `ship.js`/`session-cost.js`, so it can't be economy-owned). It is exposed to this module on the doorway as `api.llmPricing` (a tracked R73-style domain leak, like `api.llmCache`). It relocates behind a port if/when an llm-infra domain is carved (tranche 2). The economy scope-map glob lists `src/bongos/llm-pricing.js` for task-affinity even though the FILE stays in core.
38
+ - **The recent-ships feed + estimation-drift + grade-trend reads** (`db.recentShippedTasks`, `<redacted>`, `getEstVsActualRatio`, `estimationDriftSummary`, `recentGradesForBuilder`, `builderRollingAvgGrade`, `rollingAvgGrade`, `gradeTrendByDay`) — these stay `db.*` (lifecycle/sessions reads, not economy ledger SQL); out of scope for this carve.
39
+ - **The karma feed** (`recentKarmaForBuilder`, `karmaDelta30d`, `karma_log`) — stays in core `db.js` (a separate social-signal domain).
40
+ - **The economy-owned CLIs** — a command travels with its domain but stays under `scripts/`: `backfill-cost.js` (requires `../../modules/economy/cost-classify`), `diagnose-achievements.js` (requires `../../modules/economy/streak`). (The memory/grading-carve precedent.)
41
+
42
+ ## Tables
43
+
44
+ None owned. `credit_log`, `cost_log`, `cost_baseline`, `achievements`, `builder_achievements` (+ their migrations) were created before the module system and stay in core `migrations/` (the schema-migrations stem-key makes a later relocation a no-op). The module owns the *queries*; any **new** economy migration belongs in `modules/economy/migrations/` namespaced `economy_*` (the additive rule).
45
+
46
+ ## Tests
47
+
48
+ `tests/credit_grant.mjs` (credits.js), `tests/cost.mjs`/`tests/cost_audit.mjs`/`tests/cost_budget_status.mjs` (cost-classify.js), `tests/cost_summary_shape.mjs`, `tests/streak.mjs`, and `tests/diff_derived_signals.mjs` import from `modules/economy/…`. The lifecycle-attribution tests (`tests/grade_attribution.mjs`, `tests/confirm_attribution.mjs`, `tests/grade_server_authoritative.mjs`, `tests/override_attribution.mjs`, `tests/override_request_ownership.mjs`) register the `reward` port (and stub `achievements` on the live module object) before driving `db.applyGrade`/`confirmTask`/`decideOverrideRequest`. See ADR 0093.
@@ -0,0 +1,594 @@
1
+ 'use strict';
2
+
3
+ // Achievement evaluation — runs inside existing DB transactions so unlocks
4
+ // are atomic with the action that triggered them.
5
+ //
6
+ // Three entry points, each called by the relevant route:
7
+ // evaluateAfterClaim(client, builderId, claimId)
8
+ // evaluateAfterShip(client, builderId, taskId)
9
+ // evaluateAfterCreditAward(client, builderId, totalBefore, totalAfter)
10
+ //
11
+ // Each returns an array of { id, name, credit_bonus } for achievements just
12
+ // unlocked in this call — the route adds them to its API response as
13
+ // just_unlocked.
14
+
15
+ const streak = require('./streak');
16
+ // Carved into modules/economy/ (BV1.R77 / ADR 0093 §1-2): the achievement GETTER
17
+ // slice (listAchievements/getBuilderAchievements/getLeaderboardWithAchievements/
18
+ // getLockedAchievementsProgress/renderProgressText), moved from src/bongos/db.js,
19
+ // reads the shared pool through the published doorway — a module never requires a
20
+ // core internal. The evaluators above take a tx `client` from the caller.
21
+ const { pool } = require('../../src/module-api');
22
+
23
+ async function alreadyUnlocked(client, builderId, achievementId) {
24
+ const r = await client.query(
25
+ 'SELECT 1 FROM builder_achievements WHERE builder_id=$1 AND achievement_id=$2',
26
+ [builderId, achievementId]
27
+ );
28
+ return r.rowCount > 0;
29
+ }
30
+
31
+ async function unlockAchievement(client, builderId, achievementId, taskId) {
32
+ const ach = await client.query(
33
+ 'SELECT id, name, credit_bonus FROM achievements WHERE id=$1',
34
+ [achievementId]
35
+ );
36
+ if (ach.rowCount === 0) return null;
37
+ const { id, name, credit_bonus } = ach.rows[0];
38
+
39
+ await client.query(
40
+ `INSERT INTO builder_achievements (builder_id, achievement_id, unlocked_at, unlocked_by_task_id)
41
+ VALUES ($1, $2, now(), $3)
42
+ ON CONFLICT DO NOTHING`,
43
+ [builderId, id, taskId ?? null]
44
+ );
45
+
46
+ if (credit_bonus > 0) {
47
+ await client.query(
48
+ `INSERT INTO credit_log (builder_id, task_id, delta, reason, recorded_at)
49
+ VALUES ($1, $2, $3, $4, now())`,
50
+ [builderId, taskId ?? null, credit_bonus, `achievement.${id}`]
51
+ );
52
+ // trigger on credit_log bumps builders.total_credits automatically
53
+ }
54
+
55
+ return { id, name, credit_bonus };
56
+ }
57
+
58
+ async function evaluateAfterClaim(client, builderId, _claimId) {
59
+ const results = [];
60
+
61
+ // first-claim: this is the builder's very first claim
62
+ if (!await alreadyUnlocked(client, builderId, 'first-claim')) {
63
+ const count = await client.query(
64
+ 'SELECT COUNT(*) FROM claims WHERE builder_id=$1',
65
+ [builderId]
66
+ );
67
+ if (Number(count.rows[0].count) === 1) {
68
+ const unlocked = await unlockAchievement(client, builderId, 'first-claim', null);
69
+ if (unlocked) results.push(unlocked);
70
+ }
71
+ }
72
+
73
+ return results;
74
+ }
75
+
76
+ // touches[] cleanup [3/8] (task 878): the prefix-keyed shipper badges should
77
+ // reflect what was ACTUALLY shipped, not the predicted touches[]. ship.js
78
+ // computes the committed changed-files for the grader (touches-independent per
79
+ // #536) and passes them through /grade → applyGrade → here as `changedFiles`.
80
+ // When that list is present we key the badges off it; otherwise we fall back to
81
+ // the task's touches[] (manual confirms, older callers, or a ship with no diff
82
+ // info). Once #882 backfills touches[] from the committed diff at ship time the
83
+ // fallback itself becomes diff-accurate, so the two converge.
84
+ function filesForBadges(changedFiles, touches) {
85
+ return Array.isArray(changedFiles) && changedFiles.length > 0
86
+ ? changedFiles
87
+ : Array.isArray(touches) ? touches : [];
88
+ }
89
+
90
+ async function evaluateAfterShip(client, builderId, taskId, changedFiles = null) {
91
+ const results = [];
92
+
93
+ // first-ship: this is the builder's very first ship.
94
+ //
95
+ // BUG FIX (PMS-V2 #190, 2026-05-11): originally queried session_logs and
96
+ // compared `=== 1`. That was wrong because the session_logs row for THIS
97
+ // ship is INSERTed in db.js AFTER evaluateAfterShip returns (line ~614),
98
+ // so at evaluator time the count reflects only PRIOR ships. The first
99
+ // ship therefore had count===0, never matched `=== 1`, and the
100
+ // achievement never fired.
101
+ //
102
+ // Switched to claims.outcome='shipped' (the claim row HAS been UPDATEd
103
+ // to outcome='shipped' + released_at=now() before this evaluator runs,
104
+ // per db.js line ~540) and check `=== 1` — the just-shipped claim is
105
+ // the only matching row, meaning this is the first ship.
106
+ if (!await alreadyUnlocked(client, builderId, 'first-ship')) {
107
+ const count = await client.query(
108
+ `SELECT COUNT(*) FROM claims
109
+ WHERE builder_id=$1 AND outcome='shipped'`,
110
+ [builderId]
111
+ );
112
+ if (Number(count.rows[0].count) === 1) {
113
+ const unlocked = await unlockAchievement(client, builderId, 'first-ship', taskId);
114
+ if (unlocked) results.push(unlocked);
115
+ }
116
+ }
117
+
118
+ // art-pipeline-shipper: the shipped diff includes art/ (falls back to touches[]).
119
+ if (!await alreadyUnlocked(client, builderId, 'art-pipeline-shipper')) {
120
+ const task = await client.query(
121
+ 'SELECT touches FROM tasks WHERE id=$1',
122
+ [taskId]
123
+ );
124
+ if (task.rowCount > 0) {
125
+ const files = filesForBadges(changedFiles, task.rows[0].touches || []);
126
+ if (files.some((t) => t.startsWith('art/'))) {
127
+ const unlocked = await unlockAchievement(client, builderId, 'art-pipeline-shipper', taskId);
128
+ if (unlocked) results.push(unlocked);
129
+ }
130
+ }
131
+ }
132
+
133
+ // gds-shipper: the shipped diff includes src/bongos/ or scripts/gds/ (falls back to touches[]).
134
+ if (!await alreadyUnlocked(client, builderId, 'gds-shipper')) {
135
+ const task = await client.query(
136
+ 'SELECT touches FROM tasks WHERE id=$1',
137
+ [taskId]
138
+ );
139
+ if (task.rowCount > 0) {
140
+ const files = filesForBadges(changedFiles, task.rows[0].touches || []);
141
+ if (files.some((t) => t.startsWith('src/bongos/') || t.startsWith('scripts/gds/'))) {
142
+ const unlocked = await unlockAchievement(client, builderId, 'gds-shipper', taskId);
143
+ if (unlocked) results.push(unlocked);
144
+ }
145
+ }
146
+ }
147
+
148
+ // first-parallel-claim (strict): two of this builder's claims overlapped on
149
+ // the wall clock AND both shipped successfully. Awarded on the LATER of the
150
+ // two ships. Called from inside resolveClaim's transaction after the current
151
+ // claim has been resolved with outcome='shipped' and released_at=now(), so
152
+ // both legs of the pair are visible to this query.
153
+ //
154
+ // Locked definition (PMS-V2 planning, limitations/pms-v2.md):
155
+ // - outcome='shipped' required on BOTH claims (abandoned/partial don't count)
156
+ // - claim intervals must overlap: tstzrange(A) && tstzrange(B)
157
+ // - unlocked_by_task_id = the second-shipped claim's task_id
158
+ // - unlocked_at = the later released_at (handled by unlockAchievement's now())
159
+ if (!await alreadyUnlocked(client, builderId, 'first-parallel-claim')) {
160
+ // Find any pair of shipped claims by this builder whose intervals overlap.
161
+ // Pick the pair with the latest second-ship; report the second-shipped
162
+ // claim's task_id so the achievement is attributed to it.
163
+ const pair = await client.query(
164
+ `WITH shipped AS (
165
+ SELECT id, task_id, claimed_at, released_at
166
+ FROM claims
167
+ WHERE builder_id = $1
168
+ AND outcome = 'shipped'
169
+ AND released_at IS NOT NULL
170
+ )
171
+ SELECT b.task_id AS later_task_id
172
+ FROM shipped a
173
+ JOIN shipped b ON b.id <> a.id
174
+ WHERE tstzrange(a.claimed_at, a.released_at) && tstzrange(b.claimed_at, b.released_at)
175
+ AND b.released_at >= a.released_at
176
+ ORDER BY b.released_at DESC, a.released_at DESC
177
+ LIMIT 1`,
178
+ [builderId]
179
+ );
180
+ if (pair.rowCount > 0) {
181
+ const laterTaskId = pair.rows[0].later_task_id;
182
+ const unlocked = await unlockAchievement(client, builderId, 'first-parallel-claim', laterTaskId);
183
+ if (unlocked) results.push(unlocked);
184
+ }
185
+ }
186
+
187
+ // streak-3 and streak-7: consecutive qualifying ship-days in builder's local
188
+ // timezone. computeStreak reads the just-resolved claim from the same
189
+ // transaction client (claim row already has outcome='shipped' + released_at
190
+ // by the time evaluateAfterShip is called from resolveClaim). The task is
191
+ // also at status='confirmed' by then (verification passed branch only).
192
+ //
193
+ // Anti-double-unlock is enforced both here (alreadyUnlocked check) and by
194
+ // the (builder_id, achievement_id) PK on builder_achievements.
195
+ //
196
+ // Once unlocked, these achievements stay unlocked — a streak-3 unlocked
197
+ // yesterday is NOT re-locked when today is a non-ship-day. The PK enforces
198
+ // this automatically (no re-insert possible).
199
+ const needStreak3 = !await alreadyUnlocked(client, builderId, 'streak-3');
200
+ const needStreak7 = !await alreadyUnlocked(client, builderId, 'streak-7');
201
+ if (needStreak3 || needStreak7) {
202
+ const s = await streak.computeStreak(builderId, client);
203
+ if (needStreak3 && s.current_streak >= 3) {
204
+ const unlocked = await unlockAchievement(client, builderId, 'streak-3', taskId);
205
+ if (unlocked) results.push(unlocked);
206
+ }
207
+ if (needStreak7 && s.current_streak >= 7) {
208
+ const unlocked = await unlockAchievement(client, builderId, 'streak-7', taskId);
209
+ if (unlocked) results.push(unlocked);
210
+ }
211
+ }
212
+
213
+ return results;
214
+ }
215
+
216
+ // Called after credits are awarded — pass total_credits before and after the delta.
217
+ async function evaluateAfterCreditAward(client, builderId, totalBefore, totalAfter) {
218
+ const results = [];
219
+
220
+ // breaking-the-100c-bar: crossed 100 from below
221
+ if (!await alreadyUnlocked(client, builderId, 'breaking-the-100c-bar')) {
222
+ if (totalBefore < 100 && totalAfter >= 100) {
223
+ const unlocked = await unlockAchievement(client, builderId, 'breaking-the-100c-bar', null);
224
+ if (unlocked) results.push(unlocked);
225
+ }
226
+ }
227
+
228
+ return results;
229
+ }
230
+
231
+ // -------------------------------------------------------------------------
232
+ // State-based reconcile (task 1679) — the durable replacement for the fragile
233
+ // "evaluate exactly what just happened in this txn" hooks above.
234
+ //
235
+ // WHY this exists: the granular evaluators only ran on SOME ship paths.
236
+ // db.applyGrade (the subagent-grader path) called evaluateAfterShip +
237
+ // evaluateAfterCreditAward, but db.confirmTask (the --skip-grade / server
238
+ // grader_bypass path — the DOMINANT one) called NEITHER. So a builder who ships
239
+ // with grader_bypass on only ever unlocked first-claim (the claim path works).
240
+ // And breaking-the-100c-bar was boundary-only (totalBefore<100 && totalAfter>=100)
241
+ // on a credit branch the per-session cost-plus reward (ADR 0054) never hits, so
242
+ // it fired for NOBODY — even lars589 at 22k credits. The whole board looked dead.
243
+ //
244
+ // reconcileBuilderAchievements evaluates every achievement against CURRENT DB
245
+ // state and unlocks any the builder is eligible for but hasn't. It is:
246
+ // - idempotent: the alreadyUnlocked guard + the (builder_id, achievement_id)
247
+ // PK + ON CONFLICT DO NOTHING mean re-running never double-unlocks or
248
+ // double-awards a credit bonus.
249
+ // - path-independent: keyed off committed state (claims.outcome='shipped',
250
+ // tasks.touches — backfilled from the REAL diff at ship per #882 —
251
+ // builders.total_credits, credit_log), so it works no matter which ship
252
+ // path ran. Callers wrap it in a SAVEPOINT so it can never fail a ship.
253
+ // - the SINGLE SOURCE OF TRUTH for eligibility (STATE_EVALUATORS below).
254
+ // scripts/gds/diagnose-achievements.js and the backfill CLI import this same
255
+ // list, so the stale-prefix drift that silently broke gds-shipper
256
+ // (idea 44/idea 50: the diagnose/backfill copies still said src/pms/) cannot
257
+ // recur — there is now one definition, not three.
258
+ //
259
+ // Each predicate takes (client, builderId) → boolean. `client` may be a tx
260
+ // client (reconcile-at-ship) or the shared pool (diagnose / backfill CLI).
261
+
262
+ async function eligible_firstClaim(client, builderId) {
263
+ const r = await client.query('SELECT 1 FROM claims WHERE builder_id=$1 LIMIT 1', [builderId]);
264
+ return r.rowCount > 0;
265
+ }
266
+
267
+ async function eligible_firstShip(client, builderId) {
268
+ const r = await client.query(
269
+ `SELECT 1 FROM claims WHERE builder_id=$1 AND outcome='shipped' LIMIT 1`,
270
+ [builderId]
271
+ );
272
+ return r.rowCount > 0;
273
+ }
274
+
275
+ async function eligible_artPipelineShipper(client, builderId) {
276
+ const r = await client.query(
277
+ `SELECT 1
278
+ FROM claims c JOIN tasks t ON t.id = c.task_id
279
+ WHERE c.builder_id = $1 AND c.outcome = 'shipped'
280
+ AND EXISTS (SELECT 1 FROM unnest(t.touches) AS p WHERE p LIKE 'art/%')
281
+ LIMIT 1`,
282
+ [builderId]
283
+ );
284
+ return r.rowCount > 0;
285
+ }
286
+
287
+ async function eligible_gdsShipper(client, builderId) {
288
+ const r = await client.query(
289
+ `SELECT 1
290
+ FROM claims c JOIN tasks t ON t.id = c.task_id
291
+ WHERE c.builder_id = $1 AND c.outcome = 'shipped'
292
+ AND EXISTS (SELECT 1 FROM unnest(t.touches) AS p
293
+ WHERE p LIKE 'src/bongos/%' OR p LIKE 'scripts/gds/%')
294
+ LIMIT 1`,
295
+ [builderId]
296
+ );
297
+ return r.rowCount > 0;
298
+ }
299
+
300
+ async function eligible_firstParallelClaim(client, builderId) {
301
+ const r = await client.query(
302
+ `WITH shipped AS (
303
+ SELECT id, claimed_at, released_at FROM claims
304
+ WHERE builder_id = $1 AND outcome = 'shipped' AND released_at IS NOT NULL
305
+ )
306
+ SELECT 1 FROM shipped a JOIN shipped b ON b.id <> a.id
307
+ WHERE tstzrange(a.claimed_at, a.released_at) && tstzrange(b.claimed_at, b.released_at)
308
+ LIMIT 1`,
309
+ [builderId]
310
+ );
311
+ return r.rowCount > 0;
312
+ }
313
+
314
+ async function eligible_breaking100c(client, builderId) {
315
+ const r = await client.query('SELECT total_credits FROM builders WHERE id = $1', [builderId]);
316
+ return r.rowCount > 0 && Number(r.rows[0].total_credits) >= 100;
317
+ }
318
+
319
+ async function eligible_subtractor(client, builderId) {
320
+ // Mirror credits.awardNetNegativeBonus: subtractor unlocks at SUBTRACTOR_THRESHOLD
321
+ // net-negative ship bonuses. Lazy-require the threshold (credits.js requires
322
+ // this module, so a top-level require would be circular — same lazy pattern
323
+ // renderProgressText uses for ./streak).
324
+ const { SUBTRACTOR_THRESHOLD } = require('./credits');
325
+ const r = await client.query(
326
+ `SELECT COUNT(*)::int AS n FROM credit_log
327
+ WHERE builder_id = $1 AND reason = 'ship.net_negative'`,
328
+ [builderId]
329
+ );
330
+ return Number(r.rows[0].n) >= SUBTRACTOR_THRESHOLD;
331
+ }
332
+
333
+ // Streaks use longest_streak (NOT current_streak): reconcile asks "did this
334
+ // builder EVER reach an N-night streak", and per the achievement's own contract
335
+ // an unlocked streak stays unlocked even after a gap. (The live evaluateAfterShip
336
+ // checks current_streak because it only fires the instant a streak extends; the
337
+ // retroactive view is longest_streak.)
338
+ async function eligible_streak3(client, builderId) {
339
+ const s = await streak.computeStreak(builderId, client);
340
+ return s.longest_streak >= 3;
341
+ }
342
+
343
+ async function eligible_streak7(client, builderId) {
344
+ const s = await streak.computeStreak(builderId, client);
345
+ return s.longest_streak >= 7;
346
+ }
347
+
348
+ // Ordered by achievements.sort_order so banners/backfill output read naturally.
349
+ const STATE_EVALUATORS = [
350
+ { id: 'first-ship', fn: eligible_firstShip },
351
+ { id: 'first-claim', fn: eligible_firstClaim },
352
+ { id: 'first-parallel-claim', fn: eligible_firstParallelClaim },
353
+ { id: 'streak-3', fn: eligible_streak3 },
354
+ { id: 'streak-7', fn: eligible_streak7 },
355
+ { id: 'art-pipeline-shipper', fn: eligible_artPipelineShipper },
356
+ { id: 'subtractor', fn: eligible_subtractor },
357
+ { id: 'gds-shipper', fn: eligible_gdsShipper },
358
+ { id: 'breaking-the-100c-bar', fn: eligible_breaking100c },
359
+ ];
360
+
361
+ // Unlock every achievement the builder currently qualifies for but hasn't yet.
362
+ // Returns the array of just-unlocked { id, name, credit_bonus }. Idempotent.
363
+ // Callers inside a ship transaction MUST wrap this in a SAVEPOINT so a predicate
364
+ // error rolls back only the reconcile, never the ship/confirm it runs within.
365
+ async function reconcileBuilderAchievements(client, builderId, opts = {}) {
366
+ const { taskId = null } = opts;
367
+ const results = [];
368
+ for (const ev of STATE_EVALUATORS) {
369
+ if (await alreadyUnlocked(client, builderId, ev.id)) continue;
370
+ if (await ev.fn(client, builderId)) {
371
+ const unlocked = await unlockAchievement(client, builderId, ev.id, taskId);
372
+ if (unlocked) results.push(unlocked);
373
+ }
374
+ }
375
+ return results;
376
+ }
377
+
378
+ // -------------------------------------------------------------------------
379
+ // Achievements — minimal getters added by migration 006_pms_v2.
380
+ // Full evaluator + unlock writes live in src/bongos/achievements.js (task K1).
381
+ // -------------------------------------------------------------------------
382
+
383
+ async function listAchievements() {
384
+ const { rows } = await pool.query(
385
+ `SELECT id, name, description, icon, credit_bonus, sort_order
386
+ FROM achievements
387
+ ORDER BY sort_order, id`
388
+ );
389
+ return rows;
390
+ }
391
+
392
+ async function getBuilderAchievements(builderId) {
393
+ const { rows } = await pool.query(
394
+ `SELECT ba.builder_id, ba.achievement_id, ba.unlocked_at, ba.unlocked_by_task_id,
395
+ a.name, a.description, a.icon, a.credit_bonus, a.sort_order
396
+ FROM builder_achievements ba
397
+ JOIN achievements a ON a.id = ba.achievement_id
398
+ WHERE ba.builder_id = $1
399
+ ORDER BY a.sort_order`,
400
+ [builderId]
401
+ );
402
+ return rows;
403
+ }
404
+
405
+ // PMS-V2 #188: enriched leaderboard. Single query — for each builder in the
406
+ // top N (by total_credits), includes an `achievements` string[] of up to
407
+ // `perBuilderCap` achievement IDs the builder has unlocked, sorted by
408
+ // achievements.sort_order. No N+1: one round trip total.
409
+ async function getLeaderboardWithAchievements(limit = 10, perBuilderCap = 5) {
410
+ const { rows } = await pool.query(
411
+ `SELECT b.id,
412
+ b.github_login,
413
+ b.display_name,
414
+ b.avatar_url,
415
+ b.total_credits,
416
+ b.rank,
417
+ COALESCE((
418
+ SELECT array_agg(t.achievement_id ORDER BY t.sort_order)
419
+ FROM (
420
+ SELECT ba.achievement_id, a.sort_order
421
+ FROM builder_achievements ba
422
+ JOIN achievements a ON a.id = ba.achievement_id
423
+ WHERE ba.builder_id = b.id
424
+ ORDER BY a.sort_order
425
+ LIMIT $2
426
+ ) t
427
+ ), ARRAY[]::text[]) AS achievements
428
+ FROM builders b
429
+ ORDER BY b.total_credits DESC, b.created_at ASC
430
+ LIMIT $1`,
431
+ [limit, perBuilderCap]
432
+ );
433
+ return rows;
434
+ }
435
+
436
+ // PMS-V2 #188: compute human-readable progress for every achievement the
437
+ // builder hasn't unlocked yet. Returns rows shaped like:
438
+ // { achievement_id, name, description, icon, progress_text }
439
+ // Single round-trip — one aggregate query that joins achievements with the
440
+ // per-builder counters (shipped tasks, claims, art ships, pms ships,
441
+ // overlapping-pair count) and renders the progress sentence in JS.
442
+ async function getLockedAchievementsProgress(builderId) {
443
+ // One query — pulls achievements + the counters this builder needs to
444
+ // produce progress text. The CROSS JOIN against the single-row counters
445
+ // CTE is cheap; the builder_achievements anti-join (NOT EXISTS) excludes
446
+ // achievements already unlocked.
447
+ const { rows } = await pool.query(
448
+ `WITH counters AS (
449
+ SELECT
450
+ (SELECT COUNT(*) FROM session_logs
451
+ WHERE builder_id = $1 AND outcome = 'shipped') AS ships,
452
+ (SELECT COUNT(*) FROM claims
453
+ WHERE builder_id = $1) AS claims_total,
454
+ -- touches[] cleanup [3/8] (task 878): these retrospective counters key
455
+ -- off touches[] (the prediction). Unlike the one-time shipper badges
456
+ -- (re-pointed at the real diff via evaluateAfterShip), a per-load
457
+ -- aggregate over historical ships has no committed diff to read, so it
458
+ -- stays on touches[] — which becomes diff-accurate once #882 backfills
459
+ -- touches[] from the committed diff at ship time. No bespoke plumbing.
460
+ (SELECT COUNT(*) FROM tasks
461
+ WHERE shipped_by = $1 AND status = 'shipped'
462
+ AND EXISTS (SELECT 1 FROM unnest(COALESCE(touches, ARRAY[]::text[])) t
463
+ WHERE t LIKE 'art/%')) AS art_ships,
464
+ (SELECT COUNT(*) FROM tasks
465
+ WHERE shipped_by = $1 AND status = 'shipped'
466
+ AND EXISTS (SELECT 1 FROM unnest(COALESCE(touches, ARRAY[]::text[])) t
467
+ WHERE t LIKE 'src/bongos/%' OR t LIKE 'scripts/gds/%')) AS pms_ships,
468
+ (SELECT COALESCE(b.total_credits, 0) FROM builders b WHERE b.id = $1) AS total_credits,
469
+ (SELECT COUNT(*)
470
+ FROM claims a
471
+ JOIN claims b2 ON b2.id <> a.id
472
+ AND b2.builder_id = a.builder_id
473
+ WHERE a.builder_id = $1
474
+ AND a.outcome = 'shipped' AND a.released_at IS NOT NULL
475
+ AND b2.outcome = 'shipped' AND b2.released_at IS NOT NULL
476
+ AND tstzrange(a.claimed_at, a.released_at)
477
+ && tstzrange(b2.claimed_at, b2.released_at)) AS overlap_pairs
478
+ )
479
+ SELECT a.id AS achievement_id,
480
+ a.name,
481
+ a.description,
482
+ a.icon,
483
+ a.credit_bonus,
484
+ c.ships,
485
+ c.claims_total,
486
+ c.art_ships,
487
+ c.pms_ships,
488
+ c.total_credits,
489
+ c.overlap_pairs
490
+ FROM achievements a
491
+ CROSS JOIN counters c
492
+ WHERE NOT EXISTS (
493
+ SELECT 1 FROM builder_achievements ba
494
+ WHERE ba.builder_id = $1 AND ba.achievement_id = a.id
495
+ )
496
+ ORDER BY a.sort_order`,
497
+ [builderId]
498
+ );
499
+
500
+ return rows.map((r) => ({
501
+ achievement_id: r.achievement_id,
502
+ name: r.name,
503
+ description: r.description,
504
+ icon: r.icon,
505
+ progress_text: renderProgressText(r),
506
+ }));
507
+ }
508
+
509
+ // Pure function — turns the counters row into a human-readable progress
510
+ // sentence. Fallbacks gracefully when src/bongos/streak.js (task #52) hasn't
511
+ // shipped yet: the streak achievements report a generic "track N consecutive
512
+ // ship-days" hint instead of a real count.
513
+ function renderProgressText(row) {
514
+ const id = row.achievement_id;
515
+ const ships = Number(row.ships || 0);
516
+ const claimsTotal = Number(row.claims_total || 0);
517
+ const artShips = Number(row.art_ships || 0);
518
+ const pmsShips = Number(row.pms_ships || 0);
519
+ const totalCredits = Number(row.total_credits || 0);
520
+ const overlapPairs = Number(row.overlap_pairs || 0);
521
+
522
+ // Optional dependency — task #52 may or may not have shipped yet.
523
+ let streak = null;
524
+ try {
525
+ // eslint-disable-next-line global-require
526
+ streak = require('./streak');
527
+ } catch (_) {
528
+ streak = null;
529
+ }
530
+
531
+ switch (id) {
532
+ case 'first-ship':
533
+ return ships === 0
534
+ ? 'needs first shipped task'
535
+ : 'keep building';
536
+ case 'first-claim':
537
+ return claimsTotal === 0
538
+ ? 'needs first claim'
539
+ : 'keep building';
540
+ case 'first-parallel-claim':
541
+ return overlapPairs === 0
542
+ ? 'needs two shipped tasks with overlapping claim windows'
543
+ : 'keep building';
544
+ case 'streak-3':
545
+ case 'streak-7': {
546
+ const threshold = id === 'streak-3' ? 3 : 7;
547
+ // Use streak.js if present (task #52). Render as e.g.
548
+ // "1 of 3 ships toward streak-3"
549
+ if (streak && typeof streak.computeStreak === 'function') {
550
+ try {
551
+ // computeStreak may be async — handle both shapes by ignoring promise
552
+ // returns (we can't await inside this sync renderer). If async, fall
553
+ // through to the generic hint.
554
+ const res = streak.computeStreak();
555
+ if (res && typeof res.then !== 'function' && typeof res.current_streak === 'number') {
556
+ const cur = Math.max(0, Math.min(res.current_streak, threshold));
557
+ return `${cur} of ${threshold} ships toward ${id}`;
558
+ }
559
+ } catch (_) { /* fall through */ }
560
+ }
561
+ return `track ${threshold} consecutive ship-days`;
562
+ }
563
+ case 'art-pipeline-shipper':
564
+ return artShips === 0
565
+ ? 'needs one shipped task touching art/'
566
+ : 'keep building';
567
+ case 'gds-shipper':
568
+ return pmsShips === 0
569
+ ? 'needs one shipped task touching src/bongos/ or scripts/gds/'
570
+ : 'keep building';
571
+ case 'breaking-the-100c-bar': {
572
+ const have = Math.max(0, Math.min(totalCredits, 100));
573
+ return `${have} of 100c toward breaking-the-100c-bar`;
574
+ }
575
+ default:
576
+ return 'keep building';
577
+ }
578
+ }
579
+
580
+ module.exports = {
581
+ evaluateAfterClaim,
582
+ evaluateAfterShip,
583
+ evaluateAfterCreditAward,
584
+ reconcileBuilderAchievements,
585
+ STATE_EVALUATORS,
586
+ alreadyUnlocked,
587
+ unlockAchievement,
588
+ filesForBadges,
589
+ listAchievements,
590
+ getBuilderAchievements,
591
+ getLeaderboardWithAchievements,
592
+ getLockedAchievementsProgress,
593
+ renderProgressText,
594
+ };