@bongos/core 1.19.1081 → 1.20.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 (253) hide show
  1. package/.bongos-core.json +528 -193
  2. package/.claude/skills/planning-session/SKILL.md +6 -2
  3. package/clients/bongos-client/README.md +1 -1
  4. package/clients/bongos-client/bongos-client.global.js +32 -0
  5. package/clients/bongos-client/index.cjs +32 -0
  6. package/clients/bongos-client/index.d.ts +51 -6
  7. package/clients/bongos-client/index.mjs +32 -0
  8. package/docs/adr/0099-delayed-redacted-mirror-export.md +5 -1
  9. package/docs/adr/0111-instance-hosting-provisioning-module.md +1 -0
  10. package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +17 -0
  11. package/docs/adr/0176-private-repo-deploy-keys.md +2 -0
  12. package/docs/adr/0310-a-speciality-offers-skills-and-the-adopter-chooses-them.md +1 -1
  13. package/docs/adr/0348-the-web-tier-may-look-read-only-at-what-an-owners-render-key-can-see.md +53 -0
  14. package/docs/adr/0349-a-version-preview-is-a-sandboxed-child-the-web-tier-launches.md +106 -0
  15. package/docs/adr/0350-the-hub-holds-a-per-project-write-deploy-key-so-a-hosted-upgrade-reaches-github.md +103 -0
  16. package/docs/adr/README.md +3 -0
  17. package/docs/api/openapi.json +851 -19
  18. package/docs/api-reference.md +33 -9
  19. package/docs/architecture.md +6 -2
  20. package/docs/copy-inventory.md +620 -553
  21. package/docs/copy-registry.json +1467 -820
  22. package/docs/file-map.md +2 -0
  23. package/docs/module-api-changelog.md +8 -0
  24. package/docs/modules-contract.md +1 -0
  25. package/docs/page-inventory.json +38 -4
  26. package/docs/page-readings.json +1666 -1558
  27. package/migrations/core_260_goals_working_area.sql +63 -0
  28. package/migrations/core_261_grade_attempts_verdicts.sql +24 -0
  29. package/migrations/core_262_drop_builder_box_blocked.sql +33 -0
  30. package/modules/agents/lib/validate.js +43 -0
  31. package/modules/autonomy/gauge.js +38 -2
  32. package/modules/grading/grader-subagent.js +37 -2
  33. package/modules/grading/grader-workers/reader.js +65 -5
  34. package/modules/hall-ui/public/approval-queue.css +33 -7
  35. package/modules/hall-ui/public/approval-queue.js +9 -2
  36. package/modules/hall-ui/public/atlas.html +1 -1
  37. package/modules/hall-ui/public/blockers.html +1 -1
  38. package/modules/hall-ui/public/board-room.html +1 -1
  39. package/modules/hall-ui/public/brand-holes.js +121 -0
  40. package/modules/hall-ui/public/collab.html +1 -1
  41. package/modules/hall-ui/public/collab.js +1 -1
  42. package/modules/hall-ui/public/copy-desk.html +1 -1
  43. package/modules/hall-ui/public/deploy.html +6 -1
  44. package/modules/hall-ui/public/deploy.js +22 -8
  45. package/modules/hall-ui/public/diagrams.html +1 -1
  46. package/modules/hall-ui/public/dom-utils.js +20 -0
  47. package/modules/hall-ui/public/drachmae.html +1 -1
  48. package/modules/hall-ui/public/fleet.html +1 -1
  49. package/modules/hall-ui/public/gate.html +1 -1
  50. package/modules/hall-ui/public/goal-inbox.js +1 -1
  51. package/modules/hall-ui/public/goals.html +1 -1
  52. package/modules/hall-ui/public/government.html +1 -1
  53. package/modules/hall-ui/public/idea.html +1 -1
  54. package/modules/hall-ui/public/idea.js +28 -0
  55. package/modules/hall-ui/public/ideas.html +1 -1
  56. package/modules/hall-ui/public/ideas.js +19 -3
  57. package/modules/hall-ui/public/index.html +5 -1
  58. package/modules/hall-ui/public/modules.html +1 -1
  59. package/modules/hall-ui/public/primer.html +1 -1
  60. package/modules/hall-ui/public/profile-nudge.js +21 -4
  61. package/modules/hall-ui/public/profile.html +1 -1
  62. package/modules/hall-ui/public/profile.js +1 -1
  63. package/modules/hall-ui/public/project-settings.html +1 -1
  64. package/modules/hall-ui/public/ranks.html +1 -1
  65. package/modules/hall-ui/public/roadmap.html +1 -1
  66. package/modules/hall-ui/public/roster.html +1 -1
  67. package/modules/hall-ui/public/sessions.html +1 -1
  68. package/modules/hall-ui/public/settings.html +19 -30
  69. package/modules/hall-ui/public/settings.js +24 -177
  70. package/modules/hall-ui/public/settings.states.json +1 -1
  71. package/modules/hall-ui/public/shell.js +4 -2
  72. package/modules/hall-ui/public/studio.css +14 -8
  73. package/modules/hall-ui/public/studio.html +5 -4
  74. package/modules/hall-ui/public/task.html +1 -1
  75. package/modules/hall-ui/public/thinking.css +6 -3
  76. package/modules/hall-ui/public/thinking.html +1 -1
  77. package/modules/hall-ui/public/tweak-editor-lib.js +82 -1
  78. package/modules/hall-ui/public/tweak-editor.css +142 -11
  79. package/modules/hall-ui/public/tweak-editor.html +25 -9
  80. package/modules/hall-ui/public/tweak-editor.js +243 -10
  81. package/modules/hall-ui/public/watch.html +1 -1
  82. package/modules/hall-ui/public/work.html +1 -1
  83. package/modules/hall-ui/records/approval-queue.md +6 -0
  84. package/modules/hall-ui/records/tweak-editor.md +6 -0
  85. package/modules/ideas/ratify.js +36 -8
  86. package/modules/ideas/routes/ratify-goal.js +6 -0
  87. package/modules/lifecycle/db-analytics.js +79 -10
  88. package/modules/lifecycle/db-claims.js +48 -1
  89. package/modules/lifecycle/db-deps-criteria.js +94 -40
  90. package/modules/lifecycle/db-goals.js +4 -1
  91. package/modules/lifecycle/db-grade.js +9 -1
  92. package/modules/lifecycle/db-relevance-flags.js +183 -0
  93. package/modules/lifecycle/db-versions.js +4 -3
  94. package/modules/lifecycle/db.js +19 -0
  95. package/modules/lifecycle/done-when.js +5 -3
  96. package/modules/lifecycle/est-advisory.js +31 -4
  97. package/modules/lifecycle/goal-task-relevance-advisory.js +153 -0
  98. package/modules/lifecycle/goal-task-relevance-judge.js +226 -0
  99. package/modules/lifecycle/migrations/lifecycle_014_goal_task_relevance_flags.sql +82 -0
  100. package/modules/lifecycle/module.json +2 -1
  101. package/modules/lifecycle/routes/claims.js +8 -1
  102. package/modules/lifecycle/routes/goal-task-relevance.js +72 -0
  103. package/modules/lifecycle/routes/goals.js +1 -1
  104. package/modules/lifecycle/routes/tasks.js +27 -24
  105. package/modules/lifecycle/routes/visuals.js +9 -0
  106. package/modules/lifecycle/ship-preflight.js +7 -11
  107. package/modules/lifecycle/task-visuals.js +109 -5
  108. package/modules/npm-release/module.json +2 -1
  109. package/modules/npm-release/preview/commands.js +81 -0
  110. package/modules/npm-release/preview/divert.js +95 -0
  111. package/modules/npm-release/preview/env.js +78 -0
  112. package/modules/npm-release/preview/proxy.js +107 -0
  113. package/modules/npm-release/preview/runtime.js +83 -0
  114. package/modules/npm-release/preview/supervisor.js +175 -0
  115. package/modules/npm-release/public/work.js +65 -1
  116. package/modules/npm-release/routes/preview.js +133 -0
  117. package/modules/provisioning/app-status.js +83 -0
  118. package/modules/provisioning/module.json +2 -1
  119. package/modules/provisioning/pollers/app-liveness.js +110 -0
  120. package/modules/provisioning/render-lookup.js +68 -0
  121. package/modules/provisioning/render-standup.js +44 -1
  122. package/modules/provisioning/routes/render-standup.js +81 -6
  123. package/modules/provisioning/starter-bundles.js +4 -1
  124. package/modules/public-landing/public/account-private.states.json +14 -0
  125. package/modules/public-landing/public/account.html +513 -0
  126. package/modules/public-landing/public/account.probes.json +37 -0
  127. package/modules/public-landing/public/account.states.json +16 -0
  128. package/modules/public-landing/public/index.html +5 -2
  129. package/modules/public-landing/public/projects.html +661 -18
  130. package/modules/public-landing/public/projects.states.json +8 -1
  131. package/modules/render-deploy/deploys.js +203 -0
  132. package/modules/render-deploy/migrations/render_deploy_001_app.sql +22 -0
  133. package/modules/render-deploy/module.json +25 -0
  134. package/modules/render-deploy/public/deploy.css +10 -0
  135. package/modules/render-deploy/public/deploy.js +249 -0
  136. package/modules/render-deploy/render.js +56 -0
  137. package/modules/render-deploy/routes/act.js +88 -0
  138. package/modules/render-deploy/routes/app.js +65 -0
  139. package/modules/render-deploy/routes/history.js +38 -0
  140. package/modules/specialities/db.js +27 -8
  141. package/modules/specialities/migrations/specialities_003_skills.sql +46 -0
  142. package/modules/specialities/routes/specialities.js +51 -3
  143. package/modules/specialities/skills.js +94 -0
  144. package/modules/specialities/specialities.js +56 -9
  145. package/modules/ui-design/kit/fixtures/me-cross-project-private.json +12 -0
  146. package/modules/ui-design/kit/fixtures/me__cross-project.json +15 -0
  147. package/modules/ui-design/kit/fixtures/provisioning-instance-render.json +39 -0
  148. package/modules/ui-design/kit/lib.js +3 -1
  149. package/modules/ui-design/kit/serve.js +96 -0
  150. package/package-lock.json +2 -2
  151. package/package.json +1 -1
  152. package/release-notes.json +169 -0
  153. package/scripts/gds/agents-sync.js +13 -3
  154. package/scripts/gds/autobongos-run.js +80 -2
  155. package/scripts/gds/autobongos-service.cmd +12 -0
  156. package/scripts/gds/copy-apply.js +14 -0
  157. package/scripts/gds/dev-box-guard.js +3 -2
  158. package/scripts/gds/fitness.js +9 -0
  159. package/scripts/gds/grade-correlation-audit.js +42 -12
  160. package/scripts/gds/grade-replay.js +1 -1
  161. package/scripts/gds/provision-core-upgrade.js +38 -7
  162. package/scripts/gds/provision-pin-key.js +176 -0
  163. package/scripts/gds/provision-render.js +62 -31
  164. package/scripts/gds/provision-teardown.js +7 -2
  165. package/scripts/gds/provision-units.js +31 -0
  166. package/scripts/gds/provision.js +10 -10
  167. package/scripts/gds/publish-manifest.js +1 -0
  168. package/scripts/gds/render-api.js +19 -0
  169. package/scripts/gds/render-payload.js +39 -65
  170. package/scripts/gds/run-unit-tests.js +10 -0
  171. package/scripts/gds/ship-finish.js +19 -20
  172. package/scripts/gds/smoke-dependencies.sh +37 -8
  173. package/scripts/gds/status.js +12 -4
  174. package/scripts/gds/upgrade.js +2 -2
  175. package/scripts/public-mirror-export.js +7 -1
  176. package/src/bongos/module-scope-map.js +13 -0
  177. package/src/bongos/serve-internal.js +3 -1
  178. package/src/module-api.js +10 -1
  179. package/src/platform-server.js +39 -0
  180. package/tests/account_privacy_flags.mjs +10 -6
  181. package/tests/agents_authoring.mjs +15 -1
  182. package/tests/agents_sync.mjs +106 -5
  183. package/tests/agents_validate.mjs +45 -0
  184. package/tests/api_path_404.mjs +6 -0
  185. package/tests/autobongos_cadence.mjs +7 -0
  186. package/tests/autobongos_loop.mjs +136 -1
  187. package/tests/autonomy_gauge.mjs +62 -0
  188. package/tests/blocker_hall_live_proof.mjs +275 -0
  189. package/tests/claim_gate_ci_unblock.mjs +116 -0
  190. package/tests/claim_gate_rebase.mjs +15 -3
  191. package/tests/collab_page.mjs +10 -0
  192. package/tests/conductor_main_e2e.mjs +97 -0
  193. package/tests/core_262_drop_box_blocked_db.mjs +143 -0
  194. package/tests/core_upgrade_runner.mjs +1 -0
  195. package/tests/dependency_writes_atomic.mjs +191 -0
  196. package/tests/deploy_page_projects.mjs +2 -1
  197. package/tests/effective_visibility_predicate.mjs +15 -0
  198. package/tests/est_advisory.mjs +27 -0
  199. package/tests/goal_map_page.mjs +26 -0
  200. package/tests/goal_task_relevance.mjs +518 -0
  201. package/tests/goal_working_area.mjs +146 -0
  202. package/tests/grade_attempts.mjs +61 -0
  203. package/tests/grade_attribution.mjs +23 -0
  204. package/tests/grade_correlation_audit.mjs +54 -1
  205. package/tests/grader_reader_lens.mjs +55 -2
  206. package/tests/grader_root_outage.mjs +6 -1
  207. package/tests/grader_subagent_tools_arg.mjs +102 -0
  208. package/tests/hall_approval_queue.mjs +54 -2
  209. package/tests/hall_settings_world.mjs +3 -1
  210. package/tests/hall_tweak_editor.mjs +316 -11
  211. package/tests/hub_account_page.mjs +394 -0
  212. package/tests/idea_detail_page.mjs +64 -0
  213. package/tests/idea_goal_ratification.mjs +64 -0
  214. package/tests/idea_spark_hall.mjs +60 -9
  215. package/tests/ideator_full_idea_shapes_space_proof.mjs +1 -1
  216. package/tests/landing_page.mjs +6 -3
  217. package/tests/module-scope-map.mjs +31 -8
  218. package/tests/module_api.mjs +1 -0
  219. package/tests/module_loader.mjs +1 -1
  220. package/tests/nav_permission_atoms.mjs +1 -1
  221. package/tests/no_phantom_mirror_workflow.mjs +24 -0
  222. package/tests/npm_release_preview_commands.mjs +89 -0
  223. package/tests/npm_release_preview_divert.mjs +164 -0
  224. package/tests/npm_release_preview_env.mjs +100 -0
  225. package/tests/npm_release_preview_proxy.mjs +162 -0
  226. package/tests/npm_release_preview_routes.mjs +208 -0
  227. package/tests/npm_release_preview_supervisor.mjs +203 -0
  228. package/tests/pin_write_key.mjs +383 -0
  229. package/tests/planning_session_skill.mjs +27 -0
  230. package/tests/platform_boot.mjs +71 -0
  231. package/tests/profile_nudge_links.mjs +86 -0
  232. package/tests/profile_ui_cross_project.mjs +1 -1
  233. package/tests/projects_hub.mjs +2 -2
  234. package/tests/projects_hub_app_status.mjs +249 -0
  235. package/tests/projects_hub_app_step.mjs +282 -52
  236. package/tests/projects_hub_render_connect.mjs +295 -0
  237. package/tests/provision_render.mjs +121 -28
  238. package/tests/provision_settings_apply.mjs +62 -0
  239. package/tests/provisioning_app_status.mjs +204 -0
  240. package/tests/provisioning_render_route.mjs +126 -6
  241. package/tests/render_check.mjs +2 -1
  242. package/tests/render_deploy.mjs +495 -0
  243. package/tests/rot_inbox.mjs +8 -0
  244. package/tests/ship_preflight.mjs +61 -8
  245. package/tests/smoke_dependencies_witness.mjs +46 -0
  246. package/tests/speciality_skills.mjs +214 -0
  247. package/tests/studio_room_height.mjs +70 -0
  248. package/tests/task_detail_includes.mjs +10 -0
  249. package/tests/task_visuals_instance_root.mjs +150 -0
  250. package/tests/tweak_batch_apply.mjs +21 -0
  251. package/tests/ui_design_kit.mjs +36 -4
  252. package/tests/upgrade.mjs +1 -1
  253. package/tests/upgrade_persist_pin.mjs +24 -0
@@ -33,7 +33,7 @@ This mirrors GDS-V3 criterion C2 (`three-ranks-gate-everything`) and matches the
33
33
 
34
34
  **Enforce the gate at the very top of the session, before reading anything else:**
35
35
 
36
- 1. Call `GET /api/bongos/me` and read `builder.rank`. Compare case-insensitively (lowercase it before testing).
36
+ 1. Call `GET /api/bongos/me` and read `builder.rank`. Compare case-insensitively (lowercase it before testing). **If it answers `401`, or the CLI says the Bongos CLI session is no longer valid**, stop before anything else and tell the builder to run `/builder-reauth` (the fast Settings re-issue), then re-run this skill — there is nothing to lose yet. (A session that is valid here can still expire before Phase 5, which is why Phase 4 spools and Phase 5 probes again; task 1002865.)
37
37
  2. **If `rank` is present and lowercases to `xenos`** → stop immediately. Tell the builder: *"Planning sessions set the scope-truth of a version — they're a Metic+ operation. You're currently Xenos. You can still **file** a criterion proposal or task idea via `POST /api/bongos/inbox` (which lands in idea_inbox for a Metic+ builder to ratify at the next planning session); ask an Archon for promotion if you need to run sessions directly."* Do not pull state, do not present criteria, do not propose tasks.
38
38
  3. **If `rank` lowercases to `metic`** → proceed in **Metic-mode**: run the five-phase structure below conversationally, but in Phase 5 write proposals to `idea_inbox` (kind=`criterion-proposal` for criteria, kind=`feature` for tasks) tagged with the target version — filed with `node scripts/gds/capture.js "…" --via planning` (or `filed_via: 'planning'` on `POST /inbox`), so the sky records the door they came through (task 1004233; every other filing's door is read off the session). Any Metic+ builder ratifies them (`idea.ratify`, metic-floored since ADR 0157) — typically at the next planning session. Since [ADR 0090](../../../docs/adr/0090-metic-task-authoring.md) a Metic MAY `POST /tasks` directly, and since [ADR 0154](../../../docs/adr/0154-goal-owner-criterion-authoring.md) a Metic MAY write a `done_when_criteria` row for a goal they own or manage. What needs an Archon is a VERSION-level criterion (no `goal_id`), one in a goal you don't hold, and — since [ADR 0250](../../../docs/adr/0250-strict-versioning-the-version-boundary-is-the-scope-gate.md) §6 (task 1003608) — **creating a version at all**: `version.create` returned to the Archon floor, because once the version boundary carries the scope gate, cutting a version is the way around it rather than authoring. ADR 0157 had briefly delegated it to Metic; it no longer is. The spec-draft (Phase 3) and the in-depth interview (Phase 4) run identically in Metic-mode — the only difference is the Phase-5 write (you file proposals, you don't seed tasks directly).
39
39
 
@@ -195,6 +195,8 @@ Tell the user the spec is written and where, then move straight to the interview
195
195
 
196
196
  **This is the heart of the new flow — it replaces asking for task-by-task approval.** Read the spec you just wrote, then interview the owner with the **AskUserQuestion tool** to resolve every non-obvious decision before a single task is seeded.
197
197
 
198
+ **Spool every answer to the spec file as it lands (task 1002865).** After each AskUserQuestion round, write the decisions into the spec file's *Design decisions & assumptions* and strike them from *Open questions* before you ask the next round — never hold the interview only in the conversation. The spec on disk is what Phase 5 reads; if the Bongos login expires mid-session, a re-auth then costs a minute, not the interview.
199
+
198
200
  **Run it as a loop, not a one-shot:**
199
201
 
200
202
  1. From the spec's *Open questions* (plus anything the task outline leaves genuinely undecided), assemble a round of up to **4 questions** and ask them with AskUserQuestion. Put a recommended option first when you have a view; always leave room for "Other."
@@ -263,7 +265,9 @@ This is what the V3.R02 (task 309) dependency system encodes; Phase 5 writes bot
263
265
 
264
266
  ### Phase 5 — Land it
265
267
 
266
- Once the spec is finalized (Phase 4), **read `docs/specs/<ver>-<goal-slug>.md` as the source of truth** and do the writes in this exact order. (If the goal and its criteria already exist — e.g. this session planned tasks for a pre-existing goal — skip the goal/criteria creation in step 2 and seed the tasks under the existing goal, linking them via `criterion_ids` + `goal_id`.)
268
+ Once the spec is finalized (Phase 4), **read `docs/specs/<ver>-<goal-slug>.md` as the source of truth** and do the writes in this exact order.
269
+
270
+ **Probe the session right before the first write, and recover on a 401 (task 1002865).** Call `GET /api/bongos/me` again here: a session that passed the gate at Phase 1 can expire during a long interview (the retro that filed this: 200 at the gate, 401 by Phase 5). If the probe — or ANY write below — answers `401` / "session is no longer valid", **do not abandon the session**: tell the builder to run `/builder-reauth`, wait for it, then **resume** from the write that failed. Everything the session decided is already in the spec file (Phase 4 spooled it), and the writes are idempotent — the meta task and every seeded task on `source_ref`, criteria on `criterion_id` (a 409 means already seeded), dependencies on `(task_id, depends_on_task_id)` — so re-running the seed script after a re-auth creates nothing twice. (If the goal and its criteria already exist — e.g. this session planned tasks for a pre-existing goal — skip the goal/criteria creation in step 2 and seed the tasks under the existing goal, linking them via `criterion_ids` + `goal_id`.)
267
271
 
268
272
  1. **Create a meta planning-session task** (`source_ref='<ver>-planning-N'`) that backs all the writes — version='<ver>', kind='decision', status='ready', priority=5, the full session described in its body. Claim it. (For a long session — a big spec + a multi-round interview — create and claim this meta task **early, at Phase 1**, so the spec-write and interview are themselves covered by a claim. A rebase-gated builder can't claim new work; as Archon, proceed and record the session in the meta task even if the claim is blocked, noting it.)
269
273
 
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
5
5
  by hand; it regenerates when the spec changes, so it can never drift from the routes.
6
6
 
7
7
  - API version: **v1** (served at `/api/bongos/v1`)
8
- - 440 operations across 67 resource groups
8
+ - 454 operations across 69 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -372,6 +372,12 @@ function createClient(opts = {}) {
372
372
  // POST /github/repos — rank: any-builder — POST /github/repos
373
373
  postGithubRepos: (args) => request("POST", "/github/repos", { hasBody: true }, args),
374
374
  },
375
+ "goalTaskRelevance": {
376
+ // POST /goal-task-relevance/{id}/decide — rank: metic+archon — POST /goal-task-relevance/:id/decide
377
+ postGoalTaskRelevanceIdDecide: (args) => request("POST", "/goal-task-relevance/{id}/decide", { hasBody: true }, args),
378
+ // GET /goal-task-relevance/pending — rank: metic+archon — GET /goal-task-relevance/pending
379
+ getGoalTaskRelevancePending: (args) => request("GET", "/goal-task-relevance/pending", { hasBody: false }, args),
380
+ },
375
381
  "goals": {
376
382
  // GET /goals — rank: any-builder — GET /goals
377
383
  getGoals: (args) => request("GET", "/goals", { hasBody: false }, args),
@@ -717,6 +723,16 @@ function createClient(opts = {}) {
717
723
  postMyProjectsJoin: (args) => request("POST", "/my-projects/join", { hasBody: true }, args),
718
724
  },
719
725
  "npmRelease": {
726
+ // DELETE /npm-release/preview — rank: any-builder — DELETE /npm-release/preview
727
+ deleteNpmReleasePreview: (args) => request("DELETE", "/npm-release/preview", { hasBody: false }, args),
728
+ // GET /npm-release/preview — rank: any-builder — GET /npm-release/preview
729
+ getNpmReleasePreview: (args) => request("GET", "/npm-release/preview", { hasBody: false }, args),
730
+ // POST /npm-release/preview — rank: any-builder — POST /npm-release/preview
731
+ postNpmReleasePreview: (args) => request("POST", "/npm-release/preview", { hasBody: true }, args),
732
+ // GET /npm-release/preview/enter — rank: any-builder — GET /npm-release/preview/enter
733
+ getNpmReleasePreviewEnter: (args) => request("GET", "/npm-release/preview/enter", { hasBody: false }, args),
734
+ // GET /npm-release/preview/exit — rank: any-builder — GET /npm-release/preview/exit
735
+ getNpmReleasePreviewExit: (args) => request("GET", "/npm-release/preview/exit", { hasBody: false }, args),
720
736
  // GET /npm-release/task/{id} — rank: any-builder — GET /npm-release/task/:id
721
737
  getNpmReleaseTaskId: (args) => request("GET", "/npm-release/task/{id}", { hasBody: false }, args),
722
738
  // GET /npm-release/work — rank: archon — GET /npm-release/work
@@ -797,6 +813,8 @@ function createClient(opts = {}) {
797
813
  postProvisioningInstancesIdGithubApp: (args) => request("POST", "/provisioning/instances/{id}/github-app", { hasBody: true }, args),
798
814
  // GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder — GET /provisioning/instances/:id/invite-suggestions
799
815
  getProvisioningInstancesIdInviteSuggestions: (args) => request("GET", "/provisioning/instances/{id}/invite-suggestions", { hasBody: false }, args),
816
+ // GET /provisioning/instances/{id}/render — rank: any-builder — GET /provisioning/instances/:id/render
817
+ getProvisioningInstancesIdRender: (args) => request("GET", "/provisioning/instances/{id}/render", { hasBody: false }, args),
800
818
  // POST /provisioning/instances/{id}/render — rank: any-builder — POST /provisioning/instances/:id/render
801
819
  postProvisioningInstancesIdRender: (args) => request("POST", "/provisioning/instances/{id}/render", { hasBody: true }, args),
802
820
  // POST /provisioning/instances/{id}/repo-private — rank: any-builder — POST /provisioning/instances/:id/repo-private
@@ -813,6 +831,8 @@ function createClient(opts = {}) {
813
831
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
814
832
  // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
815
833
  getProvisioningRecommendations: (args) => request("GET", "/provisioning/recommendations", { hasBody: false }, args),
834
+ // POST /provisioning/render/lookup — rank: any-builder — POST /provisioning/render/lookup
835
+ postProvisioningRenderLookup: (args) => request("POST", "/provisioning/render/lookup", { hasBody: true }, args),
816
836
  // GET /provisioning/slug-available — rank: any-builder — GET /provisioning/slug-available
817
837
  getProvisioningSlugAvailable: (args) => request("GET", "/provisioning/slug-available", { hasBody: false }, args),
818
838
  // GET /provisioning/starter-bundles — rank: public — GET /provisioning/starter-bundles
@@ -864,6 +884,16 @@ function createClient(opts = {}) {
864
884
  // POST /removal-proposals/{id}/decide — rank: metic+archon — POST /removal-proposals/:id/decide
865
885
  postRemovalProposalsIdDecide: (args) => request("POST", "/removal-proposals/{id}/decide", { hasBody: true }, args),
866
886
  },
887
+ "renderDeploy": {
888
+ // POST /render-deploy/act — rank: archon — POST /render-deploy/act
889
+ postRenderDeployAct: (args) => request("POST", "/render-deploy/act", { hasBody: true }, args),
890
+ // GET /render-deploy/app — rank: archon — GET /render-deploy/app
891
+ getRenderDeployApp: (args) => request("GET", "/render-deploy/app", { hasBody: false }, args),
892
+ // PUT /render-deploy/app — rank: archon — PUT /render-deploy/app
893
+ putRenderDeployApp: (args) => request("PUT", "/render-deploy/app", { hasBody: true }, args),
894
+ // GET /render-deploy/history — rank: archon — GET /render-deploy/history
895
+ getRenderDeployHistory: (args) => request("GET", "/render-deploy/history", { hasBody: false }, args),
896
+ },
867
897
  "scouting": {
868
898
  // GET /scouting — rank: metic+archon — GET /scouting
869
899
  getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
@@ -949,6 +979,8 @@ function createClient(opts = {}) {
949
979
  deleteSpecialitiesIdDocumentsDocId: (args) => request("DELETE", "/specialities/{id}/documents/{docId}", { hasBody: false }, args),
950
980
  // POST /specialities/{id}/offer — rank: metic+archon — POST /specialities/:id/offer
951
981
  postSpecialitiesIdOffer: (args) => request("POST", "/specialities/{id}/offer", { hasBody: true }, args),
982
+ // PUT /specialities/{id}/skills — rank: any-builder — PUT /specialities/:id/skills
983
+ putSpecialitiesIdSkills: (args) => request("PUT", "/specialities/{id}/skills", { hasBody: true }, args),
952
984
  // POST /specialities/{id}/unoffer — rank: metic+archon — POST /specialities/:id/unoffer
953
985
  postSpecialitiesIdUnoffer: (args) => request("POST", "/specialities/{id}/unoffer", { hasBody: true }, args),
954
986
  // GET /specialities/offered — rank: any-builder — GET /specialities/offered
@@ -371,6 +371,12 @@ function createClient(opts = {}) {
371
371
  // POST /github/repos — rank: any-builder — POST /github/repos
372
372
  postGithubRepos: (args) => request("POST", "/github/repos", { hasBody: true }, args),
373
373
  },
374
+ "goalTaskRelevance": {
375
+ // POST /goal-task-relevance/{id}/decide — rank: metic+archon — POST /goal-task-relevance/:id/decide
376
+ postGoalTaskRelevanceIdDecide: (args) => request("POST", "/goal-task-relevance/{id}/decide", { hasBody: true }, args),
377
+ // GET /goal-task-relevance/pending — rank: metic+archon — GET /goal-task-relevance/pending
378
+ getGoalTaskRelevancePending: (args) => request("GET", "/goal-task-relevance/pending", { hasBody: false }, args),
379
+ },
374
380
  "goals": {
375
381
  // GET /goals — rank: any-builder — GET /goals
376
382
  getGoals: (args) => request("GET", "/goals", { hasBody: false }, args),
@@ -716,6 +722,16 @@ function createClient(opts = {}) {
716
722
  postMyProjectsJoin: (args) => request("POST", "/my-projects/join", { hasBody: true }, args),
717
723
  },
718
724
  "npmRelease": {
725
+ // DELETE /npm-release/preview — rank: any-builder — DELETE /npm-release/preview
726
+ deleteNpmReleasePreview: (args) => request("DELETE", "/npm-release/preview", { hasBody: false }, args),
727
+ // GET /npm-release/preview — rank: any-builder — GET /npm-release/preview
728
+ getNpmReleasePreview: (args) => request("GET", "/npm-release/preview", { hasBody: false }, args),
729
+ // POST /npm-release/preview — rank: any-builder — POST /npm-release/preview
730
+ postNpmReleasePreview: (args) => request("POST", "/npm-release/preview", { hasBody: true }, args),
731
+ // GET /npm-release/preview/enter — rank: any-builder — GET /npm-release/preview/enter
732
+ getNpmReleasePreviewEnter: (args) => request("GET", "/npm-release/preview/enter", { hasBody: false }, args),
733
+ // GET /npm-release/preview/exit — rank: any-builder — GET /npm-release/preview/exit
734
+ getNpmReleasePreviewExit: (args) => request("GET", "/npm-release/preview/exit", { hasBody: false }, args),
719
735
  // GET /npm-release/task/{id} — rank: any-builder — GET /npm-release/task/:id
720
736
  getNpmReleaseTaskId: (args) => request("GET", "/npm-release/task/{id}", { hasBody: false }, args),
721
737
  // GET /npm-release/work — rank: archon — GET /npm-release/work
@@ -796,6 +812,8 @@ function createClient(opts = {}) {
796
812
  postProvisioningInstancesIdGithubApp: (args) => request("POST", "/provisioning/instances/{id}/github-app", { hasBody: true }, args),
797
813
  // GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder — GET /provisioning/instances/:id/invite-suggestions
798
814
  getProvisioningInstancesIdInviteSuggestions: (args) => request("GET", "/provisioning/instances/{id}/invite-suggestions", { hasBody: false }, args),
815
+ // GET /provisioning/instances/{id}/render — rank: any-builder — GET /provisioning/instances/:id/render
816
+ getProvisioningInstancesIdRender: (args) => request("GET", "/provisioning/instances/{id}/render", { hasBody: false }, args),
799
817
  // POST /provisioning/instances/{id}/render — rank: any-builder — POST /provisioning/instances/:id/render
800
818
  postProvisioningInstancesIdRender: (args) => request("POST", "/provisioning/instances/{id}/render", { hasBody: true }, args),
801
819
  // POST /provisioning/instances/{id}/repo-private — rank: any-builder — POST /provisioning/instances/:id/repo-private
@@ -812,6 +830,8 @@ function createClient(opts = {}) {
812
830
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
813
831
  // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
814
832
  getProvisioningRecommendations: (args) => request("GET", "/provisioning/recommendations", { hasBody: false }, args),
833
+ // POST /provisioning/render/lookup — rank: any-builder — POST /provisioning/render/lookup
834
+ postProvisioningRenderLookup: (args) => request("POST", "/provisioning/render/lookup", { hasBody: true }, args),
815
835
  // GET /provisioning/slug-available — rank: any-builder — GET /provisioning/slug-available
816
836
  getProvisioningSlugAvailable: (args) => request("GET", "/provisioning/slug-available", { hasBody: false }, args),
817
837
  // GET /provisioning/starter-bundles — rank: public — GET /provisioning/starter-bundles
@@ -863,6 +883,16 @@ function createClient(opts = {}) {
863
883
  // POST /removal-proposals/{id}/decide — rank: metic+archon — POST /removal-proposals/:id/decide
864
884
  postRemovalProposalsIdDecide: (args) => request("POST", "/removal-proposals/{id}/decide", { hasBody: true }, args),
865
885
  },
886
+ "renderDeploy": {
887
+ // POST /render-deploy/act — rank: archon — POST /render-deploy/act
888
+ postRenderDeployAct: (args) => request("POST", "/render-deploy/act", { hasBody: true }, args),
889
+ // GET /render-deploy/app — rank: archon — GET /render-deploy/app
890
+ getRenderDeployApp: (args) => request("GET", "/render-deploy/app", { hasBody: false }, args),
891
+ // PUT /render-deploy/app — rank: archon — PUT /render-deploy/app
892
+ putRenderDeployApp: (args) => request("PUT", "/render-deploy/app", { hasBody: true }, args),
893
+ // GET /render-deploy/history — rank: archon — GET /render-deploy/history
894
+ getRenderDeployHistory: (args) => request("GET", "/render-deploy/history", { hasBody: false }, args),
895
+ },
866
896
  "scouting": {
867
897
  // GET /scouting — rank: metic+archon — GET /scouting
868
898
  getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
@@ -948,6 +978,8 @@ function createClient(opts = {}) {
948
978
  deleteSpecialitiesIdDocumentsDocId: (args) => request("DELETE", "/specialities/{id}/documents/{docId}", { hasBody: false }, args),
949
979
  // POST /specialities/{id}/offer — rank: metic+archon — POST /specialities/:id/offer
950
980
  postSpecialitiesIdOffer: (args) => request("POST", "/specialities/{id}/offer", { hasBody: true }, args),
981
+ // PUT /specialities/{id}/skills — rank: any-builder — PUT /specialities/:id/skills
982
+ putSpecialitiesIdSkills: (args) => request("PUT", "/specialities/{id}/skills", { hasBody: true }, args),
951
983
  // POST /specialities/{id}/unoffer — rank: metic+archon — POST /specialities/:id/unoffer
952
984
  postSpecialitiesIdUnoffer: (args) => request("POST", "/specialities/{id}/unoffer", { hasBody: true }, args),
953
985
  // GET /specialities/offered — rank: any-builder — GET /specialities/offered
@@ -62,6 +62,7 @@ export interface GetDiscordChannelsSnapshotResponse { ok: boolean; guild_id: unk
62
62
  export interface GetDoneWhenPendingReviewResponse { criteria: unknown; count: unknown }
63
63
  export interface GetGithubRepoResponse { ok: boolean; repo: unknown; private_deployable: boolean }
64
64
  export interface GetGithubReposResponse { repos: unknown }
65
+ export interface GetGoalTaskRelevancePendingResponse { flags: unknown; count: unknown }
65
66
  export interface GetGoalsIdConflictsResponse { ok: boolean; goal_id: unknown; conflicts: unknown; cross_goals_considered: unknown }
66
67
  export interface GetGoalsIdRequestsResponse { requests: unknown }
67
68
  export interface GetGoalsIdResponse { goal: unknown; members: unknown; criteria: unknown; dependencies: unknown; criterionless_task_count: unknown; admitted: unknown; open_tasks: unknown }
@@ -121,6 +122,7 @@ export interface GetProvisioningGithubAppStatusResponse { ok: boolean; status: u
121
122
  export interface GetProvisioningHealthResponse { module: unknown; ok: boolean; coreVersion: unknown }
122
123
  export interface GetProvisioningInstancesIdEnvManifestResponse { instance: unknown; env_vars: unknown; environments: unknown; values_held: boolean; note: unknown }
123
124
  export interface GetProvisioningInstancesIdInviteSuggestionsResponse { suggested: unknown; seeking: unknown; reason: unknown; unavailable?: unknown }
125
+ export interface GetProvisioningInstancesIdRenderResponse { ok: boolean; app: unknown; env_vars: unknown; values_held: boolean }
124
126
  export interface GetProvisioningInstancesIdResponse { instance: unknown; open_intent: unknown; github_app: unknown }
125
127
  export interface GetProvisioningInstancesIdSettingsResponse { ok: boolean; settings: unknown; planet: unknown; options: unknown }
126
128
  export interface GetProvisioningInstancesResponse { instances: unknown }
@@ -142,6 +144,7 @@ export interface GetPublicTasksIdResponse { task: unknown }
142
144
  export interface GetPublicUptimeResponse { services: unknown }
143
145
  export interface GetPublicVersionsResponse { versions: unknown; page: PageInfo }
144
146
  export interface GetRemovalProposalsResponse { pending: unknown; count: unknown }
147
+ export interface GetRenderDeployAppResponse { app: unknown }
145
148
  export interface GetScoutingHandleResponse { sliver: unknown }
146
149
  export interface GetScoutingResponse { builders: unknown; name_only: unknown }
147
150
  export interface GetSecurityDocsResponse { docs: unknown }
@@ -217,7 +220,7 @@ export interface PatchProvisioningInstancesIdDetailResponse { ok: boolean; descr
217
220
  export interface PatchProvisioningInstancesIdEnvManifestVarIdRequest { name?: string; description?: string; environments?: unknown[]; required?: boolean }
218
221
  export interface PatchProvisioningInstancesIdEnvManifestVarIdResponse { ok: boolean; env_var: unknown; values_held: boolean }
219
222
  export interface PatchProvisioningInstancesIdSettingsResponse { ok: boolean; saved: unknown; planet: unknown; push: unknown }
220
- export interface PatchSpecialitiesIdRequest { name?: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean }
223
+ export interface PatchSpecialitiesIdRequest { name?: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean; skills?: string[] }
221
224
  export interface PatchSpecialitiesIdResponse { speciality: unknown }
222
225
  export interface PatchTaskRecommendationsIdRequest { status: "declined" | "withdrawn" }
223
226
  export interface PatchTaskRecommendationsIdResponse { ok: boolean; recommendation: unknown }
@@ -289,6 +292,8 @@ export interface PostGithubRepoVisibilityRequest { repo: string; visibility: "pu
289
292
  export interface PostGithubRepoVisibilityResponse { ok: boolean; repo: unknown; private_deployable: boolean }
290
293
  export interface PostGithubReposRequest { name: string }
291
294
  export interface PostGithubReposResponse { repo: unknown }
295
+ export interface PostGoalTaskRelevanceIdDecideRequest { decision: "confirmed_gaming" | "false_positive"; note?: string }
296
+ export interface PostGoalTaskRelevanceIdDecideResponse { ok: boolean; flag: unknown }
292
297
  export interface PostGoalsIdArchiveRequest { reason?: string; dispositions?: Record<string, unknown> }
293
298
  export interface PostGoalsIdArchiveResponse { ok: boolean; goal: unknown; applied: unknown }
294
299
  export interface PostGoalsIdConflictsResolveRequest { action: string; note?: string; touches?: string[]; first_task_id?: StringifiableId; then_task_id?: StringifiableId; task_id?: StringifiableId }
@@ -340,7 +345,7 @@ export interface PostHelpRequestsIdRepliesResponse { ok: boolean; reply: unknown
340
345
  export interface PostHelpRequestsRequest { needs_craft?: string; needs_builder_id?: number; what_is_stuck: string; task_id?: number; goal_id?: number }
341
346
  export interface PostHelpRequestsResponse { ok: boolean; help_request: unknown }
342
347
  export interface PostInboxIdDevelopRequest { field_values: Record<string, unknown>; template_key?: string; recommendation?: string }
343
- export interface PostInboxIdRatifyGoalRequest { target_version: string; scope_modules?: string[]; admit_reason?: string; notes_md?: string }
348
+ export interface PostInboxIdRatifyGoalRequest { target_version: string; scope_modules?: string[]; admit_reason?: string; notes_md?: string; success_criterion?: string }
344
349
  export interface PostInboxIdRatifyRequest { notes_md?: string }
345
350
  export interface PostInboxIdResubmitRequest { field_values: Record<string, unknown>; template_key?: string; recommendation?: string }
346
351
  export interface PostInboxIdSparkResponse { idea: unknown; sparked: boolean; unchanged: boolean }
@@ -375,9 +380,10 @@ export interface PostMyProjectsInvitesClientIdAcceptResponse { ok: boolean; acce
375
380
  export interface PostMyProjectsInvitesClientIdDeclineResponse { ok: boolean; accepted: boolean }
376
381
  export interface PostMyProjectsJoinRequest { origin: string; note?: string }
377
382
  export interface PostMyProjectsJoinResponse { ok: boolean; status: unknown; project: unknown; message: unknown }
383
+ export interface PostNpmReleasePreviewRequest { version: string }
378
384
  export interface PostOverrideRequestsIdDecideRequest { decision: string; note?: string }
379
385
  export interface PostProjectsInviteRequest { client_id: string; github_login: string }
380
- export interface PostProjectsProjectIdSpecialitiesRequest { name: string; discipline: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean }
386
+ export interface PostProjectsProjectIdSpecialitiesRequest { name: string; discipline: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean; skills?: string[] }
381
387
  export interface PostProjectsProjectIdSpecialitiesResponse { speciality: unknown }
382
388
  export interface PostProjectsRequest { origin: string; name: string; tagline?: string; description?: string; art_url?: string; type?: string; template?: string }
383
389
  export interface PostProjectsResponse { project: unknown }
@@ -389,13 +395,16 @@ export interface PostProvisioningInstancesIdEnvManifestRequest { name: string; d
389
395
  export interface PostProvisioningInstancesIdForceTeardownResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; superseded: unknown; message: unknown }
390
396
  export interface PostProvisioningInstancesIdGithubAppRequest { account?: string }
391
397
  export interface PostProvisioningInstancesIdGithubAppResponse { state: unknown; account: unknown; post_url: unknown; personal_url: unknown; org_url: unknown; org_login: unknown; manifest: unknown; redirect_url: unknown; expires_at: unknown }
392
- export interface PostProvisioningInstancesIdRenderRequest { key: string; owner_id: string; mode: string; service_id?: string; web_plan?: string; db_plan?: string; region?: string }
393
- export interface PostProvisioningInstancesIdRenderResponse { ok: boolean; queued: boolean; action: unknown; mode: unknown; message: unknown }
398
+ export interface PostProvisioningInstancesIdRenderRequest { key: string; owner_id: string; mode: string; service_id?: string; web_plan?: string; db_plan?: string; region?: string; runtime?: string; build_command?: string; start_command?: string; database?: boolean }
399
+ export interface PostProvisioningInstancesIdRenderResponse { ok: boolean; queued: boolean; action: unknown; mode: unknown; with_setup: boolean; message: unknown }
394
400
  export interface PostProvisioningInstancesIdRepoPrivateResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; message: unknown }
395
401
  export interface PostProvisioningInstancesIdRestartResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; message: unknown }
396
402
  export interface PostProvisioningInstancesIdTeardownResponse { ok: boolean; queued: unknown; action: unknown; status: unknown; superseded: unknown; message: unknown }
397
403
  export interface PostProvisioningInstancesRequest { slug: string; target_ref?: string; hosting_shape?: string; domain?: string; no_address?: boolean; tier?: string; onboard_mode?: string; type?: string; description?: string; detail?: Record<string, unknown>; modules?: string[] }
404
+ export interface PostProvisioningRenderLookupRequest { key: string; owner_id?: string }
398
405
  export interface PostRemovalProposalsIdDecideRequest { verdict: string; note?: string }
406
+ export interface PostRenderDeployActRequest { action?: string; deployId?: string; confirm?: unknown; expectLiveDeployId?: unknown }
407
+ export interface PostRenderDeployActResponse { ok: boolean; action: unknown; started: unknown; render: unknown }
399
408
  export interface PostSearchMarkRequest { chunk_id?: StringifiableId; useful?: unknown }
400
409
  export interface PostSearchRequest { expand?: unknown; q?: string; source_kind?: string; limit?: unknown }
401
410
  export interface PostSearchResponse { expand?: unknown; chunk?: unknown; query?: unknown; count?: unknown; total_full_tokens?: unknown; results?: unknown; corpus?: unknown }
@@ -420,7 +429,7 @@ export interface PostSpecialitiesIdDocumentsRequest { title: string; body_md: st
420
429
  export interface PostSpecialitiesIdDocumentsResponse { skipped?: boolean; reason?: unknown; document?: unknown }
421
430
  export interface PostSpecialitiesIdOfferResponse { speciality: unknown }
422
431
  export interface PostSpecialitiesIdUnofferResponse { speciality: unknown }
423
- export interface PostSpecialitiesRequest { name: string; discipline: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean }
432
+ export interface PostSpecialitiesRequest { name: string; discipline: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean; skills?: string[] }
424
433
  export interface PostSpecialitiesResponse { speciality: unknown }
425
434
  export interface PostSsoActivityRollupRequest { client_id: string; client_secret: string; github_id: StringifiableId; credits?: number; tasks_shipped?: number; karma?: number; rank?: string; disciplines?: unknown; recent_ships?: unknown }
426
435
  export interface PostSsoActivityRollupResponse { ok: boolean }
@@ -474,6 +483,10 @@ export interface PutGovernmentRanksRankKeyPermissionsPermissionKeyResponse { ok:
474
483
  export interface PutMingleOptInRequest { opted_in: boolean }
475
484
  export interface PutMingleOptInResponse { opted_in: unknown; updated_at: unknown }
476
485
  export interface PutMingleProjectRequest { enabled: boolean }
486
+ export interface PutRenderDeployAppRequest { ownerId?: string; serviceId?: string }
487
+ export interface PutRenderDeployAppResponse { app: unknown }
488
+ export interface PutSpecialitiesIdSkillsRequest { enabled_skills: string[] }
489
+ export interface PutSpecialitiesIdSkillsResponse { adoption: unknown }
477
490
  export interface PutTasksIdDependenciesRequest { depends_on_task_ids: unknown[] }
478
491
  export interface PutTasksIdDependenciesResponse { ok: boolean; written: unknown; dependencies: unknown }
479
492
  export type StringifiableId = number | string;
@@ -778,6 +791,12 @@ export interface BongosClient {
778
791
  /** POST /github/repos — rank: any-builder */
779
792
  postGithubRepos(args: RequestArgs & { body: PostGithubReposRequest }): Promise<PostGithubReposResponse>;
780
793
  };
794
+ "goalTaskRelevance": {
795
+ /** POST /goal-task-relevance/{id}/decide — rank: metic+archon */
796
+ postGoalTaskRelevanceIdDecide(args: RequestArgs & { body: PostGoalTaskRelevanceIdDecideRequest }): Promise<PostGoalTaskRelevanceIdDecideResponse>;
797
+ /** GET /goal-task-relevance/pending — rank: metic+archon */
798
+ getGoalTaskRelevancePending(args?: RequestArgs): Promise<GetGoalTaskRelevancePendingResponse>;
799
+ };
781
800
  "goals": {
782
801
  /** GET /goals — rank: any-builder */
783
802
  getGoals(args?: RequestArgs): Promise<GetGoalsResponse>;
@@ -1123,6 +1142,16 @@ export interface BongosClient {
1123
1142
  postMyProjectsJoin(args: RequestArgs & { body: PostMyProjectsJoinRequest }): Promise<PostMyProjectsJoinResponse>;
1124
1143
  };
1125
1144
  "npmRelease": {
1145
+ /** DELETE /npm-release/preview — rank: any-builder */
1146
+ deleteNpmReleasePreview(args?: RequestArgs): Promise<ApiResponse>;
1147
+ /** GET /npm-release/preview — rank: any-builder */
1148
+ getNpmReleasePreview(args?: RequestArgs): Promise<ApiResponse>;
1149
+ /** POST /npm-release/preview — rank: any-builder */
1150
+ postNpmReleasePreview(args: RequestArgs & { body: PostNpmReleasePreviewRequest }): Promise<ApiResponse>;
1151
+ /** GET /npm-release/preview/enter — rank: any-builder */
1152
+ getNpmReleasePreviewEnter(args?: RequestArgs): Promise<ApiResponse>;
1153
+ /** GET /npm-release/preview/exit — rank: any-builder */
1154
+ getNpmReleasePreviewExit(args?: RequestArgs): Promise<ApiResponse>;
1126
1155
  /** GET /npm-release/task/{id} — rank: any-builder */
1127
1156
  getNpmReleaseTaskId(args?: RequestArgs): Promise<ApiResponse>;
1128
1157
  /** GET /npm-release/work — rank: archon */
@@ -1203,6 +1232,8 @@ export interface BongosClient {
1203
1232
  postProvisioningInstancesIdGithubApp(args?: RequestArgs & { body?: PostProvisioningInstancesIdGithubAppRequest }): Promise<PostProvisioningInstancesIdGithubAppResponse>;
1204
1233
  /** GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder */
1205
1234
  getProvisioningInstancesIdInviteSuggestions(args?: RequestArgs): Promise<GetProvisioningInstancesIdInviteSuggestionsResponse>;
1235
+ /** GET /provisioning/instances/{id}/render — rank: any-builder */
1236
+ getProvisioningInstancesIdRender(args?: RequestArgs): Promise<GetProvisioningInstancesIdRenderResponse>;
1206
1237
  /** POST /provisioning/instances/{id}/render — rank: any-builder */
1207
1238
  postProvisioningInstancesIdRender(args: RequestArgs & { body: PostProvisioningInstancesIdRenderRequest }): Promise<PostProvisioningInstancesIdRenderResponse>;
1208
1239
  /** POST /provisioning/instances/{id}/repo-private — rank: any-builder */
@@ -1219,6 +1250,8 @@ export interface BongosClient {
1219
1250
  getProvisioningOnboardPlan(args?: RequestArgs): Promise<GetProvisioningOnboardPlanResponse>;
1220
1251
  /** GET /provisioning/recommendations — rank: public */
1221
1252
  getProvisioningRecommendations(args?: RequestArgs): Promise<GetProvisioningRecommendationsResponse>;
1253
+ /** POST /provisioning/render/lookup — rank: any-builder */
1254
+ postProvisioningRenderLookup(args: RequestArgs & { body: PostProvisioningRenderLookupRequest }): Promise<ApiResponse>;
1222
1255
  /** GET /provisioning/slug-available — rank: any-builder */
1223
1256
  getProvisioningSlugAvailable(args?: RequestArgs): Promise<GetProvisioningSlugAvailableResponse>;
1224
1257
  /** GET /provisioning/starter-bundles — rank: public */
@@ -1270,6 +1303,16 @@ export interface BongosClient {
1270
1303
  /** POST /removal-proposals/{id}/decide — rank: metic+archon */
1271
1304
  postRemovalProposalsIdDecide(args: RequestArgs & { body: PostRemovalProposalsIdDecideRequest }): Promise<ApiResponse>;
1272
1305
  };
1306
+ "renderDeploy": {
1307
+ /** POST /render-deploy/act — rank: archon */
1308
+ postRenderDeployAct(args?: RequestArgs & { body?: PostRenderDeployActRequest }): Promise<PostRenderDeployActResponse>;
1309
+ /** GET /render-deploy/app — rank: archon */
1310
+ getRenderDeployApp(args?: RequestArgs): Promise<GetRenderDeployAppResponse>;
1311
+ /** PUT /render-deploy/app — rank: archon */
1312
+ putRenderDeployApp(args?: RequestArgs & { body?: PutRenderDeployAppRequest }): Promise<PutRenderDeployAppResponse>;
1313
+ /** GET /render-deploy/history — rank: archon */
1314
+ getRenderDeployHistory(args?: RequestArgs): Promise<ApiResponse>;
1315
+ };
1273
1316
  "scouting": {
1274
1317
  /** GET /scouting — rank: metic+archon */
1275
1318
  getScouting(args?: RequestArgs): Promise<GetScoutingResponse>;
@@ -1355,6 +1398,8 @@ export interface BongosClient {
1355
1398
  deleteSpecialitiesIdDocumentsDocId(args?: RequestArgs): Promise<DeleteSpecialitiesIdDocumentsDocIdResponse>;
1356
1399
  /** POST /specialities/{id}/offer — rank: metic+archon */
1357
1400
  postSpecialitiesIdOffer(args?: RequestArgs): Promise<PostSpecialitiesIdOfferResponse>;
1401
+ /** PUT /specialities/{id}/skills — rank: any-builder */
1402
+ putSpecialitiesIdSkills(args: RequestArgs & { body: PutSpecialitiesIdSkillsRequest }): Promise<PutSpecialitiesIdSkillsResponse>;
1358
1403
  /** POST /specialities/{id}/unoffer — rank: metic+archon */
1359
1404
  postSpecialitiesIdUnoffer(args?: RequestArgs): Promise<PostSpecialitiesIdUnofferResponse>;
1360
1405
  /** GET /specialities/offered — rank: any-builder */
@@ -368,6 +368,12 @@ export function createClient(opts = {}) {
368
368
  // POST /github/repos — rank: any-builder — POST /github/repos
369
369
  postGithubRepos: (args) => request("POST", "/github/repos", { hasBody: true }, args),
370
370
  },
371
+ "goalTaskRelevance": {
372
+ // POST /goal-task-relevance/{id}/decide — rank: metic+archon — POST /goal-task-relevance/:id/decide
373
+ postGoalTaskRelevanceIdDecide: (args) => request("POST", "/goal-task-relevance/{id}/decide", { hasBody: true }, args),
374
+ // GET /goal-task-relevance/pending — rank: metic+archon — GET /goal-task-relevance/pending
375
+ getGoalTaskRelevancePending: (args) => request("GET", "/goal-task-relevance/pending", { hasBody: false }, args),
376
+ },
371
377
  "goals": {
372
378
  // GET /goals — rank: any-builder — GET /goals
373
379
  getGoals: (args) => request("GET", "/goals", { hasBody: false }, args),
@@ -713,6 +719,16 @@ export function createClient(opts = {}) {
713
719
  postMyProjectsJoin: (args) => request("POST", "/my-projects/join", { hasBody: true }, args),
714
720
  },
715
721
  "npmRelease": {
722
+ // DELETE /npm-release/preview — rank: any-builder — DELETE /npm-release/preview
723
+ deleteNpmReleasePreview: (args) => request("DELETE", "/npm-release/preview", { hasBody: false }, args),
724
+ // GET /npm-release/preview — rank: any-builder — GET /npm-release/preview
725
+ getNpmReleasePreview: (args) => request("GET", "/npm-release/preview", { hasBody: false }, args),
726
+ // POST /npm-release/preview — rank: any-builder — POST /npm-release/preview
727
+ postNpmReleasePreview: (args) => request("POST", "/npm-release/preview", { hasBody: true }, args),
728
+ // GET /npm-release/preview/enter — rank: any-builder — GET /npm-release/preview/enter
729
+ getNpmReleasePreviewEnter: (args) => request("GET", "/npm-release/preview/enter", { hasBody: false }, args),
730
+ // GET /npm-release/preview/exit — rank: any-builder — GET /npm-release/preview/exit
731
+ getNpmReleasePreviewExit: (args) => request("GET", "/npm-release/preview/exit", { hasBody: false }, args),
716
732
  // GET /npm-release/task/{id} — rank: any-builder — GET /npm-release/task/:id
717
733
  getNpmReleaseTaskId: (args) => request("GET", "/npm-release/task/{id}", { hasBody: false }, args),
718
734
  // GET /npm-release/work — rank: archon — GET /npm-release/work
@@ -793,6 +809,8 @@ export function createClient(opts = {}) {
793
809
  postProvisioningInstancesIdGithubApp: (args) => request("POST", "/provisioning/instances/{id}/github-app", { hasBody: true }, args),
794
810
  // GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder — GET /provisioning/instances/:id/invite-suggestions
795
811
  getProvisioningInstancesIdInviteSuggestions: (args) => request("GET", "/provisioning/instances/{id}/invite-suggestions", { hasBody: false }, args),
812
+ // GET /provisioning/instances/{id}/render — rank: any-builder — GET /provisioning/instances/:id/render
813
+ getProvisioningInstancesIdRender: (args) => request("GET", "/provisioning/instances/{id}/render", { hasBody: false }, args),
796
814
  // POST /provisioning/instances/{id}/render — rank: any-builder — POST /provisioning/instances/:id/render
797
815
  postProvisioningInstancesIdRender: (args) => request("POST", "/provisioning/instances/{id}/render", { hasBody: true }, args),
798
816
  // POST /provisioning/instances/{id}/repo-private — rank: any-builder — POST /provisioning/instances/:id/repo-private
@@ -809,6 +827,8 @@ export function createClient(opts = {}) {
809
827
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
810
828
  // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
811
829
  getProvisioningRecommendations: (args) => request("GET", "/provisioning/recommendations", { hasBody: false }, args),
830
+ // POST /provisioning/render/lookup — rank: any-builder — POST /provisioning/render/lookup
831
+ postProvisioningRenderLookup: (args) => request("POST", "/provisioning/render/lookup", { hasBody: true }, args),
812
832
  // GET /provisioning/slug-available — rank: any-builder — GET /provisioning/slug-available
813
833
  getProvisioningSlugAvailable: (args) => request("GET", "/provisioning/slug-available", { hasBody: false }, args),
814
834
  // GET /provisioning/starter-bundles — rank: public — GET /provisioning/starter-bundles
@@ -860,6 +880,16 @@ export function createClient(opts = {}) {
860
880
  // POST /removal-proposals/{id}/decide — rank: metic+archon — POST /removal-proposals/:id/decide
861
881
  postRemovalProposalsIdDecide: (args) => request("POST", "/removal-proposals/{id}/decide", { hasBody: true }, args),
862
882
  },
883
+ "renderDeploy": {
884
+ // POST /render-deploy/act — rank: archon — POST /render-deploy/act
885
+ postRenderDeployAct: (args) => request("POST", "/render-deploy/act", { hasBody: true }, args),
886
+ // GET /render-deploy/app — rank: archon — GET /render-deploy/app
887
+ getRenderDeployApp: (args) => request("GET", "/render-deploy/app", { hasBody: false }, args),
888
+ // PUT /render-deploy/app — rank: archon — PUT /render-deploy/app
889
+ putRenderDeployApp: (args) => request("PUT", "/render-deploy/app", { hasBody: true }, args),
890
+ // GET /render-deploy/history — rank: archon — GET /render-deploy/history
891
+ getRenderDeployHistory: (args) => request("GET", "/render-deploy/history", { hasBody: false }, args),
892
+ },
863
893
  "scouting": {
864
894
  // GET /scouting — rank: metic+archon — GET /scouting
865
895
  getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
@@ -945,6 +975,8 @@ export function createClient(opts = {}) {
945
975
  deleteSpecialitiesIdDocumentsDocId: (args) => request("DELETE", "/specialities/{id}/documents/{docId}", { hasBody: false }, args),
946
976
  // POST /specialities/{id}/offer — rank: metic+archon — POST /specialities/:id/offer
947
977
  postSpecialitiesIdOffer: (args) => request("POST", "/specialities/{id}/offer", { hasBody: true }, args),
978
+ // PUT /specialities/{id}/skills — rank: any-builder — PUT /specialities/:id/skills
979
+ putSpecialitiesIdSkills: (args) => request("PUT", "/specialities/{id}/skills", { hasBody: true }, args),
948
980
  // POST /specialities/{id}/unoffer — rank: metic+archon — POST /specialities/:id/unoffer
949
981
  postSpecialitiesIdUnoffer: (args) => request("POST", "/specialities/{id}/unoffer", { hasBody: true }, args),
950
982
  // GET /specialities/offered — rank: any-builder — GET /specialities/offered
@@ -15,7 +15,7 @@ The redaction surface is real, not theoretical: at build time **23** published f
15
15
 
16
16
  ## Decision
17
17
 
18
- `scripts/public-mirror-export.js` (orchestration) + `scripts/gds/mirror-redact.js` (redaction library) + `.github/workflows/sync-public-mirror.yml` (schedule/transport). Seven decisions carry the weight:
18
+ `scripts/public-mirror-export.js` (orchestration) + `scripts/gds/mirror-redact.js` (redaction library) + `.github/workflows/sync-public-mirror.yml` (schedule/transport; **never built, see the 2026-09-29 correction at the end**). Seven decisions carry the weight:
19
19
 
20
20
  ### 1. Snapshot, not history replay
21
21
  Each run picks the **newest commit whose committer date is ≥ 180 days old** (`pickSnapshotCommit`) and exports that single tree. The mirror accumulates one lagged snapshot commit per run — always ~6 months behind. Rejected replaying/redacting full history: far more code + risk (rewrite every commit) for no gain the "done-when" asks for. Matches the status-mirror precedent (sync current state as commits).
@@ -53,3 +53,7 @@ Transport reuses the ADR-0029/[#741](https://example.com/builders#/task/741) pat
53
53
  - **Share one regex set for redact + detect.** The blind-spot bug above: the gate can't catch what its own bounded rule missed. Rejected — the detector is a separate, stricter substring scan.
54
54
  - **TruffleHog as the only secret check.** Strong but network-dependent and verify-only (no transform); can't run in the exporter's own deterministic self-check or the unit tests. Kept the reusable in-process scrubber as the authoritative gate; TruffleHog may layer on later.
55
55
  - **Write then scan the mirror on disk.** A failed run would leave a dirty (unpushed) tree and risk a partial state. In-memory-then-write makes abort atomic. Rejected.
56
+
57
+ ## Correction (2026-09-29, task 1003405)
58
+
59
+ The workflow named above, `sync-public-mirror.yml`, was never added to the repo, so the weekly schedule described in the transport decision never existed. Publishing the redacted public mirror is a **manual** step: `node scripts/public-mirror-export.js --repo-dir <mirror-checkout> --push`. Automating it would open a new public release channel and needs the owner's approval first; it is captured as idea 1001159 rather than built. The design above is left as originally written.
@@ -1,6 +1,7 @@
1
1
  # ADR 0111 — Instance hosting + domains as a Cloud Bongos module: the `provisioning` module boundary + the self-host / managed split
2
2
 
3
3
  - **Status:** Accepted, **superseded in part by [ADR 0323](0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md)** (2026-09-21) — the module boundary and the enqueue-only trust boundary STAND; the DigitalOcean droplet and `co-tenant` shapes it provisions do not. Customer projects move to a managed platform; DigitalOcean hosts hubs only.
4
+ - **Amended by [ADR 0348](0348-the-web-tier-may-look-read-only-at-what-an-owners-render-key-can-see.md)** (2026-09-29): §2 has one read-only exception — the web tier may ask Render what an owner's own key can see (workspaces, and the web services in one of them), holding the key for that request only. Every write to a cloud account still happens in the runner.
4
5
  - **Status:** §2 STANDS and is now kernel-enforced as of [task 1004176](https://cloudbongos.com/builders#/task/1004176) (2026-09-23). It was, until then, enforced by the code alone — the web tier does only enqueue intents, but both tiers run as the same unix user and the token file was readable by it, so the boundary was a convention ([ADR 0327](0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md) §5). A systemd drop-in (`InaccessiblePaths=/etc/cloudbongos/box.env`, tracked at `scripts/gds/cloudbongos-token-isolation.conf`) now puts an empty mode-000 node over that file in the web tier's own mount namespace. The two tiers still run as the same unix user; the isolation is namespace-based, not ownership-based, and the reasoning for that narrower remedy is in [ADR 0327](0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md) §5.
5
6
  - **Status (original):** Accepted (boundary + split decided with the owner; build is task-pending — see §Consequences for the seeded tasks)
6
7
  - **Date:** 2026-07-03
@@ -106,3 +106,20 @@ Seeded as tasks under this ADR (dependencies noted): pay-on-land (economy + life
106
106
  `needs_rebase` state + reconciler flag (lifecycle + migration) → claim gate (lifecycle/claims)
107
107
  → clawback migration (depends on pay-on-land being live) → hall + `/builder-start` surfacing →
108
108
  tests. See the [#2035](https://example.com/builders#/task/2035) dependency graph.
109
+
110
+ ## Amendment — the CI-unblock exemption (task 1004370, 2026-09-30)
111
+
112
+ The gate assumed an owed rebase is always the builder's to clear. It is not when main's own CI
113
+ is red for a reason outside every branch (2026-09-29: an npm advisory against `undici` tripped
114
+ the audit gate). Then no confirmed task can land, so every builder holding one is refused new
115
+ claims, including the claim on the fix that would let their task land, and release is no exit
116
+ either because a confirmed task has no open claim to release.
117
+
118
+ So the gate now lets exactly one shape of task through: **P1 and `kind=infra`**, the shape a
119
+ CI-unblock is filed in (`isRebaseGateExempt` in `modules/lifecycle/db-claims.js`). Filing one
120
+ needs `task.create`, which is Metic-floored, so the door is no wider than the people who could
121
+ already file the fix. The owed rebases are still reported everywhere, and the gate still
122
+ refuses every other claim. The two other options the task named were not taken: skipping the
123
+ gate while main's last CI run is red would make the claim path depend on reading GitHub check
124
+ state, which is unreadable from this app in places (`checks_unreadable`); and a release-to-ready
125
+ path for confirmed tasks would make the builder throw away graded work to get unstuck.
@@ -2,6 +2,8 @@
2
2
 
3
3
  Date: 2026-08-17 · Status: accepted · Task: 1002735 (walk finding N4, idea 1000708)
4
4
 
5
+ > **Amended by [ADR 0350](0350-the-hub-holds-a-per-project-write-deploy-key-so-a-hosted-upgrade-reaches-github.md):** the hub now also holds a second, WRITABLE per-project key (`cloudbongos-pin-<slug>`), kept outside the checkout, so an upgraded pin reaches the repo without the owner's one-hour token. The pull key described here is unchanged.
6
+
5
7
  ## Context
6
8
 
7
9
  A standalone instance's repo is cloned/pushed **once** with the owner's `repo`-scoped OAuth
@@ -74,7 +74,7 @@ Already shipped in `specialities_catalog`: `owner_kind` (`builder` | `project`),
74
74
 
75
75
  Deliberately separate tasks, because the middle one is where the ruling lives and it should not be a sub-bullet of a schema change:
76
76
 
77
- 1. **Schema + validation** — the offered set on the catalog, the enabled set on the adoption, `validateDraft`, the routes. Refuses a skill the instance does not have.
77
+ 1. **Schema + validation** — the offered set on the catalog, the enabled set on the adoption, `validateDraft`, the routes. Refuses a skill the instance does not have. *Built in task 1004072 (`skills` / `enabled_skills`, specialities_003, `modules/specialities/skills.js`).*
78
78
  2. **The walkthrough** — the adoption flow that presents each skill and takes a decision. The ruling's real deliverable.
79
79
  3. **Injection** — the enabled set reaches the session through the contract the Conductor already injects; a line naming the skills this builder leans on, per [ADR 0296](0296-a-role-speciality-is-data-over-three-existing-surfaces.md)'s pattern of using surfaces that exist.
80
80
 
@@ -0,0 +1,53 @@
1
+ # ADR 0348 — The web tier may look, read-only, at what an owner's Render key can see
2
+
3
+ - **Status:** accepted
4
+ - **Date:** 2026-09-29
5
+ - **Task:** [task 1004352](https://cloudbongos.com/builders#/task/1004352) (goal 1000106 — working area 1, Project creation)
6
+ - **Deciders:** Lars (Archon) chose both decisions in chat on 2026-09-29, from options Claude laid out. Claude wrote the record.
7
+ - **Amends:** [ADR 0111](0111-instance-hosting-provisioning-module.md) §2 ("the internet-facing web process never calls a cloud API") — one narrow, read-only exception
8
+ - **Keeps:** [ADR 0327](0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md) §2 (the key is borrowed, never stored) and §3 (we never destroy an owner's infrastructure) · [ADR 0345](0345-we-host-every-projects-hall-and-its-app-deploys-where-the-owner-chooses.md) (we host the hall; the app goes where the owner chooses)
9
+
10
+ ## Context
11
+
12
+ The setup wizard's app step lets an owner put their app on their own Render account ([task 1004351](https://cloudbongos.com/builders#/task/1004351), [task 1004352](https://cloudbongos.com/builders#/task/1004352)). Two things the owner must see before Create can only come from Render itself:
13
+
14
+ - **Whether the key works.** A refused key discovered after Create is a project with a broken promise on its done screen.
15
+ - **Which workspaces the key reaches.** A Render key belongs to a *user*, and reaches every workspace that user is in — measured on 2026-09-22 at three, one of them another builder's (ADR 0327). The owner has to choose one. Picking the first would be exactly the mistake ADR 0327 exists to prevent.
16
+
17
+ ADR 0111 §2 says the web process never calls a cloud API; the runner does, from the intent queue. The runner can't answer an owner who is still on the page, and keeping the key between a check and a Create would break ADR 0327 §2.
18
+
19
+ There was a second, related problem. Create queues the project's own `provision` run, and a project has one open-intent slot, so a separate `render-standup` request made a moment later collides with it.
20
+
21
+ ## Decision
22
+
23
+ ### 1. One read-only look, on the owner's own key
24
+
25
+ `POST /provisioning/render/lookup` (`modules/provisioning/render-lookup.js`) may call Render from the web tier, and nothing else may. Its limits are the whole exception:
26
+
27
+ - **GET only, two calls:** the workspace list, and the web services in one named workspace. Nothing in it can create, change or delete anything.
28
+ - **The key is the owner's own, held for that one request.** It travels in a POST body, never a URL; it is never stored, logged or sent back. Nothing encrypts it, because nothing keeps it.
29
+ - **Every service in the answer is checked to carry the workspace asked about.** One that doesn't voids the whole answer. This is the runner client's guard (`scripts/gds/render-api.js`), carried here as two GETs because a module may not require that file (ADR 0083).
30
+ - **It is capped per builder** (20 a minute): a wizard needs a handful.
31
+
32
+ What this does *not* change: every write to an owner's Render account still happens in the runner, from the queue, on a key borrowed for one run.
33
+
34
+ ### 2. The key rides the project's own setup run
35
+
36
+ When the wizard sends the key right after Create, and the project's `provision` run holds the open slot, the key is attached to **that** run (`attachToProvision`). It goes in one statement, only onto a run that holds no key yet, and the table's CHECK still refuses a key on a resolved run. After the project is up, the runner sets the app up on Render in the same drain (`afterProvision`) and clears the key whatever happens:
37
+
38
+ - **Project up, app set up:** done.
39
+ - **Project up, app failed:** the run is still a success, since the project is live. The app's failure is recorded on `app_host` and in the run's note.
40
+ - **Project failed:** Render is never called. The key is cleared at once, so a provision retry never carries it into a later run, and the owner connects Render again once the project is live.
41
+
42
+ ## Consequences
43
+
44
+ - The web tier now makes outbound calls to one third party, on user-supplied credentials. That is a new egress path, and the reason decision 1 is drawn so narrowly: read-only, one host, capped, key never kept.
45
+ - A compromised web tier could read keys from lookup requests. It could already read them from the setup request (ADR 0327 §2 says so plainly), so this adds no new exposure of the key.
46
+ - The key waits on the provision run for as long as the project takes to stand up: minutes, and at most the leg's 30-minute limit, after which it is refused and cleared.
47
+ - A resumed wizard draft asks for the key again, because the key never enters the draft.
48
+
49
+ ## Alternatives considered
50
+
51
+ - **Keep the rule strict: no check before Create.** The owner types a workspace id, and a refused key surfaces after Create. The owner rejected this: it fails the task's done-when and leaves the workspace choice to guesswork.
52
+ - **Let the browser call Render directly.** It depends on Render allowing cross-origin calls from our page, which we can't rely on. It would also move the workspace guard somewhere we can't test on the server.
53
+ - **Ask for the key on the project page once the project is live.** Simpler, but not one wizard pass. It stays available as the fallback when an app fails to set up ([task 1004184](https://cloudbongos.com/builders#/task/1004184)).