@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
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // regen-instance-docs.js — regenerate a STANDALONE instance's live navigation docs (task 1002314).
4
+ //
5
+ // THE GAP. On the monorepo, the gitignored whole-file navigation docs are regenerated at deploy by
6
+ // scripts/deploy/deploy-prod.sh + infra/box-source-fetch.sh (ADR 0110 §2/§3). STANDALONE instances
7
+ // (ADR 0108 — their own lean repo with @bongos/core vendored) never got that step: their bespoke
8
+ // pull-deploy regenerated NOTHING, so a fresh instance shipped with an empty docs/ and nothing kept
9
+ // the session-log index live. This script is the STANDALONE analogue of deploy-prod.sh's regen block
10
+ // — one line for an instance's deploy.sh to call after `git reset --hard` + migrate.
11
+ //
12
+ // USAGE (from the instance repo, core vendored in node_modules):
13
+ // node node_modules/@bongos/core/scripts/gds/regen-instance-docs.js
14
+ // It resolves the INSTANCE root (bongos.config.json instanceRoot / <PREFIX>_INSTANCE_ROOT / cwd) and
15
+ // writes docs/session-log-index.md THERE (gitignored on the instance, so the next
16
+ // `git reset --hard origin/main` never wipes it and no branch can ever diff it).
17
+ //
18
+ // SCOPE + CONTRACT: see regenerateNavDocs() in upgrade.js — it owns the generator list and the
19
+ // rationale for what is and isn't deploy-regenerated (repo-map is core-scoped; file-map + API docs
20
+ // are tracked/committed; diagrams are the headless-browser exception). Best-effort + LOUD per
21
+ // ADR 0110 §2 "accepted staleness": a broken generator prints `::ERROR::` (journald greps it) but
22
+ // this script ALWAYS exits 0 — a stale nav doc is tolerable; a failed deploy is not.
23
+
24
+ const path = require('node:path');
25
+ const { resolveInstanceRoot } = require('../../src/instance-config');
26
+ const { regenerateNavDocs } = require('./upgrade');
27
+
28
+ function main() {
29
+ const coreRoot = path.resolve(__dirname, '..', '..'); // the @bongos/core package this script ships in
30
+ const instanceDir = resolveInstanceRoot();
31
+ const res = regenerateNavDocs({ instanceDir, coreRoot });
32
+ if (res.ran.length) {
33
+ console.log(`regen-instance-docs: regenerated ${res.ran.join(', ')} → ${instanceDir}/docs/`);
34
+ }
35
+ if (!res.ok) {
36
+ for (const f of res.failed) {
37
+ // LOUD (ADR 0110 §2): journald greps ::ERROR:: so a broken generator surfaces.
38
+ console.error(`::ERROR:: regen-instance-docs: ${f.gen} failed — ${f.reason}`);
39
+ }
40
+ }
41
+ // Best-effort: NEVER fail the deploy. A stale/absent nav doc is tolerable; the ::ERROR:: is the alarm.
42
+ process.exit(0);
43
+ }
44
+
45
+ if (require.main === module) main();
46
+
47
+ module.exports = { main };
@@ -31,6 +31,10 @@ const { isModuleEnabled } = require('../../src/modules');
31
31
  const TESTS_DIR = path.resolve(__dirname, '..', '..', 'tests');
32
32
  const MODULES_DIR = path.resolve(__dirname, '..', '..', 'modules');
33
33
  const PER_TEST_TIMEOUT_MS = 90_000;
34
+ // Integration tests (package build + `npm install` + a spawned server) are far heavier than a
35
+ // DB-free unit file, so the `--integration` gate (task 1002221 / audit H1) gives each one a much
36
+ // longer budget than the 90s unit cap.
37
+ const INTEGRATION_TIMEOUT_MS = 300_000;
34
38
 
35
39
  // Feature-module test sets (R59 / task 1198). A test that exercises a feature
36
40
  // MODULE runs only when this instance enables that module — a vanilla Cloud
@@ -69,8 +73,10 @@ const INTEGRATION = new Set([
69
73
  // platform-server — network + package build + a spawned server, run by its own
70
74
  // .github/workflows/consumer-layout-boot.yml, not this DB-free gate (task 2142).
71
75
  'consumer_layout_boot',
72
- 'discord_autojoin', 'discord_oauth', 'linkify_refs', 'memory_isolation',
73
- 'memory_pull', 'parallel-load', 'session_records', 'setup_smoke',
76
+ 'claim_gate_rebase', 'clawback_confirmed_backlog', 'discord_autojoin', 'discord_oauth',
77
+ 'linkify_refs', 'memory_isolation',
78
+ 'memory_pull', 'needs_rebase', 'parallel-load', 'reward_mode_cost_plus_only',
79
+ 'session_records', 'setup_smoke',
74
80
  'status-probe', 'subdomain_auth',
75
81
  ]);
76
82
 
@@ -128,31 +134,50 @@ function discoverModuleTests({ modulesDir = MODULES_DIR, isEnabled = isModuleEna
128
134
  }
129
135
 
130
136
  function main() {
137
+ // Two gates from one runner (task 1002221 / audit H1):
138
+ // default — the DB-free UNIT gate: every test file MINUS the integration set (+ known-
139
+ // failing / support / disabled-module). Fast, runs in a clean checkout / per PR.
140
+ // --integration — the standing INTEGRATION-SMOKE gate: ONLY the integration set (package build +
141
+ // `npm install` + live boot etc.). Heavier, longer per-test budget; run per
142
+ // release / on a schedule in an env that provides the services (DB/network). This
143
+ // is what promotes tests/consumer_layout_boot.mjs from "excluded + ad-hoc" to a
144
+ // first-class gate a release step can invoke with one command.
145
+ const integrationMode = process.argv.includes('--integration');
146
+ const perTestTimeout = integrationMode ? INTEGRATION_TIMEOUT_MS : PER_TEST_TIMEOUT_MS;
147
+
131
148
  const files = fs
132
149
  .readdirSync(TESTS_DIR)
133
150
  .filter((f) => f.endsWith('.mjs'))
134
151
  .map((f) => f.replace(/\.mjs$/, ''))
135
- .filter((name) => !INTEGRATION.has(name) && !KNOWN_FAILING.has(name)
136
- && !SUPPORT_MODULES.has(name) && !MODULE_DISABLED.has(name))
152
+ .filter((name) => integrationMode
153
+ ? (INTEGRATION.has(name) && !KNOWN_FAILING.has(name) && !SUPPORT_MODULES.has(name))
154
+ : (!INTEGRATION.has(name) && !KNOWN_FAILING.has(name) && !SUPPORT_MODULES.has(name) && !MODULE_DISABLED.has(name)))
137
155
  .sort();
138
156
 
139
- const { included: moduleTests, skippedDisabled: moduleTestsSkipped } = discoverModuleTests();
140
-
141
- const moduleNote = MODULE_DISABLED.size
142
- ? ` + ${MODULE_DISABLED.size} disabled-module (${[...MODULE_DISABLED].sort().join(', ')})`
143
- : '';
144
- const modOwnedSkipNote = moduleTestsSkipped.length
145
- ? ` + ${moduleTestsSkipped.length} module-owned test(s) skipped (module disabled: ${[...new Set(moduleTestsSkipped.map((t) => t.key))].sort().join(', ')})`
146
- : '';
157
+ // Module-owned tests are DB-free unit tests — only the default gate runs them.
158
+ const { included: moduleTests, skippedDisabled: moduleTestsSkipped } = integrationMode
159
+ ? { included: [], skippedDisabled: [] }
160
+ : discoverModuleTests();
161
+
162
+ if (integrationMode) {
163
+ console.log(`run-unit-tests --integration: ${files.length} integration-smoke test file(s) (${files.join(', ') || 'none found'}); per-test budget ${INTEGRATION_TIMEOUT_MS / 1000}s`);
164
+ } else {
165
+ const moduleNote = MODULE_DISABLED.size
166
+ ? ` + ${MODULE_DISABLED.size} disabled-module (${[...MODULE_DISABLED].sort().join(', ')})`
167
+ : '';
168
+ const modOwnedSkipNote = moduleTestsSkipped.length
169
+ ? ` + ${moduleTestsSkipped.length} module-owned test(s) skipped (module disabled: ${[...new Set(moduleTestsSkipped.map((t) => t.key))].sort().join(', ')})`
170
+ : '';
171
+ console.log(`run-unit-tests: ${files.length + moduleTests.length} DB-free unit test file(s) (${files.length} core + ${moduleTests.length} module-owned; excluded ${INTEGRATION.size} integration + ${KNOWN_FAILING.size} known-failing${moduleNote}${modOwnedSkipNote})`);
172
+ }
147
173
  const total = files.length + moduleTests.length;
148
- console.log(`run-unit-tests: ${total} DB-free unit test file(s) (${files.length} core + ${moduleTests.length} module-owned; excluded ${INTEGRATION.size} integration + ${KNOWN_FAILING.size} known-failing${moduleNote}${modOwnedSkipNote})`);
149
174
 
150
175
  const failures = [];
151
176
  const runOne = (displayName, filePath) => {
152
177
  try {
153
178
  execFileSync(process.execPath, [filePath], {
154
179
  stdio: ['ignore', 'ignore', 'pipe'],
155
- timeout: PER_TEST_TIMEOUT_MS,
180
+ timeout: perTestTimeout,
156
181
  env: { ...process.env, NODE_ENV: 'test' },
157
182
  });
158
183
  console.log(` ok ${displayName}`);
@@ -168,12 +193,13 @@ function main() {
168
193
  for (const name of files) runOne(name, path.join(TESTS_DIR, `${name}.mjs`));
169
194
  for (const { key, name, file } of moduleTests) runOne(`${key}/${name}`, file);
170
195
 
196
+ const label = integrationMode ? 'run-unit-tests --integration' : 'run-unit-tests';
171
197
  console.log('');
172
198
  if (failures.length === 0) {
173
- console.log(`run-unit-tests: all ${total} passed.`);
199
+ console.log(`${label}: all ${total} passed.`);
174
200
  process.exit(0);
175
201
  }
176
- console.log(`run-unit-tests: ${failures.length} FAILED — ${failures.join(', ')}`);
202
+ console.log(`${label}: ${failures.length} FAILED — ${failures.join(', ')}`);
177
203
  process.exit(1);
178
204
  }
179
205
 
@@ -0,0 +1,104 @@
1
+ // Seed the tasks for goal 1000048 "SEO & public discoverability — rankable per-project
2
+ // profiles" (BONGOS-V1, internal). Source of truth:
3
+ // docs/specs/bongos-v1-seo-public-discoverability.md (status: final).
4
+ // Idempotent on (source, source_ref). Re-running resolves to the existing rows.
5
+ //
6
+ // Run: node scripts/gds/seed-bongos-v1-seo-tasks.js
7
+ const os = require('os');
8
+ const sess = require(os.homedir() + '/.config/cloudbongos/gds-session.json');
9
+ const BASE = (sess.api_base || 'https://cloudbongos.com').replace(/\/$/, '');
10
+ const TOKEN = sess.token;
11
+ const VER = 'BONGOS-V1';
12
+ const GOAL = 1000048;
13
+ const SRC = 'planning-session';
14
+ const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' };
15
+
16
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
17
+ async function api(method, path, body, _tries = 0) {
18
+ await sleep(400); // base throttle to stay under the per-IP rate limit
19
+ const res = await fetch(`${BASE}/api/gds${path}`, {
20
+ method, headers: H, body: body ? JSON.stringify(body) : undefined,
21
+ });
22
+ const text = await res.text();
23
+ let json; try { json = JSON.parse(text); } catch { json = { _raw: text.slice(0, 300) }; }
24
+ if (res.status === 429 && _tries < 8) {
25
+ const wait = ((json.error && json.error.details && json.error.details.retry_after_seconds) || 30) + 1;
26
+ console.log(` …rate-limited, waiting ${wait}s`);
27
+ await sleep(wait * 1000);
28
+ return api(method, path, body, _tries + 1);
29
+ }
30
+ return { status: res.status, ok: res.ok, json };
31
+ }
32
+
33
+ // criterion slugs (position-independent — the goal's done_when_criteria.criterion_id)
34
+ const PP = 'seo-project-profile-page', NS = 'seo-toplevel-namespace', PC = 'seo-project-content',
35
+ PM = 'seo-page-metadata', CC = 'seo-canonical-consolidation', SR = 'seo-sitemap-robots',
36
+ VG = 'seo-visibility-gated', SB = 'seo-site-baseline';
37
+
38
+ // disc: engineer (backend/API/spike) | ui (page/markup/meta). kind: spike | feature | refactor | infra | verify (proofs).
39
+ // deps: 'R##' resolve to the just-created id; a NUMBER is a real cross-goal task id, passed through.
40
+ const TASKS = [
41
+ { ref:'R01', kind:'spike', disc:'engineer', prio:5, est:180, crit:[PP,NS,PM,CC], deps:[], title:'R01 · SEO + namespace architecture ADR', desc:'Needs-exploration: profile-page rendering (server-rendered HTML from the Node/Express hub), routing precedence (/<slug> vs /bongos/* vs /api/*), the owner-picked slug model + reserved-word list, the cross-instance canonical mechanism, and how the profile reads goal-1000046 setup content. Output an ADR + confirmed sub-tasks. See docs/specs/bongos-v1-seo-public-discoverability.md.' },
42
+ { ref:'R02', kind:'feature', disc:'engineer', prio:5, est:240, crit:[PP,NS], deps:['R01'], title:'R02 · Owner-picked slug at creation + reserved-name validation + backfill', desc:'Projects get a unique owner-chosen vanity slug at creation (username-style), validated vs a reserved list (bongos, api, sso, gate, create, explore, builders, status, assets, sitemap.xml, robots.txt, ...). Auto-derive + backfill a default slug for existing projects (owner can change). Adds a step to the creation flow — coordinate with goals 1000035/1000046. Deps R01.' },
43
+ { ref:'R03', kind:'refactor',disc:'engineer', prio:5, est:240, crit:[NS], deps:['R01'], title:'R03 · Move platform pages under /bongos/… ; top-level /<slug> resolves to a project', desc:'Serve hall/status/create/explore/gate under /bongos/… with 301 redirects from old paths; never move /api, /sso, /auth, /.well-known. Top-level /<slug> resolves to a project profile after the reserved-word check. Deps R01.' },
44
+ { ref:'R04', kind:'feature', disc:'ui', prio:5, est:240, crit:[PP,PM], deps:['R02','R03'],title:'R04 · Server-rendered project profile page at /<slug>', desc:'Crawlable server-rendered HTML: project name, description, cover art, builders, tech/modules, and a prominent "Open the live app" CTA. This page is the primary shareable destination. Deps R02,R03.' },
45
+ { ref:'R05', kind:'feature', disc:'ui', prio:4, est:180, crit:[PC], deps:['R04'], title:'R05 · Render goal-1000046 setup content on the profile + auto-derive SEO copy', desc:'Read the project\'s setup content (goal 1000046) and render it on the profile; auto-derive SEO title/description from it. No separate editor (per interview). Coordinate with 1000046 — needs a real description + tags; render current fields (name/tagline) meanwhile and enrich as 1000046 lands. Deps R04.' },
46
+ { ref:'R06', kind:'feature', disc:'ui', prio:4, est:150, crit:[PM,CC], deps:['R04'], title:'R06 · Per-page SEO metadata (title/description/OG/Twitter/self-canonical)', desc:'Dynamic <title>, meta description, Open Graph + Twitter card tags, and a self-referencing canonical on each profile. Deps R04.' },
47
+ { ref:'R07', kind:'feature', disc:'ui', prio:4, est:120, crit:[PM], deps:['R04'], title:'R07 · JSON-LD structured data on profiles', desc:'Emit SoftwareApplication/CreativeWork JSON-LD on each profile page. Deps R04.' },
48
+ { ref:'R08', kind:'feature', disc:'ui', prio:4, est:150, crit:[PP], deps:['R04'], title:'R08 · Route discovery through profiles (orbs + links → /<slug>)', desc:'Make /<slug> the shareable destination: orbs cards and "view project" links point to the profile, which carries the "Open the live app" CTA — maximizing internal links to the ranking page. Deps R04. NOTE: the orbs front door is a separate static site — the orbs-side link change likely lands instance-side.' },
49
+ { ref:'R09', kind:'feature', disc:'ui', prio:4, est:180, crit:[PP,SR], deps:['R04'], title:'R09 · Crawlable projects directory via the orbs table-view', desc:'Make the orbs page\'s table view a server-rendered, crawlable, indexable HTML index of all Public projects (a plain-link list to each /<slug>), linked from the landing. This IS the directory (no separate directory page, per interview). Deps R04.' },
50
+ { ref:'R10', kind:'feature', disc:'engineer', prio:4, est:180, crit:[SR], deps:['R04','R11'],title:'R10 · sitemap.xml (public projects + core pages)', desc:'Auto-generated sitemap.xml at /sitemap.xml listing all Public project profiles + core pages; regenerates on project create/update/visibility-change (cached). Deps R04,R11.' },
51
+ { ref:'R11', kind:'feature', disc:'engineer', prio:4, est:210, crit:[VG], deps:['R04'], title:'R11 · Visibility-gated indexing (visibility metaphor)', desc:'Public→full indexable profile; Private (star)→minimal page + join/request CTA, noindex; Stealth (black hole)→404; Unlisted (dark matter)→no public page until published. HARD conceptual dependency on goal 1000046\'s visibility states (not yet seeded) — coordinate; gate on the state field once it exists. Deps R04.' },
52
+ { ref:'R12', kind:'feature', disc:'engineer', prio:3, est:120, crit:[SR], deps:['R10'], title:'R12 · robots.txt', desc:'Serve robots.txt: allow public pages, disallow /api + internal, reference /sitemap.xml. Deps R10.' },
53
+ { ref:'R13', kind:'feature', disc:'engineer', prio:3, est:240, crit:[CC], deps:['R04'], title:'R13 · Cross-instance canonical (full scope)', desc:'rel=canonical from each live instance back to its hub profile: federated/co-tenant instances emit it; hub-hosted subdomains when that tier lands; publish a documented canonical snippet for self-hosted owners. Touches instance-side core rendering → Metic+ auto-floor. Coordinate with provisioning/federation (goals 1000032/1000041). Deps R04.' },
54
+ { ref:'R14', kind:'feature', disc:'ui', prio:3, est:210, crit:[PP,PM], deps:['R04',1002278], title:'R14 · Public builder-profile SEO page (handle-based path)', desc:'Server-rendered, SEO-optimized public builder profile at a handle path (e.g. /u/<handle>): metadata + Person/ProfilePage JSON-LD, crawlable HTML. Extends goal 1000045\'s builder profiles with a public, rankable rendering. Deps R04 + goal-1000045 profile API (task 1002278).' },
55
+ { ref:'R15', kind:'feature', disc:'engineer', prio:3, est:150, crit:[SR,VG], deps:['R14','R10'],title:'R15 · Builder profiles in sitemap, consent-gated', desc:'Add consented/public builder profiles to sitemap.xml; honor goal-1000045\'s hide/opt-out flag (coordinate with 1000045 R03). Non-consented builders excluded/noindex. Deps R14,R10.' },
56
+ { ref:'R16', kind:'feature', disc:'ui', prio:2, est:120, crit:[PC], deps:['R05'], title:'R16 · SEO content nudges in the setup/edit flow', desc:'Rule-based nudges where owners author content (goal 1000046 setup/edit): description length, tags, cover image — so profiles have enough real text to rank. Coordinate with 1000046. Deps R05.' },
57
+ { ref:'R17', kind:'feature', disc:'ui', prio:3, est:150, crit:[SB], deps:['R01'], title:'R17 · Landing + Explore SEO metadata', desc:'Give the landing page (goal 1000031) and the Explore page proper title/description/Open Graph/structured data and ensure they are indexable. Coordinate with 1000031. Deps R01.' },
58
+ { ref:'R18', kind:'infra', disc:'engineer', prio:2, est:180, crit:[SB], deps:['R04'], title:'R18 · Technical-SEO + Core Web Vitals pass', desc:'Audit + fix technical SEO across public pages: mobile-friendly, load speed / Core Web Vitals, indexability. Deps R04.' },
59
+ { ref:'R19', kind:'verify', disc:'engineer', prio:2, est:120, crit:[PP,PM,CC,SR,VG,PC], deps:['R04','R06','R07','R10','R11','R14','R15'], title:'R19 · PROOF: a public project + builder profile rank-ready; non-public hidden', desc:'End-to-end proof: a real Public project profile is live at cloudbongos.com/<slug> with correct metadata + JSON-LD, appears in sitemap.xml, passes Google Rich Results + mobile-friendly tests; a public builder profile is likewise rank-ready; and a Private project is noindex + absent from the sitemap (Stealth 404s). Deps R04,R06,R07,R10,R11,R14,R15.' },
60
+ ];
61
+
62
+ const ROOTS = ['R01']; // zero-dep entry task to open for claiming
63
+
64
+ (async () => {
65
+ const idByRef = {};
66
+ let created = 0, existing = 0;
67
+ console.log(`Seeding ${TASKS.length} tasks under goal ${GOAL} (${VER})…`);
68
+ for (const t of TASKS) {
69
+ const r = await api('POST', '/tasks', {
70
+ version_id: VER, goal_id: GOAL, title: t.title, description: t.desc,
71
+ kind: t.kind, discipline: t.disc, priority: t.prio, est_minutes: t.est,
72
+ criterion_ids: t.crit, source: SRC, source_ref: `bv1-seo-${t.ref}`,
73
+ });
74
+ if (!r.ok) { console.log(` ${t.ref}: FAILED ${r.status} ${JSON.stringify(r.json)}`); continue; }
75
+ const task = r.json.task || r.json;
76
+ idByRef[t.ref] = task.id;
77
+ if (r.json.idempotent || r.json.existing) existing++; else created++;
78
+ console.log(` ${t.ref} → task ${task.id} (${t.kind}/${t.disc}, P${t.prio}, [${t.crit.join(',')}])`);
79
+ }
80
+
81
+ console.log('Wiring dependencies…');
82
+ let edges = 0;
83
+ for (const t of TASKS) {
84
+ if (!t.deps.length) continue;
85
+ const id = idByRef[t.ref];
86
+ const depIds = t.deps.map((d) => (typeof d === 'number' ? d : idByRef[d])).filter(Boolean);
87
+ if (!id || depIds.length !== t.deps.length) { console.log(` ${t.ref}: dep resolve gap, skipping`); continue; }
88
+ const r = await api('POST', `/tasks/${id}/dependencies`, { depends_on_task_ids: depIds });
89
+ if (!r.ok) { console.log(` ${t.ref}: dep FAILED ${r.status} ${JSON.stringify(r.json)}`); continue; }
90
+ edges += (r.json.added || depIds.length);
91
+ console.log(` ${t.ref} depends on ${t.deps.join(',')}`);
92
+ }
93
+
94
+ console.log('Promoting root(s) to ready…');
95
+ for (const ref of ROOTS) {
96
+ const id = idByRef[ref];
97
+ if (!id) continue;
98
+ const r = await api('POST', `/tasks/${id}/promote`, {});
99
+ console.log(` ${ref} (task ${id}): ${r.ok ? 'ready' : 'promote note ' + JSON.stringify(r.json).slice(0, 120)}`);
100
+ }
101
+
102
+ console.log(`\nDONE. created=${created} existing=${existing} depEdges=${edges}. Roots opened: ${ROOTS.join(', ')}.`);
103
+ console.log('ref→id:', JSON.stringify(idByRef));
104
+ })();
@@ -0,0 +1,126 @@
1
+ // Seed the tasks for goal 1000045 "Public builder profiles" (BONGOS-V1, internal).
2
+ // Source of truth: docs/specs/bongos-v1-public-builder-profiles.md (status: final).
3
+ // Idempotent on (source, source_ref). Re-running resolves to the existing rows.
4
+ //
5
+ // Run: node scripts/gds/seed-bv1-profiles-tasks.js
6
+ const os = require('os');
7
+ const sess = require(os.homedir() + '/.config/cloudbongos/gds-session.json');
8
+ const BASE = sess.api_base.replace(/\/$/, '');
9
+ const TOKEN = sess.token;
10
+ const VER = 'BONGOS-V1';
11
+ const GOAL = 1000045;
12
+ const SRC = 'planning-session';
13
+ const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' };
14
+
15
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
16
+ async function api(method, path, body, _tries = 0) {
17
+ await sleep(400); // base throttle to stay under the per-IP rate limit
18
+ const res = await fetch(`${BASE}/api/gds${path}`, {
19
+ method, headers: H, body: body ? JSON.stringify(body) : undefined,
20
+ });
21
+ const text = await res.text();
22
+ let json; try { json = JSON.parse(text); } catch { json = { _raw: text.slice(0, 300) }; }
23
+ if (res.status === 429 && _tries < 8) {
24
+ const wait = ((json.error && json.error.details && json.error.details.retry_after_seconds) || 30) + 1;
25
+ console.log(` …rate-limited, waiting ${wait}s`);
26
+ await sleep(wait * 1000);
27
+ return api(method, path, body, _tries + 1);
28
+ }
29
+ return { status: res.status, ok: res.ok, json };
30
+ }
31
+
32
+ // disc: engineer (backend/API/spike) | ui (frontend). kind: spike | feature | verify (proofs).
33
+ const TASKS = [
34
+ // Phase 1 — profile shows cross-project record + hide (C1,C2) — P5
35
+ { ref:'R01', kind:'spike', disc:'engineer', prio:5, est:180, crit:['C1','C2'], deps:[], title:'R01 · Design profile↔cross-project rollup join + consent model', desc:'Needs-exploration: how the public profile reads the platform-identity rollup (listScoutingRollup / platform_identity_builder_project_activity), public-by-default, and where the hide flag (C2) lives. Output an ADR + sub-tasks. See docs/specs/bongos-v1-public-builder-profiles.md.' },
36
+ { ref:'R02', kind:'feature', disc:'engineer', prio:5, est:240, crit:['C1'], deps:['R01'], title:'R02 · Profile API returns cross-project record + project names', desc:'Extend GET /builders/:id/profile to include aggregated cross-project credits/ships/karma/disciplines + the list of projects by name, from the platform-identity rollup; public by default; respects the whitelist + leak test (tests/profile_route.mjs). Done-when: another account sees the aggregate + project names, no private columns. Deps R01.' },
37
+ { ref:'R03', kind:'feature', disc:'engineer', prio:5, est:180, crit:['C2'], deps:['R01'], title:'R03 · Hide flag: builder hides cross-project stats (opt-out, live)', desc:'Self-serve opt-out that hides the cross-project record from the profile + applications, honored live everywhere. Default is shown. Deps R01.' },
38
+ { ref:'R04', kind:'feature', disc:'ui', prio:5, est:180, crit:['C1','C2'], deps:['R02','R03'], title:'R04 · Profile UI: cross-project section + self hide-toggle', desc:'Render the cross-project section (totals + project names) on the profile; show the hide toggle to the profile owner. Deps R02,R03.' },
39
+ { ref:'R05', kind:'feature', disc:'ui', prio:4, est:120, crit:['C1'], deps:['R02'], title:'R05 · Shareable-by-login profile URL (?builder=<login>)', desc:'Add a login-addressable profile URL alongside ?id=. Promotes idea #1000522. Deps R02.' },
40
+ { ref:'R06', kind:'verify', disc:'engineer', prio:4, est:90, crit:['C1','C2'], deps:['R04','R03'], title:'R06 · PROOF: cross-project record shows to a viewer; hide removes it live', desc:'Verify a 2-project builder\'s combined record shows to another account, and hiding removes it within one load. Extends tests/profile_route.mjs. Deps R04,R03.' },
41
+
42
+ // Phase 2 — apply from orbs + application carries profile (C3,C4) — P5
43
+ { ref:'R07', kind:'spike', disc:'engineer', prio:5, est:180, crit:['C3','C4'], deps:[], title:'R07 · Design application model + "project owner (registrant+delegates)" authz', desc:'Needs-exploration: extend access_requests vs a new cross-project applications record; how the profile snapshot travels hub→target; the owner (registrant + delegates) authz; pending queue + approve/decline. Output an ADR + sub-tasks. Deps none.' },
44
+ { ref:'R08', kind:'feature', disc:'engineer', prio:5, est:240, crit:['C3','C4'], deps:['R07'], title:'R08 · Application API: apply / list-pending / approve / decline', desc:'Cross-project application flow reusing the join relay (/my-projects/join → target /access-requests). Deps R07.' },
45
+ { ref:'R09', kind:'feature', disc:'engineer', prio:5, est:150, crit:['C4'], deps:['R08','R02'], title:'R09 · Application carries the applicant\'s cross-project record (+note)', desc:'Attach the applicant\'s cross-project record (subject to the C2 hide, live) + optional note to the application the owner sees. Deps R08,R02.' },
46
+ { ref:'R10', kind:'feature', disc:'ui', prio:5, est:180, crit:['C3'], deps:['R08'], title:'R10 · "Apply" affordance on the in-core browse surface', desc:'Apply action + state (applied/pending/member) on the project cards / My Projects. Deps R08.' },
47
+ { ref:'R11', kind:'feature', disc:'ui', prio:5, est:180, crit:['C4'], deps:['R08'], title:'R11 · Owner pending-applications view (approve/decline)', desc:'A project owner sees pending applications for their project and approves/declines. Deps R08.' },
48
+ { ref:'R12', kind:'feature', disc:'ui', prio:4, est:150, crit:['C3'], deps:['R10'], title:'R12 · Surface "Apply" on the orbs front door', desc:'Wire the Apply affordance onto the orbs page. NOTE: the orbs front door is a separate static site — this likely lands instance-side. Deps R10.' },
49
+ { ref:'R13', kind:'verify', disc:'engineer', prio:5, est:90, crit:['C3','C4'], deps:['R10','R11','R09'], title:'R13 · PROOF: apply → owner sees record → approves → applicant joins', desc:'End-to-end verify of the apply→approve flow carrying the profile. Deps R10,R11,R09.' },
50
+
51
+ // Phase 3 — owners browse builder profiles (C5) — P4
52
+ { ref:'R14', kind:'feature', disc:'engineer', prio:4, est:210, crit:['C5'], deps:['R02'], title:'R14 · Graduate /scouting to project-owner-facing + opt-out-of-recruiting flag', desc:'Widen the Archon-only /scouting to a project owner (registrant+delegates); add a builder opt-out-of-recruiting flag. Touches authz → Metic+ floor. Deps R02.' },
53
+ { ref:'R15', kind:'feature', disc:'ui', prio:4, est:210, crit:['C5'], deps:['R14'], title:'R15 · Owner recruiting UI (search/filter/sort; honors hide + opt-out)', desc:'Owner-facing recruiting surface: search/filter by discipline, sort by track record; honors C2 hide + recruiting opt-out. Deps R14.' },
54
+ { ref:'R16', kind:'feature', disc:'ui', prio:4, est:150, crit:['C5'], deps:['R15','R08'], title:'R16 · Browse → invite/recruit a builder to your project', desc:'Invite/recruit a builder from the browse surface, tying into the application/invite flow. Deps R15,R08.' },
55
+ { ref:'R17', kind:'verify', disc:'engineer', prio:4, est:90, crit:['C5'], deps:['R15','R16'], title:'R17 · PROOF: non-Archon owner browses, filters, invites', desc:'Verify a non-Archon project owner browses builder profiles, filters by discipline, invites one. Deps R15,R16.' },
56
+
57
+ // Phase 4 — builder-to-builder connections + degrees (C6) — P4
58
+ { ref:'R18', kind:'spike', disc:'engineer', prio:4, est:180, crit:['C6'], deps:[], title:'R18 · Design connections model incl. 1st/2nd/3rd-degree traversal', desc:'Needs-exploration: platform-level connections (account↔account) with request/accept/decline/remove; degree-of-separation traversal (1st/2nd/3rd); "people you may know" from native signals. Output an ADR + sub-tasks. Deps none.' },
59
+ { ref:'R19', kind:'feature', disc:'engineer', prio:4, est:240, crit:['C6'], deps:['R18'], title:'R19 · Connections API: request/accept/decline/remove/list + degree queries', desc:'The connection graph API incl. degree-of-separation queries. Deps R18.' },
60
+ { ref:'R20', kind:'feature', disc:'ui', prio:4, est:180, crit:['C6'], deps:['R19','R04'], title:'R20 · Connections on the profile (with degree labels) + connect button', desc:'Show a builder\'s connections (public) with 1st/2nd/3rd-degree labels; connect/pending/accept from the profile. Deps R19,R04.' },
61
+ { ref:'R21', kind:'feature', disc:'engineer', prio:4, est:150, crit:['C6'], deps:['R19'], title:'R21 · "Builders you may know" from mutuals + shared projects/guilds', desc:'Suggest connections from mutual connections + shared projects/guilds (2nd/3rd degree). Deps R19.' },
62
+ { ref:'R22', kind:'verify', disc:'engineer', prio:4, est:90, crit:['C6'], deps:['R20','R21'], title:'R22 · PROOF: two builders connect; each sees the other + a 2nd-degree suggestion', desc:'Verify request→accept, mutual visibility, and a 2nd-degree suggestion appears. Deps R20,R21.' },
63
+
64
+ // Phase 5 — guilds + apply/invite + guild map (C7,C8,C9) — P3
65
+ { ref:'R23', kind:'spike', disc:'engineer', prio:3, est:210, crit:['C7','C8','C9'], deps:['R18','R07'], title:'R23 · Design guild model (tables, roles, public/unlisted, rollup, map ranking)', desc:'Needs-exploration: platform-level guilds + guild_members (multi-guild, distinct from goal_members); roles; public/unlisted visibility; collective rollup (excludes hidden members); guild↔project application reuse; map ranking. Output an ADR + sub-tasks. Deps R18,R07.' },
66
+ { ref:'R24', kind:'feature', disc:'engineer', prio:3, est:240, crit:['C7'], deps:['R23'], title:'R24 · Guild CRUD + membership API + public/unlisted visibility', desc:'Create guild, invite/accept/join-request, roster, leave; owner sets public/unlisted. Deps R23.' },
67
+ { ref:'R25', kind:'feature', disc:'ui', prio:3, est:210, crit:['C7'], deps:['R24'], title:'R25 · Guild page UI (identity, roster, collective record)', desc:'Guild page: identity, roster, collective track record (N of M counted). Deps R24.' },
68
+ { ref:'R26', kind:'feature', disc:'engineer', prio:3, est:180, crit:['C7'], deps:['R24','R02'], title:'R26 · Guild collective track-record rollup (excludes hidden members)', desc:'Aggregate members\' cross-project stats into the guild total; exclude C2-hidden members ("N of M counted"). Deps R24,R02.' },
69
+ { ref:'R27', kind:'feature', disc:'engineer', prio:3, est:210, crit:['C8'], deps:['R24','R08'], title:'R27 · Guild → project applications + owner invites a guild (each-member-opt-in)', desc:'Guild applies to / is invited to a project (guild-level mirror of R08); each member opts in before being attached. Deps R24,R08.' },
70
+ { ref:'R28', kind:'feature', disc:'ui', prio:3, est:150, crit:['C8'], deps:['R27','R11'], title:'R28 · Owner view: pending guild applications', desc:'Extends the owner application view (R11) to guild applications. Deps R27,R11.' },
71
+ { ref:'R29', kind:'spike', disc:'engineer', prio:3, est:150, crit:['C9'], deps:['R26'], title:'R29 · Design guild map ranking + orb-sky viz approach', desc:'Needs-exploration: rank guilds by size/success; render on the orb-sky visual language (goal 1000044). Output design + sub-tasks. Deps R26.' },
72
+ { ref:'R30', kind:'feature', disc:'engineer', prio:3, est:150, crit:['C9'], deps:['R26'], title:'R30 · Guild map API (ranked; public guilds only; honors hide)', desc:'Ranked guilds by size/success; only public (not unlisted) guilds; honors member hide. Deps R26.' },
73
+ { ref:'R31', kind:'feature', disc:'ui', prio:3, est:210, crit:['C9'], deps:['R30','R29','R15'], title:'R31 · Guild map UI on the recruiting surface (orb-sky visual)', desc:'Visual guild map on the owner recruiting surface. Deps R30,R29,R15.' },
74
+ { ref:'R32', kind:'verify', disc:'engineer', prio:3, est:120, crit:['C7','C8','C9'], deps:['R25','R27','R31'], title:'R32 · PROOF: form guild → applies (members opt in) → owner approves → ranked on map', desc:'End-to-end verify of the guild lifecycle incl. the map. Deps R25,R27,R31.' },
75
+
76
+ // Phase 6 — connection proximity via orb-sky physics (C10) — P3
77
+ { ref:'R33', kind:'spike', disc:'engineer', prio:3, est:210, crit:['C10'], deps:['R19','R23'], title:'R33 · Design connection→orb-physics proximity + degree model', desc:'Needs-exploration: connection strength (direct + mutuals + shared projects/guilds + co-shipped; no time-decay) feeding orb-world physics (goals 1000044/1000049); cluster detection. NOTE cross-goal dependency on orb-physics infra. Output an ADR + sub-tasks. Deps R19,R23.' },
78
+ { ref:'R34', kind:'feature', disc:'engineer', prio:3, est:210, crit:['C10'], deps:['R33'], title:'R34 · Connection-strength + degree + cluster compute API', desc:'Compute connection strength + degrees + close-knit clusters; feeds orb physics + recruiting. Deps R33.' },
79
+ { ref:'R35', kind:'feature', disc:'ui', prio:3, est:180, crit:['C10'], deps:['R34','R25'], title:'R35 · Builder-side: clusters in the orb sky → invite a close cluster to a guild', desc:'Close connections cluster in the orb sky; invite a cluster to form a guild from it. Deps R34,R25.' },
80
+ { ref:'R36', kind:'feature', disc:'ui', prio:3, est:180, crit:['C10'], deps:['R34','R16'], title:'R36 · Project-side: recruit a close-knit cluster together', desc:'Surface close-knit clusters on the recruiting surface; recruit them together. Deps R34,R16.' },
81
+ { ref:'R37', kind:'verify', disc:'engineer', prio:3, est:120, crit:['C10'], deps:['R35','R36'], title:'R37 · PROOF: cluster forms a guild from the sky; owner recruits a cluster', desc:'End-to-end verify of the proximity-driven guild-forming + cluster-recruiting. Deps R35,R36.' },
82
+ ];
83
+
84
+ const ROOTS = ['R01', 'R07', 'R18']; // zero-dep entry spikes to open for claiming
85
+
86
+ (async () => {
87
+ const idByRef = {};
88
+ let created = 0, existing = 0;
89
+ console.log(`Seeding ${TASKS.length} tasks under goal ${GOAL} (${VER})…`);
90
+ for (const t of TASKS) {
91
+ const r = await api('POST', '/tasks', {
92
+ version_id: VER, goal_id: GOAL, title: t.title, description: t.desc,
93
+ kind: t.kind, discipline: t.disc, priority: t.prio, est_minutes: t.est,
94
+ criterion_ids: t.crit, source: SRC, source_ref: `bv1-profiles-${t.ref}`,
95
+ });
96
+ if (!r.ok) { console.log(` ${t.ref}: FAILED ${r.status} ${JSON.stringify(r.json)}`); continue; }
97
+ const task = r.json.task || r.json;
98
+ idByRef[t.ref] = task.id;
99
+ if (r.json.idempotent || r.json.existing) existing++; else created++;
100
+ console.log(` ${t.ref} → task ${task.id} (${t.kind}/${t.disc}, P${t.prio}, [${t.crit.join(',')}])`);
101
+ }
102
+
103
+ console.log('Wiring dependencies…');
104
+ let edges = 0;
105
+ for (const t of TASKS) {
106
+ if (!t.deps.length) continue;
107
+ const id = idByRef[t.ref];
108
+ const depIds = t.deps.map((d) => idByRef[d]).filter(Boolean);
109
+ if (!id || depIds.length !== t.deps.length) { console.log(` ${t.ref}: dep resolve gap, skipping`); continue; }
110
+ const r = await api('POST', `/tasks/${id}/dependencies`, { depends_on_task_ids: depIds });
111
+ if (!r.ok) { console.log(` ${t.ref}: dep FAILED ${r.status} ${JSON.stringify(r.json)}`); continue; }
112
+ edges += (r.json.added || depIds.length);
113
+ console.log(` ${t.ref} depends on ${t.deps.join(',')}`);
114
+ }
115
+
116
+ console.log('Promoting root spikes to ready…');
117
+ for (const ref of ROOTS) {
118
+ const id = idByRef[ref];
119
+ if (!id) continue;
120
+ const r = await api('POST', `/tasks/${id}/promote`, {});
121
+ console.log(` ${ref} (task ${id}): ${r.ok ? 'ready' : 'promote note ' + JSON.stringify(r.json).slice(0,120)}`);
122
+ }
123
+
124
+ console.log(`\nDONE. created=${created} existing=${existing} depEdges=${edges}. Roots opened: ${ROOTS.join(', ')}.`);
125
+ console.log('ref→id:', JSON.stringify(idByRef));
126
+ })();