@bongos/core 1.19.804 → 1.19.805

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 (235) hide show
  1. package/.bongos-core.json +257 -237
  2. package/.claude/skills/ask-for-help/SKILL.md +6 -6
  3. package/.claude/skills/backlog-review/SKILL.md +1 -1
  4. package/.claude/skills/blocker-review/SKILL.md +7 -7
  5. package/.claude/skills/blocker-solve/SKILL.md +5 -5
  6. package/.claude/skills/bug-triage/SKILL.md +7 -7
  7. package/.claude/skills/builder-claim/SKILL.md +3 -3
  8. package/.claude/skills/builder-cost/SKILL.md +2 -2
  9. package/.claude/skills/builder-end/SKILL.md +2 -2
  10. package/.claude/skills/builder-exit/SKILL.md +7 -7
  11. package/.claude/skills/builder-key/SKILL.md +2 -2
  12. package/.claude/skills/builder-reauth/SKILL.md +2 -2
  13. package/.claude/skills/builder-redteam/SKILL.md +7 -7
  14. package/.claude/skills/builder-release/SKILL.md +2 -2
  15. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  16. package/.claude/skills/builder-setup/SKILL.md +3 -3
  17. package/.claude/skills/builder-ship/SKILL.md +1 -1
  18. package/.claude/skills/builder-stage/SKILL.md +1 -1
  19. package/.claude/skills/builder-start/SKILL.md +1 -1
  20. package/.claude/skills/fix-task/SKILL.md +4 -4
  21. package/.claude/skills/goal-create/SKILL.md +18 -18
  22. package/.claude/skills/goal-review/SKILL.md +7 -7
  23. package/.claude/skills/grade-audit/SKILL.md +5 -5
  24. package/.claude/skills/grade-recover/SKILL.md +4 -4
  25. package/.claude/skills/grader-health/SKILL.md +6 -6
  26. package/.claude/skills/idea-triage/SKILL.md +14 -14
  27. package/.claude/skills/merge-mode/SKILL.md +3 -3
  28. package/.claude/skills/planning-session/SKILL.md +20 -20
  29. package/.claude/skills/priority-session/SKILL.md +10 -10
  30. package/.claude/skills/recall/SKILL.md +1 -1
  31. package/.claude/skills/scan-before-install/SKILL.md +3 -3
  32. package/.claude/skills/status/SKILL.md +2 -2
  33. package/.claude/skills/strand-fix/SKILL.md +2 -2
  34. package/clients/bongos-client/README.md +1 -1
  35. package/clients/bongos-client/bongos-client.global.js +2 -0
  36. package/clients/bongos-client/index.cjs +2 -0
  37. package/clients/bongos-client/index.d.ts +2 -0
  38. package/clients/bongos-client/index.mjs +2 -0
  39. package/docs/api/openapi.json +45 -11
  40. package/docs/api-reference.md +11 -10
  41. package/docs/module-api-changelog.md +2 -0
  42. package/modules/builder-settings/profile-nudge-prefs.js +1 -1
  43. package/modules/builder-settings/render-prefs.js +1 -1
  44. package/modules/dev-box/app/README.md +1 -1
  45. package/modules/dev-box/app/src/gds-client.js +11 -9
  46. package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
  47. package/modules/dev-box/app/test/unit.mjs +13 -13
  48. package/modules/dev-box/box-access.js +3 -3
  49. package/modules/dev-box/box-onboard.js +7 -7
  50. package/modules/discord/bug-attachments.js +1 -1
  51. package/modules/economy/cost-classify.js +6 -6
  52. package/modules/grading/grader-rubric.json +1 -1
  53. package/modules/grading/grader-score.js +1 -1
  54. package/modules/hall-ui/module.json +1 -1
  55. package/modules/hall-ui/public/drachmae.js +3 -3
  56. package/modules/hall-ui/public/idea.js +1 -1
  57. package/modules/hall-ui/public/md-reader.js +1 -1
  58. package/modules/hall-ui/public/people.html +1 -1
  59. package/modules/hall-ui/public/people.js +2 -2
  60. package/modules/hall-ui/public/primer.js +4 -4
  61. package/modules/hall-ui/public/roster.js +1 -1
  62. package/modules/hall-ui/public/shell.js +1 -1
  63. package/modules/hall-ui/public/task.js +1 -1
  64. package/modules/ideas/inbox.js +2 -2
  65. package/modules/lifecycle/db-analytics.js +1 -1
  66. package/modules/lifecycle/done-when.js +4 -4
  67. package/modules/lifecycle/version-close.js +1 -1
  68. package/modules/memory/learnings.js +2 -2
  69. package/modules/memory/memory.js +1 -1
  70. package/modules/onboarding/onboarding.js +1 -1
  71. package/modules/platform-identity/routes/my-projects.js +1 -1
  72. package/modules/platform-identity/routes/sso.js +2 -2
  73. package/modules/public-landing/public/index.html +2 -2
  74. package/modules/public-landing/public/projects-floor.states.json +1 -1
  75. package/modules/public-landing/public/projects.html +1 -1
  76. package/modules/public-landing/public/projects.states.json +1 -1
  77. package/modules/sessions/db.js +120 -0
  78. package/modules/sessions/module.json +2 -2
  79. package/modules/sessions/pollers/session-upload-health.js +111 -0
  80. package/modules/sessions/pulse.js +2 -2
  81. package/modules/sessions/routes/sessions.js +46 -0
  82. package/modules/sessions/upload-health.js +197 -0
  83. package/modules/status-ui/module.json +1 -1
  84. package/modules/status-ui/public/explore.js +1 -1
  85. package/package-lock.json +2 -2
  86. package/package.json +1 -1
  87. package/scripts/gds/agent-invoke.js +3 -3
  88. package/scripts/gds/api.js +4 -4
  89. package/scripts/gds/api.sh +1 -1
  90. package/scripts/gds/architect-audit.js +1 -1
  91. package/scripts/gds/artifact-audit.js +2 -2
  92. package/scripts/gds/audit-ships.js +2 -2
  93. package/scripts/gds/backfill-cost.js +1 -1
  94. package/scripts/gds/backfill-sessions.js +1 -1
  95. package/scripts/gds/backfill-subagent-rewards.js +1 -1
  96. package/scripts/gds/backfill-task-rewards.js +2 -2
  97. package/scripts/gds/box-auth-check.js +1 -1
  98. package/scripts/gds/box-sync.js +3 -3
  99. package/scripts/gds/box.js +10 -10
  100. package/scripts/gds/build-cli-package.js +3 -3
  101. package/scripts/gds/capture.js +2 -2
  102. package/scripts/gds/ci-grade.js +1 -1
  103. package/scripts/gds/claim-recall.js +2 -2
  104. package/scripts/gds/cli-lib.js +3 -3
  105. package/scripts/gds/context-pack.js +1 -1
  106. package/scripts/gds/copy-apply.js +2 -2
  107. package/scripts/gds/dev-lib.js +2 -2
  108. package/scripts/gds/fetch-art-key.js +2 -2
  109. package/scripts/gds/fetch-sound-prefs.js +3 -3
  110. package/scripts/gds/grade-smoke.js +1 -1
  111. package/scripts/gds/hooks/pre-push.js +1 -1
  112. package/scripts/gds/init.js +9 -9
  113. package/scripts/gds/key-card.js +1 -1
  114. package/scripts/gds/learning-capture.js +2 -2
  115. package/scripts/gds/linkify-refs.js +2 -2
  116. package/scripts/gds/local-preview-lib.js +1 -1
  117. package/scripts/gds/login.js +11 -10
  118. package/scripts/gds/main-audit.js +1 -1
  119. package/scripts/gds/newcomer-floor.config.json +1 -1
  120. package/scripts/gds/newcomer-floor.js +2 -2
  121. package/scripts/gds/newcomer-floor.templates.json +2 -2
  122. package/scripts/gds/onboarding-ship.js +1 -1
  123. package/scripts/gds/paste-token.js +3 -3
  124. package/scripts/gds/portability-smoke-memory.sh +5 -5
  125. package/scripts/gds/prove-strict-versioning.js +2 -2
  126. package/scripts/gds/provision-net.js +2 -2
  127. package/scripts/gds/provision-units.js +3 -3
  128. package/scripts/gds/pulse.js +2 -2
  129. package/scripts/gds/push-path-brief.js +2 -2
  130. package/scripts/gds/reauth.js +1 -1
  131. package/scripts/gds/recall.js +1 -1
  132. package/scripts/gds/redteam-patrol.js +3 -3
  133. package/scripts/gds/render-ideas.js +5 -5
  134. package/scripts/gds/repo-metrics.js +1 -1
  135. package/scripts/gds/sandbox-stage.js +3 -3
  136. package/scripts/gds/seed-adopt-tasks.js +3 -3
  137. package/scripts/gds/seed-board-room-tasks.js +1 -1
  138. package/scripts/gds/seed-bongos-app-tasks.js +2 -2
  139. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
  140. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
  141. package/scripts/gds/seed-bongos-tasks.js +5 -5
  142. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
  143. package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
  144. package/scripts/gds/seed-bv1-community-tasks.js +1 -1
  145. package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
  146. package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
  147. package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
  148. package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
  149. package/scripts/gds/seed-gds-v4-tasks.js +3 -3
  150. package/scripts/gds/seed-medusa-tasks.js +1 -1
  151. package/scripts/gds/seed-productization-tasks.js +1 -1
  152. package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
  153. package/scripts/gds/seed-provisioning-tasks.js +2 -2
  154. package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
  155. package/scripts/gds/seed-v2-world-tasks.js +2 -2
  156. package/scripts/gds/seed-verify-criteria.js +1 -1
  157. package/scripts/gds/session-digest.js +1 -1
  158. package/scripts/gds/session.js +2 -2
  159. package/scripts/gds/setup.js +7 -7
  160. package/scripts/gds/ship-flow.js +3 -3
  161. package/scripts/gds/ship-grade-steps.js +3 -3
  162. package/scripts/gds/ship-memory-sync.js +1 -1
  163. package/scripts/gds/ship-session-upload.js +3 -3
  164. package/scripts/gds/smoke-batch-claim.sh +10 -10
  165. package/scripts/gds/smoke-batch-release.sh +14 -14
  166. package/scripts/gds/smoke-claim-consistency.sh +19 -19
  167. package/scripts/gds/smoke-dependencies.sh +9 -9
  168. package/scripts/gds/smoke-write.sh +11 -11
  169. package/scripts/gds/start.js +1 -1
  170. package/scripts/gds/status.js +2 -2
  171. package/scripts/gds/strand-watch.js +1 -1
  172. package/scripts/gds/triage.js +4 -4
  173. package/scripts/gds/version-close.js +2 -2
  174. package/scripts/hall-preview/README.md +1 -1
  175. package/scripts/hall-preview/server.js +1 -1
  176. package/src/bongos/auth-admission.js +3 -3
  177. package/src/bongos/auth-idp.js +2 -2
  178. package/src/bongos/auth.js +3 -3
  179. package/src/bongos/db.js +2 -2
  180. package/src/bongos/llm-cache.js +2 -2
  181. package/src/bongos/metrics.js +1 -1
  182. package/src/bongos/middleware/audit.js +3 -3
  183. package/src/bongos/middleware/rate-limit.js +1 -1
  184. package/src/bongos/platform-visibility-gate.js +2 -2
  185. package/src/bongos/routes/_helpers.js +1 -1
  186. package/src/bongos/routes/audit-log.js +1 -1
  187. package/src/bongos/routes/auth.js +5 -5
  188. package/src/bongos/routes/backup.js +1 -1
  189. package/src/bongos/routes/builders.js +1 -1
  190. package/src/bongos/routes/instance.js +1 -1
  191. package/src/bongos/routes/live.js +1 -1
  192. package/src/bongos/routes/me.js +2 -2
  193. package/src/bongos/routes/modules.js +2 -2
  194. package/src/bongos/routes/public.js +1 -1
  195. package/src/bongos/routes/security.js +4 -4
  196. package/src/bongos/routes.js +1 -1
  197. package/src/bongos/serve-internal.js +6 -6
  198. package/src/branding.js +1 -1
  199. package/src/module-api.js +1 -1
  200. package/src/module-seams.js +2 -2
  201. package/src/platform-server.js +2 -2
  202. package/tests/api_alias_exceptions.mjs +67 -0
  203. package/tests/application_echo.mjs +12 -12
  204. package/tests/artifact_audit.mjs +1 -1
  205. package/tests/auth_page_gate.mjs +4 -4
  206. package/tests/auth_web_recovery.mjs +11 -11
  207. package/tests/bongos_login.mjs +7 -4
  208. package/tests/box_env.mjs +6 -6
  209. package/tests/bug_attachments.mjs +1 -1
  210. package/tests/cli_sessions.mjs +1 -1
  211. package/tests/dev_lib.mjs +1 -1
  212. package/tests/discord_bugs.mjs +2 -2
  213. package/tests/discord_inbound.mjs +2 -2
  214. package/tests/explore_visible_states.mjs +1 -1
  215. package/tests/government_page_gates.mjs +1 -1
  216. package/tests/hall_reference_world.mjs +1 -1
  217. package/tests/idea_ideate_full.mjs +1 -1
  218. package/tests/idp_federation.mjs +2 -2
  219. package/tests/llm-cache.mjs +1 -1
  220. package/tests/manage_manifest_shared_read.mjs +3 -3
  221. package/tests/people_directory_clip.mjs +1 -1
  222. package/tests/planning_session_skill.mjs +1 -1
  223. package/tests/platform_visibility_gate.mjs +15 -15
  224. package/tests/profile_route.mjs +25 -25
  225. package/tests/projects_hub.mjs +2 -2
  226. package/tests/provision.mjs +2 -2
  227. package/tests/provision_settings_apply.mjs +4 -4
  228. package/tests/sandbox_stage.mjs +8 -8
  229. package/tests/scouting_owner_access_and_reach.mjs +3 -3
  230. package/tests/session_upload_health.mjs +329 -0
  231. package/tests/setup_device_flow_fallback.mjs +1 -1
  232. package/tests/skill_ask_for_help.mjs +3 -3
  233. package/tests/skill_grade_audit.mjs +2 -2
  234. package/tests/skill_grader_health.mjs +3 -3
  235. package/tests/smoke_write_contract.mjs +1 -1
@@ -14,7 +14,7 @@ This is the live-flight complement to `/planning-session`: planning sessions set
14
14
 
15
15
  **Enforce the gate at the very top of the session, before reading anything else:**
16
16
 
17
- 1. Call `GET /api/gds/me` and read `builder.rank`. Compare case-insensitively (lowercase it before testing) — the `builders.rank` enum casing is defined by V3.R04; until it ships, normalize defensively.
17
+ 1. Call `GET /api/bongos/me` and read `builder.rank`. Compare case-insensitively (lowercase it before testing) — the `builders.rank` enum casing is defined by V3.R04; until it ships, normalize defensively.
18
18
  2. **If `rank` is present and lowercases to `xenos`** → stop immediately. Tell the builder: *"Priority sessions are a Metic+ operation — they reweight the whole team's idea queue. You're currently Xenos. Ask an Archon to promote you, then run this again."* Do not read the inbox, do not propose a ranking.
19
19
  3. **If `rank` lowercases to `metic` or `archon`** → proceed.
20
20
  4. **If `rank` is absent** (the server-enforced rank system — V3.R04 / criterion C7 — has not shipped yet, so `/me` returns no `rank` field): treat the session as available, exactly as `/planning-session` does today ("available to all builders for now; rank-gates to Metic+ at end of V3"). Note in the session-log entry that the gate ran in pre-rank passthrough mode. The moment `builders.rank` lands, this skill enforces it for real with no edit — the check above already reads the field.
@@ -40,10 +40,10 @@ This is the live-flight complement to `/planning-session`: planning sessions set
40
40
 
41
41
  Read everything the reweighting depends on. Do this before asking the builder anything, so their answers land against real data, not guesses.
42
42
 
43
- 1. `GET /api/gds/me` — rank gate (above) **and** the builder's `active_claims` (don't suggest claiming something they already hold) and `total_credits`.
44
- 2. `GET /api/gds/inbox` — the open ideas. This is the set you will rank. Capture each idea's `id`, `title`, `body_md`, `kind`, `suggested_version`, `suggested_priority`, `captured_at`, `captured_by`.
45
- 3. `GET /api/gds/tasks/claimable` — what's *actually claimable right now* (deps shipped, parallel-safe). The "what should I claim next?" answer must come from this list, never from an idea that hasn't been promoted to a task yet.
46
- 4. `GET /api/gds/blockers` (read-public, no auth) — open blockers. An idea that would resolve or route around a current blocker scores higher on the "unblock the most builders" axis.
43
+ 1. `GET /api/bongos/me` — rank gate (above) **and** the builder's `active_claims` (don't suggest claiming something they already hold) and `total_credits`.
44
+ 2. `GET /api/bongos/inbox` — the open ideas. This is the set you will rank. Capture each idea's `id`, `title`, `body_md`, `kind`, `suggested_version`, `suggested_priority`, `captured_at`, `captured_by`.
45
+ 3. `GET /api/bongos/tasks/claimable` — what's *actually claimable right now* (deps shipped, parallel-safe). The "what should I claim next?" answer must come from this list, never from an idea that hasn't been promoted to a task yet.
46
+ 4. `GET /api/bongos/blockers` (read-public, no auth) — open blockers. An idea that would resolve or route around a current blocker scores higher on the "unblock the most builders" axis.
47
47
 
48
48
  If `open_count` is 0, print *"inbox empty — nothing to reprioritize. Running `/builder-start` instead to surface claimable tasks."* and stop the priority flow.
49
49
 
@@ -90,7 +90,7 @@ Leverage is weighted highest because unblocking the team is the strongest team-l
90
90
 
91
91
  ### Phase 4 — "What should I claim next?" + land the log
92
92
 
93
- **Make the claim suggestion.** This is the single most useful output. Cross the ranking against `GET /api/gds/tasks/claimable` and the builder's Q7 (time/energy):
93
+ **Make the claim suggestion.** This is the single most useful output. Cross the ranking against `GET /api/bongos/tasks/claimable` and the builder's Q7 (time/energy):
94
94
 
95
95
  - The top-ranked idea is only a valid claim suggestion **if it's already a claimable task**. An open idea is *not* claimable — it's an idea. If the top idea hasn't been promoted to a task yet, say so and offer: *"This isn't a task yet — want me to promote it via `/idea-triage`, or claim the highest-ranked thing that's already a task?"*
96
96
  - Filter claimable tasks by the ranking's themes and by Q7: if the builder said "quick win," prefer low `est_minutes`; if "deep block," prefer the high-leverage foundational work even if it's bigger.
@@ -114,15 +114,15 @@ Prepend a one-line link to the CLAUDE.md §13 Session Log index (newest at top),
114
114
  # legacy fallback pms-session.json) and signs every request. Prefer driving the
115
115
  # API through it rather than re-deriving the token inline.
116
116
  node -e "const {apiCall}=require('./scripts/gds/cli-lib.js'); \
117
- apiCall('GET','/api/gds/me').then(r=>console.log(JSON.stringify(r.data,null,2)))"
117
+ apiCall('GET','/api/bongos/me').then(r=>console.log(JSON.stringify(r.data,null,2)))"
118
118
 
119
119
  # Phase 1 — pull state
120
120
  node -e "const {apiCall}=require('./scripts/gds/cli-lib.js'); \
121
- apiCall('GET','/api/gds/inbox').then(r=>console.log(JSON.stringify(r.data,null,2)))"
121
+ apiCall('GET','/api/bongos/inbox').then(r=>console.log(JSON.stringify(r.data,null,2)))"
122
122
  node -e "const {apiCall}=require('./scripts/gds/cli-lib.js'); \
123
- apiCall('GET','/api/gds/tasks/claimable').then(r=>console.log(JSON.stringify(r.data,null,2)))"
123
+ apiCall('GET','/api/bongos/tasks/claimable').then(r=>console.log(JSON.stringify(r.data,null,2)))"
124
124
  node -e "const {apiCall}=require('./scripts/gds/cli-lib.js'); \
125
- apiCall('GET','/api/gds/blockers').then(r=>console.log(JSON.stringify(r.data,null,2)))" # read-public
125
+ apiCall('GET','/api/bongos/blockers').then(r=>console.log(JSON.stringify(r.data,null,2)))" # read-public
126
126
 
127
127
  # Phase 4 — the suggestion resolves to a real claim command
128
128
  node scripts/gds/claim.js <task_id> --worktree <worktree-name>
@@ -49,5 +49,5 @@ Each summary result shows the hit id (`#NNN`, the handle for `--expand`), the ti
49
49
 
50
50
  ## Files this skill touches
51
51
 
52
- - Calls: `POST /api/gds/search` via `scripts/gds/recall.js` — twice over the same route: `{ q }` for the summary layer (step 1) and `{ expand: <id> }` for one hit's full content (step 2).
52
+ - Calls: `POST /api/bongos/search` via `scripts/gds/recall.js` — twice over the same route: `{ q }` for the summary layer (step 1) and `{ expand: <id> }` for one hit's full content (step 2).
53
53
  - Reads: `~/.config/otb/gds-session.json` (the session token, like every `/builder-*` CLI).
@@ -95,11 +95,11 @@ Step by step:
95
95
 
96
96
  1. **Validate the target** (targets section above). Refuse early and plainly.
97
97
  2. **Quarantine + fetch.** `createQuarantine({ forbiddenRoots })` — list every workspace root; the pen refuses the repo, sync folders (OneDrive etc.), and workspace roots so an artifact's own `CLAUDE.md` can never auto-load. `fetchArtifact` hard-fails with a recordable abort code on timeout/caps/private hosts; record aborted scans too (step 7) — a scan that died must be visible as "died, here is why".
98
- 3. **Prior-scan lookup.** `node scripts/gds/api.js GET "/api/gds/security/scans?content_hash=<manifest.contentHash>"` — if these exact bytes were scanned before, surface that verdict before spending panel budget (any rank can read).
98
+ 3. **Prior-scan lookup.** `node scripts/gds/api.js GET "/api/bongos/security/scans?content_hash=<manifest.contentHash>"` — if these exact bytes were scanned before, surface that verdict before spending panel budget (any rank can read).
99
99
  4. **Mirror, then floor.** `buildMirror` writes the scrubbed fenced reading room; `runFloor` persists `floor-report.json` inside the pen — pass `extraFindings: fetched.findings` so fetch-stage evidence is IN the arithmetic, not just in prose. Hard rule 4 applies between this step and the next.
100
100
  5. **Panel + verify per tier.** Spawn the lenses at the MIRROR. Collect the lens JSONs; run the verify pass; drop only cleanly-refuted panel findings.
101
101
  6. **Reduce + report.** `reduceVerdict({ floorReport, lenses, tier })`, then `assembleReport({ target: { url, sha, contentHash }, tier, reduced, floorReport, lenses, engineVersion })` with `engineVersion` = `sbi/1.0.0 floor/<floor_version>`. Write the markdown to `~/.config/otb/scan-reports/<UTC-stamp>-<host>-<sha7>.md`. (Fetch findings are already in `floorReport` from step 4 — do not re-add them here.)
102
- 7. **Record the scan row.** POST `/api/gds/security/scans` via `scripts/gds/api.js` with `--body-file` (never a shell heredoc). **Required on every row:** `target_url`, `artifact_kind` (`repo` | `plugin` | `marketplace`), `tier`, `completion`, `engine_version`. **`verdict` is required exactly when `completion` is `complete`, and must be absent otherwise** — the route enforces that coupling, so an aborted scan carries `completion: 'aborted'` + `abort_code` and NO verdict. Optional: `resolved_sha`, `content_hash`, `file_count`, `total_bytes`, the four `findings_<severity>` counts, `findings_summary` (one-line scrubbed claims only), `action_taken`. A successful scan therefore looks like:
102
+ 7. **Record the scan row.** POST `/api/bongos/security/scans` via `scripts/gds/api.js` with `--body-file` (never a shell heredoc). **Required on every row:** `target_url`, `artifact_kind` (`repo` | `plugin` | `marketplace`), `tier`, `completion`, `engine_version`. **`verdict` is required exactly when `completion` is `complete`, and must be absent otherwise** — the route enforces that coupling, so an aborted scan carries `completion: 'aborted'` + `abort_code` and NO verdict. Optional: `resolved_sha`, `content_hash`, `file_count`, `total_bytes`, the four `findings_<severity>` counts, `findings_summary` (one-line scrubbed claims only), `action_taken`. A successful scan therefore looks like:
103
103
 
104
104
  ```json
105
105
  { "target_url": "https://github.com/owner/repo", "artifact_kind": "repo",
@@ -150,7 +150,7 @@ For a dangerous verdict, failed sanitize gates, or a user who just wants the fun
150
150
  1. `selectDocFiles(entries)` — the ONLY files a model may read for this landing, via the mirror. Documentation only, never code: the spec describes WHAT to build, derived from the artifact's own docs.
151
151
  2. Spawn one doc-reader subagent at those mirror files → it returns one-line functional requirements (JSON array of strings).
152
152
  3. `assembleRebuildSpec({ target, docPaths, requirements })` — script-owned framing, every line scrubbed. Write `REBUILD-SPEC.md` next to the scan report in `~/.config/otb/scan-reports/`.
153
- 4. Offer to file it as a Bongos task: `POST /api/gds/tasks` (status `backlog`, body = the spec markdown; Metic+) or `node scripts/gds/capture.js` into the idea inbox otherwise. Record `rebuild_spec`.
153
+ 4. Offer to file it as a Bongos task: `POST /api/bongos/tasks` (status `backlog`, body = the spec markdown; Metic+) or `node scripts/gds/capture.js` into the idea inbox otherwise. Record `rebuild_spec`.
154
154
 
155
155
  ## What this skill does NOT do
156
156
 
@@ -8,7 +8,7 @@ You are answering a project-status question. Before this skill existed, doing so
8
8
 
9
9
  ## What this skill does
10
10
 
11
- Rolls up a version's done-when criteria → gating tasks → live statuses → what's left, in one call to the public `GET /api/gds/versions/:id/progress`. Read-only and unauthenticated, so it works even before `/builder-setup`. As of task 1288 it produces a **deterministic card** (same shape every time) — your job is to render it, not to re-summarize it.
11
+ Rolls up a version's done-when criteria → gating tasks → live statuses → what's left, in one call to the public `GET /api/bongos/versions/:id/progress`. Read-only and unauthenticated, so it works even before `/builder-setup`. As of task 1288 it produces a **deterministic card** (same shape every time) — your job is to render it, not to re-summarize it.
12
12
 
13
13
  ## How to render it
14
14
 
@@ -29,6 +29,6 @@ Delivery is deterministic (task 1288, same methodology as `/builder-start`). The
29
29
 
30
30
  ## Files this skill touches
31
31
 
32
- - Calls: `GET /api/gds/versions/:id/progress` (public)
32
+ - Calls: `GET /api/bongos/versions/:id/progress` (public)
33
33
  - Runs: `scripts/gds/status.js` (`--hook` / `--widget` render the card; default text + `--json` unchanged)
34
34
  - Delivered by: `.claude/hooks/session-cards.js` (the card-delivery hook, task 1288)
@@ -33,11 +33,11 @@ node scripts/gds/skill-preflight.js strand-fix # exits 1 naming what is MISSIN
33
33
  gh pr list --search "N" --state all --json number,state,mergeable,url
34
34
  ```
35
35
  2. **Pick the ONE matching case.**
36
- - **A. A main commit carries `(task N` and the post-merge `unit` + `main-audit` on main are green** (`gh run list --branch main --limit 4`): the land happened; only the proof failed. The proof is the claim's recorded tip (`claims.published_head_sha`, task 1547) being an ancestor of main — and a `no_branch_no_tip` claim has none (the work rode in on another branch, e.g. a cloud-agent batch, or a `--here` claim). **Record the tip first**: the owner (Archon) sets that column on the task's latest claim to the full 40-char SHA of the main commit — a direct DB write on the box as the DB owner, so it runs under this task's own ledger with the SQL in the ship note (`UPDATE claims SET published_head_sha = '<sha>' WHERE id = (SELECT id FROM claims WHERE task_id = N ORDER BY claimed_at DESC, id DESC LIMIT 1)`). Then the reconciler proves it within ≤5 min, or flip it yourself: `node scripts/gds/api.js POST /api/gds/tasks/N/ship --body '{}'`. Never `no_artifact: true` here — the artifact exists, and the ledger would record a falsehood. Credits land on the flip (ADR 0120). (Before task 1003434 the manual POST refused even with a tip when the claim had no branch; the reconciler path always worked.)
36
+ - **A. A main commit carries `(task N` and the post-merge `unit` + `main-audit` on main are green** (`gh run list --branch main --limit 4`): the land happened; only the proof failed. The proof is the claim's recorded tip (`claims.published_head_sha`, task 1547) being an ancestor of main — and a `no_branch_no_tip` claim has none (the work rode in on another branch, e.g. a cloud-agent batch, or a `--here` claim). **Record the tip first**: the owner (Archon) sets that column on the task's latest claim to the full 40-char SHA of the main commit — a direct DB write on the box as the DB owner, so it runs under this task's own ledger with the SQL in the ship note (`UPDATE claims SET published_head_sha = '<sha>' WHERE id = (SELECT id FROM claims WHERE task_id = N ORDER BY claimed_at DESC, id DESC LIMIT 1)`). Then the reconciler proves it within ≤5 min, or flip it yourself: `node scripts/gds/api.js POST /api/bongos/tasks/N/ship --body '{}'`. Never `no_artifact: true` here — the artifact exists, and the ledger would record a falsehood. Credits land on the flip (ADR 0120). (Before task 1003434 the manual POST refused even with a tip when the claim had no branch; the reconciler path always worked.)
37
37
  - **B. A local branch exists with commits ahead of `origin/main` and no PR**: the ship never pushed. From that worktree: `git push -u origin <branch>` then `gh pr create --base main --head <branch> --fill`. Green `unit` → server auto-merge → the reconciler flips it within ~5 min. If it merges but does not flip, do **A**.
38
38
  - **C. A PR exists but is `CONFLICTING`**: the branch owner brings it up to date — `git merge origin/main`, resolve, push — not this skill, and never `--force`. **Merge, never rebase** (task 1002788): the branch is already published and the server's publish is append-only, so rewriting its history makes every later push non-fast-forward and the task un-landable while the claim gate keeps the owner's queue shut. Report the PR URL and stop.
39
39
  - **D. Nothing anywhere** — no branch, no PR, no commit: a codeless confirm. Ask what the task delivered. Work done outside this repo (on the box's instance checkout, a DB-only change captured in the ship note) is legitimately artifact-free → **A** with the reason in the ship body: `--body '{"note":"codeless: <where the work lives>"}'`. If the work was never done, release it instead so it returns to `ready`: `node scripts/gds/release.js N --reason "stranded codeless confirm; nothing delivered"`.
40
- 3. **Verify**: `node scripts/gds/api.js GET /api/gds/tasks/N` → `"status": "shipped"` (or `ready` after a release). Re-run `strand-watch.js --line` — the task must be gone from it. If the claim gate was the symptom, `claim.js` now succeeds.
40
+ 3. **Verify**: `node scripts/gds/api.js GET /api/bongos/tasks/N` → `"status": "shipped"` (or `ready` after a release). Re-run `strand-watch.js --line` — the task must be gone from it. If the claim gate was the symptom, `claim.js` now succeeds.
41
41
 
42
42
  ## Rules
43
43
 
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
5
5
  by hand; it regenerates when the spec changes, so it can never drift from the routes.
6
6
 
7
7
  - API version: **v1** (served at `/api/bongos/v1`)
8
- - 378 operations across 58 resource groups
8
+ - 379 operations across 58 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -831,6 +831,8 @@ function createClient(opts = {}) {
831
831
  getSessionsMine: (args) => request("GET", "/sessions/mine", { hasBody: false }, args),
832
832
  // GET /sessions/search — rank: metic+archon — GET /sessions/search
833
833
  getSessionsSearch: (args) => request("GET", "/sessions/search", { hasBody: false }, args),
834
+ // GET /sessions/upload-health — rank: metic+archon — GET /sessions/upload-health
835
+ getSessionsUploadHealth: (args) => request("GET", "/sessions/upload-health", { hasBody: false }, args),
834
836
  },
835
837
  "sso": {
836
838
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
@@ -830,6 +830,8 @@ function createClient(opts = {}) {
830
830
  getSessionsMine: (args) => request("GET", "/sessions/mine", { hasBody: false }, args),
831
831
  // GET /sessions/search — rank: metic+archon — GET /sessions/search
832
832
  getSessionsSearch: (args) => request("GET", "/sessions/search", { hasBody: false }, args),
833
+ // GET /sessions/upload-health — rank: metic+archon — GET /sessions/upload-health
834
+ getSessionsUploadHealth: (args) => request("GET", "/sessions/upload-health", { hasBody: false }, args),
833
835
  },
834
836
  "sso": {
835
837
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
@@ -1179,6 +1179,8 @@ export interface BongosClient {
1179
1179
  getSessionsMine(args?: RequestArgs): Promise<GetSessionsMineResponse>;
1180
1180
  /** GET /sessions/search — rank: metic+archon */
1181
1181
  getSessionsSearch(args?: RequestArgs): Promise<GetSessionsSearchResponse>;
1182
+ /** GET /sessions/upload-health — rank: metic+archon */
1183
+ getSessionsUploadHealth(args?: RequestArgs): Promise<ApiResponse>;
1182
1184
  };
1183
1185
  "sso": {
1184
1186
  /** POST /sso/activity/rollup — rank: public */
@@ -827,6 +827,8 @@ export function createClient(opts = {}) {
827
827
  getSessionsMine: (args) => request("GET", "/sessions/mine", { hasBody: false }, args),
828
828
  // GET /sessions/search — rank: metic+archon — GET /sessions/search
829
829
  getSessionsSearch: (args) => request("GET", "/sessions/search", { hasBody: false }, args),
830
+ // GET /sessions/upload-health — rank: metic+archon — GET /sessions/upload-health
831
+ getSessionsUploadHealth: (args) => request("GET", "/sessions/upload-health", { hasBody: false }, args),
830
832
  },
831
833
  "sso": {
832
834
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
@@ -1091,7 +1091,7 @@
1091
1091
  "audit-log"
1092
1092
  ],
1093
1093
  "summary": "GET /audit-log",
1094
- "description": "GET /api/gds/audit-log?limit=&offset=&builder_id=&method= Paginated, newest-first. Clamps: limit → 1..500, default 100 offset → >= 0, default 0 rank: archon — forensics surface; only the Archon should see who did what. Gate: requirePermission('audit_log.read') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `audit_log.read` (all required).",
1094
+ "description": "GET /api/bongos/audit-log?limit=&offset=&builder_id=&method= Paginated, newest-first. Clamps: limit → 1..500, default 100 offset → >= 0, default 0 rank: archon — forensics surface; only the Archon should see who did what. Gate: requirePermission('audit_log.read') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `audit_log.read` (all required).",
1095
1095
  "x-rank": "metic+archon",
1096
1096
  "x-source": "src/bongos/routes/audit-log.js",
1097
1097
  "x-permissions": [
@@ -3480,7 +3480,7 @@
3480
3480
  "builders"
3481
3481
  ],
3482
3482
  "summary": "GET /builders/:id/onboarding",
3483
- "description": "GET /builders/:id/onboarding — V3.R75 (task 294) onboarding checklist read. Returns the builder's onboarding state machine row, shaped for the /builders hall checklist UI: { builder_id, current_stage, completed_stages, started_at, completed_at, progress: { cleared, total }, stages: [{ id, label, hint, cleared, is_current }, ...], graduated: boolean } Public read (no auth). Spec says the hall renders other builders' checklists read-only — a builder's onboarding progress is roster-visible signal, same posture as rank or drachmae shown on the leaderboard. The builder's own row is also surfaced inside /api/gds/me; this endpoint is what the hall hits for the CURRENT viewer AND for any other builder whose card is rendered. rank: public — onboarding progress is a roster-visible signal.\n\n**Rank:** `public` — No authentication — any caller.",
3483
+ "description": "GET /builders/:id/onboarding — V3.R75 (task 294) onboarding checklist read. Returns the builder's onboarding state machine row, shaped for the /builders hall checklist UI: { builder_id, current_stage, completed_stages, started_at, completed_at, progress: { cleared, total }, stages: [{ id, label, hint, cleared, is_current }, ...], graduated: boolean } Public read (no auth). Spec says the hall renders other builders' checklists read-only — a builder's onboarding progress is roster-visible signal, same posture as rank or drachmae shown on the leaderboard. The builder's own row is also surfaced inside /api/bongos/me; this endpoint is what the hall hits for the CURRENT viewer AND for any other builder whose card is rendered. rank: public — onboarding progress is a roster-visible signal.\n\n**Rank:** `public` — No authentication — any caller.",
3484
3484
  "x-rank": "public",
3485
3485
  "x-source": "src/bongos/routes/builders.js",
3486
3486
  "parameters": [
@@ -8922,7 +8922,7 @@
8922
8922
  "live"
8923
8923
  ],
8924
8924
  "summary": "GET /live",
8925
- "description": "GET /api/gds/live — SSE stream of Bongos state-change nudges for the hall. rank: any-builder — requireBuilder gates anonymous/abuse traffic (defense in depth; the payload leaks nothing). Mirrors the room's task 983 signed-in gate. EventSource carries the gds_session cookie on this same-origin GET, so a signed-in viewer authenticates transparently. NOT module-gated: the hall's live refresh is core to every instance (the done-when is \"live on a game-less boot\"), so it mounts unconditionally in the GDS router.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8925
+ "description": "GET /api/bongos/live — SSE stream of Bongos state-change nudges for the hall. rank: any-builder — requireBuilder gates anonymous/abuse traffic (defense in depth; the payload leaks nothing). Mirrors the room's task 983 signed-in gate. EventSource carries the gds_session cookie on this same-origin GET, so a signed-in viewer authenticates transparently. NOT module-gated: the hall's live refresh is core to every instance (the done-when is \"live on a game-less boot\"), so it mounts unconditionally in the GDS router.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8926
8926
  "x-rank": "any-builder",
8927
8927
  "x-source": "src/bongos/routes/live.js",
8928
8928
  "responses": {
@@ -9057,7 +9057,7 @@
9057
9057
  "me"
9058
9058
  ],
9059
9059
  "summary": "GET /me",
9060
- "description": "PMS-V2 task 188: response now also carries `unlocked` (server-joined achievement metadata) + `locked_with_progress` (server-computed human-readable progress hint per locked achievement) so the /builders UI can render achievements without a follow-up API call. Additive only — existing keys preserved for back-compat with scripts/gds/me.js and the /builders web client. V3.R24 (task 244): the `builder` payload now carries `karma` (migration 040 added the column + karma_log table). The field is surfaced by db.getBuilderById() — no shape change here, just documenting that the /api/gds/me response is the canonical place clients read karma from. rank: any-builder — own identity + own contributions; preserved per CRITICAL §4.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9060
+ "description": "PMS-V2 task 188: response now also carries `unlocked` (server-joined achievement metadata) + `locked_with_progress` (server-computed human-readable progress hint per locked achievement) so the /builders UI can render achievements without a follow-up API call. Additive only — existing keys preserved for back-compat with scripts/gds/me.js and the /builders web client. V3.R24 (task 244): the `builder` payload now carries `karma` (migration 040 added the column + karma_log table). The field is surfaced by db.getBuilderById() — no shape change here, just documenting that the /api/bongos/me response is the canonical place clients read karma from. rank: any-builder — own identity + own contributions; preserved per CRITICAL §4.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9061
9061
  "x-rank": "any-builder",
9062
9062
  "x-source": "src/bongos/routes/me.js",
9063
9063
  "responses": {
@@ -11054,7 +11054,7 @@
11054
11054
  "modules"
11055
11055
  ],
11056
11056
  "summary": "GET /modules/submissions",
11057
- "description": "GET /api/gds/modules/submissions?status=&module_key= — the upstreaming review queue (task 1771 reads this). Metadata only — no file contents (a future GET .../:id can add a with-files fetch if the review UI needs it). rank: metic+archon — the review queue, same rank as filing into it. Gate: requirePermission('module.submit') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `module.submit` (all required).",
11057
+ "description": "GET /api/bongos/modules/submissions?status=&module_key= — the upstreaming review queue (task 1771 reads this). Metadata only — no file contents (a future GET .../:id can add a with-files fetch if the review UI needs it). rank: metic+archon — the review queue, same rank as filing into it. Gate: requirePermission('module.submit') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `module.submit` (all required).",
11058
11058
  "x-rank": "metic+archon",
11059
11059
  "x-source": "src/bongos/routes/modules.js",
11060
11060
  "x-permissions": [
@@ -11161,7 +11161,7 @@
11161
11161
  "modules"
11162
11162
  ],
11163
11163
  "summary": "POST /modules/:key/submit",
11164
- "description": "POST /api/gds/modules/:key/submit — ADR 0107 §1 upstreaming submission. task 1770. Body: { signed_by?: \"Name <email>\" }. Re-runs the §4 AGPL/publish pre-check + requires a DCO-style sign-off against THIS box's OWN on-disk copy of modules/:key (the authoritative check — a local `bongos module check` pass on a builder's box is a courtesy, not proof, if the module's changes aren't committed + shipped + deployed here yet). signed_by records a NEW sign-off only if none is on file; an existing .upstream-signoff.json is reused as-is (not overwritten). rank: metic+archon — files into a shared review queue, not just a toggle for the caller. Gate: requirePermission('module.submit') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `module.submit` (all required).",
11164
+ "description": "POST /api/bongos/modules/:key/submit — ADR 0107 §1 upstreaming submission. task 1770. Body: { signed_by?: \"Name <email>\" }. Re-runs the §4 AGPL/publish pre-check + requires a DCO-style sign-off against THIS box's OWN on-disk copy of modules/:key (the authoritative check — a local `bongos module check` pass on a builder's box is a courtesy, not proof, if the module's changes aren't committed + shipped + deployed here yet). signed_by records a NEW sign-off only if none is on file; an existing .upstream-signoff.json is reused as-is (not overwritten). rank: metic+archon — files into a shared review queue, not just a toggle for the caller. Gate: requirePermission('module.submit') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `module.submit` (all required).",
11165
11165
  "x-rank": "metic+archon",
11166
11166
  "x-source": "src/bongos/routes/modules.js",
11167
11167
  "x-permissions": [
@@ -13864,7 +13864,7 @@
13864
13864
  "security"
13865
13865
  ],
13866
13866
  "summary": "GET /security/adr",
13867
- "description": "GET /api/gds/security/adr Metic+ only. Returns the full security ADR as { adr_md, source, fetched_at } when the file is provisioned; otherwise 404 with a structured hint. The rank gate runs BEFORE the file-existence check so a Xenos sees 403 regardless of whether the document is provisioned — we don't want existence-or-not to leak below the rank line. rank: metic+archon — trust-tier access to the threat model + defenses inventory (ADR 0020). Gate: requirePermission('security.report.file') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151). NB the 403 code on this route is `permission_forbidden`, not `rank_forbidden` (ADR 0020 §\"A Xenos hitting the endpoint\" updated to match).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.file` (all required).",
13867
+ "description": "GET /api/bongos/security/adr Metic+ only. Returns the full security ADR as { adr_md, source, fetched_at } when the file is provisioned; otherwise 404 with a structured hint. The rank gate runs BEFORE the file-existence check so a Xenos sees 403 regardless of whether the document is provisioned — we don't want existence-or-not to leak below the rank line. rank: metic+archon — trust-tier access to the threat model + defenses inventory (ADR 0020). Gate: requirePermission('security.report.file') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151). NB the 403 code on this route is `permission_forbidden`, not `rank_forbidden` (ADR 0020 §\"A Xenos hitting the endpoint\" updated to match).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.file` (all required).",
13868
13868
  "x-rank": "metic+archon",
13869
13869
  "x-source": "src/bongos/routes/security.js",
13870
13870
  "x-permissions": [
@@ -13898,7 +13898,7 @@
13898
13898
  "security"
13899
13899
  ],
13900
13900
  "summary": "GET /security/docs",
13901
- "description": "GET /api/gds/security/docs — list doc METADATA (no content). rank: archon — index of exploit-detail engagement reports. Gate: requirePermission('security.report.adjudicate') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
13901
+ "description": "GET /api/bongos/security/docs — list doc METADATA (no content). rank: archon — index of exploit-detail engagement reports. Gate: requirePermission('security.report.adjudicate') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
13902
13902
  "x-rank": "metic+archon",
13903
13903
  "x-source": "src/bongos/routes/security.js",
13904
13904
  "x-permissions": [
@@ -13937,7 +13937,7 @@
13937
13937
  "security"
13938
13938
  ],
13939
13939
  "summary": "POST /security/docs",
13940
- "description": "POST /api/gds/security/docs — upsert a doc by slug. The director uploads each dated engagement report here after deploy. Body: { slug, title, content_md }. content_md uses a large explicit cap (full reports), NOT the small LIMITS.DESCRIPTION. Returns 201 + the row. rank: archon — writes exploit-detail report bodies. Gate: requirePermission('security.report.adjudicate') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
13940
+ "description": "POST /api/bongos/security/docs — upsert a doc by slug. The director uploads each dated engagement report here after deploy. Body: { slug, title, content_md }. content_md uses a large explicit cap (full reports), NOT the small LIMITS.DESCRIPTION. Returns 201 + the row. rank: archon — writes exploit-detail report bodies. Gate: requirePermission('security.report.adjudicate') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
13941
13941
  "x-rank": "metic+archon",
13942
13942
  "x-source": "src/bongos/routes/security.js",
13943
13943
  "x-permissions": [
@@ -13989,7 +13989,7 @@
13989
13989
  "security"
13990
13990
  ],
13991
13991
  "summary": "GET /security/docs/:slug",
13992
- "description": "GET /api/gds/security/docs/:slug — one doc WITH content, or 404. rank: archon — reads the full exploit-detail report body. Gate: requirePermission('security.report.adjudicate') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
13992
+ "description": "GET /api/bongos/security/docs/:slug — one doc WITH content, or 404. rank: archon — reads the full exploit-detail report body. Gate: requirePermission('security.report.adjudicate') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
13993
13993
  "x-rank": "metic+archon",
13994
13994
  "x-source": "src/bongos/routes/security.js",
13995
13995
  "x-permissions": [
@@ -14625,6 +14625,40 @@
14625
14625
  ]
14626
14626
  }
14627
14627
  },
14628
+ "/sessions/upload-health": {
14629
+ "get": {
14630
+ "operationId": "get_sessions_upload_health",
14631
+ "tags": [
14632
+ "sessions"
14633
+ ],
14634
+ "summary": "GET /sessions/upload-health",
14635
+ "description": "GET /sessions/upload-health — the answer to \"has anyone's session upload silently stopped?\", which before task 1003865 existed ONLY as a jsonl file on the builder's own laptop. A skipped upload means no session_records row, which means the ADR 0146 cost-plus reward never books — a builder earning nothing for work that shipped, invisible from here. Read-only and side-effect-free, so it is DELIBERATELY not a new permission: it reads the same corpus /sessions/search reads, for the same cross-builder audience, so it rides the same `session.search` gate and writes the same fail-closed audit row. A new permission would be a new thing to grant before anyone could look at a number that already exists.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `session.search` (all required).",
14636
+ "x-rank": "metic+archon",
14637
+ "x-source": "modules/sessions/routes/sessions.js",
14638
+ "x-permissions": [
14639
+ "session.search"
14640
+ ],
14641
+ "responses": {
14642
+ "200": {
14643
+ "description": "Success."
14644
+ },
14645
+ "400": {
14646
+ "$ref": "#/components/responses/BadRequest"
14647
+ },
14648
+ "401": {
14649
+ "$ref": "#/components/responses/Unauthorized"
14650
+ },
14651
+ "403": {
14652
+ "$ref": "#/components/responses/Forbidden"
14653
+ }
14654
+ },
14655
+ "security": [
14656
+ {
14657
+ "builderSession": []
14658
+ }
14659
+ ]
14660
+ }
14661
+ },
14628
14662
  "/sessions/{id}": {
14629
14663
  "get": {
14630
14664
  "operationId": "get_sessions_id",
@@ -23954,7 +23988,7 @@
23954
23988
  "description": "A required dependency/feature is not configured or is temporarily down."
23955
23989
  }
23956
23990
  },
23957
- "x-endpoint-count": 378,
23991
+ "x-endpoint-count": 379,
23958
23992
  "x-schema-count": 415,
23959
23993
  "x-undocumented-bodies": 9,
23960
23994
  "x-response-schemas": 282,
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Bongos API reference
4
4
 
5
- > **Generated from the live route files** — the route file is authoritative. 378 endpoints across 62 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 379 endpoints across 62 route files.
6
6
  > Machine-readable spec: [`docs/api/openapi.json`](api/openapi.json) (OpenAPI 3.1). Rendered docs site: **`/docs`** (e.g. `cloudbongos.com/docs`).
7
7
 
8
8
  Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust-boundary-server-enforced-permissions.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -58,7 +58,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
58
58
 
59
59
  | Method | Path | Rank | Body | Description |
60
60
  |---|---|---|---|---|
61
- | GET | `/api/bongos/audit-log` | `metic+archon` | — | GET /api/gds/audit-log?limit=&offset=&builder_id=&method= Paginated, newest-first. |
61
+ | GET | `/api/bongos/audit-log` | `metic+archon` | — | GET /api/bongos/audit-log?limit=&offset=&builder_id=&method= Paginated, newest-first. |
62
62
 
63
63
  ## `auth` (18)
64
64
 
@@ -369,7 +369,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
369
369
 
370
370
  | Method | Path | Rank | Body | Description |
371
371
  |---|---|---|---|---|
372
- | GET | `/api/bongos/live` | `any-builder` | — | GET /api/gds/live — SSE stream of Bongos state-change nudges for the hall. |
372
+ | GET | `/api/bongos/live` | `any-builder` | — | GET /api/bongos/live — SSE stream of Bongos state-change nudges for the hall. |
373
373
 
374
374
  ## `llm-cache` (2)
375
375
 
@@ -444,8 +444,8 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
444
444
  |---|---|---|---|---|
445
445
  | GET | `/api/bongos/modules` | `any-builder` | — | list every on-disk module with attribution + provenance (same read gate as the atlas/primer pages). |
446
446
  | POST | `/api/bongos/modules/:key/enable` | `metic+archon` | `enabled` | toggling a module changes running behavior for the whole instance, not just the caller. |
447
- | POST | `/api/bongos/modules/:key/submit` | `metic+archon` | `signed_by` | POST /api/gds/modules/:key/submit — ADR 0107 §1 upstreaming submission. |
448
- | GET | `/api/bongos/modules/submissions` | `metic+archon` | — | GET /api/gds/modules/submissions?status=&module_key= — the upstreaming review queue (task 1771 reads this). |
447
+ | POST | `/api/bongos/modules/:key/submit` | `metic+archon` | `signed_by` | POST /api/bongos/modules/:key/submit — ADR 0107 §1 upstreaming submission. |
448
+ | GET | `/api/bongos/modules/submissions` | `metic+archon` | — | GET /api/bongos/modules/submissions?status=&module_key= — the upstreaming review queue (task 1771 reads this). |
449
449
 
450
450
  ## `my-projects` (6)
451
451
 
@@ -561,10 +561,10 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
561
561
 
562
562
  | Method | Path | Rank | Body | Description |
563
563
  |---|---|---|---|---|
564
- | GET | `/api/bongos/security/adr` | `metic+archon` | — | GET /api/gds/security/adr Metic+ only. |
565
- | GET | `/api/bongos/security/docs` | `metic+archon` | — | GET /api/gds/security/docs — list doc METADATA (no content). |
566
- | POST | `/api/bongos/security/docs` | `metic+archon` | `slug`, `title`, `content_md` | POST /api/gds/security/docs — upsert a doc by slug. |
567
- | GET | `/api/bongos/security/docs/:slug` | `metic+archon` | — | GET /api/gds/security/docs/:slug — one doc WITH content, or 404. |
564
+ | GET | `/api/bongos/security/adr` | `metic+archon` | — | GET /api/bongos/security/adr Metic+ only. |
565
+ | GET | `/api/bongos/security/docs` | `metic+archon` | — | GET /api/bongos/security/docs — list doc METADATA (no content). |
566
+ | POST | `/api/bongos/security/docs` | `metic+archon` | `slug`, `title`, `content_md` | POST /api/bongos/security/docs — upsert a doc by slug. |
567
+ | GET | `/api/bongos/security/docs/:slug` | `metic+archon` | — | GET /api/bongos/security/docs/:slug — one doc WITH content, or 404. |
568
568
  | GET | `/api/bongos/security/reports` | `metic+archon` | — | GET /api/bongos/security/reports?status=<status> Archon-only, newest-first. |
569
569
  | POST | `/api/bongos/security/reports` | `metic+archon` | `target`, `severity`, `title`, `description`, `repro_steps_md` | POST /api/bongos/security/reports — file a new vulnerability report. |
570
570
  | POST | `/api/bongos/security/reports/:id/confirm` | `metic+archon` | `drachmae_awarded` | POST /api/bongos/security/reports/:id/confirm Body: { drachmae_awarded?: integer } — defaults to the severity tier bounty if omitted. |
@@ -580,7 +580,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
580
580
  |---|---|---|---|---|
581
581
  | POST | `/api/bongos/session/optimize` | `any-builder` | `mode`, `time_budget_min`, `max_parallel` | pick own next work; the optimizer reads/recommends only. |
582
582
 
583
- ## `sessions` (4)
583
+ ## `sessions` (5)
584
584
 
585
585
  | Method | Path | Rank | Body | Description |
586
586
  |---|---|---|---|---|
@@ -588,6 +588,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
588
588
  | GET | `/api/bongos/sessions/:id` | `any-builder` | — | own session full detail (deep-dive); cross-builder fetch requires Archon + a fail-closed audit row (BFG-principal posture until 6C.1). |
589
589
  | GET | `/api/bongos/sessions/mine` | `any-builder` | — | your OWN sessions (self-serve; no audit needed). |
590
590
  | GET | `/api/bongos/sessions/search` | `metic+archon` | — | cross-builder corpus search (BFG-principal posture until 6C.1). |
591
+ | GET | `/api/bongos/sessions/upload-health` | `metic+archon` | — | GET /sessions/upload-health — the answer to "has anyone's session upload silently stopped?", which before task 1003865 existed ONLY as a … |
591
592
 
592
593
  ## `sso` (8)
593
594
 
@@ -2082,5 +2082,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2082
2082
  landed since 1.19.802 with no explicit bump. run 35175617185. (task 1002620)
2083
2083
  1.19.804 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2084
2084
  landed since 1.19.803 with no explicit bump. run 35178689663. (task 1002620)
2085
+ 1.19.805 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2086
+ landed since 1.19.804 with no explicit bump. run 35180781365. (task 1002620)
2085
2087
  ---------------------------------------------------------------------------
2086
2088
  ```
@@ -20,7 +20,7 @@
20
20
  // a scalar boolean; a missing key means "not dismissed", which keeps the column
21
21
  // sparse. applyPatch leaves sibling keys alone.
22
22
  //
23
- // This module is the single source of truth: GET/PATCH /api/gds/me/profile-nudge
23
+ // This module is the single source of truth: GET/PATCH /api/bongos/me/profile-nudge
24
24
  // read and write it, and the hall's attention-card slice reads the resolved
25
25
  // boolean to decide whether to render the line at all.
26
26
 
@@ -59,7 +59,7 @@
59
59
  // so the column stays sparse and a builder who never touches this gets a card
60
60
  // pitched at the profile they did set.
61
61
  //
62
- // This module is the single source of truth: GET/PATCH /api/gds/me/render + the
62
+ // This module is the single source of truth: GET/PATCH /api/bongos/me/render + the
63
63
  // /me payload surface it, the /settings UI reads it, and the start/claim/ship
64
64
  // CLIs read the resolved level to decide what to emit.
65
65
 
@@ -9,7 +9,7 @@ What it does beyond the switch — each fixing a failure observed in the
9
9
  2026-06-10 onboarding sessions that killed the old `curl | bash` flow:
10
10
 
11
11
  - **Pairing sign-in** — opens the builders' hall, one Approve click, token
12
- delivered over the app's own secret channel (`/api/gds/auth/app-pair/*`).
12
+ delivered over the app's own secret channel (`/api/bongos/auth/app-pair/*`).
13
13
  The session is written to `~/.config/otb/gds-session.json`, the same file
14
14
  the `/builder-*` CLI uses — pairing the app signs in the CLI too.
15
15
  - **SSH key done right** — generates `~/.ssh/otb_builder` (ed25519) with real
@@ -8,8 +8,10 @@
8
8
  // only thing that changed is the transport: the endpoint paths are now the
9
9
  // spec-derived generated methods, which can never drift from the routes.
10
10
  //
11
- // Endpoints stay on the PERMANENT unversioned /api/gds alias (ADR 0117) so shipped
12
- // binaries keep working; the generated methods are relative to that base.
11
+ // Endpoints use the canonical unversioned /api/bongos base (ADR 0117); the generated
12
+ // methods are relative to it. The permanent /api/gds alias is what ALREADY-SHIPPED
13
+ // binaries call — editing this source cannot reach them, and the server mounts both,
14
+ // so a future build asking for the canonical path costs nobody anything (task 1003707).
13
15
 
14
16
  const createGeneratedClient = require('./vendor/bongos-client.cjs');
15
17
  const { apiBase } = require('./config');
@@ -28,7 +30,7 @@ class GdsError extends Error {
28
30
  // fetchImpl is a seam for tests; it defaults to the platform fetch.
29
31
  function createClient({ getToken, getApiBase, fetchImpl } = {}) {
30
32
  // Build a generated client bound to the current origin + token. `root` is the
31
- // base path under the origin ('/api/gds' for the API, '' for same-origin static
33
+ // base path under the origin ('/api/bongos' for the API, '' for same-origin static
32
34
  // assets like the release manifest). throwOnError:false → result-mode, which we
33
35
  // translate back into the GdsError contract callers expect.
34
36
  function gen(root) {
@@ -39,7 +41,7 @@ function createClient({ getToken, getApiBase, fetchImpl } = {}) {
39
41
  fetch: fetchImpl || undefined,
40
42
  });
41
43
  }
42
- const gds = () => gen('/api/gds');
44
+ const gds = () => gen('/api/bongos');
43
45
 
44
46
  // Unwrap a result-mode { status, ok, data } into the legacy contract: return the
45
47
  // parsed body on 2xx, throw GdsError(status, body) otherwise — byte-identical to
@@ -52,7 +54,7 @@ function createClient({ getToken, getApiBase, fetchImpl } = {}) {
52
54
 
53
55
  return {
54
56
  // Generic escape hatch, kept for parity with the old surface. `path` is the full
55
- // path under the origin (e.g. '/api/gds/box/me'), so it routes through baseUrl:''.
57
+ // path under the origin (e.g. '/api/bongos/box/me'), so it routes through baseUrl:''.
56
58
  call: (method, path, body) => unwrap(gen('').request(method, path, body !== undefined ? { body } : {})),
57
59
  // identity
58
60
  logout: () => unwrap(gds().auth.postAuthLogout()),
@@ -79,10 +81,10 @@ function createClient({ getToken, getApiBase, fetchImpl } = {}) {
79
81
  // request() escape hatch (like latestRelease) rather than a named generated
80
82
  // method, so the shipped binary keeps working regardless of whether the
81
83
  // vendored client has been regenerated for the new /box/scope route yet.
82
- claimableTasks: () => unwrap(gen('').request('GET', '/api/gds/tasks/claimable')),
83
- claimTask: (taskId) => unwrap(gen('').request('POST', '/api/gds/claims', { body: { task_id: taskId } })),
84
- boxScope: () => unwrap(gen('').request('GET', '/api/gds/box/scope')),
85
- // update check (public route at the origin root, not under /api/gds).
84
+ claimableTasks: () => unwrap(gen('').request('GET', '/api/bongos/tasks/claimable')),
85
+ claimTask: (taskId) => unwrap(gen('').request('POST', '/api/bongos/claims', { body: { task_id: taskId } })),
86
+ boxScope: () => unwrap(gen('').request('GET', '/api/bongos/box/scope')),
87
+ // update check (public route at the origin root, not under /api/bongos).
86
88
  // task 1002649: polls the EXTENSIONLESS /version twin, NOT latest.json — a
87
89
  // front proxy with a file-matcher can eat *.json paths before Node (the
88
90
  // live instance's pre-ADR-0152 vhost 404'd latest.json empty while this
@@ -830,6 +830,8 @@ function createClient(opts = {}) {
830
830
  getSessionsMine: (args) => request("GET", "/sessions/mine", { hasBody: false }, args),
831
831
  // GET /sessions/search — rank: metic+archon — GET /sessions/search
832
832
  getSessionsSearch: (args) => request("GET", "/sessions/search", { hasBody: false }, args),
833
+ // GET /sessions/upload-health — rank: metic+archon — GET /sessions/upload-health
834
+ getSessionsUploadHealth: (args) => request("GET", "/sessions/upload-health", { hasBody: false }, args),
833
835
  },
834
836
  "sso": {
835
837
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
@@ -434,19 +434,19 @@ function recordingClient(response = { ok: true, status: 200, text: async () => '
434
434
  }
435
435
 
436
436
  const ENDPOINTS = [
437
- ['logout', [], 'POST', '/api/gds/auth/logout', undefined],
438
- ['pairStart', ['Lars-Mac', 'darwin'], 'POST', '/api/gds/auth/app-pair/start', { device_name: 'Lars-Mac', platform: 'darwin' }],
439
- ['pairPoll', ['pt'], 'POST', '/api/gds/auth/app-pair/poll', { poll_token: 'pt' }],
440
- ['boxMe', [], 'GET', '/api/gds/box/me', undefined],
441
- ['boxEnsure', [], 'POST', '/api/gds/box/ensure', undefined],
442
- ['boxClose', [], 'POST', '/api/gds/box/close', undefined],
443
- ['boxHeartbeat', [], 'POST', '/api/gds/box/heartbeat', undefined],
444
- ['boxTerminal', [], 'GET', '/api/gds/box/terminal', undefined],
445
- ['registerSshKey', ['ssh-ed25519 AAA', 'lars'], 'POST', '/api/gds/box/ssh-key', { public_key: 'ssh-ed25519 AAA', label: 'lars' }],
446
- ['managedSettings', [], 'GET', '/api/gds/box/managed-settings', undefined],
447
- ['claimableTasks', [], 'GET', '/api/gds/tasks/claimable', undefined],
448
- ['claimTask', ['1002388'], 'POST', '/api/gds/claims', { task_id: '1002388' }],
449
- ['boxScope', [], 'GET', '/api/gds/box/scope', undefined],
437
+ ['logout', [], 'POST', '/api/bongos/auth/logout', undefined],
438
+ ['pairStart', ['Lars-Mac', 'darwin'], 'POST', '/api/bongos/auth/app-pair/start', { device_name: 'Lars-Mac', platform: 'darwin' }],
439
+ ['pairPoll', ['pt'], 'POST', '/api/bongos/auth/app-pair/poll', { poll_token: 'pt' }],
440
+ ['boxMe', [], 'GET', '/api/bongos/box/me', undefined],
441
+ ['boxEnsure', [], 'POST', '/api/bongos/box/ensure', undefined],
442
+ ['boxClose', [], 'POST', '/api/bongos/box/close', undefined],
443
+ ['boxHeartbeat', [], 'POST', '/api/bongos/box/heartbeat', undefined],
444
+ ['boxTerminal', [], 'GET', '/api/bongos/box/terminal', undefined],
445
+ ['registerSshKey', ['ssh-ed25519 AAA', 'lars'], 'POST', '/api/bongos/box/ssh-key', { public_key: 'ssh-ed25519 AAA', label: 'lars' }],
446
+ ['managedSettings', [], 'GET', '/api/bongos/box/managed-settings', undefined],
447
+ ['claimableTasks', [], 'GET', '/api/bongos/tasks/claimable', undefined],
448
+ ['claimTask', ['1002388'], 'POST', '/api/bongos/claims', { task_id: '1002388' }],
449
+ ['boxScope', [], 'GET', '/api/bongos/box/scope', undefined],
450
450
  ['latestRelease', [], 'GET', '/downloads/devbox/version', undefined],
451
451
  ];
452
452
 
@@ -13,7 +13,7 @@
13
13
  // THE MODEL (ADR 0016 extended from "writes are gated" to "source is gated")
14
14
  // --------------------------------------------------------------------------
15
15
  // A box holds NO permanent baked credential. At boot — and on a refresh cron —
16
- // the box calls GET /api/gds/box/source-access authenticated as the builder. The
16
+ // the box calls GET /api/bongos/box/source-access authenticated as the builder. The
17
17
  // GDS reads the builder's LIVE rank+status (their machine cannot forge it) and
18
18
  // either DENIES (403 → the box scrubs its credential + clone) or returns a
19
19
  // scope-appropriate clone spec plus a short-lived, operator-supplied credential
@@ -60,7 +60,7 @@ const {
60
60
  // `public/` game client — so EVERY box (not just Metic+ full-clone boxes) can run
61
61
  // the live sandbox (sandbox-<login>.example.com, ADR 0044). The box serves
62
62
  // the game from a GAME-ONLY entry (src/preview-server.js) that never mounts
63
- // /api/gds, so the privacy boundary that matters for a PUBLIC sandbox URL is the
63
+ // /api/bongos, so the privacy boundary that matters for a PUBLIC sandbox URL is the
64
64
  // RUNTIME (what the box process exposes), NOT source exclusion. That is consistent
65
65
  // with the rest of this list: newcomers already hold the build-tooling source
66
66
  // (scripts, .claude, src/bongos — no secrets), so adding the game source changes no
@@ -86,7 +86,7 @@ const STARTER_SPARSE_PATHS = [
86
86
  // The product/game runtime so the box can serve the live sandbox (ADR 0052).
87
87
  // The game-only entry (src/preview-server.js) registers WorldRoom + QueueRoom
88
88
  // from src/rooms and renders src/world + the public/ client; none of it mounts
89
- // /api/gds. `public/` is the game client (NOT modules/hall-ui/public/, the hall
89
+ // /api/bongos. `public/` is the game client (NOT modules/hall-ui/public/, the hall
90
90
  // surface carved in BV1.R85, which stays out of a starter box).
91
91
  'src/world', 'src/rooms', 'public',
92
92
  // infra/ carries the box's own bring-up scripts (box-heartbeat.sh,