@bongos/core 1.18.18 → 1.19.2

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 (251) hide show
  1. package/.bongos-core.json +515 -195
  2. package/.claude/skills/builder-box/SKILL.md +1 -1
  3. package/.claude/skills/builder-claim/SKILL.md +1 -1
  4. package/.claude/skills/goal-create/SKILL.md +1 -1
  5. package/.claude/skills/idea-triage/SKILL.md +1 -1
  6. package/.claude/skills/planning-session/SKILL.md +5 -5
  7. package/.claude/skills/scan-before-install/SKILL.md +165 -0
  8. package/clients/bongos-client/README.md +1 -1
  9. package/clients/bongos-client/bongos-client.global.js +63 -41
  10. package/clients/bongos-client/index.cjs +63 -41
  11. package/clients/bongos-client/index.d.ts +78 -44
  12. package/clients/bongos-client/index.mjs +63 -41
  13. package/docs/adr/0020-security-model-public-stub.md +1 -1
  14. package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +2 -0
  15. package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +1 -1
  16. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +2 -1
  17. package/docs/adr/0155-adopt-private-repo-widen-oauth-scope.md +51 -0
  18. package/docs/adr/0156-user-set-display-name-wins.md +62 -0
  19. package/docs/adr/0157-archon-is-rank-and-identity-only.md +93 -0
  20. package/docs/adr/0158-choke-point-verdict-taxonomy.md +174 -0
  21. package/docs/adr/0159-merge-gate-reconciliation.md +88 -0
  22. package/docs/adr/0160-main-audit-repo-verifiable-caller.md +77 -0
  23. package/docs/adr/README.md +8 -0
  24. package/docs/api/openapi.json +1209 -233
  25. package/docs/api-reference.md +61 -46
  26. package/docs/architecture.md +1 -1
  27. package/docs/canonical-permissions.md +61 -16
  28. package/docs/design/vanilla-hall-ui-redesign-scope.md +1 -1
  29. package/docs/file-map.md +4 -1
  30. package/docs/onboarding/diagrams/assertions.json +3 -3
  31. package/docs/recipes/core-release-pipeline.md +179 -0
  32. package/docs/recipes/packaging-the-core.md +2 -0
  33. package/docs/recipes/parallel-goal-waves.md +1 -3
  34. package/docs/recipes/private-npm-distribution.md +2 -0
  35. package/docs/recipes/upgrading-the-core.md +2 -0
  36. package/migrations/core_197_display_name_source.sql +56 -0
  37. package/migrations/core_204_rekey_active_claim_per_session_worktree.sql +77 -0
  38. package/modules/autonomy/routes/autonomy.js +1 -1
  39. package/modules/builder-settings/db.js +7 -1
  40. package/modules/dev-box/app/src/vendor/bongos-client.cjs +63 -41
  41. package/modules/dev-box/routes/box.js +11 -9
  42. package/modules/discord/auth.js +3 -1
  43. package/modules/discord/routes/discord.js +8 -2
  44. package/modules/discord/ship-broadcast.js +48 -1
  45. package/modules/governance/catalog.js +70 -20
  46. package/modules/governance/db.js +102 -0
  47. package/modules/governance/migrations/governance_006_version_create.sql +38 -0
  48. package/modules/governance/migrations/governance_007_delegate_archon_ops_to_metic.sql +72 -0
  49. package/modules/governance/routes/governance.js +235 -6
  50. package/modules/grading/grader-workers/index.js +18 -9
  51. package/modules/hall-ui/public/gate.js +6 -2
  52. package/modules/hall-ui/public/goals-page.js +6 -2
  53. package/modules/hall-ui/public/governance.css +100 -0
  54. package/modules/hall-ui/public/governance.html +77 -0
  55. package/modules/hall-ui/public/governance.js +353 -0
  56. package/modules/hall-ui/public/harbor.js +14 -8
  57. package/modules/hall-ui/public/instances-panel.js +3 -1
  58. package/modules/hall-ui/public/new-project-wizard.js +6 -0
  59. package/modules/hall-ui/public/people.html +51 -0
  60. package/modules/hall-ui/public/people.js +100 -0
  61. package/modules/hall-ui/public/profile.html +2 -1
  62. package/modules/hall-ui/public/profile.js +9 -3
  63. package/modules/hall-ui/public/sessions.js +4 -2
  64. package/modules/hall-ui/public/shell.js +28 -7
  65. package/modules/hall-ui/public/task-detail.js +6 -3
  66. package/modules/hall-ui/public/watch.js +17 -9
  67. package/modules/ideas/blockers.js +44 -7
  68. package/modules/ideas/routes/blockers.js +12 -7
  69. package/modules/ideas/routes/inbox.js +2 -2
  70. package/modules/lifecycle/db.js +84 -17
  71. package/modules/lifecycle/github-push.js +37 -10
  72. package/modules/lifecycle/publish-reconciler.js +128 -31
  73. package/modules/lifecycle/routes/claims.js +10 -4
  74. package/modules/lifecycle/routes/dependencies.js +2 -2
  75. package/modules/lifecycle/routes/done-when.js +4 -4
  76. package/modules/lifecycle/routes/gate-approvals.js +9 -3
  77. package/modules/lifecycle/routes/goals.js +5 -5
  78. package/modules/lifecycle/routes/tasks.js +16 -16
  79. package/modules/lifecycle/routes/versions.js +13 -2
  80. package/modules/lifecycle/ship-card.js +38 -7
  81. package/modules/memory/routes/memory.js +2 -2
  82. package/modules/onboarding/routes/access-requests.js +3 -3
  83. package/modules/platform-identity/routes/projects.js +10 -6
  84. package/modules/platform-identity/routes/scouting.js +2 -2
  85. package/modules/provisioning/migrations/provisioning_004_onboard_mode.sql +30 -0
  86. package/modules/provisioning/provisioning.js +24 -6
  87. package/modules/provisioning/routes/provisioning.js +24 -6
  88. package/modules/security/artifact-scan/aggregate.js +133 -0
  89. package/modules/security/artifact-scan/detectors/capabilities.js +53 -0
  90. package/modules/security/artifact-scan/detectors/config-obfuscation.js +41 -0
  91. package/modules/security/artifact-scan/detectors/credentials.js +112 -0
  92. package/modules/security/artifact-scan/detectors/dependencies.js +115 -0
  93. package/modules/security/artifact-scan/detectors/hooks.js +116 -0
  94. package/modules/security/artifact-scan/detectors/injection.js +118 -0
  95. package/modules/security/artifact-scan/detectors/mcp.js +102 -0
  96. package/modules/security/artifact-scan/detectors/network.js +67 -0
  97. package/modules/security/artifact-scan/detectors/npm-lifecycle.js +67 -0
  98. package/modules/security/artifact-scan/detectors/permissions.js +91 -0
  99. package/modules/security/artifact-scan/detectors/shared.js +219 -0
  100. package/modules/security/artifact-scan/fence-local.js +99 -0
  101. package/modules/security/artifact-scan/fetch.js +330 -0
  102. package/modules/security/artifact-scan/floor.js +319 -0
  103. package/modules/security/artifact-scan/limits.js +66 -0
  104. package/modules/security/artifact-scan/manifest.js +203 -0
  105. package/modules/security/artifact-scan/mirror.js +158 -0
  106. package/modules/security/artifact-scan/quarantine.js +149 -0
  107. package/modules/security/artifact-scan/rebuild-spec.js +120 -0
  108. package/modules/security/artifact-scan/report.js +155 -0
  109. package/modules/security/artifact-scan/sanitize.js +317 -0
  110. package/modules/security/migrations/security_001_tool_scans.sql +145 -0
  111. package/modules/security/module.json +2 -2
  112. package/modules/security/routes/reports.js +11 -7
  113. package/modules/security/routes/scans.js +115 -0
  114. package/modules/security/scan-store.js +214 -0
  115. package/modules/security/tests/aggregate.mjs +283 -0
  116. package/modules/security/tests/artifact_scan.mjs +591 -0
  117. package/modules/security/tests/floor.mjs +549 -0
  118. package/modules/security/tests/mirror.mjs +350 -0
  119. package/modules/security/tests/sanitize_rebuild.mjs +499 -0
  120. package/modules/security/tests/scan_store.mjs +250 -0
  121. package/modules/security/tests/tool_scans_migration.mjs +116 -0
  122. package/modules/sessions/routes/sessions.js +6 -5
  123. package/package-lock.json +2 -2
  124. package/package.json +1 -1
  125. package/public-landing/create.html +13 -3
  126. package/scripts/gds/abandon.js +1 -1
  127. package/scripts/gds/audit-authorship.sh +6 -0
  128. package/scripts/gds/box.js +1 -1
  129. package/scripts/gds/claim.js +15 -0
  130. package/scripts/gds/cli-lib.js +16 -4
  131. package/scripts/gds/gating.js +28 -13
  132. package/scripts/gds/gen-api-docs.js +1 -1
  133. package/scripts/gds/goal.js +234 -0
  134. package/scripts/gds/init.js +70 -15
  135. package/scripts/gds/main-audit.js +80 -11
  136. package/scripts/gds/mirror-redact.js +6 -0
  137. package/scripts/gds/newcomer-floor.js +2 -2
  138. package/scripts/gds/provision.js +230 -94
  139. package/scripts/gds/run-unit-tests.js +9 -1
  140. package/scripts/gds/sandbox-stage.js +66 -9
  141. package/scripts/gds/search-ingest-md.js +1 -0
  142. package/scripts/gds/sequence.js +67 -8
  143. package/scripts/gds/ship.js +183 -50
  144. package/scripts/hall-preview/server.js +1 -1
  145. package/scripts/migrate.sh +99 -14
  146. package/src/bongos/auth.js +129 -27
  147. package/src/bongos/db-kernel.js +66 -5
  148. package/src/bongos/db.js +6 -7
  149. package/src/bongos/github-repos.js +19 -7
  150. package/src/bongos/goal-scope-check.js +1 -1
  151. package/src/bongos/module-scope-map.js +3 -1
  152. package/src/bongos/permission-path-check.js +1 -1
  153. package/src/bongos/route-rank-check.js +73 -30
  154. package/src/bongos/routes/audit-log.js +4 -2
  155. package/src/bongos/routes/auth.js +8 -4
  156. package/src/bongos/routes/backup.js +7 -4
  157. package/src/bongos/routes/builders.js +23 -11
  158. package/src/bongos/routes/github.js +15 -4
  159. package/src/bongos/routes/llm-cache.js +5 -2
  160. package/src/bongos/routes/modules.js +9 -5
  161. package/src/bongos/routes/security.js +21 -12
  162. package/src/bongos/serve-internal.js +22 -7
  163. package/src/module-api.js +86 -1
  164. package/src/platform-server.js +14 -0
  165. package/tests/api_client.mjs +18 -2
  166. package/tests/api_path_404.mjs +3 -0
  167. package/tests/art_stage.mjs +2 -1
  168. package/tests/atlas.mjs +32 -4
  169. package/tests/auth_admission_gate.mjs +17 -5
  170. package/tests/auth_error_brand.mjs +41 -21
  171. package/tests/auth_resolve_failure.mjs +155 -0
  172. package/tests/blocker_link.mjs +88 -0
  173. package/tests/bongos_downloads.mjs +2 -1
  174. package/tests/box_dns_repoint.mjs +2 -0
  175. package/tests/box_ship_permissions.mjs +2 -0
  176. package/tests/box_terminal_ssrf.mjs +23 -17
  177. package/tests/claim_error_surface.mjs +23 -0
  178. package/tests/claude_materialize.mjs +4 -0
  179. package/tests/cli_box_scope.mjs +40 -0
  180. package/tests/cloud_bongos_pack.mjs +34 -4
  181. package/tests/conductor.mjs +2 -1
  182. package/tests/criterion_authoring_gate.mjs +28 -5
  183. package/tests/currency_label.mjs +10 -1
  184. package/tests/deploy_instance.mjs +2 -0
  185. package/tests/devbox_downloads.mjs +2 -1
  186. package/tests/display_name.mjs +95 -6
  187. package/tests/eviction_policy.mjs +2 -1
  188. package/tests/file_map.mjs +10 -0
  189. package/tests/first_admin_bootstrap.mjs +10 -2
  190. package/tests/first_run_engine_check.mjs +2 -1
  191. package/tests/fitness.mjs +26 -6
  192. package/tests/gate_approvals.mjs +15 -2
  193. package/tests/github_push_land_proof.mjs +50 -4
  194. package/tests/github_repos_helpers.mjs +30 -5
  195. package/tests/github_token_store.mjs +23 -0
  196. package/tests/goal_abuse_matrix.mjs +13 -3
  197. package/tests/goal_cli.mjs +89 -0
  198. package/tests/governance_abuse_matrix.mjs +386 -0
  199. package/tests/governance_fold.mjs +156 -0
  200. package/tests/governance_fold_bench.mjs +50 -0
  201. package/tests/governance_live_proof.mjs +201 -0
  202. package/tests/governance_page_gates.mjs +21 -9
  203. package/tests/governance_parity.mjs +11 -2
  204. package/tests/governance_require_permission.mjs +125 -1
  205. package/tests/governance_routes.mjs +334 -0
  206. package/tests/grader.mjs +7 -3
  207. package/tests/hall_nav.mjs +14 -4
  208. package/tests/helpers.mjs +73 -0
  209. package/tests/hook_core_resolve.mjs +2 -1
  210. package/tests/host_topology_skips.mjs +97 -0
  211. package/tests/infra_exec_paths.mjs +14 -4
  212. package/tests/init.mjs +128 -0
  213. package/tests/known_failing_ratchet.mjs +89 -0
  214. package/tests/lifecycle-card.mjs +2 -1
  215. package/tests/main_audit.mjs +72 -1
  216. package/tests/memory_isolation.mjs +56 -9
  217. package/tests/migrate_root_resolution.mjs +124 -1
  218. package/tests/mirror_redact.mjs +19 -0
  219. package/tests/module_api.mjs +3 -1
  220. package/tests/module_loader.mjs +4 -0
  221. package/tests/modules.mjs +35 -7
  222. package/tests/modules_route.mjs +29 -5
  223. package/tests/onboarding_observability.mjs +49 -11
  224. package/tests/onboarding_route_signals.mjs +1 -0
  225. package/tests/one_active_claim_per_session.mjs +80 -0
  226. package/tests/pre_compact.mjs +2 -1
  227. package/tests/preview_server.mjs +2 -1
  228. package/tests/profile_route.mjs +1 -0
  229. package/tests/provision.mjs +170 -0
  230. package/tests/provisioning_onboard_mode.mjs +180 -0
  231. package/tests/publish_manifest.mjs +16 -3
  232. package/tests/publish_reconciler.mjs +181 -10
  233. package/tests/rank_tier_single_source.mjs +205 -0
  234. package/tests/recall_hints.mjs +2 -1
  235. package/tests/repo_map.mjs +4 -0
  236. package/tests/route_permission_check.mjs +14 -5
  237. package/tests/rubric_fixtures.mjs +3 -0
  238. package/tests/run_routine_two_root.mjs +2 -0
  239. package/tests/sandbox_stage.mjs +69 -7
  240. package/tests/search_ingest.mjs +7 -0
  241. package/tests/security_docs.mjs +28 -6
  242. package/tests/sequence.mjs +64 -0
  243. package/tests/session-cards.mjs +2 -1
  244. package/tests/session_start_freshness.mjs +2 -1
  245. package/tests/ship_broadcast_server.mjs +63 -1
  246. package/tests/ship_card.mjs +66 -0
  247. package/tests/ship_ci_deploy.mjs +66 -1
  248. package/tests/ship_smoke_gate.mjs +76 -0
  249. package/tests/versions_route.mjs +15 -0
  250. package/tests/workflow_exec_paths.mjs +16 -4
  251. package/tests/worktree_guard.mjs +2 -1
@@ -101,6 +101,10 @@
101
101
  "name": "goals",
102
102
  "description": "Endpoints under `/api/bongos/goals`."
103
103
  },
104
+ {
105
+ "name": "governance",
106
+ "description": "Endpoints under `/api/bongos/governance`."
107
+ },
104
108
  {
105
109
  "name": "grades",
106
110
  "description": "Endpoints under `/api/bongos/grades`."
@@ -206,9 +210,12 @@
206
210
  "access-requests"
207
211
  ],
208
212
  "summary": "GET /access-requests",
209
- "description": "GET /access-requests?status=pending — Archon queue. Defaults to pending; pass ?status=invited|dismissed for the resolved history. rank: archon — the queue exposes would-be builders' usernames.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
213
+ "description": "GET /access-requests?status=pending — Archon queue. Defaults to pending; pass ?status=invited|dismissed for the resolved history. rank: archon — the queue exposes would-be builders' usernames.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `access_request.review` (all required).",
210
214
  "x-rank": "archon",
211
215
  "x-source": "modules/onboarding/routes/access-requests.js",
216
+ "x-permissions": [
217
+ "access_request.review"
218
+ ],
212
219
  "responses": {
213
220
  "200": {
214
221
  "description": "Success.",
@@ -309,9 +316,12 @@
309
316
  "access-requests"
310
317
  ],
311
318
  "summary": "PATCH /access-requests/:id",
312
- "description": "PATCH /access-requests/:id — Archon resolves a request. body: { status: 'invited' | 'dismissed' }. 'invited' = admitted to the hall (the only sign-in gate — no repo access needed); 'dismissed' = declined / spam / dup. The row stays as the audit trail either way. rank: archon — same gate as the rest of the roster management surface.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
319
+ "description": "PATCH /access-requests/:id — Archon resolves a request. body: { status: 'invited' | 'dismissed' }. 'invited' = admitted to the hall (the only sign-in gate — no repo access needed); 'dismissed' = declined / spam / dup. The row stays as the audit trail either way. rank: archon — same gate as the rest of the roster management surface.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `access_request.review` (all required).",
313
320
  "x-rank": "archon",
314
321
  "x-source": "modules/onboarding/routes/access-requests.js",
322
+ "x-permissions": [
323
+ "access_request.review"
324
+ ],
315
325
  "parameters": [
316
326
  {
317
327
  "name": "id",
@@ -455,9 +465,12 @@
455
465
  "audit-log"
456
466
  ],
457
467
  "summary": "GET /audit-log",
458
- "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.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
459
- "x-rank": "archon",
468
+ "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).",
469
+ "x-rank": "metic+archon",
460
470
  "x-source": "src/bongos/routes/audit-log.js",
471
+ "x-permissions": [
472
+ "audit_log.read"
473
+ ],
461
474
  "responses": {
462
475
  "200": {
463
476
  "description": "Success.",
@@ -958,9 +971,12 @@
958
971
  "auth"
959
972
  ],
960
973
  "summary": "POST /auth/revoke",
961
- "description": "POST /auth/revoke — V3.R38 / task 259. Archon-only. Kill a SINGLE session by its primary-key id. Used for surgical lockouts (e.g. a compromised CLI on a known builder's laptop) without disturbing that builder's other sessions. Body: { session_id: <bigint> }. Response: { ok, revoked: 0|1 }. rank: archon — kills an arbitrary session; can lock other builders out.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
974
+ "description": "POST /auth/revoke — V3.R38 / task 259. Archon-only. Kill a SINGLE session by its primary-key id. Used for surgical lockouts (e.g. a compromised CLI on a known builder's laptop) without disturbing that builder's other sessions. Body: { session_id: <bigint> }. Response: { ok, revoked: 0|1 }. rank: archon — kills an arbitrary session; can lock other builders out. Gate: requirePermission('auth.session.revoke') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151).\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `auth.session.revoke` (all required).",
962
975
  "x-rank": "archon",
963
976
  "x-source": "src/bongos/routes/auth.js",
977
+ "x-permissions": [
978
+ "auth.session.revoke"
979
+ ],
964
980
  "requestBody": {
965
981
  "required": false,
966
982
  "content": {
@@ -1007,9 +1023,12 @@
1007
1023
  "auth"
1008
1024
  ],
1009
1025
  "summary": "POST /auth/revoke-all",
1010
- "description": "POST /auth/revoke-all — V3.R38 / task 259. Archon-only. Kill EVERY active session for a given builder. Used at demotion (auto-called from setBuilderRank when newRank moves down the ladder — C7 rank-change-near- instant) and as a manual operator hammer. Body: { builder_id: <bigint> }. Response: { ok, revoked: <count> }. rank: archon — same authority as PATCH /builders/:id/rank.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
1026
+ "description": "POST /auth/revoke-all — V3.R38 / task 259. Archon-only. Kill EVERY active session for a given builder. Used at demotion (auto-called from setBuilderRank when newRank moves down the ladder — C7 rank-change-near- instant) and as a manual operator hammer. Body: { builder_id: <bigint> }. Response: { ok, revoked: <count> }. rank: archon — same authority as PATCH /builders/:id/rank. Gate: requirePermission('auth.session.revoke') — BV1.R104; the same atom /auth/revoke gates on (ADR 0151).\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `auth.session.revoke` (all required).",
1011
1027
  "x-rank": "archon",
1012
1028
  "x-source": "src/bongos/routes/auth.js",
1029
+ "x-permissions": [
1030
+ "auth.session.revoke"
1031
+ ],
1013
1032
  "requestBody": {
1014
1033
  "required": false,
1015
1034
  "content": {
@@ -1126,9 +1145,12 @@
1126
1145
  "autonomy"
1127
1146
  ],
1128
1147
  "summary": "GET /autonomy/precheck",
1129
- "description": "**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
1130
- "x-rank": "archon",
1148
+ "description": "**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `autonomy.precheck` (all required).",
1149
+ "x-rank": "metic+archon",
1131
1150
  "x-source": "modules/autonomy/routes/autonomy.js",
1151
+ "x-permissions": [
1152
+ "autonomy.precheck"
1153
+ ],
1132
1154
  "responses": {
1133
1155
  "200": {
1134
1156
  "description": "Success."
@@ -1157,9 +1179,12 @@
1157
1179
  "backup"
1158
1180
  ],
1159
1181
  "summary": "GET /backup/status",
1160
- "description": "any working builder may check or trigger a backup.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
1182
+ "description": "any working builder may check or trigger a backup. Gate: requirePermission('backup.manage') — 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:** `backup.manage` (all required).",
1161
1183
  "x-rank": "metic+archon",
1162
1184
  "x-source": "src/bongos/routes/backup.js",
1185
+ "x-permissions": [
1186
+ "backup.manage"
1187
+ ],
1163
1188
  "responses": {
1164
1189
  "200": {
1165
1190
  "description": "Success.",
@@ -1195,9 +1220,12 @@
1195
1220
  "backup"
1196
1221
  ],
1197
1222
  "summary": "POST /backup/trigger",
1198
- "description": "**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
1223
+ "description": "kicks off a fresh dump; same gate as the status read. Gate: requirePermission('backup.manage') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `backup.manage` (all required).",
1199
1224
  "x-rank": "metic+archon",
1200
1225
  "x-source": "src/bongos/routes/backup.js",
1226
+ "x-permissions": [
1227
+ "backup.manage"
1228
+ ],
1201
1229
  "responses": {
1202
1230
  "200": {
1203
1231
  "description": "Success.",
@@ -1360,9 +1388,12 @@
1360
1388
  "blockers"
1361
1389
  ],
1362
1390
  "summary": "POST /blockers/:id/link",
1363
- "description": "Link an existing blocker to a task (puts the task in 'blocked' status if it's currently 'backlog' or 'ready'). Metic+ (task 360 / ADR 0018) — same blocker-review grant as resolve above. rank: metic+archon — link a blocker to a task; same blocker-review grant as resolve.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
1391
+ "description": "Link an existing blocker to a task. A task that is currently 'ready' is parked in 'blocked' so it stops advertising as claimable and the resolve-side trigger can release it; every other status is left alone (task 1002559 — see LINK_BLOCKABLE_STATUSES for why 'backlog' is excluded). Metic+ (task 360 / ADR 0018) — same blocker-review grant as resolve above. rank: metic+archon — link a blocker to a task; same blocker-review grant as resolve.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `blocker.review` (all required).",
1364
1392
  "x-rank": "metic+archon",
1365
1393
  "x-source": "modules/ideas/routes/blockers.js",
1394
+ "x-permissions": [
1395
+ "blocker.review"
1396
+ ],
1366
1397
  "parameters": [
1367
1398
  {
1368
1399
  "name": "id",
@@ -1423,9 +1454,12 @@
1423
1454
  "blockers"
1424
1455
  ],
1425
1456
  "summary": "POST /blockers/:id/resolve",
1426
- "description": "Resolve. Auto-promotes any blocked tasks linked via task_blockers. Metic+ (task 360 / ADR 0018): blocker review is one of the operations C2 assigns to Metic, so this widened from archon-only to metic+archon when the three-rank model went live. Any builder can still FILE a blocker (POST /blockers above); a Xenos cannot resolve or link them. rank: metic+archon — blocker review (auto-promotes linked blocked tasks); criterion C2 / task 360 / ADR 0018.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
1457
+ "description": "Resolve. Auto-promotes any blocked tasks linked via task_blockers. Metic+ (task 360 / ADR 0018): blocker review is one of the operations C2 assigns to Metic, so this widened from archon-only to metic+archon when the three-rank model went live. Any builder can still FILE a blocker (POST /blockers above); a Xenos cannot resolve or link them. rank: metic+archon — blocker review (auto-promotes linked blocked tasks); criterion C2 / task 360 / ADR 0018.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `blocker.review` (all required).",
1427
1458
  "x-rank": "metic+archon",
1428
1459
  "x-source": "modules/ideas/routes/blockers.js",
1460
+ "x-permissions": [
1461
+ "blocker.review"
1462
+ ],
1429
1463
  "parameters": [
1430
1464
  {
1431
1465
  "name": "id",
@@ -2156,9 +2190,12 @@
2156
2190
  "boxes"
2157
2191
  ],
2158
2192
  "summary": "GET /boxes",
2159
- "description": "GET /boxes — full roster across all builders. rank: archon (exposes every builder's box + IP + cost; same gate as the rest of roster management).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2160
- "x-rank": "archon",
2193
+ "description": "GET /boxes — full roster across all builders. rank: archon (exposes every builder's box + IP + cost; same gate as the rest of roster management).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `box.fleet.manage` (all required).",
2194
+ "x-rank": "metic+archon",
2161
2195
  "x-source": "modules/dev-box/routes/box.js",
2196
+ "x-permissions": [
2197
+ "box.fleet.manage"
2198
+ ],
2162
2199
  "responses": {
2163
2200
  "200": {
2164
2201
  "description": "Success.",
@@ -2194,9 +2231,12 @@
2194
2231
  "boxes"
2195
2232
  ],
2196
2233
  "summary": "GET /boxes/cost-ledger",
2197
- "description": "GET /boxes/cost-ledger — the full per-builder container-cost ledger + totals (task 602). rank: archon — cost oversight across every builder without a DB query. Declared among the archon routes (archon-first) so the route-rank auditor's 20-line lookahead classifies it correctly.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2198
- "x-rank": "archon",
2234
+ "description": "GET /boxes/cost-ledger — the full per-builder container-cost ledger + totals (task 602). rank: archon — cost oversight across every builder without a DB query. Declared among the archon routes (archon-first) so the route-rank auditor's 20-line lookahead classifies it correctly.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `box.fleet.manage` (all required).",
2235
+ "x-rank": "metic+archon",
2199
2236
  "x-source": "modules/dev-box/routes/box.js",
2237
+ "x-permissions": [
2238
+ "box.fleet.manage"
2239
+ ],
2200
2240
  "responses": {
2201
2241
  "200": {
2202
2242
  "description": "Success."
@@ -2225,9 +2265,12 @@
2225
2265
  "boxes"
2226
2266
  ],
2227
2267
  "summary": "PATCH /boxes/:builderId/block",
2228
- "description": "PATCH /boxes/:builderId/block — Archon bars (or un-bars) a builder from OPENING dev boxes (idea 257 / task 1163; migration 104). Body: { blocked: bool (required), reason?: string, // recorded on block; shown back to the builder close_current?: bool } // on block, ALSO deprovision a running box Block alone is \"no new opens\" (decideEnsureAction → BOX_PROVISION_BLOCKED); it does NOT touch a box that is already active. close_current adds the explicit teardown the owner asked be optional (\"options for both\"). rank: archon. Archon-first ordering (see above).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2229
- "x-rank": "archon",
2268
+ "description": "PATCH /boxes/:builderId/block — Archon bars (or un-bars) a builder from OPENING dev boxes (idea 257 / task 1163; migration 104). Body: { blocked: bool (required), reason?: string, // recorded on block; shown back to the builder close_current?: bool } // on block, ALSO deprovision a running box Block alone is \"no new opens\" (decideEnsureAction → BOX_PROVISION_BLOCKED); it does NOT touch a box that is already active. close_current adds the explicit teardown the owner asked be optional (\"options for both\"). rank: archon. Archon-first ordering (see above).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `box.fleet.manage` (all required).",
2269
+ "x-rank": "metic+archon",
2230
2270
  "x-source": "modules/dev-box/routes/box.js",
2271
+ "x-permissions": [
2272
+ "box.fleet.manage"
2273
+ ],
2231
2274
  "parameters": [
2232
2275
  {
2233
2276
  "name": "builderId",
@@ -2288,9 +2331,12 @@
2288
2331
  "boxes"
2289
2332
  ],
2290
2333
  "summary": "POST /boxes/:builderId/close",
2291
- "description": "POST /boxes/:builderId/close — Archon force-closes ANY builder's box (idea 257 / task 1163). Trust-safe by the same mechanism as the builder's own POST /box/close: it ENQUEUES a 'deprovision' intent and the control-plane runner executes it, so the web tier never holds DO_API_TOKEN (ADR 0031 §9.4). rank: archon (acts on another builder's paid infrastructure). Declared among the archon routes (archon-first) so the route-rank auditor's 20-line lookahead classifies it correctly.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2292
- "x-rank": "archon",
2334
+ "description": "POST /boxes/:builderId/close — Archon force-closes ANY builder's box (idea 257 / task 1163). Trust-safe by the same mechanism as the builder's own POST /box/close: it ENQUEUES a 'deprovision' intent and the control-plane runner executes it, so the web tier never holds DO_API_TOKEN (ADR 0031 §9.4). rank: archon (acts on another builder's paid infrastructure). Declared among the archon routes (archon-first) so the route-rank auditor's 20-line lookahead classifies it correctly.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `box.fleet.manage` (all required).",
2335
+ "x-rank": "metic+archon",
2293
2336
  "x-source": "modules/dev-box/routes/box.js",
2337
+ "x-permissions": [
2338
+ "box.fleet.manage"
2339
+ ],
2294
2340
  "parameters": [
2295
2341
  {
2296
2342
  "name": "builderId",
@@ -2461,9 +2507,12 @@
2461
2507
  "builders"
2462
2508
  ],
2463
2509
  "summary": "GET /builders/roster",
2464
- "description": "GET /builders/roster — V3.R14 (task 238) onboarding observability. Archon-only roster of every builder with their identity + onboarding signals + active-claim posture. Powers the management panel in the /builders hall so the Archon can promote / demote / release-stale-claim without dropping into psql. Optional query param: ?stale_hours=N (default 24). Defines what counts as \"stale\" for the per-row stale_claim flag — mirrors the threshold the stale-claim-release sweeper uses but exposed as a roster knob so the Archon can dial it in if needed. rank: archon — surfaces every builder's onboarding state.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2465
- "x-rank": "archon",
2510
+ "description": "GET /builders/roster — V3.R14 (task 238) onboarding observability. Archon-only roster of every builder with their identity + onboarding signals + active-claim posture. Powers the management panel in the /builders hall so the Archon can promote / demote / release-stale-claim without dropping into psql. Optional query param: ?stale_hours=N (default 24). Defines what counts as \"stale\" for the per-row stale_claim flag — mirrors the threshold the stale-claim-release sweeper uses but exposed as a roster knob so the Archon can dial it in if needed. rank: archon — surfaces every builder's onboarding state. Gate: requirePermission('builder.roster.read') — BV1.R104; the same atom /grades/by-builder and /builders/:id/active-claims already gate on (ADR 0151).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `builder.roster.read` (all required).",
2511
+ "x-rank": "metic+archon",
2466
2512
  "x-source": "src/bongos/routes/builders.js",
2513
+ "x-permissions": [
2514
+ "builder.roster.read"
2515
+ ],
2467
2516
  "responses": {
2468
2517
  "200": {
2469
2518
  "description": "Success.",
@@ -2499,9 +2548,12 @@
2499
2548
  "builders"
2500
2549
  ],
2501
2550
  "summary": "GET /builders/:id/active-claims",
2502
- "description": "GET /builders/:id/active-claims — V3.R14 (task 238). Archon-only detail view of a single builder's active claims, with the same stale_claim flag the roster computes. The roster only carries boolean \"has any stale claim?\"; this endpoint surfaces *which* claim is stale so the Archon can target the release. rank: archon — privileged read of another builder's work surface.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2503
- "x-rank": "archon",
2551
+ "description": "GET /builders/:id/active-claims — V3.R14 (task 238). Archon-only detail view of a single builder's active claims, with the same stale_claim flag the roster computes. The roster only carries boolean \"has any stale claim?\"; this endpoint surfaces *which* claim is stale so the Archon can target the release. rank: archon — privileged read of another builder's work surface. NOT ownership-scoped. Gate: requirePermission('builder.roster.read') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `builder.roster.read` (all required).",
2552
+ "x-rank": "metic+archon",
2504
2553
  "x-source": "src/bongos/routes/builders.js",
2554
+ "x-permissions": [
2555
+ "builder.roster.read"
2556
+ ],
2505
2557
  "parameters": [
2506
2558
  {
2507
2559
  "name": "id",
@@ -2551,9 +2603,12 @@
2551
2603
  "builders"
2552
2604
  ],
2553
2605
  "summary": "PATCH /builders/:id/budget",
2554
- "description": "PATCH /builders/:id/budget — set or clear a builder's monthly spend ceiling (V3.R84 task 302, criterion C3). Archon-only. Body: { monthly_budget_usd: <num> } sets the per-builder override — the manual emergency brake; a positive value engages the warn/over thresholds. { monthly_budget_usd: null } clears it: the builder becomes UNCAPPED (there is no default cap — ADR 0085). This is the \"budget per-builder configurable by Archon\" done-when. 404 if no such builder. rank: archon — changes another builder's cost ceiling.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2555
- "x-rank": "archon",
2606
+ "description": "PATCH /builders/:id/budget — set or clear a builder's monthly spend ceiling (V3.R84 task 302, criterion C3). Archon-only. Body: { monthly_budget_usd: <num> } sets the per-builder override — the manual emergency brake; a positive value engages the warn/over thresholds. { monthly_budget_usd: null } clears it: the builder becomes UNCAPPED (there is no default cap — ADR 0085). This is the \"budget per-builder configurable by Archon\" done-when. 404 if no such builder. rank: archon — changes another builder's cost ceiling. NOT ownership-scoped: archon-only admin op. Gate: requirePermission('builder.budget.set') — 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:** `builder.budget.set` (all required).",
2607
+ "x-rank": "metic+archon",
2556
2608
  "x-source": "src/bongos/routes/builders.js",
2609
+ "x-permissions": [
2610
+ "builder.budget.set"
2611
+ ],
2557
2612
  "parameters": [
2558
2613
  {
2559
2614
  "name": "id",
@@ -2698,9 +2753,12 @@
2698
2753
  "builders"
2699
2754
  ],
2700
2755
  "summary": "PATCH /builders/:id/rank",
2701
- "description": "sole chokepoint that mutates builders.rank; ADR 0016 §enforcement.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2756
+ "description": "sole chokepoint that mutates builders.rank; ADR 0016 §enforcement. Gate: requirePermission('builder.rank.set') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151). The atom is `system: true`, so no CUSTOM role may ever be granted it — only the seeded archon role holds it, which is exactly the meta-escalation wall ADR 0016 wants.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `builder.rank.set` (all required).",
2702
2757
  "x-rank": "archon",
2703
2758
  "x-source": "src/bongos/routes/builders.js",
2759
+ "x-permissions": [
2760
+ "builder.rank.set"
2761
+ ],
2704
2762
  "parameters": [
2705
2763
  {
2706
2764
  "name": "id",
@@ -2761,9 +2819,12 @@
2761
2819
  "builders"
2762
2820
  ],
2763
2821
  "summary": "PATCH /builders/:id/status",
2764
- "description": "PATCH /builders/:id/status — graceful exit + reactivation (V3.R88 task 307). Archon-only. { status: 'inactive', reason? } deactivates (releases active claims, seals their session_logs, rank → xenos, blocks new claims while preserving all credit/history); { status: 'active' } reactivates. Cannot change your own status (no last-Archon footgun — same guard as /rank). rank: archon — deactivation/reactivation; preserves credit history but blocks claims.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
2822
+ "description": "PATCH /builders/:id/status — graceful exit + reactivation (V3.R88 task 307). Archon-only. { status: 'inactive', reason? } deactivates (releases active claims, seals their session_logs, rank → xenos, blocks new claims while preserving all credit/history); { status: 'active' } reactivates. Cannot change your own status (no last-Archon footgun — same guard as /rank). rank: archon — deactivation/reactivation; preserves credit history but blocks claims. Gate: requirePermission('builder.status.set') — BV1.R104; the seeded rank-role makes the permission and the old rank floor identical (ADR 0151).\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `builder.status.set` (all required).",
2765
2823
  "x-rank": "archon",
2766
2824
  "x-source": "src/bongos/routes/builders.js",
2825
+ "x-permissions": [
2826
+ "builder.status.set"
2827
+ ],
2767
2828
  "parameters": [
2768
2829
  {
2769
2830
  "name": "id",
@@ -3006,9 +3067,12 @@
3006
3067
  "claims"
3007
3068
  ],
3008
3069
  "summary": "POST /claims/:id/release-on-behalf",
3009
- "description": "POST /claims/:id/release-on-behalf — V3.R14 (task 238). Archon-only escape hatch. The normal /claims/:id/resolve path only accepts the original claimant; this route lets the Archon release someone else's stuck claim (typically a stale one the sweeper has not picked up yet, or a deliberate intervention). Body: { reason: string }. The reason is required — every Archon intervention needs a paper trail. Capped at LIMITS.NOTES. The release sets outcome='abandoned' and returns the task to status='ready' (same as a normal abandon). No credits land. The session_logs row carries the original builder_id with notes_md tagged \"[archon-release]\" + the acting Archon's @login so an audit grep can find every third-party release.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3010
- "x-rank": "archon",
3070
+ "description": "POST /claims/:id/release-on-behalf — V3.R14 (task 238). Archon-only escape hatch. The normal /claims/:id/resolve path only accepts the original claimant; this route lets the Archon release someone else's stuck claim (typically a stale one the sweeper has not picked up yet, or a deliberate intervention). Body: { reason: string }. The reason is required — every Archon intervention needs a paper trail. Capped at LIMITS.NOTES. The release sets outcome='abandoned' and returns the task to status='ready' (same as a normal abandon). No credits land. The session_logs row carries the original builder_id with notes_md tagged \"[archon-release]\" + the acting Archon's @login so an audit grep can find every third-party release.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `claim.release.any` (all required).",
3071
+ "x-rank": "metic+archon",
3011
3072
  "x-source": "modules/lifecycle/routes/claims.js",
3073
+ "x-permissions": [
3074
+ "claim.release.any"
3075
+ ],
3012
3076
  "parameters": [
3013
3077
  {
3014
3078
  "name": "id",
@@ -3167,9 +3231,12 @@
3167
3231
  "dependencies"
3168
3232
  ],
3169
3233
  "summary": "POST /dependencies",
3170
- "description": "POST /dependencies — create an edge \"from is blocked until to is done\". rank: archon.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3234
+ "description": "POST /dependencies — create an edge \"from is blocked until to is done\". rank: archon.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `dependency.cross_tier.manage` (all required).",
3171
3235
  "x-rank": "archon",
3172
3236
  "x-source": "modules/lifecycle/routes/dependencies.js",
3237
+ "x-permissions": [
3238
+ "dependency.cross_tier.manage"
3239
+ ],
3173
3240
  "responses": {
3174
3241
  "200": {
3175
3242
  "description": "Success.",
@@ -3203,9 +3270,12 @@
3203
3270
  "dependencies"
3204
3271
  ],
3205
3272
  "summary": "DELETE /dependencies",
3206
- "description": "DELETE /dependencies — remove an edge (body carries the 4-tuple). rank: archon.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3273
+ "description": "DELETE /dependencies — remove an edge (body carries the 4-tuple). rank: archon.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `dependency.cross_tier.manage` (all required).",
3207
3274
  "x-rank": "archon",
3208
3275
  "x-source": "modules/lifecycle/routes/dependencies.js",
3276
+ "x-permissions": [
3277
+ "dependency.cross_tier.manage"
3278
+ ],
3209
3279
  "responses": {
3210
3280
  "200": {
3211
3281
  "description": "Success.",
@@ -3241,9 +3311,12 @@
3241
3311
  "discord"
3242
3312
  ],
3243
3313
  "summary": "GET /discord/channels/plan",
3244
- "description": "GET /api/bongos/discord/channels/plan — dry run. Returns the ops the bot WOULD apply to make Discord match docs/discord/channels.json, plus warnings. No writes. 503 when the bot is disabled / not connected to a guild. rank: archon — channel administration command.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3245
- "x-rank": "archon",
3314
+ "description": "GET /api/bongos/discord/channels/plan — dry run. Returns the ops the bot WOULD apply to make Discord match docs/discord/channels.json, plus warnings. No writes. 503 when the bot is disabled / not connected to a guild. rank: archon — channel administration command.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `discord.channels.manage` (all required).",
3315
+ "x-rank": "metic+archon",
3246
3316
  "x-source": "modules/discord/routes/discord.js",
3317
+ "x-permissions": [
3318
+ "discord.channels.manage"
3319
+ ],
3247
3320
  "responses": {
3248
3321
  "200": {
3249
3322
  "description": "Success.",
@@ -3279,9 +3352,12 @@
3279
3352
  "discord"
3280
3353
  ],
3281
3354
  "summary": "POST /discord/channels/reconcile",
3282
- "description": "POST /api/bongos/discord/channels/reconcile — apply the config to Discord now. Best-effort; returns how many ops applied/failed. 503 when the bot is disabled / not connected. rank: archon — channel administration command.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3283
- "x-rank": "archon",
3355
+ "description": "POST /api/bongos/discord/channels/reconcile — apply the config to Discord now. Best-effort; returns how many ops applied/failed. 503 when the bot is disabled / not connected. rank: archon — channel administration command.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `discord.channels.manage` (all required).",
3356
+ "x-rank": "metic+archon",
3284
3357
  "x-source": "modules/discord/routes/discord.js",
3358
+ "x-permissions": [
3359
+ "discord.channels.manage"
3360
+ ],
3285
3361
  "responses": {
3286
3362
  "200": {
3287
3363
  "description": "Success.",
@@ -3317,9 +3393,12 @@
3317
3393
  "done-when"
3318
3394
  ],
3319
3395
  "summary": "GET /done-when/pending-review",
3320
- "description": "Auth (Metic+): the criterion review queue — every criterion auto-flagged \"met — pending review\" (≥1 linked task, all shipped, not yet confirmed), derived from task_criteria + ship status (ADR 0086 §6 / BV1.R63). Powers the /goal-review skill. Optional ?version= scopes to one version. Gated Metic+ to match the satisfy route below — this is the planner's closing queue, not a public surface. rank: metic+archon — the planner review queue (mirrors the satisfy gate).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
3396
+ "description": "Auth (Metic+): the criterion review queue — every criterion auto-flagged \"met — pending review\" (≥1 linked task, all shipped, not yet confirmed), derived from task_criteria + ship status (ADR 0086 §6 / BV1.R63). Powers the /goal-review skill. Optional ?version= scopes to one version. Gated Metic+ to match the satisfy route below — this is the planner's closing queue, not a public surface. rank: metic+archon — the planner review queue (mirrors the satisfy gate).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `criterion.review` (all required).",
3321
3397
  "x-rank": "metic+archon",
3322
3398
  "x-source": "modules/lifecycle/routes/done-when.js",
3399
+ "x-permissions": [
3400
+ "criterion.review"
3401
+ ],
3323
3402
  "responses": {
3324
3403
  "200": {
3325
3404
  "description": "Success.",
@@ -3355,9 +3434,12 @@
3355
3434
  "done-when"
3356
3435
  ],
3357
3436
  "summary": "POST /done-when/:criterionId/satisfy",
3358
- "description": "Auth (Metic+): confirm a criterion — flip it to satisfied. Accepts optional satisfied_by_task_id so the UI can show which ship-task fulfilled it. When the criterion belongs to a goal and was its LAST unsatisfied one, the goal auto- flips open→achieved (ADR 0086 §6 / BV1.R63). Re-ranked Archon→Metic+ so the planner — not only the Archon — closes the criterion/goal loop; the route is pinned in route-rank-check.MODULE_EXPECTED_RANKS.lifecycle so a further downgrade is caught. rank: metic+archon — criterion confirmation + goal auto-achieve (the closing loop).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
3437
+ "description": "Auth (Metic+): confirm a criterion — flip it to satisfied. Accepts optional satisfied_by_task_id so the UI can show which ship-task fulfilled it. When the criterion belongs to a goal and was its LAST unsatisfied one, the goal auto- flips open→achieved (ADR 0086 §6 / BV1.R63). Re-ranked Archon→Metic+ so the planner — not only the Archon — closes the criterion/goal loop; the route is pinned in route-rank-check.MODULE_EXPECTED_RANKS.lifecycle so a further downgrade is caught. rank: metic+archon — criterion confirmation + goal auto-achieve (the closing loop).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `criterion.satisfy` (all required).",
3359
3438
  "x-rank": "metic+archon",
3360
3439
  "x-source": "modules/lifecycle/routes/done-when.js",
3440
+ "x-permissions": [
3441
+ "criterion.satisfy"
3442
+ ],
3361
3443
  "parameters": [
3362
3444
  {
3363
3445
  "name": "criterionId",
@@ -3418,9 +3500,12 @@
3418
3500
  "done-when"
3419
3501
  ],
3420
3502
  "summary": "POST /done-when/:criterionId/unsatisfy",
3421
- "description": "Auth: flip a criterion back to unsatisfied (rare; for corrections). rank: archon — un-flip a criterion; same gate as satisfy.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3422
- "x-rank": "archon",
3503
+ "description": "Auth: flip a criterion back to unsatisfied (rare; for corrections). rank: archon — un-flip a criterion; same gate as satisfy.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `criterion.unsatisfy` (all required).",
3504
+ "x-rank": "metic+archon",
3423
3505
  "x-source": "modules/lifecycle/routes/done-when.js",
3506
+ "x-permissions": [
3507
+ "criterion.unsatisfy"
3508
+ ],
3424
3509
  "parameters": [
3425
3510
  {
3426
3511
  "name": "criterionId",
@@ -3470,9 +3555,12 @@
3470
3555
  "gate-approvals"
3471
3556
  ],
3472
3557
  "summary": "GET /gate-approvals",
3473
- "description": "GET /gate-approvals — open PRs awaiting owner approval (gate-review red), with the verdict + per-file reasons + changed files + diff link. rank: archon.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3474
- "x-rank": "archon",
3558
+ "description": "GET /gate-approvals — open PRs awaiting owner approval (gate-review red), with the verdict + per-file reasons + changed files + diff link. rank: metic+archon. BV1.R105 left this on requireRank because `gate_approval.decide` was declared over the /approve WRITE only and no atom named the read. ADR 0157 extends the catalog with exactly that atom — `gate_approval.read`, floor metic — so the mapping is now one the catalog makes. The split is load-bearing, not cosmetic: `page.view.governance` opens /gate to Metic, and without a Metic-readable data endpoint that page would render nothing but a 403. Approving a held PR stays archon (`.decide`, system).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `gate_approval.read` (all required).",
3559
+ "x-rank": "metic+archon",
3475
3560
  "x-source": "modules/lifecycle/routes/gate-approvals.js",
3561
+ "x-permissions": [
3562
+ "gate_approval.read"
3563
+ ],
3476
3564
  "responses": {
3477
3565
  "200": {
3478
3566
  "description": "Success."
@@ -3501,9 +3589,12 @@
3501
3589
  "gate-approvals"
3502
3590
  ],
3503
3591
  "summary": "POST /gate-approvals/:pr/approve",
3504
- "description": "POST /gate-approvals/:pr/approve — record owner approval for a stuck gate PR and re-run the gate-review check so it clears. rank: archon (clears the hard floor — pinned in route-rank-check.EXPECTED_RANKS for downgrade protection).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3592
+ "description": "POST /gate-approvals/:pr/approve — record owner approval for a stuck gate PR and re-run the gate-review check so it clears. rank: archon (clears the hard floor — pinned in route-rank-check.EXPECTED_RANKS for downgrade protection).\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `gate_approval.decide` (all required).",
3505
3593
  "x-rank": "archon",
3506
3594
  "x-source": "modules/lifecycle/routes/gate-approvals.js",
3595
+ "x-permissions": [
3596
+ "gate_approval.decide"
3597
+ ],
3507
3598
  "parameters": [
3508
3599
  {
3509
3600
  "name": "pr",
@@ -3674,9 +3765,12 @@
3674
3765
  "goals"
3675
3766
  ],
3676
3767
  "summary": "POST /goals",
3677
- "description": "POST /goals — create a goal. rank: metic+archon — a Metic or Archon may create a goal; creation of a goal whose scope_modules includes a PROTECTED module is Archon-only (in-handler).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
3768
+ "description": "POST /goals — create a goal. rank: metic+archon — a Metic or Archon may create a goal; creation of a goal whose scope_modules includes a PROTECTED module is Archon-only (in-handler).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `goal.create` (all required).",
3678
3769
  "x-rank": "metic+archon",
3679
3770
  "x-source": "modules/lifecycle/routes/goals.js",
3771
+ "x-permissions": [
3772
+ "goal.create"
3773
+ ],
3680
3774
  "requestBody": {
3681
3775
  "required": true,
3682
3776
  "content": {
@@ -3754,9 +3848,12 @@
3754
3848
  "goals"
3755
3849
  ],
3756
3850
  "summary": "POST /goals/reorder",
3757
- "description": "POST /goals/reorder — Archon drag-to-reorder: set the priority order of every goal WITHIN one version (task 1760). ordered_ids must be exactly that version's goal ids, each once (db.reorderGoals fails closed otherwise) — a partial list can't silently orphan a goal's priority. Mounted BEFORE GET /goals/:id so 'reorder' is never captured as an id. rank: archon — priority is an owner decision, never self-granted by a goal's own member/manager (unlike the goal-authority routes above).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
3758
- "x-rank": "archon",
3851
+ "description": "POST /goals/reorder — Archon drag-to-reorder: set the priority order of every goal WITHIN one version (task 1760). ordered_ids must be exactly that version's goal ids, each once (db.reorderGoals fails closed otherwise) — a partial list can't silently orphan a goal's priority. Mounted BEFORE GET /goals/:id so 'reorder' is never captured as an id. rank: archon — priority is an owner decision, never self-granted by a goal's own member/manager (unlike the goal-authority routes above).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `goal.reorder` (all required).",
3852
+ "x-rank": "metic+archon",
3759
3853
  "x-source": "modules/lifecycle/routes/goals.js",
3854
+ "x-permissions": [
3855
+ "goal.reorder"
3856
+ ],
3760
3857
  "requestBody": {
3761
3858
  "required": true,
3762
3859
  "content": {
@@ -3855,9 +3952,12 @@
3855
3952
  "goals"
3856
3953
  ],
3857
3954
  "summary": "POST /goals/:id/archive",
3858
- "description": "POST /goals/:id/archive — retire a goal (open|achieved → archived). Archived goals are re-openable (below). This is the lifecycle disposition the /goal-review skill reaches for once a goal is achieved (ADR 0086 §6 / BV1.R64). rank: metic+archon — a goal member (Metic+) or an Archon dispositions the goal.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
3955
+ "description": "POST /goals/:id/archive — retire a goal (open|achieved → archived). Archived goals are re-openable (below). This is the lifecycle disposition the /goal-review skill reaches for once a goal is achieved (ADR 0086 §6 / BV1.R64). rank: metic+archon — a goal member (Metic+) or an Archon dispositions the goal.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `goal.archive` (all required).",
3859
3956
  "x-rank": "metic+archon",
3860
3957
  "x-source": "modules/lifecycle/routes/goals.js",
3958
+ "x-permissions": [
3959
+ "goal.archive"
3960
+ ],
3861
3961
  "parameters": [
3862
3962
  {
3863
3963
  "name": "id",
@@ -4396,9 +4496,12 @@
4396
4496
  "goals"
4397
4497
  ],
4398
4498
  "summary": "POST /goals/:id/reopen",
4399
- "description": "POST /goals/:id/reopen — bring an archived goal back to open (ADR 0086 §6 / BV1.R64). Only archived → open; an already open/achieved goal is a 409. rank: metic+archon — same gate as archive.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
4499
+ "description": "POST /goals/:id/reopen — bring an archived goal back to open (ADR 0086 §6 / BV1.R64). Only archived → open; an already open/achieved goal is a 409. rank: metic+archon — same gate as archive.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `goal.archive` (all required).",
4400
4500
  "x-rank": "metic+archon",
4401
4501
  "x-source": "modules/lifecycle/routes/goals.js",
4502
+ "x-permissions": [
4503
+ "goal.archive"
4504
+ ],
4402
4505
  "parameters": [
4403
4506
  {
4404
4507
  "name": "id",
@@ -4694,9 +4797,12 @@
4694
4797
  "goals"
4695
4798
  ],
4696
4799
  "summary": "POST /goals/:id/scope",
4697
- "description": "POST /goals/:id/scope — \"ask to widen\": add module(s) to a goal's scope_modules (ADR 0086 §4 / BV1.R64). Scope is NEVER self-granted, so this is the gated approve-and-apply: requireRank('metic','archon') + the caller must be a member (or Archon), and a PROTECTED module can only be added by an Archon (mirrors the POST /goals create gate). A sub-Metic member therefore cannot widen at all — they ask a Metic+/Archon out-of-band, exactly as joining a protected goal works (R57). The goal must be open. Body: { add: [\"module-key\", ...] }; idempotent (set-union). rank: metic+archon — widens the module wall; pinned in route-rank-check.EXPECTED_RANKS.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
4800
+ "description": "POST /goals/:id/scope — \"ask to widen\": add module(s) to a goal's scope_modules (ADR 0086 §4 / BV1.R64). Scope is NEVER self-granted, so this is the gated approve-and-apply: requireRank('metic','archon') + the caller must be a member (or Archon), and a PROTECTED module can only be added by an Archon (mirrors the POST /goals create gate). A sub-Metic member therefore cannot widen at all — they ask a Metic+/Archon out-of-band, exactly as joining a protected goal works (R57). The goal must be open. Body: { add: [\"module-key\", ...] }; idempotent (set-union). rank: metic+archon — widens the module wall; pinned in route-rank-check.EXPECTED_RANKS.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `goal.scope.widen` (all required).",
4698
4801
  "x-rank": "metic+archon",
4699
4802
  "x-source": "modules/lifecycle/routes/goals.js",
4803
+ "x-permissions": [
4804
+ "goal.scope.widen"
4805
+ ],
4700
4806
  "parameters": [
4701
4807
  {
4702
4808
  "name": "id",
@@ -4991,23 +5097,26 @@
4991
5097
  ]
4992
5098
  }
4993
5099
  },
4994
- "/grades/by-builder": {
5100
+ "/governance/assignments": {
4995
5101
  "get": {
4996
- "operationId": "get_grades_by_builder",
5102
+ "operationId": "get_governance_assignments",
4997
5103
  "tags": [
4998
- "grades"
5104
+ "governance"
4999
5105
  ],
5000
- "summary": "GET /grades/by-builder",
5001
- "description": "GET /grades/by-builder?days=30 — per-builder grade breakdown (task 726). Archon-only monitoring read backing the MARKS section of the /watch page: who is passing/failing the grader, over a window. Aggregated from task_grades joined through tasks.shipped_by. Mirrors the rank gate on the roster + audit-log reads — it exposes cross-builder quality data, so it is the Ruling Hand's alone (the project-wide aggregate stays public via /public/grades; this per-builder split does not). rank: archon.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
5106
+ "summary": "GET /governance/assignments",
5107
+ "description": "governance.manage — every builder↔role assignment row.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5002
5108
  "x-rank": "archon",
5003
- "x-source": "src/bongos/routes/builders.js",
5109
+ "x-source": "modules/governance/routes/governance.js",
5110
+ "x-permissions": [
5111
+ "governance.manage"
5112
+ ],
5004
5113
  "responses": {
5005
5114
  "200": {
5006
5115
  "description": "Success.",
5007
5116
  "content": {
5008
5117
  "application/json": {
5009
5118
  "schema": {
5010
- "$ref": "#/components/schemas/GetGradesByBuilderResponse"
5119
+ "$ref": "#/components/schemas/GetGovernanceAssignmentsResponse"
5011
5120
  }
5012
5121
  }
5013
5122
  }
@@ -5027,53 +5136,176 @@
5027
5136
  "builderSession": []
5028
5137
  }
5029
5138
  ]
5139
+ },
5140
+ "post": {
5141
+ "operationId": "post_governance_assignments",
5142
+ "tags": [
5143
+ "governance"
5144
+ ],
5145
+ "summary": "POST /governance/assignments",
5146
+ "description": "governance.manage — assign a CUSTOM role to a builder. assigned_by is ALWAYS the session builder, never input (the audit trail's \"who did this\" must be the authenticated actor).\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5147
+ "x-rank": "archon",
5148
+ "x-source": "modules/governance/routes/governance.js",
5149
+ "x-permissions": [
5150
+ "governance.manage"
5151
+ ],
5152
+ "requestBody": {
5153
+ "required": true,
5154
+ "content": {
5155
+ "application/json": {
5156
+ "schema": {
5157
+ "$ref": "#/components/schemas/PostGovernanceAssignmentsRequest"
5158
+ }
5159
+ }
5160
+ },
5161
+ "x-validated": true
5162
+ },
5163
+ "responses": {
5164
+ "200": {
5165
+ "description": "Success."
5166
+ },
5167
+ "400": {
5168
+ "$ref": "#/components/responses/ValidationFailed"
5169
+ },
5170
+ "401": {
5171
+ "$ref": "#/components/responses/Unauthorized"
5172
+ },
5173
+ "403": {
5174
+ "$ref": "#/components/responses/Forbidden"
5175
+ }
5176
+ },
5177
+ "security": [
5178
+ {
5179
+ "builderSession": []
5180
+ }
5181
+ ]
5030
5182
  }
5031
5183
  },
5032
- "/healthz": {
5184
+ "/governance/assignments/{builderId}/{roleKey}": {
5185
+ "delete": {
5186
+ "operationId": "delete_governance_assignments_builderId_roleKey",
5187
+ "tags": [
5188
+ "governance"
5189
+ ],
5190
+ "summary": "DELETE /governance/assignments/:builderId/:roleKey",
5191
+ "description": "governance.manage — remove a custom-role assignment. Idempotent: `removed` says whether a row went away.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5192
+ "x-rank": "archon",
5193
+ "x-source": "modules/governance/routes/governance.js",
5194
+ "x-permissions": [
5195
+ "governance.manage"
5196
+ ],
5197
+ "parameters": [
5198
+ {
5199
+ "name": "builderId",
5200
+ "in": "path",
5201
+ "required": true,
5202
+ "schema": {
5203
+ "type": "string"
5204
+ },
5205
+ "description": "Path parameter `builderId`."
5206
+ },
5207
+ {
5208
+ "name": "roleKey",
5209
+ "in": "path",
5210
+ "required": true,
5211
+ "schema": {
5212
+ "type": "string"
5213
+ },
5214
+ "description": "Path parameter `roleKey`."
5215
+ }
5216
+ ],
5217
+ "responses": {
5218
+ "200": {
5219
+ "description": "Success.",
5220
+ "content": {
5221
+ "application/json": {
5222
+ "schema": {
5223
+ "$ref": "#/components/schemas/DeleteGovernanceAssignmentsBuilderIdRoleKeyResponse"
5224
+ }
5225
+ }
5226
+ }
5227
+ },
5228
+ "400": {
5229
+ "$ref": "#/components/responses/BadRequest"
5230
+ },
5231
+ "401": {
5232
+ "$ref": "#/components/responses/Unauthorized"
5233
+ },
5234
+ "403": {
5235
+ "$ref": "#/components/responses/Forbidden"
5236
+ },
5237
+ "404": {
5238
+ "$ref": "#/components/responses/NotFound"
5239
+ }
5240
+ },
5241
+ "security": [
5242
+ {
5243
+ "builderSession": []
5244
+ }
5245
+ ]
5246
+ }
5247
+ },
5248
+ "/governance/permissions": {
5033
5249
  "get": {
5034
- "operationId": "get_healthz",
5250
+ "operationId": "get_governance_permissions",
5035
5251
  "tags": [
5036
- "healthz"
5252
+ "governance"
5253
+ ],
5254
+ "summary": "GET /governance/permissions",
5255
+ "description": "governance.manage — the permission catalog + principals, straight from code (the catalog is CODE, not a table); no DB read. `grantable` is the flag the tab renders LOCKED from; principals are read-only by construction.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5256
+ "x-rank": "archon",
5257
+ "x-source": "modules/governance/routes/governance.js",
5258
+ "x-permissions": [
5259
+ "governance.manage"
5037
5260
  ],
5038
- "summary": "GET /healthz",
5039
- "description": "liveness probe; status.amazonprimea.com hits this anonymously.\n\n**Rank:** `public` — No authentication — any caller.",
5040
- "x-rank": "public",
5041
- "x-source": "src/bongos/routes/healthz.js",
5042
5261
  "responses": {
5043
5262
  "200": {
5044
5263
  "description": "Success.",
5045
5264
  "content": {
5046
5265
  "application/json": {
5047
5266
  "schema": {
5048
- "$ref": "#/components/schemas/GetHealthzResponse"
5267
+ "$ref": "#/components/schemas/GetGovernancePermissionsResponse"
5049
5268
  }
5050
5269
  }
5051
5270
  }
5052
5271
  },
5053
5272
  "400": {
5054
5273
  "$ref": "#/components/responses/BadRequest"
5274
+ },
5275
+ "401": {
5276
+ "$ref": "#/components/responses/Unauthorized"
5277
+ },
5278
+ "403": {
5279
+ "$ref": "#/components/responses/Forbidden"
5055
5280
  }
5056
5281
  },
5057
- "security": []
5282
+ "security": [
5283
+ {
5284
+ "builderSession": []
5285
+ }
5286
+ ]
5058
5287
  }
5059
5288
  },
5060
- "/inbox": {
5289
+ "/governance/roles": {
5061
5290
  "get": {
5062
- "operationId": "get_inbox",
5291
+ "operationId": "get_governance_roles",
5063
5292
  "tags": [
5064
- "inbox"
5293
+ "governance"
5294
+ ],
5295
+ "summary": "GET /governance/roles",
5296
+ "description": "governance.manage — the full role list with each role's grants.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5297
+ "x-rank": "archon",
5298
+ "x-source": "modules/governance/routes/governance.js",
5299
+ "x-permissions": [
5300
+ "governance.manage"
5065
5301
  ],
5066
- "summary": "GET /inbox",
5067
- "description": "read open ideas; skill-friction rows filtered by viewer rank.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5068
- "x-rank": "any-builder",
5069
- "x-source": "modules/ideas/routes/inbox.js",
5070
5302
  "responses": {
5071
5303
  "200": {
5072
5304
  "description": "Success.",
5073
5305
  "content": {
5074
5306
  "application/json": {
5075
5307
  "schema": {
5076
- "$ref": "#/components/schemas/GetInboxResponse"
5308
+ "$ref": "#/components/schemas/GetGovernanceRolesResponse"
5077
5309
  }
5078
5310
  }
5079
5311
  }
@@ -5095,20 +5327,23 @@
5095
5327
  ]
5096
5328
  },
5097
5329
  "post": {
5098
- "operationId": "post_inbox",
5330
+ "operationId": "post_governance_roles",
5099
5331
  "tags": [
5100
- "inbox"
5332
+ "governance"
5333
+ ],
5334
+ "summary": "POST /governance/roles",
5335
+ "description": "governance.manage — create a CUSTOM role (is_system false, no seeded_rank — the seeded four exist only via governance_002). Grants are added one at a time via the toggle below, so creation carries none.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5336
+ "x-rank": "archon",
5337
+ "x-source": "modules/governance/routes/governance.js",
5338
+ "x-permissions": [
5339
+ "governance.manage"
5101
5340
  ],
5102
- "summary": "POST /inbox",
5103
- "description": "for ordinary ideas; metic+ for kind='criterion-proposal'. Anyone can file a general contribution (the open-to-all path that idea-triage's \"Xenos can still file\" line guarantees). But kind= 'criterion-proposal' is the marker the /planning-session skill writes from Metic-mode, and a planning-session proposal reshapes the next version's scope-truth — that's a trusted-builder operation (V3.R87 / task 306). Gate it here so a Xenos can't slip a criterion proposal in via raw curl after the skill itself refuses to run for them.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5104
- "x-rank": "any-builder",
5105
- "x-source": "modules/ideas/routes/inbox.js",
5106
5341
  "requestBody": {
5107
5342
  "required": true,
5108
5343
  "content": {
5109
5344
  "application/json": {
5110
5345
  "schema": {
5111
- "$ref": "#/components/schemas/PostInboxRequest"
5346
+ "$ref": "#/components/schemas/PostGovernanceRolesRequest"
5112
5347
  }
5113
5348
  }
5114
5349
  },
@@ -5120,7 +5355,7 @@
5120
5355
  "content": {
5121
5356
  "application/json": {
5122
5357
  "schema": {
5123
- "$ref": "#/components/schemas/PostInboxResponse"
5358
+ "$ref": "#/components/schemas/PostGovernanceRolesResponse"
5124
5359
  }
5125
5360
  }
5126
5361
  }
@@ -5142,25 +5377,37 @@
5142
5377
  ]
5143
5378
  }
5144
5379
  },
5145
- "/inbox/{id}": {
5146
- "get": {
5147
- "operationId": "get_inbox_id",
5380
+ "/governance/roles/{roleKey}/permissions/{permissionKey}": {
5381
+ "put": {
5382
+ "operationId": "put_governance_roles_roleKey_permissions_permissionKey",
5148
5383
  "tags": [
5149
- "inbox"
5384
+ "governance"
5385
+ ],
5386
+ "summary": "PUT /governance/roles/:roleKey/permissions/:permissionKey",
5387
+ "description": "governance.manage — grant one OPERATIONAL permission to a custom role (the toggle's ON half). The order of refusals is the authority order: role exists → role is custom → the key exists → the key is grantable.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5388
+ "x-rank": "archon",
5389
+ "x-source": "modules/governance/routes/governance.js",
5390
+ "x-permissions": [
5391
+ "governance.manage"
5150
5392
  ],
5151
- "summary": "GET /inbox/:id",
5152
- "description": "single idea read for the \"#NNN\" deep-link resolver (task 1047). Mirrors GET /blockers/:id. The hall resolves /#/idea/N by id, but the /inbox LIST returns only the open-first-50, so a closed/older idea ref would dead-end at a \"no such idea\" card. getIdea() reads any idea by id. Authed: a logged-out resolve hits the hall's softAuth \"sign in\" card, so no idea text is exposed publicly (the linked refs are public, the bodies aren't).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5153
- "x-rank": "any-builder",
5154
- "x-source": "modules/ideas/routes/inbox.js",
5155
5393
  "parameters": [
5156
5394
  {
5157
- "name": "id",
5395
+ "name": "roleKey",
5158
5396
  "in": "path",
5159
5397
  "required": true,
5160
5398
  "schema": {
5161
5399
  "type": "string"
5162
5400
  },
5163
- "description": "Path parameter `id`."
5401
+ "description": "Path parameter `roleKey`."
5402
+ },
5403
+ {
5404
+ "name": "permissionKey",
5405
+ "in": "path",
5406
+ "required": true,
5407
+ "schema": {
5408
+ "type": "string"
5409
+ },
5410
+ "description": "Path parameter `permissionKey`."
5164
5411
  }
5165
5412
  ],
5166
5413
  "responses": {
@@ -5169,7 +5416,7 @@
5169
5416
  "content": {
5170
5417
  "application/json": {
5171
5418
  "schema": {
5172
- "$ref": "#/components/schemas/GetInboxIdResponse"
5419
+ "$ref": "#/components/schemas/PutGovernanceRolesRoleKeyPermissionsPermissionKeyResponse"
5173
5420
  }
5174
5421
  }
5175
5422
  }
@@ -5193,50 +5440,321 @@
5193
5440
  }
5194
5441
  ]
5195
5442
  },
5196
- "patch": {
5197
- "operationId": "patch_inbox_id",
5443
+ "delete": {
5444
+ "operationId": "delete_governance_roles_roleKey_permissions_permissionKey",
5198
5445
  "tags": [
5199
- "inbox"
5446
+ "governance"
5447
+ ],
5448
+ "summary": "DELETE /governance/roles/:roleKey/permissions/:permissionKey",
5449
+ "description": "governance.manage — revoke a grant (the toggle's OFF half). Deliberately NOT validated against the catalog: a grant whose key the catalog since retired is exactly the row an Archon most needs to remove (the resolver already drops it — this is hygiene, not authority).\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `governance.manage` (all required).",
5450
+ "x-rank": "archon",
5451
+ "x-source": "modules/governance/routes/governance.js",
5452
+ "x-permissions": [
5453
+ "governance.manage"
5200
5454
  ],
5201
- "summary": "PATCH /inbox/:id",
5202
- "description": "Metic+ (task 360 / ADR 0018): idea triage (promote/discard/merge) shapes the backlog. Criterion C2 assigns triage to Metic, so this widened from archon-only to metic+archon when the three-rank model went live. Any builder can still FILE an idea (POST /inbox above); a Xenos cannot triage. rank: metic+archon — idea triage shapes the backlog; criterion C2 / task 360 / ADR 0018.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
5203
- "x-rank": "metic+archon",
5204
- "x-source": "modules/ideas/routes/inbox.js",
5205
5455
  "parameters": [
5206
5456
  {
5207
- "name": "id",
5457
+ "name": "roleKey",
5208
5458
  "in": "path",
5209
5459
  "required": true,
5210
5460
  "schema": {
5211
5461
  "type": "string"
5212
5462
  },
5213
- "description": "Path parameter `id`."
5463
+ "description": "Path parameter `roleKey`."
5464
+ },
5465
+ {
5466
+ "name": "permissionKey",
5467
+ "in": "path",
5468
+ "required": true,
5469
+ "schema": {
5470
+ "type": "string"
5471
+ },
5472
+ "description": "Path parameter `permissionKey`."
5214
5473
  }
5215
5474
  ],
5216
- "requestBody": {
5217
- "required": false,
5218
- "content": {
5219
- "application/json": {
5220
- "schema": {
5221
- "$ref": "#/components/schemas/PatchInboxIdRequest"
5222
- }
5223
- }
5224
- },
5225
- "x-validated": true
5226
- },
5227
5475
  "responses": {
5228
5476
  "200": {
5229
5477
  "description": "Success.",
5230
5478
  "content": {
5231
5479
  "application/json": {
5232
5480
  "schema": {
5233
- "$ref": "#/components/schemas/PatchInboxIdResponse"
5481
+ "$ref": "#/components/schemas/DeleteGovernanceRolesRoleKeyPermissionsPermissionKeyResponse"
5234
5482
  }
5235
5483
  }
5236
5484
  }
5237
5485
  },
5238
5486
  "400": {
5239
- "$ref": "#/components/responses/ValidationFailed"
5487
+ "$ref": "#/components/responses/BadRequest"
5488
+ },
5489
+ "401": {
5490
+ "$ref": "#/components/responses/Unauthorized"
5491
+ },
5492
+ "403": {
5493
+ "$ref": "#/components/responses/Forbidden"
5494
+ },
5495
+ "404": {
5496
+ "$ref": "#/components/responses/NotFound"
5497
+ }
5498
+ },
5499
+ "security": [
5500
+ {
5501
+ "builderSession": []
5502
+ }
5503
+ ]
5504
+ }
5505
+ },
5506
+ "/grades/by-builder": {
5507
+ "get": {
5508
+ "operationId": "get_grades_by_builder",
5509
+ "tags": [
5510
+ "grades"
5511
+ ],
5512
+ "summary": "GET /grades/by-builder",
5513
+ "description": "GET /grades/by-builder?days=30 — per-builder grade breakdown (task 726). Archon-only monitoring read backing the MARKS section of the /watch page: who is passing/failing the grader, over a window. Aggregated from task_grades joined through tasks.shipped_by. Mirrors the rank gate on the roster + audit-log reads — it exposes cross-builder quality data, so it is the Ruling Hand's alone (the project-wide aggregate stays public via /public/grades; this per-builder split does not). rank: archon — NOT ownership-scoped: archon-only cross-builder read. Gate: requirePermission('builder.roster.read') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `builder.roster.read` (all required).",
5514
+ "x-rank": "metic+archon",
5515
+ "x-source": "src/bongos/routes/builders.js",
5516
+ "x-permissions": [
5517
+ "builder.roster.read"
5518
+ ],
5519
+ "responses": {
5520
+ "200": {
5521
+ "description": "Success.",
5522
+ "content": {
5523
+ "application/json": {
5524
+ "schema": {
5525
+ "$ref": "#/components/schemas/GetGradesByBuilderResponse"
5526
+ }
5527
+ }
5528
+ }
5529
+ },
5530
+ "400": {
5531
+ "$ref": "#/components/responses/BadRequest"
5532
+ },
5533
+ "401": {
5534
+ "$ref": "#/components/responses/Unauthorized"
5535
+ },
5536
+ "403": {
5537
+ "$ref": "#/components/responses/Forbidden"
5538
+ }
5539
+ },
5540
+ "security": [
5541
+ {
5542
+ "builderSession": []
5543
+ }
5544
+ ]
5545
+ }
5546
+ },
5547
+ "/healthz": {
5548
+ "get": {
5549
+ "operationId": "get_healthz",
5550
+ "tags": [
5551
+ "healthz"
5552
+ ],
5553
+ "summary": "GET /healthz",
5554
+ "description": "liveness probe; status.amazonprimea.com hits this anonymously.\n\n**Rank:** `public` — No authentication — any caller.",
5555
+ "x-rank": "public",
5556
+ "x-source": "src/bongos/routes/healthz.js",
5557
+ "responses": {
5558
+ "200": {
5559
+ "description": "Success.",
5560
+ "content": {
5561
+ "application/json": {
5562
+ "schema": {
5563
+ "$ref": "#/components/schemas/GetHealthzResponse"
5564
+ }
5565
+ }
5566
+ }
5567
+ },
5568
+ "400": {
5569
+ "$ref": "#/components/responses/BadRequest"
5570
+ }
5571
+ },
5572
+ "security": []
5573
+ }
5574
+ },
5575
+ "/inbox": {
5576
+ "get": {
5577
+ "operationId": "get_inbox",
5578
+ "tags": [
5579
+ "inbox"
5580
+ ],
5581
+ "summary": "GET /inbox",
5582
+ "description": "read open ideas; skill-friction rows filtered by viewer rank.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5583
+ "x-rank": "any-builder",
5584
+ "x-source": "modules/ideas/routes/inbox.js",
5585
+ "responses": {
5586
+ "200": {
5587
+ "description": "Success.",
5588
+ "content": {
5589
+ "application/json": {
5590
+ "schema": {
5591
+ "$ref": "#/components/schemas/GetInboxResponse"
5592
+ }
5593
+ }
5594
+ }
5595
+ },
5596
+ "400": {
5597
+ "$ref": "#/components/responses/BadRequest"
5598
+ },
5599
+ "401": {
5600
+ "$ref": "#/components/responses/Unauthorized"
5601
+ },
5602
+ "403": {
5603
+ "$ref": "#/components/responses/Forbidden"
5604
+ }
5605
+ },
5606
+ "security": [
5607
+ {
5608
+ "builderSession": []
5609
+ }
5610
+ ]
5611
+ },
5612
+ "post": {
5613
+ "operationId": "post_inbox",
5614
+ "tags": [
5615
+ "inbox"
5616
+ ],
5617
+ "summary": "POST /inbox",
5618
+ "description": "for ordinary ideas; metic+ for kind='criterion-proposal'. Anyone can file a general contribution (the open-to-all path that idea-triage's \"Xenos can still file\" line guarantees). But kind= 'criterion-proposal' is the marker the /planning-session skill writes from Metic-mode, and a planning-session proposal reshapes the next version's scope-truth — that's a trusted-builder operation (V3.R87 / task 306). Gate it here so a Xenos can't slip a criterion proposal in via raw curl after the skill itself refuses to run for them.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5619
+ "x-rank": "any-builder",
5620
+ "x-source": "modules/ideas/routes/inbox.js",
5621
+ "requestBody": {
5622
+ "required": true,
5623
+ "content": {
5624
+ "application/json": {
5625
+ "schema": {
5626
+ "$ref": "#/components/schemas/PostInboxRequest"
5627
+ }
5628
+ }
5629
+ },
5630
+ "x-validated": true
5631
+ },
5632
+ "responses": {
5633
+ "200": {
5634
+ "description": "Success.",
5635
+ "content": {
5636
+ "application/json": {
5637
+ "schema": {
5638
+ "$ref": "#/components/schemas/PostInboxResponse"
5639
+ }
5640
+ }
5641
+ }
5642
+ },
5643
+ "400": {
5644
+ "$ref": "#/components/responses/ValidationFailed"
5645
+ },
5646
+ "401": {
5647
+ "$ref": "#/components/responses/Unauthorized"
5648
+ },
5649
+ "403": {
5650
+ "$ref": "#/components/responses/Forbidden"
5651
+ }
5652
+ },
5653
+ "security": [
5654
+ {
5655
+ "builderSession": []
5656
+ }
5657
+ ]
5658
+ }
5659
+ },
5660
+ "/inbox/{id}": {
5661
+ "get": {
5662
+ "operationId": "get_inbox_id",
5663
+ "tags": [
5664
+ "inbox"
5665
+ ],
5666
+ "summary": "GET /inbox/:id",
5667
+ "description": "single idea read for the \"#NNN\" deep-link resolver (task 1047). Mirrors GET /blockers/:id. The hall resolves /#/idea/N by id, but the /inbox LIST returns only the open-first-50, so a closed/older idea ref would dead-end at a \"no such idea\" card. getIdea() reads any idea by id. Authed: a logged-out resolve hits the hall's softAuth \"sign in\" card, so no idea text is exposed publicly (the linked refs are public, the bodies aren't).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5668
+ "x-rank": "any-builder",
5669
+ "x-source": "modules/ideas/routes/inbox.js",
5670
+ "parameters": [
5671
+ {
5672
+ "name": "id",
5673
+ "in": "path",
5674
+ "required": true,
5675
+ "schema": {
5676
+ "type": "string"
5677
+ },
5678
+ "description": "Path parameter `id`."
5679
+ }
5680
+ ],
5681
+ "responses": {
5682
+ "200": {
5683
+ "description": "Success.",
5684
+ "content": {
5685
+ "application/json": {
5686
+ "schema": {
5687
+ "$ref": "#/components/schemas/GetInboxIdResponse"
5688
+ }
5689
+ }
5690
+ }
5691
+ },
5692
+ "400": {
5693
+ "$ref": "#/components/responses/BadRequest"
5694
+ },
5695
+ "401": {
5696
+ "$ref": "#/components/responses/Unauthorized"
5697
+ },
5698
+ "403": {
5699
+ "$ref": "#/components/responses/Forbidden"
5700
+ },
5701
+ "404": {
5702
+ "$ref": "#/components/responses/NotFound"
5703
+ }
5704
+ },
5705
+ "security": [
5706
+ {
5707
+ "builderSession": []
5708
+ }
5709
+ ]
5710
+ },
5711
+ "patch": {
5712
+ "operationId": "patch_inbox_id",
5713
+ "tags": [
5714
+ "inbox"
5715
+ ],
5716
+ "summary": "PATCH /inbox/:id",
5717
+ "description": "Metic+ (task 360 / ADR 0018): idea triage (promote/discard/merge) shapes the backlog. Criterion C2 assigns triage to Metic, so this widened from archon-only to metic+archon when the three-rank model went live. Any builder can still FILE an idea (POST /inbox above); a Xenos cannot triage. rank: metic+archon — idea triage shapes the backlog; criterion C2 / task 360 / ADR 0018.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `idea.triage` (all required).",
5718
+ "x-rank": "metic+archon",
5719
+ "x-source": "modules/ideas/routes/inbox.js",
5720
+ "x-permissions": [
5721
+ "idea.triage"
5722
+ ],
5723
+ "parameters": [
5724
+ {
5725
+ "name": "id",
5726
+ "in": "path",
5727
+ "required": true,
5728
+ "schema": {
5729
+ "type": "string"
5730
+ },
5731
+ "description": "Path parameter `id`."
5732
+ }
5733
+ ],
5734
+ "requestBody": {
5735
+ "required": false,
5736
+ "content": {
5737
+ "application/json": {
5738
+ "schema": {
5739
+ "$ref": "#/components/schemas/PatchInboxIdRequest"
5740
+ }
5741
+ }
5742
+ },
5743
+ "x-validated": true
5744
+ },
5745
+ "responses": {
5746
+ "200": {
5747
+ "description": "Success.",
5748
+ "content": {
5749
+ "application/json": {
5750
+ "schema": {
5751
+ "$ref": "#/components/schemas/PatchInboxIdResponse"
5752
+ }
5753
+ }
5754
+ }
5755
+ },
5756
+ "400": {
5757
+ "$ref": "#/components/responses/ValidationFailed"
5240
5758
  },
5241
5759
  "401": {
5242
5760
  "$ref": "#/components/responses/Unauthorized"
@@ -5262,9 +5780,12 @@
5262
5780
  "inbox"
5263
5781
  ],
5264
5782
  "summary": "POST /inbox/:id/ratify",
5265
- "description": "V3.R31 (task 252) — Archon ratifies a criterion-proposal idea, atomically: - INSERT done_when_criteria row on the target version - UPDATE idea_inbox SET status='promoted', reviewed_at=now() - INSERT karma_log (delta=+3, reason='proposal_ratified') for proposer (V3.R28 / task 248 tuned the delta from +5 → +3; tunable.) - INSERT criterion_proposal_audit row capturing who/when/what Archon-only — done_when_criteria writes are scope-shaping (criterion C2 in canonical-permissions.md). The kind='criterion-proposal' POST is Metic+ (gated above), but the ratification is the Archon decision. Returns 400 if the source idea isn't kind='criterion-proposal' or its body_md isn't a parseable {target_version, criterion_md, sort_order_hint} JSON object. Returns 404 if the idea doesn't exist. Returns 409 if the idea is already promoted/discarded/merged (status != 'open'). All four writes happen in one transaction — partial failures roll back cleanly.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
5266
- "x-rank": "archon",
5783
+ "description": "V3.R31 (task 252) — Archon ratifies a criterion-proposal idea, atomically: - INSERT done_when_criteria row on the target version - UPDATE idea_inbox SET status='promoted', reviewed_at=now() - INSERT karma_log (delta=+3, reason='proposal_ratified') for proposer (V3.R28 / task 248 tuned the delta from +5 → +3; tunable.) - INSERT criterion_proposal_audit row capturing who/when/what Archon-only — done_when_criteria writes are scope-shaping (criterion C2 in canonical-permissions.md). The kind='criterion-proposal' POST is Metic+ (gated above), but the ratification is the Archon decision. Returns 400 if the source idea isn't kind='criterion-proposal' or its body_md isn't a parseable {target_version, criterion_md, sort_order_hint} JSON object. Returns 404 if the idea doesn't exist. Returns 409 if the idea is already promoted/discarded/merged (status != 'open'). All four writes happen in one transaction — partial failures roll back cleanly.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `idea.ratify` (all required).",
5784
+ "x-rank": "metic+archon",
5267
5785
  "x-source": "modules/ideas/routes/inbox.js",
5786
+ "x-permissions": [
5787
+ "idea.ratify"
5788
+ ],
5268
5789
  "parameters": [
5269
5790
  {
5270
5791
  "name": "id",
@@ -5483,9 +6004,12 @@
5483
6004
  "llm-cache"
5484
6005
  ],
5485
6006
  "summary": "POST /llm-cache/lookup",
5486
- "description": "POST /llm-cache/lookup — hit/miss + atomic hit_count bump. Best-effort: any DB error inside lookup() already returns null → we report a miss. rank: metic — only the same trust tier that can store may read a stored result.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
6007
+ "description": "POST /llm-cache/lookup — hit/miss + atomic hit_count bump. Best-effort: any DB error inside lookup() already returns null → we report a miss. rank: metic — only the same trust tier that can store may read a stored result. Gate: requirePermission('llm_cache.use') — 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:** `llm_cache.use` (all required).",
5487
6008
  "x-rank": "metic+archon",
5488
6009
  "x-source": "src/bongos/routes/llm-cache.js",
6010
+ "x-permissions": [
6011
+ "llm_cache.use"
6012
+ ],
5489
6013
  "requestBody": {
5490
6014
  "required": false,
5491
6015
  "content": {
@@ -5532,9 +6056,12 @@
5532
6056
  "llm-cache"
5533
6057
  ],
5534
6058
  "summary": "POST /llm-cache/store",
5535
- "description": "POST /llm-cache/store — upsert a freshly-produced result. rank: metic — a store seeds a result that a later run replays at $0 and trusts.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
6059
+ "description": "POST /llm-cache/store — upsert a freshly-produced result. rank: metic — a store seeds a result that a later run replays at $0 and trusts. Gate: requirePermission('llm_cache.use') — BV1.R104.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `llm_cache.use` (all required).",
5536
6060
  "x-rank": "metic+archon",
5537
6061
  "x-source": "src/bongos/routes/llm-cache.js",
6062
+ "x-permissions": [
6063
+ "llm_cache.use"
6064
+ ],
5538
6065
  "requestBody": {
5539
6066
  "required": false,
5540
6067
  "content": {
@@ -6593,9 +7120,12 @@
6593
7120
  "memory"
6594
7121
  ],
6595
7122
  "summary": "GET /memory/builders/:builderId/file",
6596
- "description": "GET /memory/builders/:builderId/file?path=... — Archon reads ONE of ANOTHER builder's files (content included). Audit-logged. 404 if the target has no file at that path.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
6597
- "x-rank": "archon",
7123
+ "description": "GET /memory/builders/:builderId/file?path=... — Archon reads ONE of ANOTHER builder's files (content included). Audit-logged. 404 if the target has no file at that path.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `memory.read.any` (all required).",
7124
+ "x-rank": "metic+archon",
6598
7125
  "x-source": "modules/memory/routes/memory.js",
7126
+ "x-permissions": [
7127
+ "memory.read.any"
7128
+ ],
6599
7129
  "parameters": [
6600
7130
  {
6601
7131
  "name": "builderId",
@@ -6645,9 +7175,12 @@
6645
7175
  "memory"
6646
7176
  ],
6647
7177
  "summary": "GET /memory/builders/:builderId/files",
6648
- "description": "GET /memory/builders/:builderId/files — Archon lists ANOTHER builder's memory file metadata. Audit-logged.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
6649
- "x-rank": "archon",
7178
+ "description": "GET /memory/builders/:builderId/files — Archon lists ANOTHER builder's memory file metadata. Audit-logged.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `memory.read.any` (all required).",
7179
+ "x-rank": "metic+archon",
6650
7180
  "x-source": "modules/memory/routes/memory.js",
7181
+ "x-permissions": [
7182
+ "memory.read.any"
7183
+ ],
6651
7184
  "parameters": [
6652
7185
  {
6653
7186
  "name": "builderId",
@@ -6901,9 +7434,12 @@
6901
7434
  "modules"
6902
7435
  ],
6903
7436
  "summary": "GET /modules/submissions",
6904
- "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.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
7437
+ "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).",
6905
7438
  "x-rank": "metic+archon",
6906
7439
  "x-source": "src/bongos/routes/modules.js",
7440
+ "x-permissions": [
7441
+ "module.submit"
7442
+ ],
6907
7443
  "responses": {
6908
7444
  "200": {
6909
7445
  "description": "Success.",
@@ -6939,9 +7475,12 @@
6939
7475
  "modules"
6940
7476
  ],
6941
7477
  "summary": "POST /modules/:key/enable",
6942
- "description": "toggling a module changes running behavior for the whole instance, not just the caller.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
7478
+ "description": "toggling a module changes running behavior for the whole instance, not just the caller. Gate: requirePermission('module.enable') — 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:** `module.enable` (all required).",
6943
7479
  "x-rank": "metic+archon",
6944
7480
  "x-source": "src/bongos/routes/modules.js",
7481
+ "x-permissions": [
7482
+ "module.enable"
7483
+ ],
6945
7484
  "parameters": [
6946
7485
  {
6947
7486
  "name": "key",
@@ -7002,9 +7541,12 @@
7002
7541
  "modules"
7003
7542
  ],
7004
7543
  "summary": "POST /modules/:key/submit",
7005
- "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.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
7544
+ "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).",
7006
7545
  "x-rank": "metic+archon",
7007
7546
  "x-source": "src/bongos/routes/modules.js",
7547
+ "x-permissions": [
7548
+ "module.submit"
7549
+ ],
7008
7550
  "parameters": [
7009
7551
  {
7010
7552
  "name": "key",
@@ -7346,9 +7888,12 @@
7346
7888
  "override-requests"
7347
7889
  ],
7348
7890
  "summary": "GET /override-requests",
7349
- "description": "GET /override-requests?status=open — Archon queue. Status defaults to open; pass ?status=approved or ?status=denied for the resolved history. rank: archon — same gate as the audit log + Archon view.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7350
- "x-rank": "archon",
7891
+ "description": "GET /override-requests?status=open — Archon queue. Status defaults to open; pass ?status=approved or ?status=denied for the resolved history. rank: archon — same gate as the audit log + Archon view.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `override_request.decide` (all required).",
7892
+ "x-rank": "metic+archon",
7351
7893
  "x-source": "modules/lifecycle/routes/tasks.js",
7894
+ "x-permissions": [
7895
+ "override_request.decide"
7896
+ ],
7352
7897
  "responses": {
7353
7898
  "200": {
7354
7899
  "description": "Success.",
@@ -7384,9 +7929,12 @@
7384
7929
  "override-requests"
7385
7930
  ],
7386
7931
  "summary": "POST /override-requests/:id/decide",
7387
- "description": "POST /override-requests/:id/decide — body: { decision: 'approve'|'deny', note? } On approve, atomically flips the task completed→confirmed and awards the credits to the original requester (NOT the Archon). On deny, only the row updates; the task stays at completed and the builder must release or re-ship after fixing whatever the grader caught. rank: archon — grader-bypass authority; same gate as POST /tasks/:id/confirm.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7388
- "x-rank": "archon",
7932
+ "description": "POST /override-requests/:id/decide — body: { decision: 'approve'|'deny', note? } On approve, atomically flips the task completed→confirmed and awards the credits to the original requester (NOT the Archon). On deny, only the row updates; the task stays at completed and the builder must release or re-ship after fixing whatever the grader caught. rank: archon — grader-bypass authority; same gate as POST /tasks/:id/confirm.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `override_request.decide` (all required).",
7933
+ "x-rank": "metic+archon",
7389
7934
  "x-source": "modules/lifecycle/routes/tasks.js",
7935
+ "x-permissions": [
7936
+ "override_request.decide"
7937
+ ],
7390
7938
  "parameters": [
7391
7939
  {
7392
7940
  "name": "id",
@@ -7440,9 +7988,12 @@
7440
7988
  "projects"
7441
7989
  ],
7442
7990
  "summary": "GET /projects",
7443
- "description": "the full curation list (includes unfeatured + owner attribution).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7444
- "x-rank": "archon",
7991
+ "description": "the full curation list (includes unfeatured + owner attribution). BV1.R105 left this on requireRank because `project.curate` was declared over the writes + GET /scouting, not over this read. ADR 0157 extends that atom's guards to name GET /projects and lowers its floor archon→metic, so the mapping now exists and the audience is the working rank.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `project.curate` (all required).",
7992
+ "x-rank": "metic+archon",
7445
7993
  "x-source": "modules/platform-identity/routes/projects.js",
7994
+ "x-permissions": [
7995
+ "project.curate"
7996
+ ],
7446
7997
  "responses": {
7447
7998
  "200": {
7448
7999
  "description": "Success.",
@@ -7476,9 +8027,12 @@
7476
8027
  "projects"
7477
8028
  ],
7478
8029
  "summary": "POST /projects",
7479
- "description": "create / update a catalog entry (manual seed for hand-wired instances; federated projects auto-catalogue at registration).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7480
- "x-rank": "archon",
8030
+ "description": "create / update a catalog entry (manual seed for hand-wired instances; federated projects auto-catalogue at registration).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `project.curate` (all required).",
8031
+ "x-rank": "metic+archon",
7481
8032
  "x-source": "modules/platform-identity/routes/projects.js",
8033
+ "x-permissions": [
8034
+ "project.curate"
8035
+ ],
7482
8036
  "requestBody": {
7483
8037
  "required": true,
7484
8038
  "content": {
@@ -7553,9 +8107,12 @@
7553
8107
  "projects"
7554
8108
  ],
7555
8109
  "summary": "POST /projects/invite",
7556
- "description": "invite a builder into a project (ADR 0141 §5, task #1002115). Pre-seeds a 'pending' membership the invitee accepts from My Projects. V1 invites by github_login and requires the invitee to already have a platform account (they build on some project); inviting someone entirely new to the platform (GitHub-id resolution) is a follow-up.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7557
- "x-rank": "archon",
8110
+ "description": "invite a builder into a project (ADR 0141 §5, task #1002115). Pre-seeds a 'pending' membership the invitee accepts from My Projects. V1 invites by github_login and requires the invitee to already have a platform account (they build on some project); inviting someone entirely new to the platform (GitHub-id resolution) is a follow-up.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `project.curate` (all required).",
8111
+ "x-rank": "metic+archon",
7558
8112
  "x-source": "modules/platform-identity/routes/projects.js",
8113
+ "x-permissions": [
8114
+ "project.curate"
8115
+ ],
7559
8116
  "requestBody": {
7560
8117
  "required": true,
7561
8118
  "content": {
@@ -7595,9 +8152,12 @@
7595
8152
  "projects"
7596
8153
  ],
7597
8154
  "summary": "PATCH /projects/:id/featured",
7598
- "description": "the feature / unfeature control (the ADR 0141 §5 curation gate).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7599
- "x-rank": "archon",
8155
+ "description": "the feature / unfeature control (the ADR 0141 §5 curation gate).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `project.curate` (all required).",
8156
+ "x-rank": "metic+archon",
7600
8157
  "x-source": "modules/platform-identity/routes/projects.js",
8158
+ "x-permissions": [
8159
+ "project.curate"
8160
+ ],
7601
8161
  "parameters": [
7602
8162
  {
7603
8163
  "name": "id",
@@ -7658,9 +8218,12 @@
7658
8218
  "provisioning"
7659
8219
  ],
7660
8220
  "summary": "GET /provisioning/fleet",
7661
- "description": "GET /provisioning/fleet — the full instance roster across all owners. rank: archon (exposes every owner's instance + cost; the /boxes precedent).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7662
- "x-rank": "archon",
8221
+ "description": "GET /provisioning/fleet — the full instance roster across all owners. rank: archon (exposes every owner's instance + cost; the /boxes precedent).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `provisioning.fleet.manage` (all required).",
8222
+ "x-rank": "metic+archon",
7663
8223
  "x-source": "modules/provisioning/routes/provisioning.js",
8224
+ "x-permissions": [
8225
+ "provisioning.fleet.manage"
8226
+ ],
7664
8227
  "responses": {
7665
8228
  "200": {
7666
8229
  "description": "Success.",
@@ -7696,9 +8259,12 @@
7696
8259
  "provisioning"
7697
8260
  ],
7698
8261
  "summary": "GET /provisioning/fleet/cost-ledger",
7699
- "description": "GET /provisioning/fleet/cost-ledger — per-instance monthly estimate + total. rank: archon — cost oversight across the fleet (the /boxes/cost-ledger precedent). Declared among the archon routes (archon-first) for correct auditor classification.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7700
- "x-rank": "archon",
8262
+ "description": "GET /provisioning/fleet/cost-ledger — per-instance monthly estimate + total. rank: archon — cost oversight across the fleet (the /boxes/cost-ledger precedent). Declared among the archon routes (archon-first) for correct auditor classification.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `provisioning.fleet.manage` (all required).",
8263
+ "x-rank": "metic+archon",
7701
8264
  "x-source": "modules/provisioning/routes/provisioning.js",
8265
+ "x-permissions": [
8266
+ "provisioning.fleet.manage"
8267
+ ],
7702
8268
  "responses": {
7703
8269
  "200": {
7704
8270
  "description": "Success."
@@ -7840,7 +8406,7 @@
7840
8406
  "provisioning"
7841
8407
  ],
7842
8408
  "summary": "POST /provisioning/instances",
7843
- "description": "POST /provisioning/instances — request a new instance. rank: any authenticated builder (own resource). ENQUEUES a 'provision' intent + records the request; the runner (task P3) does the real standup. Idempotent on slug for the SAME owner (re-request returns the existing row); a slug owned by ANOTHER builder → 409. Body: { slug (required), target_ref?, hosting_shape? (co-tenant|dedicated), domain?, tier? }.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8409
+ "description": "POST /provisioning/instances — request a new instance. rank: any authenticated builder (own resource). ENQUEUES a 'provision' intent + records the request; the runner (task P3) does the real standup. Idempotent on slug for the SAME owner (re-request returns the existing row); a slug owned by ANOTHER builder → 409. Body: { slug (required), target_ref?, hosting_shape? (co-tenant|dedicated), domain?, tier?, onboard_mode? (greenfield|adopt) }. onboard_mode is LOAD-BEARING, not a label (task 1002562): the control-plane runner branches its repo scaffold on it. 'adopt' means target_ref is a repo the owner ALREADY has, so the runner must clone + layer onto its history instead of pushing a fresh tree at `main` (which an existing repo rejects as unrelated history). Absent → 'greenfield', the safe default.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
7844
8410
  "x-rank": "any-builder",
7845
8411
  "x-source": "modules/provisioning/routes/provisioning.js",
7846
8412
  "requestBody": {
@@ -7934,9 +8500,12 @@
7934
8500
  "provisioning"
7935
8501
  ],
7936
8502
  "summary": "POST /provisioning/instances/:id/force-teardown",
7937
- "description": "POST /provisioning/instances/:id/force-teardown — Archon tears down ANY instance. Trust-safe by the same mechanism as the owner's own teardown: it ENQUEUES a 'teardown' intent for the control-plane runner; the web tier never holds cloud tokens. rank: archon (acts on another owner's infrastructure). Declared among the archon routes (archon-first).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
7938
- "x-rank": "archon",
8503
+ "description": "POST /provisioning/instances/:id/force-teardown — Archon tears down ANY instance. Trust-safe by the same mechanism as the owner's own teardown: it ENQUEUES a 'teardown' intent for the control-plane runner; the web tier never holds cloud tokens. rank: archon (acts on another owner's infrastructure). Declared among the archon routes (archon-first).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `provisioning.fleet.manage` (all required).",
8504
+ "x-rank": "metic+archon",
7939
8505
  "x-source": "modules/provisioning/routes/provisioning.js",
8506
+ "x-permissions": [
8507
+ "provisioning.fleet.manage"
8508
+ ],
7940
8509
  "parameters": [
7941
8510
  {
7942
8511
  "name": "id",
@@ -8661,9 +9230,12 @@
8661
9230
  "scouting"
8662
9231
  ],
8663
9232
  "summary": "GET /scouting",
8664
- "description": "the internal talent directory across every project. The Archon gate here is the load-bearing protection (\"NOT shown to builders\"): a non-Archon is 403'd before any cross-builder data is read.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
8665
- "x-rank": "archon",
9233
+ "description": "the internal talent directory across every project. The Archon gate here is the load-bearing protection (\"NOT shown to builders\"): a non-Archon is 403'd before any cross-builder data is read.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `project.curate` (all required).",
9234
+ "x-rank": "metic+archon",
8666
9235
  "x-source": "modules/platform-identity/routes/scouting.js",
9236
+ "x-permissions": [
9237
+ "project.curate"
9238
+ ],
8667
9239
  "responses": {
8668
9240
  "200": {
8669
9241
  "description": "Success.",
@@ -8790,9 +9362,12 @@
8790
9362
  "security"
8791
9363
  ],
8792
9364
  "summary": "GET /security/adr",
8793
- "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).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
9365
+ "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).",
8794
9366
  "x-rank": "metic+archon",
8795
9367
  "x-source": "src/bongos/routes/security.js",
9368
+ "x-permissions": [
9369
+ "security.report.file"
9370
+ ],
8796
9371
  "responses": {
8797
9372
  "200": {
8798
9373
  "description": "Success."
@@ -8821,9 +9396,12 @@
8821
9396
  "security"
8822
9397
  ],
8823
9398
  "summary": "GET /security/docs",
8824
- "description": "GET /api/gds/security/docs — list doc METADATA (no content). rank: archon — index of exploit-detail engagement reports.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
8825
- "x-rank": "archon",
9399
+ "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).",
9400
+ "x-rank": "metic+archon",
8826
9401
  "x-source": "src/bongos/routes/security.js",
9402
+ "x-permissions": [
9403
+ "security.report.adjudicate"
9404
+ ],
8827
9405
  "responses": {
8828
9406
  "200": {
8829
9407
  "description": "Success.",
@@ -8857,9 +9435,12 @@
8857
9435
  "security"
8858
9436
  ],
8859
9437
  "summary": "POST /security/docs",
8860
- "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.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
8861
- "x-rank": "archon",
9438
+ "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).",
9439
+ "x-rank": "metic+archon",
8862
9440
  "x-source": "src/bongos/routes/security.js",
9441
+ "x-permissions": [
9442
+ "security.report.adjudicate"
9443
+ ],
8863
9444
  "requestBody": {
8864
9445
  "required": true,
8865
9446
  "content": {
@@ -8906,9 +9487,12 @@
8906
9487
  "security"
8907
9488
  ],
8908
9489
  "summary": "GET /security/docs/:slug",
8909
- "description": "GET /api/gds/security/docs/:slug — one doc WITH content, or 404. rank: archon — reads the full exploit-detail report body.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
8910
- "x-rank": "archon",
9490
+ "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).",
9491
+ "x-rank": "metic+archon",
8911
9492
  "x-source": "src/bongos/routes/security.js",
9493
+ "x-permissions": [
9494
+ "security.report.adjudicate"
9495
+ ],
8912
9496
  "parameters": [
8913
9497
  {
8914
9498
  "name": "slug",
@@ -8958,9 +9542,12 @@
8958
9542
  "security"
8959
9543
  ],
8960
9544
  "summary": "GET /security/reports",
8961
- "description": "GET /api/bongos/security/reports?status=<status> Archon-only, newest-first. The Archon dashboard view fetches this on load + after each adjudication action. ?status= narrows to one lifecycle bucket (open / repro_attempted / confirmed / disputed / fixed / wontfix); omitted = all. rank: archon — adjudication surface; reading every builder's reports.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
8962
- "x-rank": "archon",
9545
+ "description": "GET /api/bongos/security/reports?status=<status> Archon-only, newest-first. The Archon dashboard view fetches this on load + after each adjudication action. ?status= narrows to one lifecycle bucket (open / repro_attempted / confirmed / disputed / fixed / wontfix); omitted = all. rank: metic+archon — adjudication surface; reading every builder's reports. BV1.R105 left this on requireRank because `security.report.adjudicate` was declared over the adjudication WRITES + /security/docs CRUD, not over this read. ADR 0157 extends that atom's guards to name GET /security/reports and lowers its floor archon→metic, so the mapping now exists and the audience is the working rank.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
9546
+ "x-rank": "metic+archon",
8963
9547
  "x-source": "modules/security/routes/reports.js",
9548
+ "x-permissions": [
9549
+ "security.report.adjudicate"
9550
+ ],
8964
9551
  "responses": {
8965
9552
  "200": {
8966
9553
  "description": "Success.",
@@ -8994,9 +9581,12 @@
8994
9581
  "security"
8995
9582
  ],
8996
9583
  "summary": "POST /security/reports",
8997
- "description": "POST /api/bongos/security/reports — file a new vulnerability report. V3.R64 (task 283). Used by the /builder-redteam skill. Metic+ only — Xenos can't open the bounty surface (the rank gate keeps the noise-floor sane; a Xenos who finds a real flaw can flag it through normal channels). Body: { target, severity, title, description?, repro_steps_md? } Returns 201 + the inserted row (status='open' by default; the Archon view picks it up immediately). rank: metic+archon — bounty intake; Xenos kept out by design (V3.R63).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
9584
+ "description": "POST /api/bongos/security/reports — file a new vulnerability report. V3.R64 (task 283). Used by the /builder-redteam skill. Metic+ only — Xenos can't open the bounty surface (the rank gate keeps the noise-floor sane; a Xenos who finds a real flaw can flag it through normal channels). Body: { target, severity, title, description?, repro_steps_md? } Returns 201 + the inserted row (status='open' by default; the Archon view picks it up immediately). rank: metic+archon — bounty intake; Xenos kept out by design (V3.R63).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.file` (all required).",
8998
9585
  "x-rank": "metic+archon",
8999
9586
  "x-source": "modules/security/routes/reports.js",
9587
+ "x-permissions": [
9588
+ "security.report.file"
9589
+ ],
9000
9590
  "requestBody": {
9001
9591
  "required": true,
9002
9592
  "content": {
@@ -9043,9 +9633,12 @@
9043
9633
  "security"
9044
9634
  ],
9045
9635
  "summary": "POST /security/reports/:id/confirm",
9046
- "description": "POST /api/bongos/security/reports/:id/confirm Body: { drachmae_awarded?: integer } — defaults to the severity tier bounty if omitted. Marks the report confirmed, stamps confirmed_at, and sets drachmae_awarded. rank: archon — confirms a payout-eligible report.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9047
- "x-rank": "archon",
9636
+ "description": "POST /api/bongos/security/reports/:id/confirm Body: { drachmae_awarded?: integer } — defaults to the severity tier bounty if omitted. Marks the report confirmed, stamps confirmed_at, and sets drachmae_awarded. rank: archon — confirms a payout-eligible report.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
9637
+ "x-rank": "metic+archon",
9048
9638
  "x-source": "modules/security/routes/reports.js",
9639
+ "x-permissions": [
9640
+ "security.report.adjudicate"
9641
+ ],
9049
9642
  "parameters": [
9050
9643
  {
9051
9644
  "name": "id",
@@ -9106,9 +9699,12 @@
9106
9699
  "security"
9107
9700
  ],
9108
9701
  "summary": "POST /security/reports/:id/dispute",
9109
- "description": "POST /api/bongos/security/reports/:id/dispute Marks the report disputed and clears drachmae_awarded. rank: archon — dispute adjudication.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9110
- "x-rank": "archon",
9702
+ "description": "POST /api/bongos/security/reports/:id/dispute Marks the report disputed and clears drachmae_awarded. rank: archon — dispute adjudication.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
9703
+ "x-rank": "metic+archon",
9111
9704
  "x-source": "modules/security/routes/reports.js",
9705
+ "x-permissions": [
9706
+ "security.report.adjudicate"
9707
+ ],
9112
9708
  "parameters": [
9113
9709
  {
9114
9710
  "name": "id",
@@ -9126,13 +9722,134 @@
9126
9722
  "content": {
9127
9723
  "application/json": {
9128
9724
  "schema": {
9129
- "$ref": "#/components/schemas/PostSecurityReportsIdDisputeResponse"
9725
+ "$ref": "#/components/schemas/PostSecurityReportsIdDisputeResponse"
9726
+ }
9727
+ }
9728
+ }
9729
+ },
9730
+ "400": {
9731
+ "$ref": "#/components/responses/BadRequest"
9732
+ },
9733
+ "401": {
9734
+ "$ref": "#/components/responses/Unauthorized"
9735
+ },
9736
+ "403": {
9737
+ "$ref": "#/components/responses/Forbidden"
9738
+ },
9739
+ "404": {
9740
+ "$ref": "#/components/responses/NotFound"
9741
+ }
9742
+ },
9743
+ "security": [
9744
+ {
9745
+ "builderSession": []
9746
+ }
9747
+ ]
9748
+ }
9749
+ },
9750
+ "/security/reports/{id}/fix": {
9751
+ "post": {
9752
+ "operationId": "post_security_reports_id_fix",
9753
+ "tags": [
9754
+ "security"
9755
+ ],
9756
+ "summary": "POST /security/reports/:id/fix",
9757
+ "description": "POST /api/bongos/security/reports/:id/fix Marks the report fixed and stamps fixed_at. Does not change fix_task_id — link that separately via /link-fix. rank: archon — fix-confirmation adjudication.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
9758
+ "x-rank": "metic+archon",
9759
+ "x-source": "modules/security/routes/reports.js",
9760
+ "x-permissions": [
9761
+ "security.report.adjudicate"
9762
+ ],
9763
+ "parameters": [
9764
+ {
9765
+ "name": "id",
9766
+ "in": "path",
9767
+ "required": true,
9768
+ "schema": {
9769
+ "type": "string"
9770
+ },
9771
+ "description": "Path parameter `id`."
9772
+ }
9773
+ ],
9774
+ "responses": {
9775
+ "200": {
9776
+ "description": "Success.",
9777
+ "content": {
9778
+ "application/json": {
9779
+ "schema": {
9780
+ "$ref": "#/components/schemas/PostSecurityReportsIdFixResponse"
9781
+ }
9782
+ }
9783
+ }
9784
+ },
9785
+ "400": {
9786
+ "$ref": "#/components/responses/BadRequest"
9787
+ },
9788
+ "401": {
9789
+ "$ref": "#/components/responses/Unauthorized"
9790
+ },
9791
+ "403": {
9792
+ "$ref": "#/components/responses/Forbidden"
9793
+ },
9794
+ "404": {
9795
+ "$ref": "#/components/responses/NotFound"
9796
+ }
9797
+ },
9798
+ "security": [
9799
+ {
9800
+ "builderSession": []
9801
+ }
9802
+ ]
9803
+ }
9804
+ },
9805
+ "/security/reports/{id}/link-fix": {
9806
+ "post": {
9807
+ "operationId": "post_security_reports_id_link_fix",
9808
+ "tags": [
9809
+ "security"
9810
+ ],
9811
+ "summary": "POST /security/reports/:id/link-fix",
9812
+ "description": "POST /api/bongos/security/reports/:id/link-fix Body: { task_id: integer } — attaches a fix-task FK. Doesn't change status (a confirmed report can have a linked fix-task while still open work). 422 if the referenced task doesn't exist. rank: archon — linking a report to its fix-task in the queue.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `security.report.adjudicate` (all required).",
9813
+ "x-rank": "metic+archon",
9814
+ "x-source": "modules/security/routes/reports.js",
9815
+ "x-permissions": [
9816
+ "security.report.adjudicate"
9817
+ ],
9818
+ "parameters": [
9819
+ {
9820
+ "name": "id",
9821
+ "in": "path",
9822
+ "required": true,
9823
+ "schema": {
9824
+ "type": "string"
9825
+ },
9826
+ "description": "Path parameter `id`."
9827
+ }
9828
+ ],
9829
+ "requestBody": {
9830
+ "required": true,
9831
+ "content": {
9832
+ "application/json": {
9833
+ "schema": {
9834
+ "$ref": "#/components/schemas/PostSecurityReportsIdLinkFixRequest"
9835
+ }
9836
+ }
9837
+ },
9838
+ "x-validated": true
9839
+ },
9840
+ "responses": {
9841
+ "200": {
9842
+ "description": "Success.",
9843
+ "content": {
9844
+ "application/json": {
9845
+ "schema": {
9846
+ "$ref": "#/components/schemas/PostSecurityReportsIdLinkFixResponse"
9130
9847
  }
9131
9848
  }
9132
9849
  }
9133
9850
  },
9134
9851
  "400": {
9135
- "$ref": "#/components/responses/BadRequest"
9852
+ "$ref": "#/components/responses/ValidationFailed"
9136
9853
  },
9137
9854
  "401": {
9138
9855
  "$ref": "#/components/responses/Unauthorized"
@@ -9151,34 +9868,23 @@
9151
9868
  ]
9152
9869
  }
9153
9870
  },
9154
- "/security/reports/{id}/fix": {
9155
- "post": {
9156
- "operationId": "post_security_reports_id_fix",
9871
+ "/security/scans": {
9872
+ "get": {
9873
+ "operationId": "get_security_scans",
9157
9874
  "tags": [
9158
9875
  "security"
9159
9876
  ],
9160
- "summary": "POST /security/reports/:id/fix",
9161
- "description": "POST /api/bongos/security/reports/:id/fix Marks the report fixed and stamps fixed_at. Does not change fix_task_id — link that separately via /link-fix. rank: archon — fix-confirmation adjudication.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9162
- "x-rank": "archon",
9163
- "x-source": "modules/security/routes/reports.js",
9164
- "parameters": [
9165
- {
9166
- "name": "id",
9167
- "in": "path",
9168
- "required": true,
9169
- "schema": {
9170
- "type": "string"
9171
- },
9172
- "description": "Path parameter `id`."
9173
- }
9174
- ],
9877
+ "summary": "GET /security/scans",
9878
+ "description": "GET /api/bongos/security/scans?content_hash=<64 hex> \"Have these exact bytes been scanned before, and what did the scan say?\" Newest first. Rows carry structure only, so reading them can never expose the reader to the scanned artifact's content. rank: any-builder — deliberately open to every rank (see header).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9879
+ "x-rank": "any-builder",
9880
+ "x-source": "modules/security/routes/scans.js",
9175
9881
  "responses": {
9176
9882
  "200": {
9177
9883
  "description": "Success.",
9178
9884
  "content": {
9179
9885
  "application/json": {
9180
9886
  "schema": {
9181
- "$ref": "#/components/schemas/PostSecurityReportsIdFixResponse"
9887
+ "$ref": "#/components/schemas/GetSecurityScansResponse"
9182
9888
  }
9183
9889
  }
9184
9890
  }
@@ -9191,9 +9897,6 @@
9191
9897
  },
9192
9898
  "403": {
9193
9899
  "$ref": "#/components/responses/Forbidden"
9194
- },
9195
- "404": {
9196
- "$ref": "#/components/responses/NotFound"
9197
9900
  }
9198
9901
  },
9199
9902
  "security": [
@@ -9201,35 +9904,22 @@
9201
9904
  "builderSession": []
9202
9905
  }
9203
9906
  ]
9204
- }
9205
- },
9206
- "/security/reports/{id}/link-fix": {
9907
+ },
9207
9908
  "post": {
9208
- "operationId": "post_security_reports_id_link_fix",
9909
+ "operationId": "post_security_scans",
9209
9910
  "tags": [
9210
9911
  "security"
9211
9912
  ],
9212
- "summary": "POST /security/reports/:id/link-fix",
9213
- "description": "POST /api/bongos/security/reports/:id/link-fix Body: { task_id: integer } — attaches a fix-task FK. Doesn't change status (a confirmed report can have a linked fix-task while still open work). 422 if the referenced task doesn't exist. rank: archon — linking a report to its fix-task in the queue.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9214
- "x-rank": "archon",
9215
- "x-source": "modules/security/routes/reports.js",
9216
- "parameters": [
9217
- {
9218
- "name": "id",
9219
- "in": "path",
9220
- "required": true,
9221
- "schema": {
9222
- "type": "string"
9223
- },
9224
- "description": "Path parameter `id`."
9225
- }
9226
- ],
9913
+ "summary": "POST /security/scans",
9914
+ "description": "POST /api/bongos/security/scans — record one scan run. Body: structure only, never quoted target content — the deep checks (one-line claims, fence-marker rejection, scrubbing, verdict/completion coupling) live in scanStore.normalizeScanPayload; the schema here rejects unknown/typo'd top-level fields (strict default) and pins basic shapes. rank: metic+archon — a verdict-shaped write is a trust-shaped write.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
9915
+ "x-rank": "metic+archon",
9916
+ "x-source": "modules/security/routes/scans.js",
9227
9917
  "requestBody": {
9228
9918
  "required": true,
9229
9919
  "content": {
9230
9920
  "application/json": {
9231
9921
  "schema": {
9232
- "$ref": "#/components/schemas/PostSecurityReportsIdLinkFixRequest"
9922
+ "$ref": "#/components/schemas/PostSecurityScansRequest"
9233
9923
  }
9234
9924
  }
9235
9925
  },
@@ -9241,7 +9931,7 @@
9241
9931
  "content": {
9242
9932
  "application/json": {
9243
9933
  "schema": {
9244
- "$ref": "#/components/schemas/PostSecurityReportsIdLinkFixResponse"
9934
+ "$ref": "#/components/schemas/PostSecurityScansResponse"
9245
9935
  }
9246
9936
  }
9247
9937
  }
@@ -9254,9 +9944,6 @@
9254
9944
  },
9255
9945
  "403": {
9256
9946
  "$ref": "#/components/responses/Forbidden"
9257
- },
9258
- "404": {
9259
- "$ref": "#/components/responses/NotFound"
9260
9947
  }
9261
9948
  },
9262
9949
  "security": [
@@ -9402,9 +10089,12 @@
9402
10089
  "sessions"
9403
10090
  ],
9404
10091
  "summary": "GET /sessions/search",
9405
- "description": "cross-builder corpus search (BFG-principal posture until 6C.1).\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9406
- "x-rank": "archon",
10092
+ "description": "cross-builder corpus search (BFG-principal posture until 6C.1).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `session.search` (all required).",
10093
+ "x-rank": "metic+archon",
9407
10094
  "x-source": "modules/sessions/routes/sessions.js",
10095
+ "x-permissions": [
10096
+ "session.search"
10097
+ ],
9408
10098
  "responses": {
9409
10099
  "200": {
9410
10100
  "description": "Success.",
@@ -9758,9 +10448,12 @@
9758
10448
  "tasks"
9759
10449
  ],
9760
10450
  "summary": "POST /tasks",
9761
- "description": "Task create/promote/edit (plan/scope mutation) is Metic+ as of ADR 0090 (owner decision 2026-06-26): a Metic who can run idea-triage may also seed + shape tasks. Was Archon-only (task task 106 / ADR 0016; three-rank model task 360 / ADR 0018). A Xenos/Thetes still cannot author — they file ideas. Setting rank and closing versions stay Archon. The every-route audit is task task 231 (V3.R06). rank: metic+archon — create work (plan/scope mutation); ADR 0090 (was ADR 0016/0018 archon).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
10451
+ "description": "Task create/promote/edit (plan/scope mutation) is Metic+ as of ADR 0090 (owner decision 2026-06-26): a Metic who can run idea-triage may also seed + shape tasks. Was Archon-only (task task 106 / ADR 0016; three-rank model task 360 / ADR 0018). A Xenos/Thetes still cannot author — they file ideas. Setting rank and closing versions stay Archon. The every-route audit is task task 231 (V3.R06). rank: metic+archon — create work (plan/scope mutation); ADR 0090 (was ADR 0016/0018 archon).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.create` (all required).",
9762
10452
  "x-rank": "metic+archon",
9763
10453
  "x-source": "modules/lifecycle/routes/tasks.js",
10454
+ "x-permissions": [
10455
+ "task.create"
10456
+ ],
9764
10457
  "requestBody": {
9765
10458
  "required": true,
9766
10459
  "content": {
@@ -9876,9 +10569,12 @@
9876
10569
  "tasks"
9877
10570
  ],
9878
10571
  "summary": "POST /tasks/newcomer-restock",
9879
- "description": "POST /tasks/newcomer-restock (task 1168) — bring every evergreen newcomer chore's standing pool up to its configured floor. This is the SEED + manual BACKSTOP for the on-claim restock (the live mechanism is the post-claim hook in routes/claims.js). Archon-gated like all task creation (ADR 0016). Must be registered BEFORE GET /tasks/:id so ':id' doesn't swallow the literal.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9880
- "x-rank": "archon",
10572
+ "description": "POST /tasks/newcomer-restock (task 1168) — bring every evergreen newcomer chore's standing pool up to its configured floor. This is the SEED + manual BACKSTOP for the on-claim restock (the live mechanism is the post-claim hook in routes/claims.js). Archon-gated like all task creation (ADR 0016). Must be registered BEFORE GET /tasks/:id so ':id' doesn't swallow the literal.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.newcomer_restock` (all required).",
10573
+ "x-rank": "metic+archon",
9881
10574
  "x-source": "modules/lifecycle/routes/tasks.js",
10575
+ "x-permissions": [
10576
+ "task.newcomer_restock"
10577
+ ],
9882
10578
  "responses": {
9883
10579
  "200": {
9884
10580
  "description": "Success.",
@@ -9952,9 +10648,12 @@
9952
10648
  "tasks"
9953
10649
  ],
9954
10650
  "summary": "POST /tasks/peer-votes/tally",
9955
- "description": "POST /tasks/peer-votes/tally — fold matured votes (≥7 days old, not yet counted) into karma_log, one net row per shipping builder, then mark them tallied. Idempotent + transactional. Driven by the weekly cron (.claude/scheduled-tasks/peer-vote-tally/). Archon-gated — it writes karma. rank: archon — writes karma_log on others' behalf; scope-shaping reputation. The tally transaction lives in db.tallyPeerVotes() (task 1382, ADR 0078 amendment) so this route AND the server-internal weekly timer (the carved autonomy module's poller, modules/autonomy/pollers/routine-timers.js, which reaches it via the doorway api.tallyPeerVotes — BV1.R83) share one code path and can never diverge. This route keeps the Archon gate (the HTTP surface stays Archon-only); the in-process timer has no requester to authorize.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
9956
- "x-rank": "archon",
10651
+ "description": "POST /tasks/peer-votes/tally — fold matured votes (≥7 days old, not yet counted) into karma_log, one net row per shipping builder, then mark them tallied. Idempotent + transactional. Driven by the weekly cron (.claude/scheduled-tasks/peer-vote-tally/). Archon-gated — it writes karma. rank: archon — writes karma_log on others' behalf; scope-shaping reputation. The tally transaction lives in db.tallyPeerVotes() (task 1382, ADR 0078 amendment) so this route AND the server-internal weekly timer (the carved autonomy module's poller, modules/autonomy/pollers/routine-timers.js, which reaches it via the doorway api.tallyPeerVotes — BV1.R83) share one code path and can never diverge. This route keeps the Archon gate (the HTTP surface stays Archon-only); the in-process timer has no requester to authorize.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.peer_votes.tally` (all required).",
10652
+ "x-rank": "metic+archon",
9957
10653
  "x-source": "modules/lifecycle/routes/tasks.js",
10654
+ "x-permissions": [
10655
+ "task.peer_votes.tally"
10656
+ ],
9958
10657
  "responses": {
9959
10658
  "200": {
9960
10659
  "description": "Success."
@@ -10026,9 +10725,12 @@
10026
10725
  "tasks"
10027
10726
  ],
10028
10727
  "summary": "PATCH /tasks/:id",
10029
- "description": "PATCH /tasks/:id — supports body.parent_task_id (V2 C2), body.kind (V2 B1), body.discipline (mig 014), body.parallel_safe (mig 028), and body.newcomer_friendly (task 360 / ADR 0018 + V3.R15 task 239 — body.touches was removed in touches[] cleanup [4/8] (task 879) along with the drift scanner — open a task to the Xenos sandbox; alias body.xenos_claimable accepted for pre-rename callers). Pass parent_task_id: null to detach; parallel_safe accepts true|false|null; newcomer_friendly is a boolean. Validation lives in hierarchy.js for parent; the rest are validated inline. rank: metic+archon — edit work (incl. newcomer_friendly flag); ADR 0090 (was ADR 0016 archon).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
10728
+ "description": "PATCH /tasks/:id — supports body.parent_task_id (V2 C2), body.kind (V2 B1), body.discipline (mig 014), body.parallel_safe (mig 028), and body.newcomer_friendly (task 360 / ADR 0018 + V3.R15 task 239 — body.touches was removed in touches[] cleanup [4/8] (task 879) along with the drift scanner — open a task to the Xenos sandbox; alias body.xenos_claimable accepted for pre-rename callers). Pass parent_task_id: null to detach; parallel_safe accepts true|false|null; newcomer_friendly is a boolean. Validation lives in hierarchy.js for parent; the rest are validated inline. rank: metic+archon — edit work (incl. newcomer_friendly flag); ADR 0090 (was ADR 0016 archon).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.edit` (all required).",
10030
10729
  "x-rank": "metic+archon",
10031
10730
  "x-source": "modules/lifecycle/routes/tasks.js",
10731
+ "x-permissions": [
10732
+ "task.edit"
10733
+ ],
10032
10734
  "parameters": [
10033
10735
  {
10034
10736
  "name": "id",
@@ -10082,9 +10784,12 @@
10082
10784
  "tasks"
10083
10785
  ],
10084
10786
  "summary": "POST /tasks/:id/abandon",
10085
- "description": "POST /tasks/:id/abandon — terminal \"retire this task\" transition (task 987). The lifecycle had promote/ship/confirm/resolve but no first-class way to KILL a task that is no longer relevant: the only paths to status='abandoned' were offboarding a builder or a raw SQL UPDATE, so stale/moot tasks lingered in 'ready' as claimable noise. Refuses on a shipped task (immutable history) and on a task with an active claim (release it first); idempotent on an already- abandoned task. The abandon + its `reason` land in audit_log via the writing middleware, so the ledger keeps a record of who retired what. rank: metic+archon — scope removal; the inverse of /promote, and re-ranked to match it (ADR 0152, was archon under ADR 0090). A Metic who may author, shape, and promote work may also retire it: leaving the kill switch an Archon rung higher than the create switch only forced the owner to clean up after the triage they already delegated. Not one-way any more — /promote restores an abandoned task to backlog at the same rank — and the guards below (shipped refused, active claim refused) plus the audit_log entry are unchanged.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
10787
+ "description": "POST /tasks/:id/abandon — terminal \"retire this task\" transition (task 987). The lifecycle had promote/ship/confirm/resolve but no first-class way to KILL a task that is no longer relevant: the only paths to status='abandoned' were offboarding a builder or a raw SQL UPDATE, so stale/moot tasks lingered in 'ready' as claimable noise. Refuses on a shipped task (immutable history) and on a task with an active claim (release it first); idempotent on an already- abandoned task. The abandon + its `reason` land in audit_log via the writing middleware, so the ledger keeps a record of who retired what. rank: metic+archon — scope removal; the inverse of /promote, and re-ranked to match it (ADR 0152, was archon under ADR 0090). A Metic who may author, shape, and promote work may also retire it: leaving the kill switch an Archon rung higher than the create switch only forced the owner to clean up after the triage they already delegated. Not one-way any more — /promote restores an abandoned task to backlog at the same rank — and the guards below (shipped refused, active claim refused) plus the audit_log entry are unchanged.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.abandon` (all required).",
10086
10788
  "x-rank": "metic+archon",
10087
10789
  "x-source": "modules/lifecycle/routes/tasks.js",
10790
+ "x-permissions": [
10791
+ "task.abandon"
10792
+ ],
10088
10793
  "parameters": [
10089
10794
  {
10090
10795
  "name": "id",
@@ -10307,9 +11012,12 @@
10307
11012
  "tasks"
10308
11013
  ],
10309
11014
  "summary": "POST /tasks/:id/criteria",
10310
- "description": "POST /tasks/:id/criteria — body: { criterion_ids: [ref, ...] } OR { criterion_id: ref }. Metic+. rank: metic+archon — links a task it can author to a criterion; mirrors POST deps (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11015
+ "description": "POST /tasks/:id/criteria — body: { criterion_ids: [ref, ...] } OR { criterion_id: ref }. Metic+. rank: metic+archon — links a task it can author to a criterion; mirrors POST deps (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.criterion.manage` (all required).",
10311
11016
  "x-rank": "metic+archon",
10312
11017
  "x-source": "modules/lifecycle/routes/tasks.js",
11018
+ "x-permissions": [
11019
+ "task.criterion.manage"
11020
+ ],
10313
11021
  "parameters": [
10314
11022
  {
10315
11023
  "name": "id",
@@ -10370,9 +11078,12 @@
10370
11078
  "tasks"
10371
11079
  ],
10372
11080
  "summary": "DELETE /tasks/:id/criteria/:criterionId",
10373
- "description": "DELETE /tasks/:id/criteria/:criterionId — removes one link (criterionId is the numeric done_when_criteria.id, mirroring DELETE deps/:depId). rank: metic+archon — removes a criterion↔task edge; task-shaping, Metic+ (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11081
+ "description": "DELETE /tasks/:id/criteria/:criterionId — removes one link (criterionId is the numeric done_when_criteria.id, mirroring DELETE deps/:depId). rank: metic+archon — removes a criterion↔task edge; task-shaping, Metic+ (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.criterion.manage` (all required).",
10374
11082
  "x-rank": "metic+archon",
10375
11083
  "x-source": "modules/lifecycle/routes/tasks.js",
11084
+ "x-permissions": [
11085
+ "task.criterion.manage"
11086
+ ],
10376
11087
  "parameters": [
10377
11088
  {
10378
11089
  "name": "id",
@@ -10431,9 +11142,12 @@
10431
11142
  "tasks"
10432
11143
  ],
10433
11144
  "summary": "POST /tasks/:id/demote",
10434
- "description": "POST /tasks/:id/demote — the strict inverse of /promote: flip a task ready→backlog and nothing else. Use case (task 1223): a dependency-gated task that was wrongly promoted to ready needs to go back to backlog without hand-SQL on prod. Mirrors /promote's auth (Metic+ — scope mutation, ADR 0090). Strictly ready→backlog: refuse any other current status (blocked, active, or any later lifecycle state). A claimed task is `active`, so this gate also refuses demoting work that's already in flight — demote is not a way to yank a task out from under its claim holder. No reward side-effects (the reward gate is a promote-only concern; backlog is the pre-workable state). rank: metic+archon — ready→backlog demotion; scope mutation; mirrors /promote (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11145
+ "description": "POST /tasks/:id/demote — the strict inverse of /promote: flip a task ready→backlog and nothing else. Use case (task 1223): a dependency-gated task that was wrongly promoted to ready needs to go back to backlog without hand-SQL on prod. Mirrors /promote's auth (Metic+ — scope mutation, ADR 0090). Strictly ready→backlog: refuse any other current status (blocked, active, or any later lifecycle state). A claimed task is `active`, so this gate also refuses demoting work that's already in flight — demote is not a way to yank a task out from under its claim holder. No reward side-effects (the reward gate is a promote-only concern; backlog is the pre-workable state). rank: metic+archon — ready→backlog demotion; scope mutation; mirrors /promote (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.demote` (all required).",
10435
11146
  "x-rank": "metic+archon",
10436
11147
  "x-source": "modules/lifecycle/routes/tasks.js",
11148
+ "x-permissions": [
11149
+ "task.demote"
11150
+ ],
10437
11151
  "parameters": [
10438
11152
  {
10439
11153
  "name": "id",
@@ -10533,9 +11247,12 @@
10533
11247
  "tasks"
10534
11248
  ],
10535
11249
  "summary": "POST /tasks/:id/dependencies",
10536
- "description": "POST /tasks/:id/dependencies — body: { depends_on_task_id } OR { depends_on_task_ids: [N, ...] } Returns 409 with code='cycle' if accepting would create a cycle. rank: metic+archon — task-shaping; Metic may wire deps of a task it can author (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11250
+ "description": "POST /tasks/:id/dependencies — body: { depends_on_task_id } OR { depends_on_task_ids: [N, ...] } Returns 409 with code='cycle' if accepting would create a cycle. rank: metic+archon — task-shaping; Metic may wire deps of a task it can author (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.dependency.manage` (all required).",
10537
11251
  "x-rank": "metic+archon",
10538
11252
  "x-source": "modules/lifecycle/routes/tasks.js",
11253
+ "x-permissions": [
11254
+ "task.dependency.manage"
11255
+ ],
10539
11256
  "parameters": [
10540
11257
  {
10541
11258
  "name": "id",
@@ -10594,9 +11311,12 @@
10594
11311
  "tasks"
10595
11312
  ],
10596
11313
  "summary": "PUT /tasks/:id/dependencies",
10597
- "description": "PUT /tasks/:id/dependencies — replace the full dep set. body: { depends_on_task_ids: [N, ...] } rank: metic+archon — replaces the full dep set; task-shaping, Metic+ (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11314
+ "description": "PUT /tasks/:id/dependencies — replace the full dep set. body: { depends_on_task_ids: [N, ...] } rank: metic+archon — replaces the full dep set; task-shaping, Metic+ (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.dependency.manage` (all required).",
10598
11315
  "x-rank": "metic+archon",
10599
11316
  "x-source": "modules/lifecycle/routes/tasks.js",
11317
+ "x-permissions": [
11318
+ "task.dependency.manage"
11319
+ ],
10600
11320
  "parameters": [
10601
11321
  {
10602
11322
  "name": "id",
@@ -10657,9 +11377,12 @@
10657
11377
  "tasks"
10658
11378
  ],
10659
11379
  "summary": "DELETE /tasks/:id/dependencies/:depId",
10660
- "description": "DELETE /tasks/:id/dependencies/:depId — removes the edge. rank: metic+archon — removes a dep edge; task-shaping, Metic+ (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11380
+ "description": "DELETE /tasks/:id/dependencies/:depId — removes the edge. rank: metic+archon — removes a dep edge; task-shaping, Metic+ (ADR 0090).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.dependency.manage` (all required).",
10661
11381
  "x-rank": "metic+archon",
10662
11382
  "x-source": "modules/lifecycle/routes/tasks.js",
11383
+ "x-permissions": [
11384
+ "task.dependency.manage"
11385
+ ],
10663
11386
  "parameters": [
10664
11387
  {
10665
11388
  "name": "id",
@@ -10837,9 +11560,12 @@
10837
11560
  "tasks"
10838
11561
  ],
10839
11562
  "summary": "POST /tasks/:id/promote",
10840
- "description": "backlog→ready promotion; scope mutation; ADR 0090 (was archon). Also the UN-ABANDON path (ADR 0152): 'abandoned' → 'backlog'. When abandon moved down to Metic+ it needed an undo at the same rank, or a Metic's mis-retire would be unrecoverable without Archon SQL (no other route restores an abandoned task — PATCH refuses `status` outright). A restore lands in **backlog**, never straight to ready: the task was retired for a reason, so it re-enters as un-workable and takes a second, deliberate promote to become claimable again.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11563
+ "description": "backlog→ready promotion; scope mutation; ADR 0090 (was archon). Also the UN-ABANDON path (ADR 0152): 'abandoned' → 'backlog'. When abandon moved down to Metic+ it needed an undo at the same rank, or a Metic's mis-retire would be unrecoverable without Archon SQL (no other route restores an abandoned task — PATCH refuses `status` outright). A restore lands in **backlog**, never straight to ready: the task was retired for a reason, so it re-enters as un-workable and takes a second, deliberate promote to become claimable again.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.promote` (all required).",
10841
11564
  "x-rank": "metic+archon",
10842
11565
  "x-source": "modules/lifecycle/routes/tasks.js",
11566
+ "x-permissions": [
11567
+ "task.promote"
11568
+ ],
10843
11569
  "parameters": [
10844
11570
  {
10845
11571
  "name": "id",
@@ -11042,9 +11768,12 @@
11042
11768
  "tasks"
11043
11769
  ],
11044
11770
  "summary": "POST /tasks/:id/vote",
11045
- "description": "POST /tasks/:id/vote { vote: 1 | -1 | 0 } — cast/change/clear a peer vote on a confirmed/shipped task. Metic+ only (Xenos read-only on the project). - 403 anti-self-vote if the caller shipped the task - 409 if the task isn't votable, or the vote was already folded into karma - vote: 0 clears (deletes the row, only while still untallied) rank: metic+archon — a trusted-builder reputation action.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
11771
+ "description": "POST /tasks/:id/vote { vote: 1 | -1 | 0 } — cast/change/clear a peer vote on a confirmed/shipped task. Metic+ only (Xenos read-only on the project). - 403 anti-self-vote if the caller shipped the task - 409 if the task isn't votable, or the vote was already folded into karma - vote: 0 clears (deletes the row, only while still untallied) rank: metic+archon — a trusted-builder reputation action.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `task.vote` (all required).",
11046
11772
  "x-rank": "metic+archon",
11047
11773
  "x-source": "modules/lifecycle/routes/tasks.js",
11774
+ "x-permissions": [
11775
+ "task.vote"
11776
+ ],
11048
11777
  "parameters": [
11049
11778
  {
11050
11779
  "name": "id",
@@ -11131,9 +11860,12 @@
11131
11860
  "versions"
11132
11861
  ],
11133
11862
  "summary": "POST /versions",
11134
- "description": "POST /versions — create a version + its done-when criteria in one call. The seed primitive `bongos init` (task 1204 / R65) uses so a fresh instance needs no hand-written seed-*.js script. Archon-only: creating a version is a plan/scope mutation, same gate as POST /tasks (ADR 0016). rank: archon — creates a version + its done-when criteria.\n\n**Rank:** `archon` — Archon only (the single owner — ratification, infra, rank changes).",
11135
- "x-rank": "archon",
11863
+ "description": "POST /versions — create a version + its done-when criteria in one call. The seed primitive `bongos init` (task 1204 / R65) uses so a fresh instance needs no hand-written seed-*.js script. Archon-only: creating a version is a plan/scope mutation, same gate as POST /tasks (ADR 0016). rank: archon — creates a version + its done-when criteria.\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `version.create` (all required).",
11864
+ "x-rank": "metic+archon",
11136
11865
  "x-source": "modules/lifecycle/routes/versions.js",
11866
+ "x-permissions": [
11867
+ "version.create"
11868
+ ],
11137
11869
  "requestBody": {
11138
11870
  "required": true,
11139
11871
  "content": {
@@ -11276,9 +12008,12 @@
11276
12008
  "versions"
11277
12009
  ],
11278
12010
  "summary": "POST /versions/:id/done-when",
11279
- "description": "Auth (Metic+, then the goal's own authority): create a done-when criterion at RUNTIME. ADR 0105 moved scope-truth seeds (versions/goals/criteria) out of the normal migration path, so a brand-new criterion on a RUNNING instance can no longer be added by a plain migration (migrations/instance/ applies only under the owner opt-in GDS_APPLY_INSTANCE_SEEDS=1, a DR step). This is the vector a planning session uses to add a criterion to a live version WITHOUT a droplet migrate. ADR 0154 — authority over a GOAL's criteria follows GOAL OWNERSHIP, not global rank. A Metic who may create the goal (POST /goals) and author the tasks under it (POST /tasks, ADR 0090) may now write the criteria those tasks gate — but only inside a goal they own or manage. Deliberately NOT a flat re-rank: - An unsatisfied criterion permanently blocks version close (version-close.js counts satisfied === total per VERSION, regardless of goal) and goal auto-achieve (db.achieveGoalIfComplete). There is NO delete route, so it cannot be undone via the API — the same backward ratchet as unsatisfy, which stays Archon. - So a non-Archon must name a goal_id (version-level criteria stay Archon), must be that goal's OWNER or MANAGER (isGoalOwnerOrManager — the same predicate behind visibility/invite/role management), and the goal must be open on a planning/building version. That bounds the blast radius to a workspace they already hold. An unauthorized caller is masked behind bad_goal_id so the route is not an existence oracle (ADR 0112). Pinned in route-rank-check.MODULE_EXPECTED_RANKS. rank: metic+archon — criterion create, walled by goal ownership (ADR 0154).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).",
12011
+ "description": "Auth (Metic+, then the goal's own authority): create a done-when criterion at RUNTIME. ADR 0105 moved scope-truth seeds (versions/goals/criteria) out of the normal migration path, so a brand-new criterion on a RUNNING instance can no longer be added by a plain migration (migrations/instance/ applies only under the owner opt-in GDS_APPLY_INSTANCE_SEEDS=1, a DR step). This is the vector a planning session uses to add a criterion to a live version WITHOUT a droplet migrate. ADR 0154 — authority over a GOAL's criteria follows GOAL OWNERSHIP, not global rank. A Metic who may create the goal (POST /goals) and author the tasks under it (POST /tasks, ADR 0090) may now write the criteria those tasks gate — but only inside a goal they own or manage. Deliberately NOT a flat re-rank: - An unsatisfied criterion permanently blocks version close (version-close.js counts satisfied === total per VERSION, regardless of goal) and goal auto-achieve (db.achieveGoalIfComplete). There is NO delete route, so it cannot be undone via the API — the same backward ratchet as unsatisfy, which stays Archon. - So a non-Archon must name a goal_id (version-level criteria stay Archon), must be that goal's OWNER or MANAGER (isGoalOwnerOrManager — the same predicate behind visibility/invite/role management), and the goal must be open on a planning/building version. That bounds the blast radius to a workspace they already hold. An unauthorized caller is masked behind bad_goal_id so the route is not an existence oracle (ADR 0112). Pinned in route-rank-check.MODULE_EXPECTED_RANKS. rank: metic+archon — criterion create, walled by goal ownership (ADR 0154).\n\n**Rank:** `metic+archon` — Metic or Archon rank (review/triage powers).\n\n**Permissions:** `criterion.create` (all required).",
11280
12012
  "x-rank": "metic+archon",
11281
12013
  "x-source": "modules/lifecycle/routes/done-when.js",
12014
+ "x-permissions": [
12015
+ "criterion.create"
12016
+ ],
11282
12017
  "parameters": [
11283
12018
  {
11284
12019
  "name": "id",
@@ -11423,6 +12158,40 @@
11423
12158
  "ok"
11424
12159
  ]
11425
12160
  },
12161
+ "DeleteGovernanceAssignmentsBuilderIdRoleKeyResponse": {
12162
+ "type": "object",
12163
+ "properties": {
12164
+ "ok": {
12165
+ "type": "boolean"
12166
+ },
12167
+ "builder_id": {},
12168
+ "role_key": {},
12169
+ "removed": {}
12170
+ },
12171
+ "required": [
12172
+ "ok",
12173
+ "builder_id",
12174
+ "role_key",
12175
+ "removed"
12176
+ ]
12177
+ },
12178
+ "DeleteGovernanceRolesRoleKeyPermissionsPermissionKeyResponse": {
12179
+ "type": "object",
12180
+ "properties": {
12181
+ "ok": {
12182
+ "type": "boolean"
12183
+ },
12184
+ "role_key": {},
12185
+ "permission_key": {},
12186
+ "removed": {}
12187
+ },
12188
+ "required": [
12189
+ "ok",
12190
+ "role_key",
12191
+ "permission_key",
12192
+ "removed"
12193
+ ]
12194
+ },
11426
12195
  "DeleteMemoryFileResponse": {
11427
12196
  "type": "object",
11428
12197
  "properties": {
@@ -11829,6 +12598,35 @@
11829
12598
  "goals"
11830
12599
  ]
11831
12600
  },
12601
+ "GetGovernanceAssignmentsResponse": {
12602
+ "type": "object",
12603
+ "properties": {
12604
+ "assignments": {}
12605
+ },
12606
+ "required": [
12607
+ "assignments"
12608
+ ]
12609
+ },
12610
+ "GetGovernancePermissionsResponse": {
12611
+ "type": "object",
12612
+ "properties": {
12613
+ "permissions": {},
12614
+ "principals": {}
12615
+ },
12616
+ "required": [
12617
+ "permissions",
12618
+ "principals"
12619
+ ]
12620
+ },
12621
+ "GetGovernanceRolesResponse": {
12622
+ "type": "object",
12623
+ "properties": {
12624
+ "roles": {}
12625
+ },
12626
+ "required": [
12627
+ "roles"
12628
+ ]
12629
+ },
11832
12630
  "GetGradesByBuilderResponse": {
11833
12631
  "type": "object",
11834
12632
  "properties": {
@@ -12437,6 +13235,15 @@
12437
13235
  "statuses"
12438
13236
  ]
12439
13237
  },
13238
+ "GetSecurityScansResponse": {
13239
+ "type": "object",
13240
+ "properties": {
13241
+ "scans": {}
13242
+ },
13243
+ "required": [
13244
+ "scans"
13245
+ ]
13246
+ },
12440
13247
  "GetSessionsIdResponse": {
12441
13248
  "type": "object",
12442
13249
  "properties": {
@@ -13272,10 +14079,12 @@
13272
14079
  "properties": {
13273
14080
  "ok": {
13274
14081
  "type": "boolean"
13275
- }
14082
+ },
14083
+ "blocked": {}
13276
14084
  },
13277
14085
  "required": [
13278
- "ok"
14086
+ "ok",
14087
+ "blocked"
13279
14088
  ]
13280
14089
  },
13281
14090
  "PostBlockersIdResolveRequest": {
@@ -14326,6 +15135,58 @@
14326
15135
  "succeeds_goal_id"
14327
15136
  ]
14328
15137
  },
15138
+ "PostGovernanceAssignmentsRequest": {
15139
+ "type": "object",
15140
+ "properties": {
15141
+ "builder_id": {
15142
+ "type": "integer",
15143
+ "minimum": 1
15144
+ },
15145
+ "role_key": {
15146
+ "type": "string",
15147
+ "minLength": 2,
15148
+ "maxLength": 64
15149
+ }
15150
+ },
15151
+ "required": [
15152
+ "builder_id",
15153
+ "role_key"
15154
+ ],
15155
+ "additionalProperties": false
15156
+ },
15157
+ "PostGovernanceRolesRequest": {
15158
+ "type": "object",
15159
+ "properties": {
15160
+ "role_key": {
15161
+ "type": "string",
15162
+ "minLength": 2,
15163
+ "maxLength": 64
15164
+ },
15165
+ "label": {
15166
+ "type": "string",
15167
+ "minLength": 1,
15168
+ "maxLength": 200
15169
+ },
15170
+ "description": {
15171
+ "type": "string",
15172
+ "maxLength": 2000
15173
+ }
15174
+ },
15175
+ "required": [
15176
+ "role_key",
15177
+ "label"
15178
+ ],
15179
+ "additionalProperties": false
15180
+ },
15181
+ "PostGovernanceRolesResponse": {
15182
+ "type": "object",
15183
+ "properties": {
15184
+ "role": {}
15185
+ },
15186
+ "required": [
15187
+ "role"
15188
+ ]
15189
+ },
14329
15190
  "PostInboxIdRatifyRequest": {
14330
15191
  "type": "object",
14331
15192
  "properties": {
@@ -14851,6 +15712,10 @@
14851
15712
  "tier": {
14852
15713
  "type": "string",
14853
15714
  "maxLength": 40
15715
+ },
15716
+ "onboard_mode": {
15717
+ "type": "string",
15718
+ "maxLength": 20
14854
15719
  }
14855
15720
  },
14856
15721
  "required": [
@@ -15035,6 +15900,96 @@
15035
15900
  "bounty_table"
15036
15901
  ]
15037
15902
  },
15903
+ "PostSecurityScansRequest": {
15904
+ "type": "object",
15905
+ "properties": {
15906
+ "target_url": {
15907
+ "type": "string",
15908
+ "minLength": 9,
15909
+ "maxLength": 2048
15910
+ },
15911
+ "artifact_kind": {
15912
+ "type": "string"
15913
+ },
15914
+ "resolved_sha": {
15915
+ "type": "string",
15916
+ "maxLength": 40
15917
+ },
15918
+ "content_hash": {
15919
+ "type": "string",
15920
+ "maxLength": 64
15921
+ },
15922
+ "file_count": {
15923
+ "type": "integer",
15924
+ "minimum": 0
15925
+ },
15926
+ "total_bytes": {
15927
+ "type": "integer",
15928
+ "minimum": 0
15929
+ },
15930
+ "tier": {
15931
+ "type": "string"
15932
+ },
15933
+ "verdict": {
15934
+ "type": "string"
15935
+ },
15936
+ "completion": {
15937
+ "type": "string"
15938
+ },
15939
+ "abort_code": {
15940
+ "type": "string",
15941
+ "maxLength": 64
15942
+ },
15943
+ "findings_critical": {
15944
+ "type": "integer",
15945
+ "minimum": 0
15946
+ },
15947
+ "findings_high": {
15948
+ "type": "integer",
15949
+ "minimum": 0
15950
+ },
15951
+ "findings_medium": {
15952
+ "type": "integer",
15953
+ "minimum": 0
15954
+ },
15955
+ "findings_low": {
15956
+ "type": "integer",
15957
+ "minimum": 0
15958
+ },
15959
+ "findings_summary": {
15960
+ "type": "array"
15961
+ },
15962
+ "action_taken": {
15963
+ "type": "string"
15964
+ },
15965
+ "engine_version": {
15966
+ "type": "string",
15967
+ "minLength": 1,
15968
+ "maxLength": 64
15969
+ }
15970
+ },
15971
+ "required": [
15972
+ "target_url",
15973
+ "artifact_kind",
15974
+ "tier",
15975
+ "completion",
15976
+ "engine_version"
15977
+ ],
15978
+ "additionalProperties": false
15979
+ },
15980
+ "PostSecurityScansResponse": {
15981
+ "type": "object",
15982
+ "properties": {
15983
+ "ok": {
15984
+ "type": "boolean"
15985
+ },
15986
+ "scan": {}
15987
+ },
15988
+ "required": [
15989
+ "ok",
15990
+ "scan"
15991
+ ]
15992
+ },
15038
15993
  "PostSessionOptimizeRequest": {
15039
15994
  "type": "object",
15040
15995
  "properties": {
@@ -15703,6 +16658,10 @@
15703
16658
  "type": "string",
15704
16659
  "maxLength": 32
15705
16660
  },
16661
+ "track": {
16662
+ "type": "string",
16663
+ "maxLength": 16
16664
+ },
15706
16665
  "done_when": {
15707
16666
  "type": "string",
15708
16667
  "maxLength": 8000
@@ -15733,6 +16692,23 @@
15733
16692
  "criteria"
15734
16693
  ]
15735
16694
  },
16695
+ "PutGovernanceRolesRoleKeyPermissionsPermissionKeyResponse": {
16696
+ "type": "object",
16697
+ "properties": {
16698
+ "ok": {
16699
+ "type": "boolean"
16700
+ },
16701
+ "role_key": {},
16702
+ "permission_key": {},
16703
+ "granted": {}
16704
+ },
16705
+ "required": [
16706
+ "ok",
16707
+ "role_key",
16708
+ "permission_key",
16709
+ "granted"
16710
+ ]
16711
+ },
15736
16712
  "PutTasksIdDependenciesRequest": {
15737
16713
  "type": "object",
15738
16714
  "properties": {
@@ -15884,9 +16860,9 @@
15884
16860
  "description": "A required dependency/feature is not configured or is temporarily down."
15885
16861
  }
15886
16862
  },
15887
- "x-endpoint-count": 258,
15888
- "x-schema-count": 288,
16863
+ "x-endpoint-count": 268,
16864
+ "x-schema-count": 300,
15889
16865
  "x-undocumented-bodies": 8,
15890
- "x-response-schemas": 194,
16866
+ "x-response-schemas": 203,
15891
16867
  "x-generated-by": "scripts/gds/gen-api-docs.js"
15892
16868
  }