@bongos/core 1.18.3 → 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 (469) hide show
  1. package/.bongos-core.json +1575 -285
  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 +4 -2
  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 +6 -1
  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/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
  27. package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
  28. package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
  29. package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
  30. package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
  31. package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
  32. package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
  33. package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
  34. package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
  35. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
  36. package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
  37. package/docs/adr/0152-metic-task-abandonment.md +67 -0
  38. package/docs/adr/0153-sequential-chain-runner.md +51 -0
  39. package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
  40. package/docs/adr/README.md +10 -0
  41. package/docs/api/openapi.json +843 -17
  42. package/docs/api-reference.md +23 -10
  43. package/docs/architecture.md +4 -2
  44. package/docs/branding-contract.md +3 -1
  45. package/docs/canonical-permissions.md +21 -8
  46. package/docs/file-map.md +8 -0
  47. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
  48. package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
  49. package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
  50. package/docs/onboarding/diagrams/assertions.json +4 -7
  51. package/docs/onboarding/drachmae-and-karma.md +3 -3
  52. package/docs/onboarding/primer.md +17 -16
  53. package/docs/onboarding/slash-commands.md +124 -0
  54. package/docs/recipes/builder-box-lifecycle.md +23 -0
  55. package/docs/recipes/devbox-app-release.md +14 -4
  56. package/docs/recipes/instance-first-run.md +16 -0
  57. package/docs/recipes/local-dev.md +81 -0
  58. package/docs/recipes/ops-gotchas.md +19 -1
  59. package/docs/recipes/overnight-builder.md +1 -1
  60. package/docs/recipes/parallel-goal-waves.md +174 -0
  61. package/docs/recipes/ship-and-regrade.md +2 -2
  62. package/docs/recipes/standalone-live-docs.md +48 -0
  63. package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
  64. package/migrations/003_pms.sql +6 -7
  65. package/migrations/006_pms_v2.sql +3 -31
  66. package/migrations/core_193_task_needs_rebase.sql +28 -0
  67. package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
  68. package/migrations/core_195_idea_triage_provenance.sql +57 -0
  69. package/migrations/core_196_session_reward_topup.sql +69 -0
  70. package/modules/autonomy/pollers/routine-timers.js +9 -8
  71. package/modules/builder-settings/wandering-prefs.js +61 -18
  72. package/modules/dev-box/app/README.md +73 -0
  73. package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
  74. package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
  75. package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
  76. package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
  77. package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
  78. package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
  79. package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
  80. package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
  81. package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
  82. package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
  83. package/modules/dev-box/app/assets/tray/win-off.png +0 -0
  84. package/modules/dev-box/app/assets/tray/win-on.png +0 -0
  85. package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
  86. package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
  87. package/modules/dev-box/app/build-resources/icon.png +0 -0
  88. package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
  89. package/modules/dev-box/app/electron-builder.yml +95 -0
  90. package/modules/dev-box/app/package-lock.json +5291 -0
  91. package/modules/dev-box/app/package.json +30 -0
  92. package/modules/dev-box/app/renderer/app.js +319 -0
  93. package/modules/dev-box/app/renderer/index.html +45 -0
  94. package/modules/dev-box/app/renderer/styles.css +246 -0
  95. package/modules/dev-box/app/renderer/theme.generated.css +16 -0
  96. package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
  97. package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
  98. package/modules/dev-box/app/scripts/gen-brand.js +138 -0
  99. package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
  100. package/modules/dev-box/app/scripts/gen-icons.js +286 -0
  101. package/modules/dev-box/app/scripts/vendor-client.js +23 -0
  102. package/modules/dev-box/app/src/box-controller.js +287 -0
  103. package/modules/dev-box/app/src/brand.generated.json +13 -0
  104. package/modules/dev-box/app/src/brand.js +16 -0
  105. package/modules/dev-box/app/src/config.js +19 -0
  106. package/modules/dev-box/app/src/gds-client.js +90 -0
  107. package/modules/dev-box/app/src/main.js +610 -0
  108. package/modules/dev-box/app/src/pairing.js +57 -0
  109. package/modules/dev-box/app/src/preload.js +29 -0
  110. package/modules/dev-box/app/src/session-store.js +58 -0
  111. package/modules/dev-box/app/src/ssh-setup.js +569 -0
  112. package/modules/dev-box/app/src/task-picker.js +70 -0
  113. package/modules/dev-box/app/src/tray.js +99 -0
  114. package/modules/dev-box/app/src/updater.js +55 -0
  115. package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
  116. package/modules/dev-box/app/test/unit.mjs +526 -0
  117. package/modules/dev-box/box-access.js +121 -4
  118. package/modules/dev-box/boxes.js +20 -0
  119. package/modules/dev-box/module.json +1 -1
  120. package/modules/dev-box/routes/box.js +87 -3
  121. package/modules/economy/credits.js +116 -25
  122. package/modules/economy/reward.js +8 -0
  123. package/modules/economy/streak.js +2 -1
  124. package/modules/governance/CLAUDE.md +15 -0
  125. package/modules/governance/catalog.js +419 -0
  126. package/modules/governance/config.js +174 -0
  127. package/modules/governance/db.js +125 -0
  128. package/modules/governance/migrations/governance_001_tables.sql +81 -0
  129. package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
  130. package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
  131. package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
  132. package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
  133. package/modules/governance/module.json +10 -0
  134. package/modules/governance/protected-surfaces.js +88 -0
  135. package/modules/governance/protected-surfaces.json +80 -0
  136. package/modules/governance/rank-roles.js +83 -0
  137. package/modules/governance/resolver.js +221 -0
  138. package/modules/governance/routes/governance.js +89 -0
  139. package/modules/governance/routes/role-sync.js +49 -0
  140. package/modules/governance/session-scopes.js +127 -0
  141. package/modules/governance/session-scopes.json +38 -0
  142. package/modules/hall-ui/public/atlas.css +117 -0
  143. package/modules/hall-ui/public/atlas.html +3 -114
  144. package/modules/hall-ui/public/brand-apply.js +34 -6
  145. package/modules/hall-ui/public/builders.js +187 -219
  146. package/modules/hall-ui/public/diagrams.html +2 -0
  147. package/modules/hall-ui/public/dom-utils.js +27 -0
  148. package/modules/hall-ui/public/drachmae.html +2 -0
  149. package/modules/hall-ui/public/drachmae.js +54 -1
  150. package/modules/hall-ui/public/gate.css +98 -0
  151. package/modules/hall-ui/public/gate.html +3 -95
  152. package/modules/hall-ui/public/goal-inbox.js +4 -1
  153. package/modules/hall-ui/public/goals-page.js +626 -114
  154. package/modules/hall-ui/public/goals.css +79 -1
  155. package/modules/hall-ui/public/goals.html +38 -11
  156. package/modules/hall-ui/public/hall-widgets.js +62 -52
  157. package/modules/hall-ui/public/harbor.css +123 -0
  158. package/modules/hall-ui/public/harbor.html +3 -120
  159. package/modules/hall-ui/public/index.html +11 -4
  160. package/modules/hall-ui/public/instances-panel.js +4 -1
  161. package/modules/hall-ui/public/modules.css +63 -0
  162. package/modules/hall-ui/public/modules.html +3 -60
  163. package/modules/hall-ui/public/new-project-wizard.js +7 -3
  164. package/modules/hall-ui/public/not-ready.html +2 -0
  165. package/modules/hall-ui/public/pair.css +73 -0
  166. package/modules/hall-ui/public/pair.html +3 -70
  167. package/modules/hall-ui/public/palette.js +302 -0
  168. package/modules/hall-ui/public/primer.css +13 -0
  169. package/modules/hall-ui/public/primer.html +2 -0
  170. package/modules/hall-ui/public/profile.html +2 -0
  171. package/modules/hall-ui/public/ranks.html +2 -0
  172. package/modules/hall-ui/public/roadmap.css +179 -0
  173. package/modules/hall-ui/public/roadmap.html +9 -172
  174. package/modules/hall-ui/public/roadmap.js +329 -316
  175. package/modules/hall-ui/public/sessions.css +16 -0
  176. package/modules/hall-ui/public/sessions.html +3 -13
  177. package/modules/hall-ui/public/settings.html +2 -0
  178. package/modules/hall-ui/public/settings.js +4 -4
  179. package/modules/hall-ui/public/shell.js +143 -18
  180. package/modules/hall-ui/public/style.css +231 -39
  181. package/modules/hall-ui/public/task-detail.js +347 -26
  182. package/modules/hall-ui/public/task.html +6 -1
  183. package/modules/hall-ui/public/watch.html +2 -0
  184. package/modules/hall-ui/public/work.html +8 -6
  185. package/modules/hall-ui/public/work.js +1 -1
  186. package/modules/ideas/inbox.js +61 -11
  187. package/modules/ideas/routes/inbox.js +23 -0
  188. package/modules/lifecycle/claim-eligibility.js +72 -0
  189. package/modules/lifecycle/db.js +519 -139
  190. package/modules/lifecycle/done-when.js +18 -3
  191. package/modules/lifecycle/github-push.js +19 -2
  192. package/modules/lifecycle/goal-advisory.js +114 -0
  193. package/modules/lifecycle/goal-authz.js +62 -0
  194. package/modules/lifecycle/lifecycle.js +9 -0
  195. package/modules/lifecycle/publish-reconciler.js +109 -6
  196. package/modules/lifecycle/routes/claims.js +68 -23
  197. package/modules/lifecycle/routes/done-when.js +110 -15
  198. package/modules/lifecycle/routes/goals.js +8 -38
  199. package/modules/lifecycle/routes/tasks.js +38 -6
  200. package/modules/lifecycle/ship-card.js +6 -0
  201. package/modules/onboarding/onboarding-state.js +1 -1
  202. package/modules/platform-identity/CLAUDE.md +15 -0
  203. package/modules/platform-identity/hub-device.js +147 -0
  204. package/modules/platform-identity/hub-keys.js +151 -0
  205. package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
  206. package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
  207. package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
  208. package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
  209. package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
  210. package/modules/platform-identity/module.json +18 -0
  211. package/modules/platform-identity/platform-identity.js +531 -0
  212. package/modules/platform-identity/pollers/code-sweep.js +43 -0
  213. package/modules/platform-identity/routes/my-projects.js +140 -0
  214. package/modules/platform-identity/routes/projects.js +107 -0
  215. package/modules/platform-identity/routes/scouting.js +35 -0
  216. package/modules/platform-identity/routes/sso.js +402 -0
  217. package/modules/platform-identity/tests/platform-identity.mjs +388 -0
  218. package/modules/platform-identity/ui/.gitkeep +0 -0
  219. package/modules/security/routes/reports.js +10 -0
  220. package/modules/sessions/db.js +166 -21
  221. package/modules/sessions/module.json +1 -1
  222. package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
  223. package/modules/sessions/routes/sessions.js +33 -0
  224. package/package-lock.json +2 -2
  225. package/package.json +1 -1
  226. package/public-landing/assets/anim/idle/frame_00.webp +0 -0
  227. package/public-landing/assets/anim/idle/frame_01.webp +0 -0
  228. package/public-landing/assets/anim/idle/frame_02.webp +0 -0
  229. package/public-landing/assets/anim/idle/frame_03.webp +0 -0
  230. package/public-landing/assets/anim/idle/frame_04.webp +0 -0
  231. package/public-landing/assets/anim/idle/frame_05.webp +0 -0
  232. package/public-landing/assets/anim/idle/frame_06.webp +0 -0
  233. package/public-landing/assets/anim/idle/frame_07.webp +0 -0
  234. package/public-landing/assets/anim/idle/frame_08.webp +0 -0
  235. package/public-landing/assets/anim/idle/frame_09.webp +0 -0
  236. package/public-landing/assets/anim/idle/frame_10.webp +0 -0
  237. package/public-landing/assets/anim/idle/frame_11.webp +0 -0
  238. package/public-landing/assets/anim/idle/frame_12.webp +0 -0
  239. package/public-landing/assets/anim/idle/frame_13.webp +0 -0
  240. package/public-landing/assets/anim/idle/frame_14.webp +0 -0
  241. package/public-landing/assets/anim/idle/frame_15.webp +0 -0
  242. package/public-landing/assets/anim/idle/frame_16.webp +0 -0
  243. package/public-landing/assets/anim/idle/frame_17.webp +0 -0
  244. package/public-landing/assets/anim/idle/frame_18.webp +0 -0
  245. package/public-landing/assets/anim/idle/frame_19.webp +0 -0
  246. package/public-landing/assets/anim/idle/frame_20.webp +0 -0
  247. package/public-landing/assets/anim/idle/frame_21.webp +0 -0
  248. package/public-landing/assets/anim/idle/frame_22.webp +0 -0
  249. package/public-landing/assets/anim/idle/frame_23.webp +0 -0
  250. package/public-landing/assets/anim/idle/frame_24.webp +0 -0
  251. package/public-landing/assets/anim/idle/frame_25.webp +0 -0
  252. package/public-landing/assets/anim/idle/frame_26.webp +0 -0
  253. package/public-landing/assets/anim/idle/frame_27.webp +0 -0
  254. package/public-landing/assets/anim/idle/frame_28.webp +0 -0
  255. package/public-landing/assets/anim/idle/frame_29.webp +0 -0
  256. package/public-landing/assets/anim/idle/frame_30.webp +0 -0
  257. package/public-landing/assets/anim/idle/frame_31.webp +0 -0
  258. package/public-landing/assets/anim/idle/frame_32.webp +0 -0
  259. package/public-landing/assets/anim/idle/frame_33.webp +0 -0
  260. package/public-landing/assets/anim/idle/frame_34.webp +0 -0
  261. package/public-landing/assets/anim/idle/frame_35.webp +0 -0
  262. package/public-landing/assets/anim/idle/frame_36.webp +0 -0
  263. package/public-landing/assets/anim/idle/frame_37.webp +0 -0
  264. package/public-landing/assets/anim/idle/frame_38.webp +0 -0
  265. package/public-landing/assets/anim/idle/frame_39.webp +0 -0
  266. package/public-landing/assets/anim/idle/frame_40.webp +0 -0
  267. package/public-landing/assets/anim/idle/frame_41.webp +0 -0
  268. package/public-landing/assets/anim/idle/frame_42.webp +0 -0
  269. package/public-landing/assets/anim/idle/frame_43.webp +0 -0
  270. package/public-landing/create.html +51 -58
  271. package/public-landing/gate/README.md +137 -0
  272. package/public-landing/gate/dispmaps/bar.png +0 -0
  273. package/public-landing/gate/dispmaps/flat.png +0 -0
  274. package/public-landing/gate/dispmaps/key.png +0 -0
  275. package/public-landing/gate/index.html +587 -0
  276. package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
  277. package/public-landing/gate/previews/off-the-boats.jpg +0 -0
  278. package/public-landing/gate/space.css +799 -0
  279. package/public-landing/gate/space.js +1826 -0
  280. package/public-landing/gate/sprites/enter.png +0 -0
  281. package/public-landing/gate/sprites/search.png +0 -0
  282. package/public-landing/gate/sprites/terminal-blank.png +0 -0
  283. package/public-landing/gate/sprites/tile.png +0 -0
  284. package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
  285. package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
  286. package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
  287. package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
  288. package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
  289. package/public-landing/world/assets/plates/scene-establishing.png +0 -0
  290. package/scripts/gds/abandon.js +6 -4
  291. package/scripts/gds/api.js +10 -5
  292. package/scripts/gds/api.ps1 +26 -0
  293. package/scripts/gds/api.sh +6 -0
  294. package/scripts/gds/audit-ships.js +7 -1
  295. package/scripts/gds/backfill-sessions.js +78 -18
  296. package/scripts/gds/backup.js +23 -1
  297. package/scripts/gds/box-connect-lib.js +124 -31
  298. package/scripts/gds/box-sync.js +66 -0
  299. package/scripts/gds/box.js +225 -53
  300. package/scripts/gds/cf-tunnel.js +145 -6
  301. package/scripts/gds/claim.js +34 -3
  302. package/scripts/gds/cli-lib.js +161 -27
  303. package/scripts/gds/code.js +6 -2
  304. package/scripts/gds/deploy-divergence.js +209 -0
  305. package/scripts/gds/dev-lib.js +309 -0
  306. package/scripts/gds/dev.js +322 -0
  307. package/scripts/gds/doctor.js +90 -61
  308. package/scripts/gds/fetch-art-key.js +1 -1
  309. package/scripts/gds/fetch-sound-prefs.js +2 -2
  310. package/scripts/gds/fitness.js +228 -12
  311. package/scripts/gds/gds-db-backup.service +16 -1
  312. package/scripts/gds/gds-db-offsite.service +9 -1
  313. package/scripts/gds/gen-api-client.js +1 -1
  314. package/scripts/gds/gen-api-docs.js +36 -14
  315. package/scripts/gds/gen-diagrams.js +45 -28
  316. package/scripts/gds/gen-file-map.js +2 -1
  317. package/scripts/gds/gen-freshness.js +32 -0
  318. package/scripts/gds/gen-repo-map.js +3 -2
  319. package/scripts/gds/gen-session-index.js +14 -5
  320. package/scripts/gds/hooks/pre-push.js +2 -2
  321. package/scripts/gds/init.js +60 -3
  322. package/scripts/gds/install-git-hooks.js +1 -1
  323. package/scripts/gds/key-card.js +15 -6
  324. package/scripts/gds/key-status.js +1 -1
  325. package/scripts/gds/linkify-refs.js +35 -9
  326. package/scripts/gds/login.js +16 -1
  327. package/scripts/gds/paste-token.js +7 -1
  328. package/scripts/gds/preflight.js +126 -0
  329. package/scripts/gds/provision.js +123 -12
  330. package/scripts/gds/publish-manifest.js +7 -1
  331. package/scripts/gds/reauth.js +7 -3
  332. package/scripts/gds/regen-instance-docs.js +47 -0
  333. package/scripts/gds/run-unit-tests.js +4 -2
  334. package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
  335. package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
  336. package/scripts/gds/sequence.js +425 -0
  337. package/scripts/gds/session-cost.js +10 -1
  338. package/scripts/gds/setup.js +31 -5
  339. package/scripts/gds/shell.js +5 -3
  340. package/scripts/gds/ship.js +319 -29
  341. package/scripts/gds/smoke-gds.js +139 -8
  342. package/scripts/gds/start.js +171 -22
  343. package/scripts/gds/status.js +1 -1
  344. package/scripts/gds/triage.js +10 -9
  345. package/scripts/gds/upgrade.js +124 -2
  346. package/scripts/status-mirror-sync.js +114 -84
  347. package/src/bongos/api-errors.js +1 -0
  348. package/src/bongos/auth.js +447 -102
  349. package/src/bongos/db-kernel.js +27 -0
  350. package/src/bongos/db.js +39 -0
  351. package/src/bongos/module-scope-map.js +27 -1
  352. package/src/bongos/permission-path-check.js +136 -102
  353. package/src/bongos/repo-info.js +47 -11
  354. package/src/bongos/route-rank-check.js +429 -46
  355. package/src/bongos/routes/_helpers.js +12 -1
  356. package/src/bongos/routes/auth.js +219 -2
  357. package/src/bongos/routes/backup.js +58 -2
  358. package/src/bongos/routes/me.js +35 -1
  359. package/src/bongos/serve-internal.js +84 -15
  360. package/src/branding.js +32 -0
  361. package/src/instance-config.js +30 -0
  362. package/src/module-api.js +112 -1
  363. package/src/platform-server.js +86 -9
  364. package/tests/abandon_task.mjs +59 -3
  365. package/tests/api_cli_flags.mjs +53 -0
  366. package/tests/auth_page_gate.mjs +13 -0
  367. package/tests/backfill_sessions.mjs +127 -1
  368. package/tests/backup_cli.mjs +54 -0
  369. package/tests/bongos_box_connect.mjs +77 -0
  370. package/tests/box_access.mjs +130 -1
  371. package/tests/box_credential.mjs +125 -0
  372. package/tests/box_host_keys.mjs +24 -0
  373. package/tests/box_infra_resolve.mjs +149 -0
  374. package/tests/box_scope_session.mjs +6 -2
  375. package/tests/box_sync.mjs +55 -0
  376. package/tests/box_task_scope.mjs +99 -0
  377. package/tests/branding.mjs +12 -0
  378. package/tests/cf_ruleset_preflight.mjs +142 -0
  379. package/tests/cf_tunnel.mjs +37 -0
  380. package/tests/claim_gate_rebase.mjs +98 -0
  381. package/tests/clawback_confirmed_backlog.mjs +103 -0
  382. package/tests/cli_lib_formatters.mjs +20 -0
  383. package/tests/confirm_attribution.mjs +30 -46
  384. package/tests/credit_grant.mjs +198 -10
  385. package/tests/criterion_authoring_gate.mjs +272 -0
  386. package/tests/criterion_progress.mjs +33 -1
  387. package/tests/dev_lib.mjs +253 -0
  388. package/tests/devbox_artifact_gate.mjs +75 -0
  389. package/tests/devbox_dmg_backdrop.mjs +137 -0
  390. package/tests/devbox_icons.mjs +304 -0
  391. package/tests/devbox_installer_brand.mjs +232 -0
  392. package/tests/devbox_key_register.mjs +234 -0
  393. package/tests/docs_openapi_route.mjs +110 -0
  394. package/tests/doctor_hooks.mjs +141 -0
  395. package/tests/extract_json.mjs +140 -0
  396. package/tests/fitness.mjs +89 -0
  397. package/tests/gen_freshness.mjs +96 -0
  398. package/tests/goal_advisory.mjs +251 -0
  399. package/tests/goal_criterion_confirm_ui.mjs +269 -0
  400. package/tests/goal_routes.mjs +59 -4
  401. package/tests/goal_tier.mjs +12 -3
  402. package/tests/governance_catalog.mjs +129 -0
  403. package/tests/governance_claim_eligibility.mjs +262 -0
  404. package/tests/governance_config.mjs +187 -0
  405. package/tests/governance_ownership_scope.mjs +410 -0
  406. package/tests/governance_page_gates.mjs +324 -0
  407. package/tests/governance_parity.mjs +336 -0
  408. package/tests/governance_principals.mjs +232 -0
  409. package/tests/governance_protected_surfaces.mjs +208 -0
  410. package/tests/governance_require_permission.mjs +223 -0
  411. package/tests/governance_resolver.mjs +84 -0
  412. package/tests/governance_role_sync.mjs +231 -0
  413. package/tests/governance_seed.mjs +127 -0
  414. package/tests/governance_session_scope.mjs +434 -0
  415. package/tests/governance_vanilla_boot.mjs +203 -0
  416. package/tests/grade_attribution.mjs +7 -7
  417. package/tests/hall_audit.mjs +223 -0
  418. package/tests/hall_nav.mjs +191 -0
  419. package/tests/hall_palette.mjs +206 -0
  420. package/tests/hall_signout.mjs +124 -0
  421. package/tests/hook_user_agents.mjs +10 -0
  422. package/tests/idea_triage.mjs +162 -0
  423. package/tests/idp_device_exchange.mjs +93 -0
  424. package/tests/init.mjs +51 -0
  425. package/tests/instance_config.mjs +65 -0
  426. package/tests/instance_mismatch_guard.mjs +23 -6
  427. package/tests/instance_release_config.mjs +104 -0
  428. package/tests/linkify_refs.mjs +15 -2
  429. package/tests/module_contributions.mjs +55 -0
  430. package/tests/module_loader.mjs +10 -5
  431. package/tests/module_scope_active_claims.mjs +94 -0
  432. package/tests/needs_rebase.mjs +92 -0
  433. package/tests/one_active_claim_per_session.mjs +76 -0
  434. package/tests/override_attribution.mjs +10 -8
  435. package/tests/override_request_ownership.mjs +8 -4
  436. package/tests/parse_cookie_decode.mjs +42 -0
  437. package/tests/pay_on_land.mjs +129 -0
  438. package/tests/platform_boot.mjs +100 -1
  439. package/tests/post_login_landing.mjs +42 -0
  440. package/tests/preflight_checks.mjs +72 -0
  441. package/tests/provision.mjs +132 -7
  442. package/tests/publish_branch_route.mjs +53 -0
  443. package/tests/publish_reconciler.mjs +187 -2
  444. package/tests/repo_info_binding.mjs +248 -0
  445. package/tests/reward_gate.mjs +11 -2
  446. package/tests/reward_mode_cost_plus_only.mjs +116 -0
  447. package/tests/reward_mode_surfacing.mjs +168 -0
  448. package/tests/route_permission_check.mjs +301 -0
  449. package/tests/route_rank_check.mjs +254 -12
  450. package/tests/route_validation.mjs +30 -0
  451. package/tests/sequence.mjs +267 -0
  452. package/tests/session_digest.mjs +44 -0
  453. package/tests/session_index.mjs +18 -6
  454. package/tests/session_records.mjs +39 -1
  455. package/tests/session_reward_on_land.mjs +381 -0
  456. package/tests/session_reward_reconcile.mjs +229 -0
  457. package/tests/ship_api_client_pathspec.mjs +100 -0
  458. package/tests/ship_base_flag.mjs +93 -0
  459. package/tests/ship_ci_deploy.mjs +80 -3
  460. package/tests/ship_upstream_deletion.mjs +57 -0
  461. package/tests/smoke_target.mjs +233 -0
  462. package/tests/start_env_guard.mjs +87 -0
  463. package/tests/start_rebase_warning.mjs +103 -0
  464. package/tests/status_mirror_sync.mjs +122 -0
  465. package/tests/stop_refcheck.mjs +19 -1
  466. package/tests/task_goal_link.mjs +15 -6
  467. package/tests/upgrade.mjs +139 -0
  468. package/tests/web_admission_status.mjs +162 -0
  469. package/tests/write_validation_gaps.mjs +110 -0
@@ -0,0 +1,151 @@
1
+ // modules/platform-identity/hub-keys.js — the hub's assertion-signing keys +
2
+ // EdDSA assertion minting (ADR 0141 §1, task #1002108).
3
+ //
4
+ // For CLI federation, the hub runs the GitHub device flow (its own app), then hands
5
+ // the CLI a short-lived, audience-scoped SIGNED ASSERTION that the instance verifies
6
+ // OFFLINE — so /sso/token stays browser-flow-only + server-to-server, and CLI login
7
+ // needs no instance->hub call at exchange time.
8
+ //
9
+ // Signing is ASYMMETRIC (Ed25519): the hub holds the private key; instances hold
10
+ // only the PUBLIC key (provisioned into their env). This is the deliberate split
11
+ // from the per-client shared secret (which authenticates an instance TO the hub):
12
+ // a compromised instance holds no signing key, so it can never forge an assertion
13
+ // another instance would accept. node:crypto has Ed25519 built in — no dependency,
14
+ // no PKI service.
15
+ //
16
+ // The assertion is a compact JWT (alg=EdDSA). The wire format is mirrored, by
17
+ // necessity, in the instance-side verifier (src/bongos/auth.js verifyHubAssertion)
18
+ // — the two sides live across the core<->module boundary and cannot share code
19
+ // (ADR 0091 §2 boundary-forced duplication). Keep them in lockstep:
20
+ // token = base64url(JSON(header)) "." base64url(JSON(payload)) "." base64url(sig)
21
+ // header = { alg: "EdDSA", typ: "JWT" }
22
+ // payload = { iss:"cloudbongos-hub", aud:<client_id>, sub:<github_id>,
23
+ // github_login, display_name, avatar_url, iat, exp, jti }
24
+ // sig = Ed25519(privkey, utf8(`${b64u(header)}.${b64u(payload)}`))
25
+ 'use strict';
26
+
27
+ const crypto = require('node:crypto');
28
+ const api = require('../../src/module-api');
29
+
30
+ const { resolveEnv } = api;
31
+
32
+ // Assertion lifetime — deliberately short (~120s): a human runs the CLI exchange
33
+ // within seconds of approving in the browser, so a tight window bounds replay.
34
+ const ASSERTION_TTL_MS = 120 * 1000;
35
+ const ISSUER = 'cloudbongos-hub';
36
+
37
+ const b64uJson = (obj) => Buffer.from(JSON.stringify(obj), 'utf8').toString('base64url');
38
+
39
+ // Generate a fresh Ed25519 keypair, exported as single-line base64(DER) strings
40
+ // suitable for env vars. The hub operator runs this ONCE and places the private
41
+ // key in the hub's web.env (<PREFIX>_HUB_SIGNING_KEY); the public key is provisioned
42
+ // into each federated instance (<PREFIX>_HUB_PUBLIC_KEY). Returns { privateKeyB64,
43
+ // publicKeyB64 }.
44
+ function generateHubKeypair() {
45
+ const { privateKey, publicKey } = crypto.generateKeyPairSync('ed25519');
46
+ return {
47
+ privateKeyB64: privateKey.export({ type: 'pkcs8', format: 'der' }).toString('base64'),
48
+ publicKeyB64: publicKey.export({ type: 'spki', format: 'der' }).toString('base64'),
49
+ };
50
+ }
51
+
52
+ // Load the hub's Ed25519 PRIVATE signing key from env (base64 of the PKCS8 DER).
53
+ // Returns a KeyObject or null when unset (→ device federation is "not configured").
54
+ function loadHubSigningKey({ env } = {}) {
55
+ const b64 = env ? env.HUB_SIGNING_KEY : resolveEnv('HUB_SIGNING_KEY');
56
+ if (!b64) return null;
57
+ try {
58
+ return crypto.createPrivateKey({ key: Buffer.from(String(b64), 'base64'), format: 'der', type: 'pkcs8' });
59
+ } catch (err) {
60
+ console.error('[platform-identity] HUB_SIGNING_KEY is set but unreadable:', err.message);
61
+ return null;
62
+ }
63
+ }
64
+
65
+ function hubSigningConfigured() {
66
+ return !!loadHubSigningKey();
67
+ }
68
+
69
+ // The hub's PUBLIC key (base64 of the SPKI DER), derived from the private key, for
70
+ // the GET /sso/pubkey endpoint. Returns null when the private key is unset.
71
+ function hubPublicKeyB64() {
72
+ const priv = loadHubSigningKey();
73
+ if (!priv) return null;
74
+ const pub = crypto.createPublicKey(priv);
75
+ return pub.export({ type: 'spki', format: 'der' }).toString('base64');
76
+ }
77
+
78
+ // Mint an audience-scoped, short-lived EdDSA assertion for a federated client. The
79
+ // payload carries IDENTITY ONLY (never a rank). `nowMs`/`jti` are injectable for
80
+ // deterministic tests. Returns the compact token string.
81
+ function mintHubAssertion(
82
+ { clientId, githubId, githubLogin, displayName, avatarUrl },
83
+ { signingKey, nowMs, jti } = {},
84
+ ) {
85
+ const key = signingKey || loadHubSigningKey();
86
+ if (!key) throw new Error('hub signing key not configured');
87
+ const iat = Math.floor((nowMs ?? Date.now()) / 1000);
88
+ const header = { alg: 'EdDSA', typ: 'JWT' };
89
+ const payload = {
90
+ iss: ISSUER,
91
+ aud: String(clientId),
92
+ sub: String(githubId),
93
+ github_login: githubLogin,
94
+ display_name: displayName ?? null,
95
+ avatar_url: avatarUrl ?? null,
96
+ iat,
97
+ exp: iat + Math.floor(ASSERTION_TTL_MS / 1000),
98
+ jti: jti || crypto.randomBytes(12).toString('base64url'),
99
+ };
100
+ const signingInput = `${b64uJson(header)}.${b64uJson(payload)}`;
101
+ const sig = crypto.sign(null, Buffer.from(signingInput, 'utf8'), key).toString('base64url');
102
+ return `${signingInput}.${sig}`;
103
+ }
104
+
105
+ // The purpose marker that distinguishes a back-channel LOGOUT token from a login
106
+ // assertion. Both are hub-signed EdDSA JWTs, but a logout token carries `purpose`
107
+ // + NO identity fields, and a login assertion carries identity + NO `purpose` —
108
+ // so neither verifier accepts the other's tokens (the instance login verifier
109
+ // requires github_login; the logout verifier requires this purpose). Task 1002238.
110
+ const LOGOUT_PURPOSE = 'backchannel-logout';
111
+
112
+ // Mint an audience-scoped, short-lived EdDSA BACK-CHANNEL LOGOUT token for a
113
+ // federated client (ADR 0144, task 1002238). The hub sends this to a federated
114
+ // instance's /auth/backchannel-logout when a builder signs out of the hub, so the
115
+ // instance can revoke that builder's local session too (federated single-logout).
116
+ // Carries ONLY the subject (github_id) + the purpose marker — never identity, a
117
+ // rank, or a session token (the ADR 0016 trust boundary holds here too: the hub
118
+ // says "sign this github_id out", the instance decides what that means locally).
119
+ // Same asymmetric signing + ~120s TTL + aud-binding as mintHubAssertion, so a
120
+ // token minted for one instance can't be replayed against another. nowMs/jti
121
+ // injectable for deterministic tests.
122
+ function mintHubLogoutToken({ clientId, githubId }, { signingKey, nowMs, jti } = {}) {
123
+ const key = signingKey || loadHubSigningKey();
124
+ if (!key) throw new Error('hub signing key not configured');
125
+ const iat = Math.floor((nowMs ?? Date.now()) / 1000);
126
+ const header = { alg: 'EdDSA', typ: 'JWT' };
127
+ const payload = {
128
+ iss: ISSUER,
129
+ aud: String(clientId),
130
+ sub: String(githubId),
131
+ purpose: LOGOUT_PURPOSE,
132
+ iat,
133
+ exp: iat + Math.floor(ASSERTION_TTL_MS / 1000),
134
+ jti: jti || crypto.randomBytes(12).toString('base64url'),
135
+ };
136
+ const signingInput = `${b64uJson(header)}.${b64uJson(payload)}`;
137
+ const sig = crypto.sign(null, Buffer.from(signingInput, 'utf8'), key).toString('base64url');
138
+ return `${signingInput}.${sig}`;
139
+ }
140
+
141
+ module.exports = {
142
+ ASSERTION_TTL_MS,
143
+ ISSUER,
144
+ LOGOUT_PURPOSE,
145
+ generateHubKeypair,
146
+ loadHubSigningKey,
147
+ hubSigningConfigured,
148
+ hubPublicKeyB64,
149
+ mintHubAssertion,
150
+ mintHubLogoutToken,
151
+ };
@@ -0,0 +1,114 @@
1
+ -- platform_identity_001_tables.sql — the `platform-identity` module's DB slice
2
+ -- (ADR 0141 §2, task #1002106). The Cloud Bongos hub identity-provider store:
3
+ -- platform accounts + an SSO client registry + single-use authorization codes.
4
+ --
5
+ -- The hub is an IDENTITY provider, NOT an authority (ADR 0016 / ADR 0141): none of
6
+ -- these tables carry a rank, credits, or admission — only the stable GitHub identity
7
+ -- (github_id, login, display name, avatar). Authority stays computed locally on each
8
+ -- federated instance.
9
+ --
10
+ -- Module migrations are ADDITIVE and NAMESPACED (ADR 0083 §Decision #5): every
11
+ -- object lives under the platform_identity_ prefix, there is no down-migration, and
12
+ -- the filename is platform_identity_-prefixed (ADR 0108 §5) so its stem can never
13
+ -- collide with a core / instance / other-module migration across repos.
14
+ -- `scripts/migrate.sh` discovers + applies this ONLY when the platform-identity
15
+ -- module is enabled in config/modules.json (i.e. on the hub).
16
+ --
17
+ -- Idempotent: safe to re-run.
18
+
19
+ BEGIN;
20
+
21
+ -- ---------------------------------------------------------------------------
22
+ -- platform_identity_accounts — the platform account, keyed on the stable GitHub
23
+ -- user id. One row per human who has ever signed in on the hub. Identity only.
24
+ -- ---------------------------------------------------------------------------
25
+ CREATE TABLE IF NOT EXISTS platform_identity_accounts (
26
+ id bigserial PRIMARY KEY,
27
+
28
+ -- GitHub's numeric user id — the stable, rename-proof key the whole federation
29
+ -- pivots on (a login can change; the id does not). UNIQUE = one account per human.
30
+ github_id bigint NOT NULL UNIQUE,
31
+
32
+ github_login text NOT NULL,
33
+ display_name text,
34
+ avatar_url text,
35
+
36
+ created_at timestamptz NOT NULL DEFAULT now(),
37
+ updated_at timestamptz NOT NULL DEFAULT now()
38
+ );
39
+
40
+ -- ---------------------------------------------------------------------------
41
+ -- platform_identity_sso_clients — registered federated projects (each an OAuth
42
+ -- client of the hub). Provisioning (task #1002109) writes a row per hosted
43
+ -- instance; the client_secret is stored ONLY as a hash — the plaintext lives in
44
+ -- the instance's env and never returns from the hub.
45
+ -- ---------------------------------------------------------------------------
46
+ CREATE TABLE IF NOT EXISTS platform_identity_sso_clients (
47
+ id bigserial PRIMARY KEY,
48
+
49
+ -- The public client identifier the instance presents at /sso/authorize + /sso/token.
50
+ client_id text NOT NULL UNIQUE,
51
+
52
+ -- SHA-256 hash (hex) of the client secret. NEVER the plaintext. Verified with a
53
+ -- constant-time compare at /sso/token. The secret is high-entropy (256-bit random,
54
+ -- generated by provisioning), so a fast hash is sufficient (no password-dictionary
55
+ -- surface); the hash-at-rest means a DB read leak does not expose live secrets.
56
+ secret_hash text NOT NULL,
57
+
58
+ -- Human-facing project name (for the hub Explore/catalog + audit).
59
+ name text NOT NULL,
60
+
61
+ -- The exact-match allow-list of redirect URIs this client may receive a code at.
62
+ -- An /sso/authorize redirect_uri (and the /sso/token redirect_uri) MUST appear
63
+ -- here verbatim — the open-redirect guard (ADR 0141 §2 invariant #3).
64
+ redirect_uris text[] NOT NULL DEFAULT '{}',
65
+
66
+ -- The instance's public origin (advisory / display; the authority is redirect_uris).
67
+ origin text,
68
+
69
+ -- The account that owns this project (advisory attribution; NOT an authority).
70
+ owner_github_id bigint,
71
+
72
+ status text NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended')),
73
+
74
+ created_at timestamptz NOT NULL DEFAULT now(),
75
+ updated_at timestamptz NOT NULL DEFAULT now()
76
+ );
77
+
78
+ -- ---------------------------------------------------------------------------
79
+ -- platform_identity_auth_codes — single-use authorization codes (~60s TTL). Minted
80
+ -- at /sso/authorize (browser leg), redeemed once at /sso/token (server-to-server).
81
+ -- Stores only a HASH of the opaque code (the code is a bearer secret) + an identity
82
+ -- snapshot + the binding (client_id, github_id, redirect_uri). Single-use is enforced
83
+ -- by the atomic redeem (UPDATE ... WHERE consumed_at IS NULL RETURNING) in the domain.
84
+ -- ---------------------------------------------------------------------------
85
+ CREATE TABLE IF NOT EXISTS platform_identity_auth_codes (
86
+ id bigserial PRIMARY KEY,
87
+
88
+ -- SHA-256 hash (hex) of the opaque authorization code. UNIQUE so a hash collision
89
+ -- or double-insert is impossible; the plaintext code is never stored.
90
+ code_hash text NOT NULL UNIQUE,
91
+
92
+ -- Binding: the code is valid ONLY when redeemed by this client for this account,
93
+ -- at the redirect_uri it was minted against.
94
+ client_id text NOT NULL,
95
+ github_id bigint NOT NULL,
96
+ redirect_uri text NOT NULL,
97
+
98
+ -- Identity snapshot returned on redeem — identity ONLY, never a rank.
99
+ github_login text NOT NULL,
100
+ display_name text,
101
+ avatar_url text,
102
+
103
+ expires_at timestamptz NOT NULL,
104
+ -- NULL until redeemed; the single-use guard flips it to now() atomically.
105
+ consumed_at timestamptz,
106
+ created_at timestamptz NOT NULL DEFAULT now()
107
+ );
108
+
109
+ -- Hot path: the redeem filters on code_hash (already UNIQUE-indexed) + expiry; this
110
+ -- index also backs a cheap TTL sweep of stale/consumed rows.
111
+ CREATE INDEX IF NOT EXISTS platform_identity_auth_codes_expiry
112
+ ON platform_identity_auth_codes (expires_at);
113
+
114
+ COMMIT;
@@ -0,0 +1,18 @@
1
+ -- platform_identity_002_client_origin_index.sql — index sso_clients by origin so the
2
+ -- CLI device-flow mint can resolve a client from the USER-TYPED instance origin
3
+ -- (ADR 0141 §1, task #1002108 security fix). The audience of a CLI assertion is now
4
+ -- resolved server-side from the origin the user typed, via this registry lookup —
5
+ -- NOT from a client_id the (untrusted) instance manifest supplies. That closes the
6
+ -- confused-deputy where a malicious `bongos login <evil>` could harvest a real-hub-
7
+ -- signed assertion scoped to a VICTIM instance. `origin` was advisory in _001; this
8
+ -- promotes it to an authoritative lookup key.
9
+ --
10
+ -- Additive + platform_identity_-namespaced (ADR 0083 §5). Idempotent.
11
+
12
+ BEGIN;
13
+
14
+ CREATE INDEX IF NOT EXISTS platform_identity_sso_clients_origin
15
+ ON platform_identity_sso_clients (origin)
16
+ WHERE status = 'active';
17
+
18
+ COMMIT;
@@ -0,0 +1,42 @@
1
+ -- platform_identity_003_project_memberships.sql — the hub's cross-project membership
2
+ -- directory (ADR 0141 §3, task #1002111). A federated instance posts a server-to-
3
+ -- server "check-in" on every sign-in (browser OR CLI): "this github_id builds on
4
+ -- project P, with this COARSE role". The hub upserts a row here. This is what makes a
5
+ -- CLI-only project appear in a builder's "My Projects" with no browser session ever
6
+ -- created against the hub.
7
+ --
8
+ -- Identity + a coarse role ONLY (ADR 0141: identity federated, authority local) — the
9
+ -- role is owner|builder|visitor, NEVER a rank. The project is keyed by client_id (the
10
+ -- sso_clients row that authenticated the check-in); a later projects catalog
11
+ -- (task #1002110) relates by client_id/origin for display.
12
+ --
13
+ -- Additive + platform_identity_-namespaced (ADR 0083 §5). Idempotent.
14
+
15
+ BEGIN;
16
+
17
+ CREATE TABLE IF NOT EXISTS platform_identity_project_memberships (
18
+ id bigserial PRIMARY KEY,
19
+
20
+ -- The project, identified by the sso_client that reported the membership.
21
+ client_id text NOT NULL,
22
+
23
+ -- The builder, by their stable GitHub id (joins to platform_identity_accounts).
24
+ github_id bigint NOT NULL,
25
+
26
+ -- COARSE role — never a rank. 'pending' is reserved for pre-seeded invitations
27
+ -- (task #1002115) that resolve on accept.
28
+ role text NOT NULL DEFAULT 'builder'
29
+ CHECK (role IN ('owner', 'builder', 'visitor', 'pending')),
30
+
31
+ joined_at timestamptz NOT NULL DEFAULT now(),
32
+ last_active timestamptz NOT NULL DEFAULT now(),
33
+
34
+ -- One membership row per (project, builder).
35
+ UNIQUE (client_id, github_id)
36
+ );
37
+
38
+ -- "My Projects" reads all memberships for one account.
39
+ CREATE INDEX IF NOT EXISTS platform_identity_project_memberships_github
40
+ ON platform_identity_project_memberships (github_id);
41
+
42
+ COMMIT;
@@ -0,0 +1,44 @@
1
+ -- platform_identity_004_projects.sql — the hub projects catalog (ADR 0141 §5, task
2
+ -- #1002110). One row per project the hub knows about, powering the public "Explore"
3
+ -- showcase (featured projects) + the join key for "My Projects" display. A federated
4
+ -- project is auto-catalogued when it registers as an sso_client; an Archon curates
5
+ -- the `featured` flag.
6
+ --
7
+ -- Keyed by `origin` (the project's public URL) — the natural project identity that
8
+ -- joins to sso_clients.origin and, through it, to project_memberships. Public,
9
+ -- non-authoritative directory metadata only (no rank/credits).
10
+ --
11
+ -- Additive + platform_identity_-namespaced (ADR 0083 §5). Idempotent.
12
+
13
+ BEGIN;
14
+
15
+ CREATE TABLE IF NOT EXISTS platform_identity_projects (
16
+ id bigserial PRIMARY KEY,
17
+
18
+ -- The project's public origin (e.g. https://mercury.cloudbongos.com). UNIQUE — one
19
+ -- catalog row per project; the join key to sso_clients / memberships.
20
+ origin text NOT NULL UNIQUE,
21
+
22
+ name text NOT NULL,
23
+ tagline text, -- a short one-liner for the Explore card
24
+ art_url text, -- optional cover art / logo
25
+
26
+ owner_github_id bigint, -- advisory attribution (not an authority)
27
+
28
+ -- 'hidden' keeps a row out of every listing (e.g. a deprovisioned project) without
29
+ -- deleting its history.
30
+ status text NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'hidden')),
31
+
32
+ -- The Archon-curated Explore flag. Only featured + active projects show publicly.
33
+ featured boolean NOT NULL DEFAULT false,
34
+
35
+ created_at timestamptz NOT NULL DEFAULT now(),
36
+ updated_at timestamptz NOT NULL DEFAULT now()
37
+ );
38
+
39
+ -- The Explore listing reads featured + active projects.
40
+ CREATE INDEX IF NOT EXISTS platform_identity_projects_featured
41
+ ON platform_identity_projects (featured)
42
+ WHERE featured = true AND status = 'active';
43
+
44
+ COMMIT;
@@ -0,0 +1,42 @@
1
+ -- platform_identity_005_builder_activity.sql — the hub's cross-project builder
2
+ -- activity store (ADR 0141 §4, task #1002113). Each federated project reports a
3
+ -- per-builder rollup (credits, tasks shipped, karma, rank held, disciplines,
4
+ -- recency); the hub upserts one row per (project, builder). This is the data plane
5
+ -- behind the INTERNAL, Archon-only scouting view (task #1002114) — it UPGRADES the
6
+ -- coarse ADR 0127 fleet metrics (two gauges keyed on a mutable handle) to a stable
7
+ -- github_id-keyed store.
8
+ --
9
+ -- Distinction from the identity federation: this rollup DOES carry rank_held +
10
+ -- credits, but as descriptive analytics for an internal talent directory (consent
11
+ -- via the platform T&C) — it is NEVER read as authority to grant anything on any
12
+ -- instance. Authority stays local (ADR 0141 / ADR 0016).
13
+ --
14
+ -- Additive + platform_identity_-namespaced (ADR 0083 §5). Idempotent.
15
+
16
+ BEGIN;
17
+
18
+ CREATE TABLE IF NOT EXISTS platform_identity_builder_project_activity (
19
+ id bigserial PRIMARY KEY,
20
+
21
+ -- The project (the sso_client that reported) + the builder (stable github id).
22
+ client_id text NOT NULL,
23
+ github_id bigint NOT NULL,
24
+
25
+ -- Descriptive talent signals — a snapshot, eventually-consistent, non-authoritative.
26
+ credits integer NOT NULL DEFAULT 0,
27
+ tasks_shipped integer NOT NULL DEFAULT 0,
28
+ karma integer NOT NULL DEFAULT 0,
29
+ rank_held text,
30
+ disciplines text[] NOT NULL DEFAULT '{}',
31
+
32
+ last_active timestamptz NOT NULL DEFAULT now(),
33
+ updated_at timestamptz NOT NULL DEFAULT now(),
34
+
35
+ UNIQUE (client_id, github_id)
36
+ );
37
+
38
+ -- Scouting aggregates across all projects for one builder.
39
+ CREATE INDEX IF NOT EXISTS platform_identity_builder_activity_github
40
+ ON platform_identity_builder_project_activity (github_id);
41
+
42
+ COMMIT;
@@ -0,0 +1,18 @@
1
+ {
2
+ "key": "platform-identity",
3
+ "title": "Platform identity (hub IdP)",
4
+ "description": "The Cloud Bongos hub identity-provider surface (ADR 0141): platform accounts, an SSO client registry, and an OAuth authorization-code login handoff so one platform account reaches any hosted project's builders hall with no second GitHub sign-in. Identity ONLY — the hub never mints or carries rank/credits/admission (the ADR 0016 trust boundary). Enabled ONLY on the hub instance (cloudbongos.com); ordinary hosted + self-hosted instances leave it off, so it adds zero attack surface for the common case.",
5
+ "coreVersion": "^1.14.0",
6
+ "default": false,
7
+ "author": "Cloud Bongos",
8
+ "origin": "Cloud Bongos platform (cloudbongos.com)",
9
+ "license": "AGPL-3.0",
10
+ "maintainer": "Cloud Bongos maintainers",
11
+ "contributes": {
12
+ "routes": ["sso", "projects", "my-projects", "scouting"],
13
+ "migrations": true,
14
+ "pollers": ["code-sweep"]
15
+ },
16
+ "provides": ["platform-identity.hub"],
17
+ "consumes": []
18
+ }