@bongos/core 1.18.0 → 1.18.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (553) hide show
  1. package/.bongos-core.json +1740 -640
  2. package/.claude/skills/builder-box/SKILL.md +6 -0
  3. package/.claude/skills/builder-sequence/SKILL.md +97 -0
  4. package/.claude/skills/builder-ship/SKILL.md +8 -2
  5. package/.claude/skills/builder-start/SKILL.md +11 -0
  6. package/.claude/skills/builder-sync/SKILL.md +41 -0
  7. package/.claude/skills/fix-task/SKILL.md +64 -0
  8. package/.claude/skills/goal-create/SKILL.md +158 -0
  9. package/.claude/skills/goal-review/SKILL.md +3 -1
  10. package/.claude/skills/idea-triage/SKILL.md +14 -8
  11. package/.claude/skills/merge-mode/SKILL.md +2 -2
  12. package/.claude/skills/new-project/SKILL.md +1 -0
  13. package/.claude/skills/planning-session/SKILL.md +45 -18
  14. package/.env.local.example +4 -3
  15. package/README.md +5 -3
  16. package/bin/bongos.js +1 -0
  17. package/clients/bongos-client/README.md +2 -2
  18. package/clients/bongos-client/bongos-client.global.js +82 -18
  19. package/clients/bongos-client/index.cjs +82 -18
  20. package/clients/bongos-client/index.d.ts +131 -29
  21. package/clients/bongos-client/index.mjs +82 -18
  22. package/config/branding.neutral.json +11 -2
  23. package/config/governance.neutral.json +21 -0
  24. package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
  25. package/docs/adr/0090-metic-task-authoring.md +1 -1
  26. package/docs/adr/0142-project-context-is-prose-only.md +41 -0
  27. package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
  28. package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
  29. package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
  30. package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
  31. package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
  32. package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
  33. package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
  34. package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
  35. package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
  36. package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
  37. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
  38. package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
  39. package/docs/adr/0152-metic-task-abandonment.md +67 -0
  40. package/docs/adr/0153-sequential-chain-runner.md +51 -0
  41. package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
  42. package/docs/adr/README.md +15 -2
  43. package/docs/api/openapi.json +2648 -483
  44. package/docs/api-reference.md +73 -13
  45. package/docs/architecture.md +4 -2
  46. package/docs/branding-contract.md +3 -1
  47. package/docs/canonical-permissions.md +21 -8
  48. package/docs/file-map.md +15 -7
  49. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
  50. package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
  51. package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
  52. package/docs/onboarding/diagrams/assertions.json +4 -7
  53. package/docs/onboarding/drachmae-and-karma.md +3 -3
  54. package/docs/onboarding/primer.md +17 -16
  55. package/docs/onboarding/slash-commands.md +124 -0
  56. package/docs/recipes/builder-box-lifecycle.md +23 -0
  57. package/docs/recipes/devbox-app-release.md +14 -4
  58. package/docs/recipes/instance-first-run.md +16 -0
  59. package/docs/recipes/local-dev.md +81 -0
  60. package/docs/recipes/ops-gotchas.md +19 -1
  61. package/docs/recipes/overnight-builder.md +1 -1
  62. package/docs/recipes/packaging-the-core.md +13 -0
  63. package/docs/recipes/parallel-goal-waves.md +174 -0
  64. package/docs/recipes/ship-and-regrade.md +2 -2
  65. package/docs/recipes/standalone-live-docs.md +48 -0
  66. package/docs/recipes/upgrading-the-core.md +5 -2
  67. package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
  68. package/migrations/003_pms.sql +6 -7
  69. package/migrations/006_pms_v2.sql +3 -31
  70. package/migrations/039_newcomer_friendly_column.sql +5 -0
  71. package/migrations/102_remove_box_first_provision_approval.sql +4 -0
  72. package/migrations/core_192_github_oauth_tokens.sql +33 -0
  73. package/migrations/core_193_task_needs_rebase.sql +28 -0
  74. package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
  75. package/migrations/core_195_idea_triage_provenance.sql +57 -0
  76. package/migrations/core_196_session_reward_topup.sql +69 -0
  77. package/modules/autonomy/pollers/routine-timers.js +9 -8
  78. package/modules/builder-settings/wandering-prefs.js +61 -18
  79. package/modules/dev-box/app/README.md +73 -0
  80. package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
  81. package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
  82. package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
  83. package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
  84. package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
  85. package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
  86. package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
  87. package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
  88. package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
  89. package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
  90. package/modules/dev-box/app/assets/tray/win-off.png +0 -0
  91. package/modules/dev-box/app/assets/tray/win-on.png +0 -0
  92. package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
  93. package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
  94. package/modules/dev-box/app/build-resources/icon.png +0 -0
  95. package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
  96. package/modules/dev-box/app/electron-builder.yml +95 -0
  97. package/modules/dev-box/app/package-lock.json +5291 -0
  98. package/modules/dev-box/app/package.json +30 -0
  99. package/modules/dev-box/app/renderer/app.js +319 -0
  100. package/modules/dev-box/app/renderer/index.html +45 -0
  101. package/modules/dev-box/app/renderer/styles.css +246 -0
  102. package/modules/dev-box/app/renderer/theme.generated.css +16 -0
  103. package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
  104. package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
  105. package/modules/dev-box/app/scripts/gen-brand.js +138 -0
  106. package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
  107. package/modules/dev-box/app/scripts/gen-icons.js +286 -0
  108. package/modules/dev-box/app/scripts/vendor-client.js +23 -0
  109. package/modules/dev-box/app/src/box-controller.js +287 -0
  110. package/modules/dev-box/app/src/brand.generated.json +13 -0
  111. package/modules/dev-box/app/src/brand.js +16 -0
  112. package/modules/dev-box/app/src/config.js +19 -0
  113. package/modules/dev-box/app/src/gds-client.js +90 -0
  114. package/modules/dev-box/app/src/main.js +610 -0
  115. package/modules/dev-box/app/src/pairing.js +57 -0
  116. package/modules/dev-box/app/src/preload.js +29 -0
  117. package/modules/dev-box/app/src/session-store.js +58 -0
  118. package/modules/dev-box/app/src/ssh-setup.js +569 -0
  119. package/modules/dev-box/app/src/task-picker.js +70 -0
  120. package/modules/dev-box/app/src/tray.js +99 -0
  121. package/modules/dev-box/app/src/updater.js +55 -0
  122. package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
  123. package/modules/dev-box/app/test/unit.mjs +526 -0
  124. package/modules/dev-box/box-access.js +121 -4
  125. package/modules/dev-box/boxes.js +20 -0
  126. package/modules/dev-box/module.json +1 -1
  127. package/modules/dev-box/routes/box.js +87 -3
  128. package/modules/economy/credits.js +116 -25
  129. package/modules/economy/reward.js +8 -0
  130. package/modules/economy/streak.js +2 -1
  131. package/modules/governance/CLAUDE.md +15 -0
  132. package/modules/governance/catalog.js +419 -0
  133. package/modules/governance/config.js +174 -0
  134. package/modules/governance/db.js +125 -0
  135. package/modules/governance/migrations/governance_001_tables.sql +81 -0
  136. package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
  137. package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
  138. package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
  139. package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
  140. package/modules/governance/module.json +10 -0
  141. package/modules/governance/protected-surfaces.js +88 -0
  142. package/modules/governance/protected-surfaces.json +80 -0
  143. package/modules/governance/rank-roles.js +83 -0
  144. package/modules/governance/resolver.js +221 -0
  145. package/modules/governance/routes/governance.js +89 -0
  146. package/modules/governance/routes/role-sync.js +49 -0
  147. package/modules/governance/session-scopes.js +127 -0
  148. package/modules/governance/session-scopes.json +38 -0
  149. package/modules/hall-ui/public/atlas.css +117 -0
  150. package/modules/hall-ui/public/atlas.html +3 -114
  151. package/modules/hall-ui/public/brand-apply.js +34 -6
  152. package/modules/hall-ui/public/builders.js +187 -219
  153. package/modules/hall-ui/public/diagrams.html +2 -0
  154. package/modules/hall-ui/public/dom-utils.js +27 -0
  155. package/modules/hall-ui/public/drachmae.html +2 -0
  156. package/modules/hall-ui/public/drachmae.js +54 -1
  157. package/modules/hall-ui/public/gate.css +98 -0
  158. package/modules/hall-ui/public/gate.html +3 -95
  159. package/modules/hall-ui/public/goal-inbox.js +4 -1
  160. package/modules/hall-ui/public/goals-page.js +626 -114
  161. package/modules/hall-ui/public/goals.css +79 -1
  162. package/modules/hall-ui/public/goals.html +38 -11
  163. package/modules/hall-ui/public/hall-widgets.js +62 -52
  164. package/modules/hall-ui/public/harbor.css +123 -0
  165. package/modules/hall-ui/public/harbor.html +3 -120
  166. package/modules/hall-ui/public/index.html +11 -4
  167. package/modules/hall-ui/public/instances-panel.js +4 -1
  168. package/modules/hall-ui/public/modules.css +63 -0
  169. package/modules/hall-ui/public/modules.html +3 -60
  170. package/modules/hall-ui/public/my-projects.html +78 -0
  171. package/modules/hall-ui/public/my-projects.js +142 -0
  172. package/modules/hall-ui/public/new-project-wizard.js +7 -3
  173. package/modules/hall-ui/public/not-ready.html +2 -0
  174. package/modules/hall-ui/public/pair.css +73 -0
  175. package/modules/hall-ui/public/pair.html +3 -70
  176. package/modules/hall-ui/public/palette.js +302 -0
  177. package/modules/hall-ui/public/primer.css +13 -0
  178. package/modules/hall-ui/public/primer.html +2 -0
  179. package/modules/hall-ui/public/profile.html +2 -0
  180. package/modules/hall-ui/public/ranks.html +2 -0
  181. package/modules/hall-ui/public/roadmap.css +179 -0
  182. package/modules/hall-ui/public/roadmap.html +9 -172
  183. package/modules/hall-ui/public/roadmap.js +329 -316
  184. package/modules/hall-ui/public/scouting.html +45 -0
  185. package/modules/hall-ui/public/scouting.js +73 -0
  186. package/modules/hall-ui/public/sessions.css +16 -0
  187. package/modules/hall-ui/public/sessions.html +3 -13
  188. package/modules/hall-ui/public/settings.html +2 -0
  189. package/modules/hall-ui/public/settings.js +4 -4
  190. package/modules/hall-ui/public/shell.js +143 -18
  191. package/modules/hall-ui/public/style.css +231 -39
  192. package/modules/hall-ui/public/task-detail.js +347 -26
  193. package/modules/hall-ui/public/task.html +6 -1
  194. package/modules/hall-ui/public/watch.html +2 -0
  195. package/modules/hall-ui/public/work.html +8 -6
  196. package/modules/hall-ui/public/work.js +1 -1
  197. package/modules/ideas/inbox.js +61 -11
  198. package/modules/ideas/routes/inbox.js +23 -0
  199. package/modules/lifecycle/claim-eligibility.js +72 -0
  200. package/modules/lifecycle/db.js +519 -139
  201. package/modules/lifecycle/done-when.js +18 -3
  202. package/modules/lifecycle/github-push.js +19 -2
  203. package/modules/lifecycle/goal-advisory.js +114 -0
  204. package/modules/lifecycle/goal-authz.js +62 -0
  205. package/modules/lifecycle/lifecycle.js +9 -0
  206. package/modules/lifecycle/publish-reconciler.js +109 -6
  207. package/modules/lifecycle/routes/claims.js +68 -23
  208. package/modules/lifecycle/routes/done-when.js +110 -15
  209. package/modules/lifecycle/routes/goals.js +8 -38
  210. package/modules/lifecycle/routes/tasks.js +38 -6
  211. package/modules/lifecycle/ship-card.js +6 -0
  212. package/modules/onboarding/onboarding-state.js +1 -1
  213. package/modules/platform-identity/CLAUDE.md +15 -0
  214. package/modules/platform-identity/hub-device.js +147 -0
  215. package/modules/platform-identity/hub-keys.js +151 -0
  216. package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
  217. package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
  218. package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
  219. package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
  220. package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
  221. package/modules/platform-identity/module.json +18 -0
  222. package/modules/platform-identity/platform-identity.js +531 -0
  223. package/modules/platform-identity/pollers/code-sweep.js +43 -0
  224. package/modules/platform-identity/routes/my-projects.js +140 -0
  225. package/modules/platform-identity/routes/projects.js +107 -0
  226. package/modules/platform-identity/routes/scouting.js +35 -0
  227. package/modules/platform-identity/routes/sso.js +402 -0
  228. package/modules/platform-identity/tests/platform-identity.mjs +388 -0
  229. package/modules/platform-identity/ui/.gitkeep +0 -0
  230. package/modules/security/routes/reports.js +10 -0
  231. package/modules/sessions/db.js +166 -21
  232. package/modules/sessions/module.json +1 -1
  233. package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
  234. package/modules/sessions/routes/sessions.js +33 -0
  235. package/modules/status-ui/public/explore.html +54 -0
  236. package/modules/status-ui/public/explore.js +67 -0
  237. package/package-lock.json +2 -2
  238. package/package.json +1 -1
  239. package/public-landing/assets/anim/idle/frame_00.webp +0 -0
  240. package/public-landing/assets/anim/idle/frame_01.webp +0 -0
  241. package/public-landing/assets/anim/idle/frame_02.webp +0 -0
  242. package/public-landing/assets/anim/idle/frame_03.webp +0 -0
  243. package/public-landing/assets/anim/idle/frame_04.webp +0 -0
  244. package/public-landing/assets/anim/idle/frame_05.webp +0 -0
  245. package/public-landing/assets/anim/idle/frame_06.webp +0 -0
  246. package/public-landing/assets/anim/idle/frame_07.webp +0 -0
  247. package/public-landing/assets/anim/idle/frame_08.webp +0 -0
  248. package/public-landing/assets/anim/idle/frame_09.webp +0 -0
  249. package/public-landing/assets/anim/idle/frame_10.webp +0 -0
  250. package/public-landing/assets/anim/idle/frame_11.webp +0 -0
  251. package/public-landing/assets/anim/idle/frame_12.webp +0 -0
  252. package/public-landing/assets/anim/idle/frame_13.webp +0 -0
  253. package/public-landing/assets/anim/idle/frame_14.webp +0 -0
  254. package/public-landing/assets/anim/idle/frame_15.webp +0 -0
  255. package/public-landing/assets/anim/idle/frame_16.webp +0 -0
  256. package/public-landing/assets/anim/idle/frame_17.webp +0 -0
  257. package/public-landing/assets/anim/idle/frame_18.webp +0 -0
  258. package/public-landing/assets/anim/idle/frame_19.webp +0 -0
  259. package/public-landing/assets/anim/idle/frame_20.webp +0 -0
  260. package/public-landing/assets/anim/idle/frame_21.webp +0 -0
  261. package/public-landing/assets/anim/idle/frame_22.webp +0 -0
  262. package/public-landing/assets/anim/idle/frame_23.webp +0 -0
  263. package/public-landing/assets/anim/idle/frame_24.webp +0 -0
  264. package/public-landing/assets/anim/idle/frame_25.webp +0 -0
  265. package/public-landing/assets/anim/idle/frame_26.webp +0 -0
  266. package/public-landing/assets/anim/idle/frame_27.webp +0 -0
  267. package/public-landing/assets/anim/idle/frame_28.webp +0 -0
  268. package/public-landing/assets/anim/idle/frame_29.webp +0 -0
  269. package/public-landing/assets/anim/idle/frame_30.webp +0 -0
  270. package/public-landing/assets/anim/idle/frame_31.webp +0 -0
  271. package/public-landing/assets/anim/idle/frame_32.webp +0 -0
  272. package/public-landing/assets/anim/idle/frame_33.webp +0 -0
  273. package/public-landing/assets/anim/idle/frame_34.webp +0 -0
  274. package/public-landing/assets/anim/idle/frame_35.webp +0 -0
  275. package/public-landing/assets/anim/idle/frame_36.webp +0 -0
  276. package/public-landing/assets/anim/idle/frame_37.webp +0 -0
  277. package/public-landing/assets/anim/idle/frame_38.webp +0 -0
  278. package/public-landing/assets/anim/idle/frame_39.webp +0 -0
  279. package/public-landing/assets/anim/idle/frame_40.webp +0 -0
  280. package/public-landing/assets/anim/idle/frame_41.webp +0 -0
  281. package/public-landing/assets/anim/idle/frame_42.webp +0 -0
  282. package/public-landing/assets/anim/idle/frame_43.webp +0 -0
  283. package/public-landing/create.html +252 -62
  284. package/public-landing/gate/README.md +137 -0
  285. package/public-landing/gate/dispmaps/bar.png +0 -0
  286. package/public-landing/gate/dispmaps/flat.png +0 -0
  287. package/public-landing/gate/dispmaps/key.png +0 -0
  288. package/public-landing/gate/index.html +587 -0
  289. package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
  290. package/public-landing/gate/previews/off-the-boats.jpg +0 -0
  291. package/public-landing/gate/space.css +799 -0
  292. package/public-landing/gate/space.js +1826 -0
  293. package/public-landing/gate/sprites/enter.png +0 -0
  294. package/public-landing/gate/sprites/search.png +0 -0
  295. package/public-landing/gate/sprites/terminal-blank.png +0 -0
  296. package/public-landing/gate/sprites/tile.png +0 -0
  297. package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
  298. package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
  299. package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
  300. package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
  301. package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
  302. package/public-landing/world/assets/plates/scene-establishing.png +0 -0
  303. package/scripts/gds/abandon.js +6 -4
  304. package/scripts/gds/api.js +10 -5
  305. package/scripts/gds/api.ps1 +26 -0
  306. package/scripts/gds/api.sh +6 -0
  307. package/scripts/gds/audit-ships.js +7 -1
  308. package/scripts/gds/backfill-sessions.js +78 -18
  309. package/scripts/gds/backup.js +23 -1
  310. package/scripts/gds/box-connect-lib.js +124 -31
  311. package/scripts/gds/box-sync.js +66 -0
  312. package/scripts/gds/box.js +225 -53
  313. package/scripts/gds/cf-tunnel.js +145 -6
  314. package/scripts/gds/claim.js +34 -3
  315. package/scripts/gds/cli-lib.js +161 -21
  316. package/scripts/gds/code.js +6 -2
  317. package/scripts/gds/deploy-divergence.js +209 -0
  318. package/scripts/gds/dev-lib.js +309 -0
  319. package/scripts/gds/dev.js +322 -0
  320. package/scripts/gds/doctor.js +90 -61
  321. package/scripts/gds/fetch-art-key.js +1 -1
  322. package/scripts/gds/fetch-sound-prefs.js +2 -2
  323. package/scripts/gds/fitness.js +228 -12
  324. package/scripts/gds/gds-db-backup.service +16 -1
  325. package/scripts/gds/gds-db-offsite.service +9 -1
  326. package/scripts/gds/gen-api-client.js +1 -1
  327. package/scripts/gds/gen-api-docs.js +36 -14
  328. package/scripts/gds/gen-diagrams.js +45 -28
  329. package/scripts/gds/gen-file-map.js +2 -1
  330. package/scripts/gds/gen-freshness.js +32 -0
  331. package/scripts/gds/gen-repo-map.js +3 -2
  332. package/scripts/gds/gen-session-index.js +14 -5
  333. package/scripts/gds/hooks/pre-push.js +2 -2
  334. package/scripts/gds/init.js +60 -3
  335. package/scripts/gds/install-git-hooks.js +1 -1
  336. package/scripts/gds/key-card.js +15 -6
  337. package/scripts/gds/key-status.js +1 -1
  338. package/scripts/gds/linkify-refs.js +35 -9
  339. package/scripts/gds/lint-migrations.js +102 -0
  340. package/scripts/gds/login.js +58 -11
  341. package/scripts/gds/mirror-redact.js +5 -0
  342. package/scripts/gds/package-core.js +263 -4
  343. package/scripts/gds/paste-token.js +7 -1
  344. package/scripts/gds/preflight.js +126 -0
  345. package/scripts/gds/provision.js +268 -19
  346. package/scripts/gds/publish-manifest.js +22 -1
  347. package/scripts/gds/reauth.js +7 -3
  348. package/scripts/gds/regen-instance-docs.js +47 -0
  349. package/scripts/gds/run-unit-tests.js +42 -16
  350. package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
  351. package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
  352. package/scripts/gds/sequence.js +425 -0
  353. package/scripts/gds/session-cost.js +10 -1
  354. package/scripts/gds/setup.js +72 -5
  355. package/scripts/gds/shell.js +5 -3
  356. package/scripts/gds/ship.js +433 -59
  357. package/scripts/gds/smoke-gds.js +139 -8
  358. package/scripts/gds/start.js +171 -22
  359. package/scripts/gds/status.js +1 -1
  360. package/scripts/gds/triage.js +10 -9
  361. package/scripts/gds/upgrade.js +271 -7
  362. package/scripts/migrate.sh +10 -0
  363. package/scripts/status-mirror-sync.js +114 -84
  364. package/src/bongos/api-errors.js +1 -0
  365. package/src/bongos/auth.js +809 -107
  366. package/src/bongos/db-kernel.js +27 -0
  367. package/src/bongos/db.js +105 -0
  368. package/src/bongos/github-repos.js +93 -0
  369. package/src/bongos/module-scope-map.js +27 -1
  370. package/src/bongos/permission-path-check.js +136 -102
  371. package/src/bongos/repo-info.js +47 -11
  372. package/src/bongos/route-rank-check.js +429 -46
  373. package/src/bongos/routes/_helpers.js +12 -1
  374. package/src/bongos/routes/auth.js +312 -13
  375. package/src/bongos/routes/backup.js +58 -2
  376. package/src/bongos/routes/github.js +90 -0
  377. package/src/bongos/routes/instance.js +15 -3
  378. package/src/bongos/routes/me.js +35 -1
  379. package/src/bongos/routes.js +2 -0
  380. package/src/bongos/serve-internal.js +84 -15
  381. package/src/branding.js +49 -2
  382. package/src/instance-config.js +46 -0
  383. package/src/module-api.js +140 -1
  384. package/src/platform-server.js +86 -9
  385. package/tests/abandon_task.mjs +59 -3
  386. package/tests/api_cli_flags.mjs +53 -0
  387. package/tests/auth_page_gate.mjs +13 -0
  388. package/tests/backfill_sessions.mjs +127 -1
  389. package/tests/backup_cli.mjs +54 -0
  390. package/tests/bongos_box_connect.mjs +77 -0
  391. package/tests/box_access.mjs +130 -1
  392. package/tests/box_credential.mjs +125 -0
  393. package/tests/box_host_keys.mjs +24 -0
  394. package/tests/box_infra_resolve.mjs +149 -0
  395. package/tests/box_scope_session.mjs +6 -2
  396. package/tests/box_sync.mjs +55 -0
  397. package/tests/box_task_scope.mjs +99 -0
  398. package/tests/branding.mjs +41 -23
  399. package/tests/cf_ruleset_preflight.mjs +142 -0
  400. package/tests/cf_tunnel.mjs +37 -0
  401. package/tests/claim_gate_rebase.mjs +98 -0
  402. package/tests/clawback_confirmed_backlog.mjs +103 -0
  403. package/tests/cli_lib_formatters.mjs +20 -0
  404. package/tests/confirm_attribution.mjs +30 -46
  405. package/tests/credit_grant.mjs +198 -10
  406. package/tests/criterion_authoring_gate.mjs +272 -0
  407. package/tests/criterion_progress.mjs +33 -1
  408. package/tests/dev_lib.mjs +253 -0
  409. package/tests/devbox_artifact_gate.mjs +75 -0
  410. package/tests/devbox_dmg_backdrop.mjs +137 -0
  411. package/tests/devbox_icons.mjs +304 -0
  412. package/tests/devbox_installer_brand.mjs +232 -0
  413. package/tests/devbox_key_register.mjs +234 -0
  414. package/tests/docs_openapi_route.mjs +110 -0
  415. package/tests/doctor_hooks.mjs +141 -0
  416. package/tests/extract_json.mjs +140 -0
  417. package/tests/fitness.mjs +89 -0
  418. package/tests/gen_freshness.mjs +96 -0
  419. package/tests/github_repos_helpers.mjs +91 -0
  420. package/tests/github_token_store.mjs +121 -0
  421. package/tests/goal_advisory.mjs +251 -0
  422. package/tests/goal_criterion_confirm_ui.mjs +269 -0
  423. package/tests/goal_routes.mjs +59 -4
  424. package/tests/goal_tier.mjs +12 -3
  425. package/tests/governance_catalog.mjs +129 -0
  426. package/tests/governance_claim_eligibility.mjs +262 -0
  427. package/tests/governance_config.mjs +187 -0
  428. package/tests/governance_ownership_scope.mjs +410 -0
  429. package/tests/governance_page_gates.mjs +324 -0
  430. package/tests/governance_parity.mjs +336 -0
  431. package/tests/governance_principals.mjs +232 -0
  432. package/tests/governance_protected_surfaces.mjs +208 -0
  433. package/tests/governance_require_permission.mjs +223 -0
  434. package/tests/governance_resolver.mjs +84 -0
  435. package/tests/governance_role_sync.mjs +231 -0
  436. package/tests/governance_seed.mjs +127 -0
  437. package/tests/governance_session_scope.mjs +434 -0
  438. package/tests/governance_vanilla_boot.mjs +203 -0
  439. package/tests/grade_attribution.mjs +7 -7
  440. package/tests/hall_audit.mjs +223 -0
  441. package/tests/hall_nav.mjs +191 -0
  442. package/tests/hall_palette.mjs +206 -0
  443. package/tests/hall_signout.mjs +124 -0
  444. package/tests/hook_user_agents.mjs +10 -0
  445. package/tests/idea_triage.mjs +162 -0
  446. package/tests/idp_device_exchange.mjs +198 -0
  447. package/tests/idp_federation.mjs +100 -0
  448. package/tests/init.mjs +51 -0
  449. package/tests/instance_config.mjs +65 -0
  450. package/tests/instance_mismatch_guard.mjs +23 -6
  451. package/tests/instance_release_config.mjs +104 -0
  452. package/tests/linkify_refs.mjs +15 -2
  453. package/tests/migrations_forward_safe.mjs +86 -0
  454. package/tests/module_api.mjs +1 -1
  455. package/tests/module_contributions.mjs +55 -0
  456. package/tests/module_loader.mjs +10 -5
  457. package/tests/module_scope_active_claims.mjs +94 -0
  458. package/tests/needs_rebase.mjs +92 -0
  459. package/tests/one_active_claim_per_session.mjs +76 -0
  460. package/tests/override_attribution.mjs +10 -8
  461. package/tests/override_request_ownership.mjs +8 -4
  462. package/tests/package_core.mjs +246 -1
  463. package/tests/parse_cookie_decode.mjs +42 -0
  464. package/tests/pay_on_land.mjs +129 -0
  465. package/tests/platform_boot.mjs +100 -1
  466. package/tests/post_login_landing.mjs +42 -0
  467. package/tests/preflight_checks.mjs +72 -0
  468. package/tests/provision.mjs +289 -7
  469. package/tests/pruned_lockfile_integrity.mjs +79 -0
  470. package/tests/publish_branch_route.mjs +53 -0
  471. package/tests/publish_reconciler.mjs +187 -2
  472. package/tests/repo_info_binding.mjs +248 -0
  473. package/tests/reward_gate.mjs +11 -2
  474. package/tests/reward_mode_cost_plus_only.mjs +116 -0
  475. package/tests/reward_mode_surfacing.mjs +168 -0
  476. package/tests/route_permission_check.mjs +301 -0
  477. package/tests/route_rank_check.mjs +254 -12
  478. package/tests/route_validation.mjs +30 -0
  479. package/tests/sequence.mjs +267 -0
  480. package/tests/session_digest.mjs +44 -0
  481. package/tests/session_index.mjs +18 -6
  482. package/tests/session_records.mjs +39 -1
  483. package/tests/session_reward_on_land.mjs +381 -0
  484. package/tests/session_reward_reconcile.mjs +229 -0
  485. package/tests/ship_api_client_pathspec.mjs +100 -0
  486. package/tests/ship_base_flag.mjs +93 -0
  487. package/tests/ship_ci_deploy.mjs +140 -3
  488. package/tests/ship_upstream_deletion.mjs +57 -0
  489. package/tests/smoke_target.mjs +233 -0
  490. package/tests/start_env_guard.mjs +87 -0
  491. package/tests/start_rebase_warning.mjs +103 -0
  492. package/tests/status_mirror_sync.mjs +122 -0
  493. package/tests/stop_refcheck.mjs +19 -1
  494. package/tests/task_goal_link.mjs +15 -6
  495. package/tests/upgrade.mjs +393 -5
  496. package/tests/web_admission_status.mjs +162 -0
  497. package/tests/write_validation_gaps.mjs +110 -0
  498. package/.gitignore +0 -91
  499. package/docs/adr/0139-platform-history-migration-to-cloudbongos.md +0 -94
  500. package/docs/adr/0140-cloudbongos-standalone-reprovision.md +0 -43
  501. package/scripts/hall-preview/fixtures/access-requests.json +0 -20
  502. package/scripts/hall-preview/fixtures/achievements.json +0 -76
  503. package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
  504. package/scripts/hall-preview/fixtures/audit-log.json +0 -68
  505. package/scripts/hall-preview/fixtures/blockers__detail.json +0 -12
  506. package/scripts/hall-preview/fixtures/box__me.json +0 -5
  507. package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -69
  508. package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
  509. package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
  510. package/scripts/hall-preview/fixtures/builders__roster.json +0 -48
  511. package/scripts/hall-preview/fixtures/goals.json +0 -502
  512. package/scripts/hall-preview/fixtures/goals__25.json +0 -96
  513. package/scripts/hall-preview/fixtures/goals__26.json +0 -67
  514. package/scripts/hall-preview/fixtures/goals__3.json +0 -103
  515. package/scripts/hall-preview/fixtures/goals__35.json +0 -49
  516. package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
  517. package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
  518. package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
  519. package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
  520. package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -32
  521. package/scripts/hall-preview/fixtures/inbox.json +0 -330
  522. package/scripts/hall-preview/fixtures/inbox__detail.json +0 -15
  523. package/scripts/hall-preview/fixtures/instance.json +0 -124
  524. package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
  525. package/scripts/hall-preview/fixtures/me.json +0 -476
  526. package/scripts/hall-preview/fixtures/me__art-key__own.json +0 -6
  527. package/scripts/hall-preview/fixtures/me__event-sound-prefs.json +0 -209
  528. package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
  529. package/scripts/hall-preview/fixtures/me__render.json +0 -5
  530. package/scripts/hall-preview/fixtures/me__skill-prefs.json +0 -143
  531. package/scripts/hall-preview/fixtures/me__sound-prefs.json +0 -67
  532. package/scripts/hall-preview/fixtures/me__wandering.json +0 -43
  533. package/scripts/hall-preview/fixtures/override-requests.json +0 -15
  534. package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
  535. package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
  536. package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
  537. package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
  538. package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
  539. package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
  540. package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
  541. package/scripts/hall-preview/fixtures/public__grades.json +0 -50
  542. package/scripts/hall-preview/fixtures/public__progress.json +0 -124
  543. package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
  544. package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
  545. package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
  546. package/scripts/hall-preview/fixtures/security__docs.json +0 -10
  547. package/scripts/hall-preview/fixtures/security__reports.json +0 -31
  548. package/scripts/hall-preview/fixtures/sessions__search.json +0 -9
  549. package/scripts/hall-preview/fixtures/tasks.json +0 -2420
  550. package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
  551. package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
  552. package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
  553. package/scripts/hall-preview/fixtures/versions.json +0 -89
@@ -9,8 +9,8 @@
9
9
  // permission-sensitive path" a DETECTABLE, GATEABLE event — exactly the way
10
10
  // route-rank-check.js makes "an ungated write route" detectable.
11
11
  //
12
- // This module is PURE and dependency-free (no fs, no pg, no network) so it can
13
- // run in three places with identical logic:
12
+ // This module is PURE and dependency-free (no pg, no network, no require of any
13
+ // other repo module) so it can run in three places with identical logic:
14
14
  // 1. the LOCAL pre-push git hook (scripts/gds/hooks/pre-push.js) — fast,
15
15
  // cooperative, blocks the honest builder before the push leaves the box;
16
16
  // 2. the GRADER pre-pass (modules/grading/grader.js) — folds a finding into the panel
@@ -25,6 +25,9 @@
25
25
 
26
26
  'use strict';
27
27
 
28
+ const fs = require('node:fs');
29
+ const path = require('node:path');
30
+
28
31
  // Rank → tier. MUST mirror REQUIRES_RANK_TIER in src/bongos/db.js. We keep a LOCAL
29
32
  // copy (not an import) so this module stays dependency-free for the client-side
30
33
  // pre-push hook; tests/permission_path.mjs asserts the two never drift (the
@@ -32,87 +35,82 @@
32
35
  // reintroduce here).
33
36
  const RANK_TIER = { xenos: 1, thetes: 2, metic: 3, archon: 4 };
34
37
 
35
- // The floor: a builder must be at least this tier to touch a protected path.
36
- // metic(3) = the first "trusted working rank" (scope/trust grants begin here).
37
- // xenos(1) and thetes(2) are below it — sandbox + graduated-newcomer.
38
- const MIN_TIER = RANK_TIER.metic; // 3
39
-
40
- // Permission-sensitive paths. A diff from a sub-Metic builder that touches ANY
41
- // of these is a blocker. Glob rules (see globToRegExp): a trailing '/' matches
42
- // the whole subtree; '**' matches across '/'; '*' matches within one segment.
38
+ // ── the protected-surface REGISTRY (BV1.R101, ADR 0151 §4) ──────────────────
39
+ //
40
+ // GOVERNANCE OWNS THE DATA; THE SUBSTRATE STAYS THE ENFORCER. Which paths are
41
+ // protected, at what rank floor, mapped to which `system: true` catalog
42
+ // permission, is governance-owned data in
43
+ // modules/governance/protected-surfaces.json — no longer a constant baked into
44
+ // this file. Re-mapping a floor there is a POLICY edit. It cannot move
45
+ // enforcement into the app: the three layers above (git pre-push hook, grader
46
+ // pre-pass, post-push main audit) plus gate-review.js and the goal-scope check
47
+ // read the registry out of band — no DB, no server, no HTTP — and remain the
48
+ // authority (ADR 0043). Making the request path the enforcer is the exact
49
+ // regression this task exists to prevent.
50
+ //
51
+ // WHY A REPO FILE AND NOT A DB QUERY: the enforcers run where there is no
52
+ // database and no server (a git hook on a laptop, a CI job). The registry's
53
+ // canonical form must therefore be SYNCHRONOUSLY loadable from the checkout. A
54
+ // DB-backed override belongs to the governance tab, layered on top — never a
55
+ // dependency of the hook.
56
+ //
57
+ // WHY `fs` AND NOT `require`: ADR 0083's one-way rule forbids core from
58
+ // require-ing a MODULE's code (a module's behavior + enable/disable state must
59
+ // never be something the kernel depends on), and scripts/gds/fitness.js enforces
60
+ // that on `require` edges. This is not code — it is a static declarative data
61
+ // file that ships inside the core package next to this file (modules/ ships with
62
+ // @bongos/core, ADR 0108 §1). The sibling trust primitive route-rank-check.js
63
+ // already reads modules/*/routes/*.js off disk the same way, to rank-gate them.
64
+ // Code still flows ONE way only: modules/governance/protected-surfaces.js →
65
+ // src/module-api.js → this matcher. Nothing in core requires the module.
43
66
  //
44
- // Scope rationale: the rank/permission/ship-grade/deploy machinery, DB schema
45
- // migrations, the server route + middleware layer that carries the gates, and
46
- // the trust-boundary documentation. Game/art/UI/docs work — what newcomers
47
- // actually build — is deliberately NOT here. Metic+ is unaffected entirely.
48
- const PROTECTED_GLOBS = [
49
- // --- the rank ladder + authorization machinery ---
50
- 'src/bongos/auth.js', // requireBuilder / requireRank definitions
51
- 'src/bongos/db.js', // rank tiers, REQUIRES_RANK_TIER, the CASE niels edited
52
- 'src/bongos/route-rank-check.js', // the route-gate auditor
53
- 'src/bongos/permission-path-check.js',// THIS gate (self-protect)
54
- 'src/bongos/middleware/', // audit + any auth middleware
55
- 'src/bongos/routes/', // routes carry the requireRank gates
56
- 'modules/lifecycle/routes/', // BV1.R86: the lifecycle routes (tasks/claims/versions/goals/deps/done-when/gate-approvals) carved out of src/bongos/routes/ — the gates follow the routes
57
- 'src/bongos/routes.js', // #863-followup: the route MOUNT table (a new ungated route lands here)
58
- 'server.js', // #863-followup: the Express/Colyseus entrypoint — wires every router + host routing
59
- // --- rank-gated source/box access (the crown-jewels clone decision) ---
60
- // These moved into the dev-box module (BV1.R43, ADR 0083) but stay protected:
61
- // they decide who gets a full source clone + mint the credential, sensitive by
62
- // nature wherever they live. (routes/box.js's rank gates are covered separately
63
- // by the route-rank fitness check, which scans modules/*/routes/.)
64
- 'modules/dev-box/boxes.js', // #863-followup: boxScopeForRank / provision floor — decides who gets a full source clone
65
- 'modules/dev-box/box-access.js', // #863-followup: decideSourceAccess (rank → starter|full source)
66
- 'modules/dev-box/box-credential.js', // #863-followup: mints the box source credential
67
- // --- the ship / grade / deploy pipeline ---
68
- 'modules/grading/grader.js', // BV1.R73: grading carved to modules/grading/ — the protected glob follows the file
69
- 'modules/grading/grader-workers/', // #863-followup: the adversarial panel (Narc/Hacker/Quality/Efficiency) — blunting these blunts the gate
70
- 'modules/grading/grader-rubric.json', // task 1139 (ADR 0058): the grader's scoring rubric — blunting it blunts the grade gate
71
- 'scripts/gds/ship.js',
72
- 'scripts/gds/confirm.js',
73
- 'scripts/gds/merge-mode.js',
74
- 'scripts/gds/ci-grade.js', // task 1143 (ADR 0058): CI grade-gate driver — steers the grade check
75
- 'scripts/gds/grade-smoke.js', // task 1143 (ADR 0058): grade-smoke driver
76
- 'scripts/gds/conductor-dispatch.js',// task 1143 (ADR 0058): mid-flight grader dispatch
77
- 'scripts/gds/main-audit.js', // the post-push audit (self-protect)
78
- 'scripts/gds/push-main.js', // the sanctioned main-push (carries the override)
79
- 'scripts/gds/run-unit-tests.js', // task 1139 (ADR 0058): the unit-gate test SELECTOR — muting tests here blunts the CI gate
80
- 'scripts/gds/gate-review.js', // task 1139 (ADR 0058): the automatic gatekeeper itself (self-protect)
81
- 'scripts/gds/setup.js', // /builder-setup — installs the pre-push hook
82
- 'scripts/gds/install-git-hooks.js',// the hook installer (self-protect)
83
- 'scripts/gds/hooks/', // the git hooks themselves (self-protect)
84
- 'scripts/gds/cli-lib.js', // session/token + apiCall the gate relies on
85
- 'scripts/migrate.sh', // #863-followup: applies migrations on deploy
86
- 'scripts/deploy/', // task 1139 (ADR 0058): the deploy scripts run on the droplet at deploy
87
- // BV1.R86: the ship-pipeline libs carved to modules/lifecycle/ — the protected
88
- // globs follow the files (the grading-carve precedent above). github-push is the
89
- // server-mediated branch publish (ADR 0055); conflict-resolve/publish-reconciler
90
- // self-heal + land merges; merge-lock/ship-preflight serialize + preflight a ship.
91
- 'modules/lifecycle/merge-lock.js',
92
- 'modules/lifecycle/ship-preflight.js',
93
- 'modules/lifecycle/github-push.js',
94
- 'modules/lifecycle/conflict-resolve.js',
95
- 'modules/lifecycle/publish-reconciler.js',
96
- // --- schema: migrations are never newcomer work ---
97
- 'migrations/',
98
- // --- the deploy substrate ---
99
- 'infra/',
100
- '.github/', // #863-followup: CI workflows (deploy-prod.yml, grade gate, secrets-scan) are the pipeline
101
- 'CODEOWNERS', // task 1139 (ADR 0058): the code-owner gate list itself
102
- 'config/deploy.json', // task 1139 (ADR 0058): the laptop/ci/bypass deploy switch
103
- 'package.json', // #863-followup: npm scripts + prepare/lifecycle hooks run during install/CI
104
- 'package-lock.json', // task 1143 (ADR 0058): the resolved supply chain npm ci installs on the droplet
105
- // --- the hooks the gate is DELIVERED through (self-protect Layer 1) ---
106
- '.husky/', // #863-followup: pre-push (this gate) + pre-commit (secrets guard)
107
- // --- the trust-boundary documentation + methodology core ---
108
- 'docs/canonical-permissions.md',
109
- 'docs/adr/0016-trust-boundary-server-enforced-permissions.md',
110
- 'docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md', // #863-followup: this fix's own ADR
111
- 'CLAUDE.md',
112
- // --- local automation that could weaken a gate ---
113
- '.claude/hooks/',
114
- '.claude/settings.json',
115
- ];
67
+ // FAIL-CLOSED: a missing/empty/malformed registry THROWS. It never degrades to
68
+ // "nothing is protected" — an unreadable registry is a broken install, not an
69
+ // opted-out module.
70
+ //
71
+ // Resolved from __dirname (this file is <coreRoot>/src/bongos/) rather than via
72
+ // instance-config so the load keeps zero repo imports and works in a bare git
73
+ // hook.
74
+ const REGISTRY_PATH = path.join(__dirname, '..', '..', 'modules', 'governance', 'protected-surfaces.json');
75
+
76
+ function loadRegistry(file) {
77
+ let raw;
78
+ try {
79
+ raw = JSON.parse(fs.readFileSync(file, 'utf8'));
80
+ } catch (e) {
81
+ throw new Error(`protected-surface registry unreadable at ${file}: ${e.message}. Refusing to run with an empty protected set (ADR 0043).`);
82
+ }
83
+ const surfaces = Array.isArray(raw && raw.surfaces) ? raw.surfaces : null;
84
+ if (!surfaces || surfaces.length === 0) {
85
+ throw new Error(`protected-surface registry ${file} declares no surfaces. Refusing to run with an empty protected set (ADR 0043).`);
86
+ }
87
+ const defaultFloor = raw.floor;
88
+ const defaultPermission = raw.permission;
89
+ return Object.freeze(surfaces.map((s) => {
90
+ const glob = s && s.glob;
91
+ const floor = (s && s.floor) || defaultFloor;
92
+ const permission = (s && s.permission) || defaultPermission;
93
+ if (typeof glob !== 'string' || !glob) throw new Error(`protected-surface registry ${file}: a surface is missing 'glob'`);
94
+ if (!RANK_TIER[floor]) throw new Error(`protected-surface registry ${file}: surface "${glob}" has an unknown floor "${floor}"`);
95
+ if (typeof permission !== 'string' || !permission) throw new Error(`protected-surface registry ${file}: surface "${glob}" maps to no permission`);
96
+ return Object.freeze({ glob, floor, permission, group: (s && s.group) || null, why: (s && s.why) || null });
97
+ }));
98
+ }
99
+
100
+ // The registry as loaded: [{ glob, floor, permission, group, why }] in file order.
101
+ const PROTECTED_SURFACES = loadRegistry(REGISTRY_PATH);
102
+
103
+ // The glob list, DERIVED from the registry. Kept as an export because it is the
104
+ // long-standing single source every consumer already reads (module-scope-map,
105
+ // gate-review, publish-manifest, search-ingest-md, sequence) — those keep
106
+ // working unchanged and are now registry-backed by construction.
107
+ const PROTECTED_GLOBS = PROTECTED_SURFACES.map((s) => s.glob);
108
+
109
+ // The floor a builder must clear to touch a protected path, DERIVED from the
110
+ // registry (the lowest floor any surface declares — 'metic' today). Exported
111
+ // because main-audit.js and modules/lifecycle/routes/tasks.js gate on it; the
112
+ // per-surface floor below is what actually decides a hit.
113
+ const MIN_TIER = Math.min(...PROTECTED_SURFACES.map((s) => RANK_TIER[s.floor]));
116
114
 
117
115
  const SPECIALTY =
118
116
  'deterministic: a builder below Metic must not modify rank / permission / ship-grade / deploy / migration surfaces (ADR 0016, SEC #863)';
@@ -142,31 +140,54 @@ function escapeRe(s) {
142
140
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
143
141
  }
144
142
 
145
- const COMPILED = PROTECTED_GLOBS.map((g) => ({ glob: g, re: globToRegExp(g) }));
143
+ const COMPILED = PROTECTED_SURFACES.map((s) => ({ ...s, re: globToRegExp(s.glob) }));
146
144
 
147
145
  // Normalize a path the way git reports it (forward slashes, no leading ./).
148
146
  function normalize(p) {
149
147
  return String(p || '').replace(/\\/g, '/').replace(/^\.\//, '').trim();
150
148
  }
151
149
 
152
- // Which of `files` are permission-sensitive? Returns [{ file, glob }].
150
+ // Which of `files` are permission-sensitive? Returns
151
+ // [{ file, glob, floor, permission }] — floor + permission come straight from the
152
+ // registry entry that matched, so a governance re-map flows through every caller.
153
153
  function matchProtected(files) {
154
154
  const out = [];
155
155
  for (const raw of files || []) {
156
156
  const f = normalize(raw);
157
157
  if (!f) continue;
158
158
  const hit = COMPILED.find((c) => c.re.test(f));
159
- if (hit) out.push({ file: f, glob: hit.glob });
159
+ if (hit) out.push({ file: f, glob: hit.glob, floor: hit.floor, permission: hit.permission });
160
160
  }
161
161
  return out;
162
162
  }
163
163
 
164
+ // The registry entry governing `file`, or null when the path is unprotected.
165
+ function surfaceFor(file) {
166
+ const f = normalize(file);
167
+ const hit = f ? COMPILED.find((c) => c.re.test(f)) : null;
168
+ return hit ? { glob: hit.glob, floor: hit.floor, permission: hit.permission, group: hit.group, why: hit.why } : null;
169
+ }
170
+
171
+ // The rank floor governing `file` ('metic' today), or null when unprotected.
172
+ function floorFor(file) {
173
+ const s = surfaceFor(file);
174
+ return s ? s.floor : null;
175
+ }
176
+
177
+ // The system:true catalog permission `file` maps to, or null when unprotected.
178
+ function permissionFor(file) {
179
+ const s = surfaceFor(file);
180
+ return s ? s.permission : null;
181
+ }
182
+
164
183
  function tierOf(rank) {
165
184
  return RANK_TIER[rank] ?? null; // null = unknown rank
166
185
  }
167
186
 
168
- // Is this rank below the protected-path floor? Unknown ranks are treated as
169
- // NOT-below here (no finding) — see checkPermissionPaths for why unknown must
187
+ // Is this rank below the registry's LOWEST protected-path floor? A coarse
188
+ // "could this rank be blocked by anything at all" test — main-audit.js uses it
189
+ // after matchProtected has already established a hit. Unknown ranks are treated
190
+ // as NOT-below here (no finding) — see checkPermissionPaths for why unknown must
170
191
  // fail OPEN at the grader layer (the authoritative audit, layer 3, owns the
171
192
  // unknown/dishonest case and reads the real rank from the DB).
172
193
  function isBelowFloor(rank) {
@@ -184,21 +205,26 @@ function isBelowFloor(rank) {
184
205
  // the layer that fails-closed on the dishonest path.
185
206
  function checkPermissionPaths({ changedFiles, builderRank } = {}) {
186
207
  const protectedHits = matchProtected(changedFiles);
187
- const below = isBelowFloor(builderRank);
208
+ const tier = tierOf(builderRank);
188
209
  const findings = [];
189
- if (below && protectedHits.length > 0) {
190
- for (const h of protectedHits) {
191
- findings.push({
192
- severity: 'blocker',
193
- file: h.file,
194
- glob: h.glob,
195
- summary:
196
- `${h.file} is a permission-sensitive surface (matches \`${h.glob}\`). `
197
- + `Builder rank '${builderRank}' is below Metic and may not modify the rank / permission / `
198
- + `ship-grade / deploy / migration machinery (ADR 0016, SEC #863). `
199
- + `If this change is genuinely needed, an Archon must own it.`,
200
- });
201
- }
210
+ for (const h of protectedHits) {
211
+ // Decided against the hit's OWN registry floor, not a global constant — that
212
+ // is what makes "the governance tab can re-map the floor" real. Every surface
213
+ // floors at 'metic' today, so this is identical to the previous global test.
214
+ if (tier === null || tier >= RANK_TIER[h.floor]) continue;
215
+ const floorLabel = h.floor.charAt(0).toUpperCase() + h.floor.slice(1);
216
+ findings.push({
217
+ severity: 'blocker',
218
+ file: h.file,
219
+ glob: h.glob,
220
+ floor: h.floor,
221
+ permission: h.permission,
222
+ summary:
223
+ `${h.file} is a permission-sensitive surface (matches \`${h.glob}\`). `
224
+ + `Builder rank '${builderRank}' is below ${floorLabel} and may not modify the rank / permission / `
225
+ + `ship-grade / deploy / migration machinery (ADR 0016, SEC #863). `
226
+ + `If this change is genuinely needed, an Archon must own it.`,
227
+ });
202
228
  }
203
229
  return {
204
230
  ok: findings.length === 0,
@@ -215,8 +241,11 @@ function checkPermissionPaths({ changedFiles, builderRank } = {}) {
215
241
  function toWorkerResult(result) {
216
242
  const verdict = result.hardFail ? 'fail' : 'pass';
217
243
  const n = result.findings.length;
244
+ // Floor label comes from the findings (registry data), not a hardcoded 'Metic'.
245
+ const floor = n > 0 ? result.findings[0].floor : null;
246
+ const floorLabel = floor ? floor.charAt(0).toUpperCase() + floor.slice(1) : 'the floor';
218
247
  const header = verdict === 'fail'
219
- ? `Permission-Path — FAIL (rank '${result.builderRank}' below Metic touched ${n} protected path(s))`
248
+ ? `Permission-Path — FAIL (rank '${result.builderRank}' below ${floorLabel} touched ${n} protected path(s))`
220
249
  : `Permission-Path — PASS`;
221
250
  const body = result.findings.map((f) => ` [${f.severity}] ${f.file} — ${f.summary}`).join('\n');
222
251
  return {
@@ -238,9 +267,14 @@ module.exports = {
238
267
  RANK_TIER,
239
268
  MIN_TIER,
240
269
  PROTECTED_GLOBS,
270
+ PROTECTED_SURFACES,
271
+ REGISTRY_PATH,
241
272
  SPECIALTY,
242
273
  globToRegExp,
243
274
  matchProtected,
275
+ surfaceFor,
276
+ floorFor,
277
+ permissionFor,
244
278
  tierOf,
245
279
  isBelowFloor,
246
280
  checkPermissionPaths,
@@ -44,26 +44,61 @@ function loadFromEnv() {
44
44
  return null;
45
45
  }
46
46
 
47
- function loadFromGit() {
47
+ // The directory this file's package occupies: <root>/src/bongos -> <root>. In the core
48
+ // dev checkout that is the repo root; installed, it is node_modules/@bongos/core.
49
+ const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
50
+
51
+ // Same directory? Normalizes separator style (git prints POSIX separators even on
52
+ // Windows) and surrounding whitespace, and matches the platform's case rules.
53
+ function sameDir(a, b) {
54
+ if (!a || !b) return false;
55
+ const norm = (p) => {
56
+ const abs = path.resolve(String(p).trim());
57
+ return process.platform === 'win32' ? abs.toLowerCase() : abs;
58
+ };
59
+ return norm(a) === norm(b);
60
+ }
61
+
62
+ // Resolve the remote ONLY when this package IS the git repo, never a repo found by
63
+ // walking up out of it.
64
+ //
65
+ // git discovery searches ANCESTORS of cwd. In the core dev checkout PACKAGE_ROOT is the
66
+ // repo root, so `git remote get-url origin` answers correctly. But on a live instance
67
+ // (ADR 0140) the hub runs from node_modules/@bongos/core, which is not a repo — so git
68
+ // climbed out of the package, found the enclosing INSTANCE repo, and returned its origin.
69
+ // That silently bound a DIFFERENT repo than the one the core publishes to, so every
70
+ // publish call 404'd against a repo the builder had no access to.
71
+ //
72
+ // Anchor the answer: ask git for its toplevel first and require it to EQUAL the directory
73
+ // we probed. If it differs, the repo is someone else's — return null so loadRepoInfo falls
74
+ // through to the env pin (<PREFIX>_GITHUB_OWNER/_REPO) or to an explicit no_repo_info. An
75
+ // error is strictly better than a wrong answer here: a misbind produces confident 404s
76
+ // that are hard to trace, while the error is printed verbatim by the publish-reconciler's
77
+ // boot line and names its own cure.
78
+ function loadFromGit(deps = {}) {
79
+ const exec = deps.execSync || execSync;
80
+ const root = deps.packageRoot || PACKAGE_ROOT;
81
+ const opts = { cwd: root, encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'pipe'] };
48
82
  try {
49
- const remote = execSync('git remote get-url origin', {
50
- cwd: path.resolve(__dirname, '..', '..'),
51
- encoding: 'utf8',
52
- timeout: 2000,
53
- stdio: ['ignore', 'pipe', 'pipe'],
54
- });
55
- return parseRemote(remote);
83
+ const toplevel = exec('git rev-parse --show-toplevel', opts);
84
+ if (!sameDir(toplevel, root)) return null;
85
+ return parseRemote(exec('git remote get-url origin', opts));
56
86
  } catch (_) {
57
87
  return null;
58
88
  }
59
89
  }
60
90
 
61
- function loadRepoInfo() {
91
+ // `deps` is the test seam (execSync / packageRoot); production calls this with no args.
92
+ function loadRepoInfo(deps = {}) {
62
93
  if (cached) return cached;
63
94
  const branch = ic.resolveEnv('GITHUB_BRANCH') || 'main';
64
- const parsed = loadFromEnv() || loadFromGit();
95
+ const parsed = loadFromEnv() || loadFromGit(deps);
65
96
  if (!parsed) {
66
- cached = { error: 'no_repo_info', detail: 'git remote origin not parseable and <PREFIX>_GITHUB_OWNER/REPO unset' };
97
+ cached = {
98
+ error: 'no_repo_info',
99
+ detail:
100
+ 'git remote origin not resolvable from this package (an installed core does not sit inside the repo it publishes to) and <PREFIX>_GITHUB_OWNER/REPO unset',
101
+ };
67
102
  return cached;
68
103
  }
69
104
  const base = `https://github.com/${parsed.owner}/${parsed.repo}`;
@@ -87,5 +122,6 @@ function _resetCacheForTests() {
87
122
  module.exports = {
88
123
  loadRepoInfo,
89
124
  parseRemote,
125
+ loadFromGit, // exported for unit tests — the anchor rule is the whole fix
90
126
  _resetCacheForTests,
91
127
  };