@1aboveio/skills 0.10.0

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 (397) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +90 -0
  3. package/bin/1aboveio-skills.mjs +18 -0
  4. package/package.json +28 -0
  5. package/runtime/skills/distribution/generated/recipes.json +1189 -0
  6. package/runtime/skills/distribution/scripts/bundles.mjs +280 -0
  7. package/runtime/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
  8. package/skills/backend/airflow-dag-develop/LICENSE +3 -0
  9. package/skills/backend/airflow-dag-develop/SKILL.md +111 -0
  10. package/skills/backend/app-debug/LICENSE +3 -0
  11. package/skills/backend/app-debug/SKILL.md +109 -0
  12. package/skills/backend/app-debug/references/common-errors.md +128 -0
  13. package/skills/backend/python-backend/LICENSE +3 -0
  14. package/skills/backend/python-backend/SKILL.md +326 -0
  15. package/skills/cicd-pipeline/cloud-build/LICENSE +3 -0
  16. package/skills/cicd-pipeline/cloud-build/SKILL.md +707 -0
  17. package/skills/cicd-pipeline/cloud-debug/LICENSE +3 -0
  18. package/skills/cicd-pipeline/cloud-debug/SKILL.md +316 -0
  19. package/skills/cicd-pipeline/cloud-debug/references/build-failures.md +238 -0
  20. package/skills/cicd-pipeline/cloud-debug/references/deploy-failures.md +376 -0
  21. package/skills/cicd-pipeline/cloud-debug/references/pipeline-failures.md +378 -0
  22. package/skills/cicd-pipeline/cloud-deploy/LICENSE +3 -0
  23. package/skills/cicd-pipeline/cloud-deploy/SKILL.md +229 -0
  24. package/skills/cicd-pipeline/cloud-deploy/references/config-templates.md +257 -0
  25. package/skills/cicd-pipeline/docker/LICENSE +3 -0
  26. package/skills/cicd-pipeline/docker/SKILL.md +126 -0
  27. package/skills/cicd-pipeline/google-cloud/LICENSE +3 -0
  28. package/skills/cicd-pipeline/google-cloud/SKILL.md +118 -0
  29. package/skills/cicd-pipeline/google-cloud/references/gcs.md +469 -0
  30. package/skills/cicd-pipeline/google-cloud/references/iam.md +451 -0
  31. package/skills/cicd-pipeline/google-cloud/references/project.md +349 -0
  32. package/skills/cicd-pipeline/google-cloud/references/secrets.md +336 -0
  33. package/skills/cicd-pipeline/google-cloud/references/vpc.md +312 -0
  34. package/skills/cicd-pipeline/google-cloud/scripts/create-sa.sh +36 -0
  35. package/skills/cicd-pipeline/google-cloud/scripts/gcp-config.sh +31 -0
  36. package/skills/cicd-pipeline/google-cloud/scripts/grant-iap.sh +41 -0
  37. package/skills/cicd-pipeline/google-cloud/scripts/setup-secrets.sh +48 -0
  38. package/skills/cicd-pipeline/mergify/LICENSE +3 -0
  39. package/skills/cicd-pipeline/mergify/SKILL.md +138 -0
  40. package/skills/cicd-pipeline/mergify/assets/templates/mergify.yml +237 -0
  41. package/skills/cicd-pipeline/mergify/assets/templates/ruleset.json +46 -0
  42. package/skills/cicd-pipeline/mergify/references/branch-protection.md +277 -0
  43. package/skills/cicd-pipeline/mergify/references/configuration.md +183 -0
  44. package/skills/cicd-pipeline/mergify/references/diagnosis.md +73 -0
  45. package/skills/cicd-pipeline/mergify/references/traps.md +78 -0
  46. package/skills/cicd-pipeline/mergify/references/watch-contract.md +218 -0
  47. package/skills/cicd-pipeline/mergify/scripts/audit-core.mjs +131 -0
  48. package/skills/cicd-pipeline/mergify/scripts/audit.mjs +4 -0
  49. package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +663 -0
  50. package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery.mjs +4 -0
  51. package/skills/cicd-pipeline/podman/LICENSE +3 -0
  52. package/skills/cicd-pipeline/podman/SKILL.md +70 -0
  53. package/skills/cicd-pipeline/podman/agents/openai.yaml +4 -0
  54. package/skills/cicd-pipeline/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
  55. package/skills/cicd-pipeline/podman/assets/templates/podman-service-override.conf +3 -0
  56. package/skills/cicd-pipeline/podman/references/compose-compatibility.md +70 -0
  57. package/skills/cicd-pipeline/podman/references/networking-and-ports.md +74 -0
  58. package/skills/cicd-pipeline/podman/references/rootless-services-and-sockets.md +156 -0
  59. package/skills/cicd-pipeline/podman/references/troubleshooting.md +98 -0
  60. package/skills/engineering/e2e-test/LICENSE +3 -0
  61. package/skills/engineering/e2e-test/SKILL.md +156 -0
  62. package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +272 -0
  63. package/skills/engineering/e2e-test/assets/ci-gates.github.yml +451 -0
  64. package/skills/engineering/e2e-test/assets/e2e-workflow.yml +282 -0
  65. package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
  66. package/skills/engineering/e2e-test/references/authoring/playwright-config.md +71 -0
  67. package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +219 -0
  68. package/skills/engineering/e2e-test/references/authoring/test-skipping.md +44 -0
  69. package/skills/engineering/e2e-test/references/ci-integration.md +121 -0
  70. package/skills/engineering/e2e-test/references/ci-playwright-container.md +280 -0
  71. package/skills/engineering/e2e-test/references/debugging.md +36 -0
  72. package/skills/engineering/e2e-test/references/presentation-sweep.md +131 -0
  73. package/skills/engineering/e2e-test/references/reviewing.md +39 -0
  74. package/skills/engineering/e2e-test/references/route-discovery.md +50 -0
  75. package/skills/engineering/e2e-test/references/route-manifest.md +44 -0
  76. package/skills/engineering/e2e-test/scripts/detect-routes-fastapi.py +290 -0
  77. package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
  78. package/skills/engineering/e2e-test/scripts/post-visual-evidence.mjs +158 -0
  79. package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
  80. package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
  81. package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
  82. package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
  83. package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +148 -0
  84. package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
  85. package/skills/engineering/e2e-test/scripts/presentation-visual.mjs +84 -0
  86. package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +75 -0
  87. package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
  88. package/skills/engineering/engineering-runtime/LICENSE +3 -0
  89. package/skills/engineering/engineering-runtime/SKILL.md +10 -0
  90. package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
  91. package/skills/engineering/engineering-runtime/coherence/workflow.json +553 -0
  92. package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
  93. package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
  94. package/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
  95. package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
  96. package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
  97. package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
  98. package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
  99. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +576 -0
  100. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +166 -0
  101. package/skills/engineering/ensure-coverage/LICENSE +3 -0
  102. package/skills/engineering/ensure-coverage/SKILL.md +136 -0
  103. package/skills/engineering/ensure-coverage/evals/evals.json +125 -0
  104. package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +91 -0
  105. package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +83 -0
  106. package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
  107. package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
  108. package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
  109. package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +25 -0
  110. package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
  111. package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +87 -0
  112. package/skills/engineering/ensure-coverage/references/depth/test-smells.md +23 -0
  113. package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +164 -0
  114. package/skills/engineering/ensure-coverage/references/enforcement/hooks.md +85 -0
  115. package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +109 -0
  116. package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +33 -0
  117. package/skills/engineering/ensure-coverage/references/presentation/axis.md +78 -0
  118. package/skills/engineering/ensure-coverage/references/presentation/runner-contract.md +74 -0
  119. package/skills/engineering/ensure-coverage/references/process/audit-mode.md +33 -0
  120. package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
  121. package/skills/engineering/ensure-coverage/references/process/review-contract-template.md +119 -0
  122. package/skills/engineering/ensure-coverage/references/process/scope-class.md +178 -0
  123. package/skills/engineering/ensure-coverage/references/process/test-strategy.md +55 -0
  124. package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +45 -0
  125. package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +93 -0
  126. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +178 -0
  127. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +101 -0
  128. package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +358 -0
  129. package/skills/engineering/ensure-coverage/scripts/coverage-checklist.mjs +494 -0
  130. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +663 -0
  131. package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
  132. package/skills/engineering/ensure-coverage/scripts/evidence-block.mjs +367 -0
  133. package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +269 -0
  134. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
  135. package/skills/engineering/ensure-coverage/scripts/package-lock.json +76 -0
  136. package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
  137. package/skills/engineering/ensure-coverage/scripts/scope-class.mjs +554 -0
  138. package/skills/engineering/harness-runtime/LICENSE +3 -0
  139. package/skills/engineering/harness-runtime/SKILL.md +18 -0
  140. package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
  141. package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
  142. package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
  143. package/skills/engineering/harness-runtime/contracts.md +15 -0
  144. package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
  145. package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
  146. package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
  147. package/skills/engineering/harness-runtime/index.mjs +767 -0
  148. package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
  149. package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
  150. package/skills/engineering/harness-runtime/references/model-catalog-seed.json +159 -0
  151. package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
  152. package/skills/engineering/implement-and-pr/LICENSE +3 -0
  153. package/skills/engineering/implement-and-pr/SKILL.md +176 -0
  154. package/skills/engineering/implement-and-pr/references/ci-iteration.md +10 -0
  155. package/skills/engineering/implement-and-pr/references/closeout.md +27 -0
  156. package/skills/engineering/implement-and-pr/references/contract-complete-fix-rounds.md +34 -0
  157. package/skills/engineering/implement-and-pr/references/evidence-rules.md +39 -0
  158. package/skills/engineering/implement-and-pr/references/incremental-plan.md +16 -0
  159. package/skills/engineering/implement-and-pr/references/self-review.md +23 -0
  160. package/skills/engineering/implement-and-pr/references/tdd-mode.md +18 -0
  161. package/skills/engineering/resolve-issues/LICENSE +3 -0
  162. package/skills/engineering/resolve-issues/SKILL.md +167 -0
  163. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +448 -0
  164. package/skills/engineering/resolve-issues/references/breaker.md +82 -0
  165. package/skills/engineering/resolve-issues/references/deliverables.md +27 -0
  166. package/skills/engineering/resolve-issues/references/delivery.md +108 -0
  167. package/skills/engineering/resolve-issues/references/evidence-lane.md +21 -0
  168. package/skills/engineering/resolve-issues/references/exact-head-ci.md +287 -0
  169. package/skills/engineering/resolve-issues/references/fan-out.md +33 -0
  170. package/skills/engineering/resolve-issues/references/finalization.md +68 -0
  171. package/skills/engineering/resolve-issues/references/guarantees.md +10 -0
  172. package/skills/engineering/resolve-issues/references/high-risk.md +29 -0
  173. package/skills/engineering/resolve-issues/references/incidents/848/README.md +156 -0
  174. package/skills/engineering/resolve-issues/references/intake.md +86 -0
  175. package/skills/engineering/resolve-issues/references/integration-gate.md +53 -0
  176. package/skills/engineering/resolve-issues/references/interference.md +87 -0
  177. package/skills/engineering/resolve-issues/references/loop.md +134 -0
  178. package/skills/engineering/resolve-issues/references/model-catalog.md +9 -0
  179. package/skills/engineering/resolve-issues/references/postmortem.md +27 -0
  180. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +41 -0
  181. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +48 -0
  182. package/skills/engineering/resolve-issues/references/pre-flight.md +41 -0
  183. package/skills/engineering/resolve-issues/references/regression-checklist.md +26 -0
  184. package/skills/engineering/resolve-issues/references/run-state.md +288 -0
  185. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +48 -0
  186. package/skills/engineering/resolve-issues/references/spawn-contract.md +96 -0
  187. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +40 -0
  188. package/skills/engineering/resolve-issues/references/why.md +653 -0
  189. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +49 -0
  190. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +721 -0
  191. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +962 -0
  192. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +220 -0
  193. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +420 -0
  194. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +256 -0
  195. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +168 -0
  196. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
  197. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +62 -0
  198. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +191 -0
  199. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +413 -0
  200. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +332 -0
  201. package/skills/engineering/resolve-issues/scripts/finalize.mjs +488 -0
  202. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +3307 -0
  203. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +16 -0
  204. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +51 -0
  205. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +17 -0
  206. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +166 -0
  207. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +92 -0
  208. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +73 -0
  209. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +159 -0
  210. package/skills/engineering/resolve-issues/scripts/interference.mjs +427 -0
  211. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
  212. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +419 -0
  213. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +909 -0
  214. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +322 -0
  215. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +415 -0
  216. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +697 -0
  217. package/skills/engineering/resolve-issues/scripts/report.mjs +494 -0
  218. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +172 -0
  219. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +79 -0
  220. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +334 -0
  221. package/skills/engineering/resolve-issues/scripts/run-state.mjs +4784 -0
  222. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +395 -0
  223. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +290 -0
  224. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +170 -0
  225. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +293 -0
  226. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +197 -0
  227. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +127 -0
  228. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +893 -0
  229. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +829 -0
  230. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +290 -0
  231. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +80 -0
  232. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +102 -0
  233. package/skills/engineering/resolve-release/LICENSE +3 -0
  234. package/skills/engineering/resolve-release/SKILL.md +112 -0
  235. package/skills/engineering/resolve-release/references/assembly.md +137 -0
  236. package/skills/engineering/resolve-release/references/auto-when-green.md +56 -0
  237. package/skills/engineering/resolve-release/references/candidate.md +167 -0
  238. package/skills/engineering/resolve-release/references/exposure.md +178 -0
  239. package/skills/engineering/resolve-release/references/handoff.md +24 -0
  240. package/skills/engineering/resolve-release/references/postmortem.md +230 -0
  241. package/skills/engineering/resolve-release/references/preflight.md +207 -0
  242. package/skills/engineering/resolve-release/references/principles.md +94 -0
  243. package/skills/engineering/resolve-release/references/regression-checklist.md +36 -0
  244. package/skills/engineering/resolve-release/references/related-skills.md +12 -0
  245. package/skills/engineering/resolve-release/references/routing.md +149 -0
  246. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +285 -0
  247. package/skills/engineering/resolve-release/references/versioning.md +202 -0
  248. package/skills/engineering/resolve-release/references/why.md +53 -0
  249. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +389 -0
  250. package/skills/engineering/resolve-release/scripts/build-changes.mjs +209 -0
  251. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +407 -0
  252. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +904 -0
  253. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +81 -0
  254. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +612 -0
  255. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +135 -0
  256. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +161 -0
  257. package/skills/engineering/resolve-release/scripts/doctrine.mjs +106 -0
  258. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +522 -0
  259. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +659 -0
  260. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +1014 -0
  261. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +526 -0
  262. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +169 -0
  263. package/skills/engineering/resolve-release/scripts/green-gate.mjs +599 -0
  264. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +752 -0
  265. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +56 -0
  266. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +1538 -0
  267. package/skills/engineering/resolve-release/scripts/postmortem.mjs +381 -0
  268. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +498 -0
  269. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +326 -0
  270. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +272 -0
  271. package/skills/engineering/resolve-release/scripts/report.mjs +417 -0
  272. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +114 -0
  273. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +238 -0
  274. package/skills/engineering/resolve-release/scripts/review-packet.mjs +503 -0
  275. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +263 -0
  276. package/skills/engineering/resolve-release/scripts/version-assert.mjs +339 -0
  277. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +485 -0
  278. package/skills/engineering/resolve-release/scripts/version.mjs +1199 -0
  279. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +449 -0
  280. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +21 -0
  281. package/skills/engineering/resolve-release/vendor/README.md +60 -0
  282. package/skills/engineering/resolve-release/vendor/acorn.mjs +6233 -0
  283. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +21 -0
  284. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +341 -0
  285. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +70 -0
  286. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +2 -0
  287. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +1 -0
  288. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +7 -0
  289. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
  290. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +2033 -0
  291. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +2033 -0
  292. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +7 -0
  293. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +1 -0
  294. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +2 -0
  295. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +1 -0
  296. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +2 -0
  297. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +1 -0
  298. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +2 -0
  299. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
  300. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +49 -0
  301. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +21 -0
  302. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +5 -0
  303. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +549 -0
  304. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +549 -0
  305. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +2 -0
  306. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +1 -0
  307. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +2 -0
  308. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +1 -0
  309. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +36 -0
  310. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +47 -0
  311. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +82 -0
  312. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +11 -0
  313. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +22 -0
  314. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +21 -0
  315. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
  316. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
  317. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +11 -0
  318. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +25 -0
  319. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  320. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +85 -0
  321. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +85 -0
  322. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +2 -0
  323. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +1 -0
  324. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +2 -0
  325. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +1 -0
  326. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +20 -0
  327. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +20 -0
  328. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +2 -0
  329. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +1 -0
  330. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +2 -0
  331. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +1 -0
  332. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +61 -0
  333. package/skills/engineering/review-pr/LICENSE +3 -0
  334. package/skills/engineering/review-pr/SKILL.md +123 -0
  335. package/skills/engineering/review-pr/references/adversarial-reviewer-prompt.md +42 -0
  336. package/skills/engineering/review-pr/references/code-correctness.md +5 -0
  337. package/skills/engineering/review-pr/references/contract-freshness.md +9 -0
  338. package/skills/engineering/review-pr/references/coordination.md +18 -0
  339. package/skills/engineering/review-pr/references/domain-hazards.md +123 -0
  340. package/skills/engineering/review-pr/references/finding-themes.md +7 -0
  341. package/skills/engineering/review-pr/references/github-posting.md +98 -0
  342. package/skills/engineering/review-pr/references/golden-path-smoke.md +5 -0
  343. package/skills/engineering/review-pr/references/incremental-output.md +16 -0
  344. package/skills/engineering/review-pr/references/inputs-and-discovery.md +31 -0
  345. package/skills/engineering/review-pr/references/output-format.md +99 -0
  346. package/skills/engineering/review-pr/references/over-mock-screen.md +7 -0
  347. package/skills/engineering/review-pr/references/promotion-prs.md +16 -0
  348. package/skills/engineering/review-pr/references/re-review.md +18 -0
  349. package/skills/engineering/review-pr/references/review-method.md +199 -0
  350. package/skills/engineering/review-pr/references/review-mode.md +30 -0
  351. package/skills/engineering/review-pr/references/review-posture.md +53 -0
  352. package/skills/engineering/review-pr/references/round1-depth.md +62 -0
  353. package/skills/engineering/review-pr/references/scripts.md +17 -0
  354. package/skills/engineering/review-pr/references/workflow.md +16 -0
  355. package/skills/engineering/review-pr/schemas/findings.schema.json +282 -0
  356. package/skills/engineering/review-pr/scripts/finding-contract.mjs +285 -0
  357. package/skills/engineering/review-pr/scripts/post-review.mjs +405 -0
  358. package/skills/engineering/review-pr/scripts/pr-context.mjs +207 -0
  359. package/skills/engineering/review-pr/scripts/scan-diff.mjs +365 -0
  360. package/skills/engineering/review-pr/scripts/theme-contract.mjs +57 -0
  361. package/skills/engineering/smoke/LICENSE +3 -0
  362. package/skills/engineering/smoke/SKILL.md +131 -0
  363. package/skills/engineering/smoke/assets/smoke.manifest.example.json +53 -0
  364. package/skills/engineering/smoke/references/manifest.md +192 -0
  365. package/skills/engineering/smoke/scripts/smoke.mjs +713 -0
  366. package/skills/fullstack/better-auth/LICENSE +3 -0
  367. package/skills/fullstack/better-auth/SKILL.md +601 -0
  368. package/skills/fullstack/better-auth/references/feishu-api.md +270 -0
  369. package/skills/fullstack/monorepo/LICENSE +3 -0
  370. package/skills/fullstack/monorepo/SKILL.md +465 -0
  371. package/skills/fullstack/nextjs-fullstack/LICENSE +3 -0
  372. package/skills/fullstack/nextjs-fullstack/SKILL.md +210 -0
  373. package/skills/fullstack/nextjs-fullstack/conventions.md +318 -0
  374. package/skills/fullstack/nextjs-fullstack/frontend-conventions.md +61 -0
  375. package/skills/fullstack/nextjs-fullstack/nextjs16.md +287 -0
  376. package/skills/fullstack/nextjs-fullstack/server-actions.md +409 -0
  377. package/skills/fullstack/prisma-setup/LICENSE +3 -0
  378. package/skills/fullstack/prisma-setup/SKILL.md +180 -0
  379. package/skills/fullstack/prisma-setup/nextjs.md +258 -0
  380. package/skills/fullstack/prisma-setup/turborepo.md +301 -0
  381. package/skills/fullstack/shadcn/LICENSE +3 -0
  382. package/skills/fullstack/shadcn/SKILL.md +119 -0
  383. package/skills/fullstack/shadcn/assets/shadcn-small.png +0 -0
  384. package/skills/fullstack/shadcn/assets/shadcn.png +0 -0
  385. package/skills/fullstack/shadcn/cli.md +411 -0
  386. package/skills/fullstack/shadcn/customization.md +224 -0
  387. package/skills/fullstack/shadcn/evals/evals.json +90 -0
  388. package/skills/fullstack/shadcn/mcp.md +101 -0
  389. package/skills/fullstack/shadcn/rules/base-vs-radix.md +323 -0
  390. package/skills/fullstack/shadcn/rules/component-selection.md +67 -0
  391. package/skills/fullstack/shadcn/rules/composition.md +195 -0
  392. package/skills/fullstack/shadcn/rules/data-table.md +201 -0
  393. package/skills/fullstack/shadcn/rules/forms.md +255 -0
  394. package/skills/fullstack/shadcn/rules/icons.md +103 -0
  395. package/skills/fullstack/shadcn/rules/styling.md +167 -0
  396. package/skills/fullstack/zod-v4/LICENSE +3 -0
  397. package/skills/fullstack/zod-v4/SKILL.md +287 -0
@@ -0,0 +1,288 @@
1
+ # Run-state manifest (survive the session, mechanize resume)
2
+
3
+ The orchestrators (`resolve-issues`, `resolve-release`) hold load-bearing state that, without this file, lives only in conversation: the human-confirmed model set (or, for a release, the authorization envelope), the unit roster and each unit's position in the loop, the iteration counter, the SHA an audit was built against, the release step in flight. A session that dies mid-run loses all of it — and the resume tables in those skills then have to *infer* state from artifacts, which is exactly how a stale audit gets trusted or a pre-flight gate gets re-asked (or silently skipped). The manifest fixes that: **one JSON file per run, updated at every state transition, read first on any resume.**
4
+
5
+ **Read/write/validate through [`scripts/run-state.mjs`](../scripts/run-state.mjs), never hand-roll the JSON.** Four skills update this manifest; hand-rolling the read-modify-write in each invites schema drift and transcription errors on the one artifact whose job is reliable resume. The script single-sources the path resolution, the `updatedAt` stamping, the atomic write, and the load-bearing invariants (the model-diversity guard, the status/step enums, byte-for-byte preservation of existing IDs/markers/history). It also invokes `engineering-runtime`'s public read-only Workflow coherence verifier before `init`, `resume`, every manifest write, and reads that authorize a spawn or release attempt. The verifier derives the invoked skill's authenticated transitive skill/runtime/generated identity closure; drift in that closure fails closed with member findings, while an uninvoked sibling such as `resolve-release` cannot block a `resolve-issues` transition. A malformed closure or verdict still fails before state is created, resumed or advanced and reports the generated dependency-first repair recipe without executing it. Pure inspection remains available so repair can be diagnosed. Provider facts observed while a real dependency is incoherent go through the [terminal evidence journal](terminal-evidence-journal.md), which never writes this manifest; package/npm repair remains #996's contract. Run `run-state.mjs help`; treat the script as the source of truth for what each command validates. This doc is the **why** behind the fields, and the invariants the script cannot explain to a reader.
6
+
7
+ ## Where
8
+
9
+ `${RESOLVER_RUN_DIR:-${TMPDIR:-/tmp}/resolver-runs}/<run-slug>.json` — **outside the repo**, in the system temp dir. It is ephemeral operational state, not a deliverable: no `git status` clutter, no accidental commit, no collision with the run's branch switches. Because it lives outside the working tree, **print the resolved path in the resume summary and the handoff report** (`run-state.mjs path <slug>`) — the path is how a human or a resuming session finds it.
10
+
11
+ **When the slug itself is what got lost, `run-state.mjs list`.** Every other read command takes a `<slug>`, so the session that dies holding the name leaves its successor a directory of manifests and no way in — measured while adding the command: 246 manifests on one machine, none of them enumerable. `list` renders them newest-activity-first with the facts a chooser needs (skill, target branch, unit tally, age), defaulting to the last 72h with `--all` for everything and the hidden count always reported. A manifest it cannot parse is **listed and marked unreadable, never dropped** — the run you cannot read is the one most likely to need recovering, so hiding it would break the tool exactly where it is reached for.
12
+
13
+ **Once you have the slug, `run-state.mjs resume <slug>`.** The recovery command: one screen carrying the `progress` render (reused, never re-rendered), what was **in flight** when the session died, the **next action** for each unit, the pre-flight facts a resumed run **inherits rather than re-asks** (models + efforts, target branch, delivery mode/provider, `enqueueTrigger`, `autonomy`, workspace, `skillsRoot`), and the **artifacts on disk** — the manifest path, and each unit's branch and PR where the manifest records them. Two rules make it a recovery tool rather than a pretty-printer. **The two in-flight situations stay distinct** — `in-progress` (a producer/fix spawn was underway) and `merge-ready` with no terminal delivery outcome (reviewed, never delivered) need *opposite* moves, and one merged list gets one of them wrong. And **where recorded state does not determine an action it says "cannot tell from state"** instead of inventing one: the wrong step gets taken, while the honest gap gets investigated. Exit **0** always when a report is printed (a stuck run included — the verdict is in the rows), **3** when there is no manifest, **1** when there *is* one and it could not be parsed: "could not look" is never reported as "nothing to do". → [why](why.md#recovering-a-dead-run-is-a-command-not-archaeology)
14
+
15
+ At the terminal phase, `next`/`resume` first emit `run-state.mjs reconcile-contained-unit-prs <slug>` when a delivered combined component has distinct unit PRs recorded in its publication evidence. Once those PRs have terminal reconciliation observations, they emit `run-state.mjs finalize <slug>`. They do not render branch restoration or workspace reap as separate operations: the finalizer owns, executes, validates, and atomically records both cleanup steps.
16
+
17
+ **Act through `run-state.mjs next <slug>`, never by reconstructing a CLI from this
18
+ document.** `next --json` is the executable current-phase contract: versioned data with
19
+ separate `inspections[]`, `mutations[]`, and `blocked[]`. Every emitted operation carries
20
+ an exact argv array (no shell or placeholder syntax), absolute cwd, expected exit codes,
21
+ and the transition that result authorizes. The human renderer is a pure view of the same
22
+ object. `resume` embeds and renders that object directly; its older summary rows are
23
+ compatibility narration, not a second action derivation.
24
+
25
+ Mutations are phase-gated. If operation B requires operation A to exit 0, `next` first
26
+ emits A and puts B under blocked. After A runs, derive again with cumulative executor
27
+ evidence as the optional second JSON argument, or pipe that object through `--stdin`:
28
+
29
+ ```sh
30
+ node run-state.mjs next <slug> '{"operationResults":{"exact-head-ci:#885":0}}' --json
31
+ printf '%s' "$OBSERVATION_JSON" | node run-state.mjs resume <slug> --stdin --json
32
+ ```
33
+
34
+ The accepted top-level keys are `operationResults`, `deliveryAttempts`,
35
+ `deliveryOutcomes`, and `integrationVerdicts`. Keep the object cumulative for the current
36
+ live chain. Repository identity, checkout/publication state, and merge authorization are
37
+ always re-probed/read from the manifest and cannot be overridden. Completed operations
38
+ disappear from the next result, so the caller never repeats exact-head choreography,
39
+ delivery, branch restoration, reap, or finalization after reporting it complete.
40
+
41
+ Provider results follow the same rule: delivery attempt recording requires the provider's
42
+ actual outcome/ack/reason payload, and terminal merged recording requires
43
+ `combine-and-verify delivered` exit 0. Missing state, unreadable probes, a dirty or
44
+ unpublished checkout, unresolved queue mechanics, absent merge authorization, and absent
45
+ exact-head evidence all produce blocked rows and no mutating argv.
46
+
47
+ The renderer consumes only validated facts: `repository` (`owner/name`),
48
+ `units[].exactHeadCi.{requestPath,artifactPath}`, and unit/component
49
+ `integrationVerdictPath` values (absolute paths). It invokes first-party scripts directly
50
+ for exact-head CI, delivery watch/proof, manifest outcome writes, workspace reap, and final
51
+ progress/post-mortem. Typed `scopeDecision.issueDisposition`/`prDisposition` values own
52
+ issue and PR closure; unsupported remembered flags such as `gh issue close --comment-file`
53
+ never enter the contract. This is issue #885's fmm-express #830 incident boundary.
54
+
55
+ **Temp is temp — design for it vanishing.** `${TMPDIR:-/tmp}` is cleared on reboot, may be reaped after days, and is **host-local** (a cross-machine or cloud resume won't find it). So a missing manifest is a *normal* state, not an error — `read`/`validate` exit **3**, and the caller falls back to the skill's entry-points table, which **infers state from artifacts** (open/merged PRs, the epic roster, the dated audit doc + its base SHA) and re-applies the staleness guards. The manifest is an *optimization* over that archaeology (rule 3), never the sole source of truth. For a long multi-day run where losing it mid-flight would hurt, or for cross-host/cloud resume, point the run at a durable directory (`RESOLVER_RUN_DIR`); only the path changes.
56
+
57
+ **Completion does live here.** The dedicated [finalization transition](finalization.md) writes immutable `finalization` evidence and its generated handoff only after live checks pass. The optional [post-mortem](postmortem.md) remains a read-only diagnostic and writes nothing.
58
+
59
+ ## Shape (core)
60
+
61
+ The script validates the full schema; this is the shape a reader needs, with the exhaustive deep-audit arrays (`reviewHistory`, `fixRounds`) elided — those are produced and validated by the `record-*` commands, not hand-written.
62
+
63
+ ```json
64
+ {
65
+ "schemaVersion": 2,
66
+ "runSlug": "epic-42-billing",
67
+ "skill": "resolve-issues",
68
+ "createdAt": "…", "updatedAt": "…",
69
+ "models": {
70
+ "implementation": "<model id — the one implementer every unit runs on>",
71
+ "implementationEffort": "max",
72
+ "review": "<model id — MUST differ from implementation>"
73
+ },
74
+ "targetBranch": "dev",
75
+ "originalBranch": "<branch the checkout was on at pre-flight>",
76
+ "skillsRoot": "/abs/path/to/skills-root",
77
+ "iteration": 2,
78
+ "auditBaseSha": "abc1234",
79
+ "epic": "#<epic-issue>",
80
+ "mergeShippable": false,
81
+ "inFlightCap": 4,
82
+ "workspaceRoot": "/abs/path/to/<repo>-workspaces/<slug>",
83
+ "components": [
84
+ { "id": "cluster-a", "units": ["#879"], "candidate": { "state": "assembling | frozen | authorized", "generation": 1, "updates": [], "frozen": null, "authorizations": [], "reopens": [] }, "authorizationBoundary": null, "pr": "#<combined-or-unit-pr>", "verdict": "ALIVE", "delivery": { "pr": 1001, "generation": 1, "authorizedHeadSha": "…", "mode": "queue", "provider": "mergify", "attempts": [], "observations": [], "watch": null, "queueExecution": null, "outcome": null, "outcomeAt": null, "mergedSha": null, "mergedAt": null, "blockedOn": null } }
85
+ ],
86
+ "units": [
87
+ {
88
+ "id": "#<issue>", "status": "in-progress", "stateVersion": 2,
89
+ "pr": "#<pr>", "branch": "issue-<n>-<slug>", "pushedSha": "<head on the remote — what unblocks this unit's dependents>",
90
+ "workspacePath": "/abs/path/to/<repo>-workspaces/<slug>/<unit>",
91
+ "dependsOn": [{ "unit": "#879", "source": "symbol | premise" }],
92
+ "sharedSurfaces": ["app/settings/page.tsx"],
93
+ "contractRevision": { "sha": "…", "refs": ["docs/adr/<design>.md"], "source": "pr:#<contract-pr>", "supersedesReviewThroughRound": 0 },
94
+ "reviewedContractSha": null, "lastReviewedSha": "<head the last verdict saw>",
95
+ "lastVerdict": "NEEDS_CHANGES", "reviewRounds": 2,
96
+ "rounds": [ { "round": 1, "verdict": "NEEDS_CHANGES", "headSha": "…", "changedSurfaces": ["runtime", "tests"], "reviewSubject": "code", "themeIds": ["…"], "authorizationBoundary": { "kind": "head", "value": "…" }, "scope": "delta", "at": "…" },
97
+ { "round": 2, "verdict": "PASS", "headSha": "…", "changedSurfaces": ["evidence"], "reviewSubject": "evidence", "themeIds": [], "evidenceClasses": ["stale-locator"], "authorizationBoundary": { "kind": "head", "value": "…" }, "at": "…" } ],
98
+ "reviewHistory": [], "fixRounds": [],
99
+ "highRisk": true, "implementationModel": "<diff author, when ≠ models.implementation>",
100
+ "scopeClass": "surface-bearing | no-surface", "scopeClassReason": "<derived by the classifier>",
101
+ "deliveryRef": { "componentId": "cluster-a", "generation": 1 },
102
+ "breaker": null, "blocker": null
103
+ }
104
+ ],
105
+ "decisions": [ { "question": "refund-window semantics", "status": "pending-human" } ],
106
+ "manifestMigrations": [
107
+ {
108
+ "migrationId": "resolver-manifest-v1-to-v2-phase-aware-component-evidence",
109
+ "sourceVersion": 1, "targetVersion": 2, "migratedAt": "…",
110
+ "sourceManifestSha256": "…",
111
+ "transformedContracts": []
112
+ }
113
+ ]
114
+ }
115
+ ```
116
+
117
+ ### Whole-manifest and per-unit migration are explicit and separate
118
+
119
+ Every newly initialized run carries `schemaVersion: 2`. A manifest with no marker is read as valid legacy schema version 1, with an actionable warning; explicit unknown future versions fail closed. Generic `set`/`merge`/`upsert-unit` writes must preserve both `schemaVersion` and `manifestMigrations` byte-for-byte. They cannot promote a run by adding the marker or rewrite its provenance.
120
+
121
+ The supported whole-manifest transition is:
122
+
123
+ ```sh
124
+ node run-state.mjs migrate-manifest <slug> --from 1 --to 2
125
+ ```
126
+
127
+ The command validates the declared v1 source, constructs the complete v2 candidate in memory, validates that candidate, and only then atomically replaces the file. Re-entering the same completed step validates the current manifest and leaves its bytes unchanged. Unknown sources, future targets, and skipped steps are refused with the supported path in the error.
128
+
129
+ Migration provenance is append-only and records the migration id, source and target versions, writer timestamp, source-manifest SHA-256, and every component authorization contract inspected. PR-head evidence, required-check plans, publish-only evidence, and queue-execution evidence are separate rows with `preserved` or `unavailable` status. An old terminal CI record without the newer plan/evidence fields is retained in `preservedAuthorization`, but removed from live candidate authority; an actively authorized candidate returns to `frozen`. Missing evidence is never synthesized as success.
130
+
131
+ This does not promote units. Current unit records separately carry `stateVersion: 2`; a versionless unit is legacy. The script owns that reconciliation: deletion and unit migration are never a side effect of an ordinary write (`set`/`merge`/`upsert-unit` preserve every existing ID, marker, `reviewHistory`, and `fixRounds` byte-for-byte), and `migrate-unit --version 1` remains the only path that promotes one versionless unit. A run may execute `migrate-manifest` and `migrate-unit` in either required sequence because they govern different schema boundaries.
132
+
133
+ ### Release variant (`skill: "resolve-release"`)
134
+
135
+ `resolve-release` is a serialized outward-facing state machine, not a model-driven delivery loop, so its run carries a different core than `models`/`units` — an `envelope` (the pre-flight authorization block, the analogue of `models`; a resumed release inherits it, a new release re-confirms), a `step`, and `release`/`verification`/`rollback` records. The fields the script cannot explain:
136
+ The canonical release vocabulary is exported by `scripts/release-state-contract.mjs`.
137
+ Lifecycle validation, checkpoints, post-mortems, release gates, and durable evidence consume
138
+ that registry for identity fields, verdict aliases, verification fields, and terminal states.
139
+
140
+ ### Machine-generated release history
141
+
142
+ Every canonical release state write records `releaseHistory.events[]` through `run-state.mjs`.
143
+ State events are derived from the before/after manifest and carry the prior/new `step`, prior/new
144
+ attempt state, writer timestamp, stable sequence/id, and artifact locators. Generic `set`/`merge`
145
+ and `record-release-attempt` share that append path, so one mutation produces one event; an
146
+ idempotent no-op produces none. Generic writers cannot rewrite the history, and event `id`,
147
+ `sequence`, and `at` are writer-owned even when `--now` is used for legacy manifest bookkeeping.
148
+
149
+ Outward actions use `run-state.mjs record-release-event <slug> <json>` twice: `kind: "intent"`
150
+ immediately before the action and `kind: "result"` after observing it. The contract-owned subjects
151
+ are `tag`, `candidate`, `traffic`, `processing-control`, `github-release`, and `metadata-delivery`;
152
+ intent/result share one `correlationId`, results carry `outcome`, and both carry artifact locators
153
+ plus the writer-derived current state snapshot.
154
+ One unresolved intent per subject is allowed because the release lane is serialized. Re-recording
155
+ the same correlated event is a byte-preserving resume-safe no-op; conflicting evidence fails closed.
156
+
157
+ Artifact locators are typed contract evidence, not arbitrary strings. Each subject has an allowed
158
+ type set across canonical manifest fields, Git tags and SHAs, platform revisions/services, HTTPS
159
+ URLs, and GitHub pull-request references. The writer rejects unknown fields/types, cross-subject
160
+ types, traversal/control characters, local absolute paths, oversized locators, and evidence that
161
+ contradicts the manifest's repository, service, version, tag, revision, SHA, URL, or PR identity.
162
+ Every outward-action identity-bearing locator must equal one value in that subject/type's explicit
163
+ manifest-derived set; a grammatically valid value, a value belonging to another subject, or an
164
+ allowed type with no canonical value fails closed. Multiple identities are explicit: traffic may
165
+ name the candidate or previous revision, and tag actions may name the recorded RC or final tag.
166
+ URLs use exact string identity: host case, default ports, trailing slashes, percent spelling, and
167
+ query order are not normalized. Structural safety recursively decodes only the path and rejects
168
+ malformed encoding, encoded separators/backslashes, traversal or controls at any depth, and Unicode
169
+ separator/dot lookalikes; safe query values such as an encoded slash remain ordinary data. Historical
170
+ machine-generated state-transition tag artifacts retain grammar validation because the current
171
+ attempt tag may legitimately differ from the immutable prior event; action artifacts get no such
172
+ exception.
173
+
174
+ The manifest retains 64 detailed events. Older events roll into an explicit truncation summary:
175
+ sequence/time range, last state boundary, kind/subject/outcome counts, completed/failed wait totals,
176
+ and at most one outstanding intent per subject. Postmortem reconstructs timeline, wait, and failure
177
+ intervals from this state alone; malformed or relationally inconsistent history fails closed. A
178
+ separate digest-protected replay ledger retains canonical intent/result payload evidence for at most
179
+ 64 distinct correlations over the entire run. Entries never evict or expire: after the 64th identity,
180
+ a new correlation is refused and the operator starts a new release run. Stable/conflicting replay
181
+ remains decidable for every existing completed or unresolved action across repeated truncations.
182
+
183
+ - `step` — the release step in flight (`intake | merge | promote | deploy | validate | expose | verify | discard | rollback | done`), the resume key a dead session re-enters at (after re-verifying merge-readiness against the tree). **`validate` and `expose` are split for the same reason `discard` and `rollback` are:** the two sides of the traffic shift differ in blast radius, and the recovery for one destroys production in the other. At `validate` the candidate serves nobody and deleting it is free (**`discard`**); at `expose` or later that same revision may be serving every user (**`rollback`** restores production after traffic moved). `expose` means "a shift was started and may or may not have completed" — treat it as unknown and observe the live traffic split first, since the manifest write can lag the outward action by one crash. Collapsing either pair makes a caught bug indistinguishable from an outage.
184
+ - `release` — what the version cut and tag did. `tagged`/`tagSha` record whether the immutable tag exists yet (created after verification by default). **`burned`** marks a version whose tag reached the remote but whose release was rolled back — the retry takes the next patch and never reuses it. Cut and tag are idempotent against the tree (`version.mjs` no-ops on a same-SHA re-tag and exits 0 — not 3 — on an already-cut version), so the manifest makes the answer cheap while the tree makes it true (rule 3). **`cutCommit` is the one part the tree cannot answer:** the CHANGELOG cut is idempotent, the hand-applied version-file bumps beside it (`package.json`, `VERSION`, chart tags) are not, so a resume with a non-null `cutCommit` skips the bump. `candidateSha` is the pinned release candidate — a resumed release promotes *this* SHA, never the integration branch's tip. `backMerge` is the post-release `main → dev` merge, the floor the *next* release's candidate must descend from. **`candidateRevision`/`candidateUrl` are the most perishable entries:** between build and traffic shift only the manifest records that a 0%-traffic revision exists, and a resumed run reads them to finish validating or delete it. **`candidateIdentity` says *which* candidate they are:** the tuple the running process attested (`sourceSha`, `revision`, `imageDigest`) plus `imageDigestSource`, the `tag`/`url` it was read from, and the `guarantee`/`weakenings` it was established under (`resolve-release` principle 12, written by `candidate-identity.mjs attest`). A resumed run compares against the tuple rather than re-deriving identity from an image string. **Every field is populated in every branch that accepts, weakened ones included** — `imageDigestSource` is `attestation` or `candidate-revision-spec`, and under the no-attestation weakening `imageDigest` holds the candidate revision's configured digest (`--candidate-image-digest`) rather than `null`, because step 4b's fallback compares against this field and a null there is a check that silently does not happen.
185
+ - **`envelope.version` is omitted entirely for a `dev`/staging release**, which is unversioned and identified by `shippedSha`. A resumed release inherits the confirmed bump rather than recomputing it — recomputation after more PRs land would silently pick a different version than the one authorized.
186
+ - **`envelope.repo` and `envelope.service` — the product identity for the release-lease scan.** `repo` is the repo's `owner/name` (e.g. `acme/web-app`). `service` is the deployed platform service name (e.g. the Cloud Run service), when applicable. These drive `run-state.mjs check-release-lease-scoped`, which lists held or ambiguous release attempts for the same product across run slugs before an rc is minted (#819). A manifest without them is still listed by the scan, but the match is reported as `unknown` and requires operator review.
187
+
188
+ ## Field notes — the *why*, not the field list
189
+
190
+ - `finalization` — immutable output of `run-state.mjs finalize <slug>`: freshly fetched target identity; proved unit/component ancestry; live issue/PR observations; original-branch restoration; structured workspace reap/preservation; implementation disposition tally; external/human/prerequisite completion; deferrals; autonomous breaker decisions; and the generated handoff. Generic writers cannot create, mutate, or erase it, and `validate` recomputes manifest-derived portions. A second finalization is refused. `completionAudit` is forbidden because caller-authored completion data has no authority.
191
+
192
+ - `terminalEvidenceImports[]` — append-only receipts written only by `reconcile-terminal-evidence`, each binding the content-addressed journal digest to a run unit/component association, delivery exact head, provider observation, and imported merge commit. Generic writers cannot create, rewrite, or erase the history. For a member carrying `deliveryRef`, every receipt must agree with the referenced canonical component delivery's component ID, `authorizedHeadSha`, and delivered merge identity; the member `unitId` is retained even when its own PR/head differ. Legacy unit-owned receipts agree with the unit delivery identity. The journal entry itself stays outside the manifest and has no authority until reconciliation revalidates coherence plus live provider/check/queue/target facts. See [terminal-evidence-journal.md](terminal-evidence-journal.md).
193
+
194
+ - `units[].unitKind` / `kindRecommendation` / `kindConfirmation` — typed intake from
195
+ `unit-kind.mjs`; external/human recommendations require explicit confirmation.
196
+ - `units[].evidenceLifecycle` / `evidenceLifecycleContract` — focused workflow-design
197
+ admission. Intake classifies declared scope and planned changed surfaces with unknown
198
+ entries failing toward `evidence-authorization`. A required version-1 contract inventories
199
+ every discovered condition and records its lifecycle phase, immutable SHA kind, producer,
200
+ provider/acquisition operation, consuming transition, and failure behavior. The field is
201
+ consumed by `spawn-contract.mjs`, which runs `evidence-lifecycle-contract.mjs` and refuses
202
+ a producer or reviewer spawn on absence, unsupported acquisition, mismatch, or circular
203
+ future evidence. Ordinary units may omit both fields and retain the lean path.
204
+ - `units[].externalProtocol` / `externalCompletion` — protocol and observed completion.
205
+ Artifacts cannot populate completion; actor, environment, operation, source, and required
206
+ evidence must match. External units never own implementation delivery or review verdicts.
207
+ - `units[].completionDependsOn` — delivery-only dependency on external/human completion.
208
+ It does not block produce/review; every delivery path refuses while it remains pending.
209
+
210
+ - `currentTurnCapabilities` — the exact `{ nativeTools[], spawnModelIds[] }` advertised in the turn that planned pre-flight. Empty arrays are retained; static configuration never fills them. A resumed run reports this record and does not reconstruct the old turn. Malformed present values fail validation; absence stays compatible with legacy manifests and is named by `resume` as missing.
211
+ - `models` — the pre-flight gate's confirmed set (delivery loops only; a release uses `envelope`). Two slots: `models.implementation` (the one implementer every unit runs on, **always asked**) and `models.review` (**filled from the ranking, never asked** — the manifest records the resulting pick either way, since a resume needs the model, not how it was chosen). **A slot is a model *and its operating point*:** a model's tier can differ by effort (the catalog banks a `tiers` map), so the picked effort is recorded as `models.<slot>Effort` (`high | xhigh | max`; **omit for `high`**) — without it a resumed run silently drops to `high`, a different capability tier than the human confirmed. **Confirmation attaches to the run, not the session:** a resume under the same `runSlug` inherits these without re-prompting (state the inherited set in the resume summary, so an override is one message away); a *new* run-slug re-confirms. A manifest cut before a slot was removed (`oracle`, `fortifiedImplementation`, and their `*Effort` counterparts) still reads and validates, flagged obsolete by `validate`; writing `null` to one of those keys **deletes** it — the remedy the warning names. `models.implementation`/`models.review` are excluded from that clear on purpose: live and required, so `null` stays a rejected write.
212
+ - `targetBranch` — the confirmed source/base branch, detected from the **fetched remote heads**. Like `models`, settled on day zero and attached to the run: every implementer branches off `origin/<targetBranch>` (never a stale local branch), the epic integration branch forks from it, and a base that is a production branch flags a promotion. A resumed run inherits it.
213
+ - `originalBranch` — the branch the checkout was on when the run started ([pre-flight step 5](pre-flight.md)); the run switches branches under it (no run worktree), and the handoff restores this branch on done. Null only for a detached HEAD or a disposable/isolated checkout.
214
+ - `skillsRoot` — the **absolute** skills directory resolved at pre-flight. Every spawn's `read <skillsRoot>/<skill>/SKILL.md` instruction and every workflow's skill-path arg is built from it — a relative path silently fails to read in a consumer repo and degrades the spawn to a memory-reconstructed lookalike. A resumed run inherits it; if the manifest was reaped or the recorded path no longer exists, **re-resolve it from wherever this skill was loaded** — never guess or fall back to a relative path.
215
+ - `iteration` / `auditBaseSha` — `iteration` is the epic loop's pass counter; `auditBaseSha` records the SHA an audit was built against, so a resume can ask "has HEAD moved since?" by comparing it — its consumer is the feature-derived epic exit gate in `resolve-issues`' definition-of-done. A **recorded key, not a mechanized gate today** — no script reads it, unlike `contractRevision`, which was mechanized once a removal-path audit found it dead.
216
+ - `contractRevision` / `reviewedContractSha` — the contract-freshness gate's durable pointers. `contractRevision.sha` is the target-branch commit containing the human-approved source/design/test criteria; `refs` names the authoritative artifacts. **Git ancestry — not a cached boolean — answers whether unit HEAD contains the revision**, and the mechanized [`contract-revision.mjs check`](../scripts/contract-revision.mjs) gate computes it, failing closed. A ref citing a file **not in the tree exits 2** — a distinct state from stale, because a rebase cannot conjure a document nobody wrote. `reviewedContractSha` is the revision the latest verdict used, set with `record-reviewed-contract` (which writes the unit's *current* `contractRevision.sha`, never a hand-typed value). A mismatch forces intake re-entry, rebase, whole-contract reconciliation, and full-scope review; prior verdicts/CI/runtime evidence cannot authorize exit.
217
+ - `rounds` — ***the universal typed round log; every unit writes it*** (`record-round`, protected from generic writers). One append-only entry per completed review verdict: `{ round, verdict, headSha, changedSurfaces[], reviewSubject, themeIds[], authorizationBoundary, scope?, evidenceClasses?, reopenReason?, at? }`. `changedSurfaces` is a closed diff-derived set: `runtime | tests | verification-harness | evidence | docs | none`; `none` is exclusive. The CLI derives it from Git with rename detection disabled and rejects a caller override that disagrees. `reviewSubject: code|evidence` is independent: reviewing an evidence file can still be a code-subject review, and an evidence subject may follow any changed surfaces but always requires `evidenceClasses`. A round after PASS requires `reopenReason: ci-red|head-rewritten|contract-revised|integration-finding|external-review` plus a changed `authorizationBoundary: {kind: ci|head|contract|integration, value}` whose kind matches the reason (`external-review` → `head`; epic-876 / #941). Legacy `productionMoved` records remain readable and project to explicit `changedSurfaces:[unknown]`, `reviewSubject:unknown`, `reopenReason:unknown`, and `authorizationBoundary:unknown`; the breaker refuses auto-continue until missing theme/change metadata is reconstructed or the unit is handed back. `at` and `scope` remain optional telemetry.
218
+
219
+ **Reading `evidence-audit <slug>`** — the report over rounds whose `reviewSubject` is `evidence`. It answers *what they were spent on*, and therefore what to repair: a recurring **screened** class (`stale-locator`, `unrun-gate-row`, `stale-stamp`) means a screen this repo already has was skipped or run without `--diff`; a recurring **unscreened** one (`contract-drift`, `checklist-row`) is the named incident a new screen would be added with. **Read `sameHeadAsPrevious` before the count:** an evidence-subject round at the same HEAD as the round before it had no commit between them at all, so it is usually a double-record (one entry per loop *action* rather than per verdict) rather than a round bought on unmoved code. Its repair is `fix-the-recording`, and no screen would ever have caught it. → [why](why.md#the-evidence-lanes-two-signals)
220
+ - `reviewHistory` / `fixRounds` — ***deep-audit layer, opt-in*** (the [high-risk lane](high-risk.md)'s optional mechanization; the lean loop never writes them — its required per-unit fields are only `status`/`pr`/`lastVerdict`/`reviewRounds`/`highRisk`/`implementationModel`/`lastReviewedSha`). `record-review-round`/`record-fix-round` own the exact reconciliation — the durable theme sequence, the append-only fix proofs, and the payload-qualified `states × taskKinds` matrix a stateful/concurrency theme requires. The doctrine the script enforces but can't state: **a single counterexample never closes a theme**, and a declaration or aggregate smoke row is not evidence. **Lean default since #792** (issue-664 / identity#669 schema thrash): `record-review-round {round, verdict, headSha, scope?, themeIds?, findings?}` and `record-fix-round {reviewRound, headSha, themeIds[], changedSurfaces?, classesClosed?}` write the typed round log / `leanFixRounds`; the CLI derives or validates changed surfaces without `migrate-unit` or the matrix. `headSha` is accepted on review rounds (no dual-schema trap with `record-round`). **Lean `reviewRound` is referential:** it must name an existing review on that unit (`rounds[]` and/or `reviewHistory`); orphan lean fixes are refused on write and caught by `validateUnitRoundState` on read-back. Deep matrix still required when the high-risk deep protocol is active or the payload carries `coverage`/`selfReview`/finding `theme` objects.
221
+ - `breaker` — the **circuit-breaker**'s durable decision, written only by `record-breaker-decision`: `{ firedAtRound, firedOn: review-rounds, decision: design|split|descope|continue, diagnosis, … }`. A `diagnosis` is required — the breaker hands a diagnosis, never a neutral menu. `continue` authorizes exactly one more round, then re-fires; design/split/descope block every fix/review transition until `record-intake-reentry` stamps a fresh round budget. **`firedOn` is always `review-rounds`** — a second `produce-passes` threshold (#382) was removed after early-death spawns false-fired it before any review ran; legacy values still validate on read-back, and the code never writes one again. A firing means *3 completed review rounds with no PASS verdict*, so `firedAtRound` records the completed review rounds at fire time (`≥ 1`). **The review-round budget binds both tiers:** rounds count as `max(reviewHistory.length, reviewRounds, rounds.length)` — the lean round log counts too — so a lean unit that never calls a transition command is caught by state validation instead. **Clearing binds both tiers as well:** the clear commands work on a versionless lean unit, deliberately — a gate an orchestrator can trip but never clear teaches the loop to stop writing state, and a loop that stops writing state is one nothing downstream can refuse.
222
+
223
+ **Who decided, and on what evidence (2026-07-22).** Three further fields, all optional and absent on older manifests (which read back as human decisions, no migration needed): `autoApplied: true` when the *loop* took the decision; `signal` — the computed diagnosis that drove it (`recurring-theme | churning-themes | converging | insufficient-data`); and `classCompleteFor` — the theme a `continue` mandated a class-complete fix for, and the one-shot marker that stops the same theme buying the remedy twice. The decision is computed by [`diagnose-breaker`](../scripts/run-state.mjs) from `rounds[].themeIds`, and `record-breaker-decision --auto` applies it. **`continue` and `design` may be `autoApplied` at any level; a `split` only when the same breaker entry stamps `autonomyAtDecision: "autonomous"`; a `descope` never** — a validation error rather than a convention, so even a hand-written manifest cannot record the loop deciding to build less. The stamp makes the split record self-describing, so the guard reads authorization off the decision instead of every caller threading the run's level into per-unit validation. Nothing is auto-decided at or above `BREAKER_TOTAL_ROUND_CEILING` (8 rounds). A recorded decision contradicting the computed one is a **warning**, never an error — the human may see what the round log cannot, and a logging call that can hard-fail is one an orchestrator learns to stop making. Full rationale and the 127-manifest audit: [breaker.md](breaker.md).
224
+
225
+ Only `blocked` and `skipped-already-done` are exempt from the budget — those units *stopped*. **`merge-ready` is not exempt:** it is an *exit*, and it was the one status that let an over-budget unit launder itself past the breaker into the one that claims success. **The recourse when a write is refused for budget is `record-breaker-decision`** — the intended exit, always reachable. "Always" is literal: it authorizes on a *pending* breaker rather than a raw threshold, so a re-fired breaker answers too — a produce-minted `continue` whose one round is spent on an NC review re-fires as *continue-authorization-exhausted* with both raw counters below their limits, and that state must still accept a fresh decision or it is a closed dead end (#382 BLOCK-3). Do not reach for `status: blocked` to get unstuck; it means a human-blocking impediment everywhere else. A **second** firing archives the prior decision to the append-only `breakerLog` before overwriting `breaker`, and `breakerLog` is *read*, not just kept: `record-intake-reentry` refuses a decision that already spent a re-entry on this unit (a repeat is a hand-back). Re-entry after a **`design`** decision additionally requires `contractRevision.sha` to have **moved** since the firing — `record-breaker-decision` stamps `contractShaAtDecision` (`null` when the unit has no pointer; absent on a pre-#986 manifest, read as `null`). The design *decision* is the human's; the *budget* is bought by the design artifact landing on the target branch, or the producer re-enters against the very contract that fired the breaker ([epic-986](why.md#design-gate)).
226
+
227
+ > **Resuming a run that predates a rule.** Two guards tightened after units were already valid under the old rule, so a manifest can hold a unit that was valid when written and is red now — `validate` fails and generic writes to *that* unit are refused (others still write) until a corrective write lands:
228
+ > - **The budget guard** once exempted `merge-ready`/`queued`. Recording a decision clears an over-budget unit, but the record will read `firedAtRound: <rounds already completed>` rather than 3 (the breaker never fired at the time) — say so in the diagnosis rather than letting the number imply a stop that never happened.
229
+ > - **`validateTerminalVerdict`** binds `merge-ready` to `lastVerdict === 'PASS'` exactly. A unit that is `merge-ready` with `lastVerdict` unset or on a stray value fails until the write carries `"lastVerdict":"PASS"`. **Do not manufacture that value to get unstuck:** write it only if the unit genuinely exited on an independent PASS against its current HEAD (check the review record first). If it did not, the unit was never merge-ready by guarantee 3, and the honest fix is a fresh review, not a backfill.
230
+
231
+ - `units[].disposition` — the explicit terminal taxonomy: `delivered | handed-back | already-done | descoped | blocked`. Every lifecycle consumer resolves terminal state through the shared `terminalDisposition()` compatibility reader. New delivery transitions stamp `delivered`/`handed-back`; `record-scope-decision` stamps `descoped`; old manifests remain readable from `delivery.outcome`, `status: skipped-already-done|blocked`, and the historical human `scopeDecision.decision: descope` shape. An explicit disposition wins over legacy inference and must agree with its backing evidence. `descoped` is terminal but is never resolved, delivered, or already done.
232
+ - `units[].scopeDecision` — written only by `record-scope-decision`: a human `descoped` decision with `evidence`, `at`, `reason`, non-empty `affectedRequirements`, `issueDisposition`, `prDisposition`, and literal `delivered:false`. `autoApplied:true` is refused at the state boundary. Every incoming dependency must be named in `dependencyReconciliation` and removed atomically by the same transition; otherwise the descope refuses. This makes a descoped prerequisite impossible to leave as a dangling or falsely-satisfied edge.
233
+ - `components[].verdict` — `ALIVE | DEAD | DESCOPED`, written through `record-component-verdict`; generic set/merge/upsert cannot inject or rewrite it. `DESCOPED` is accepted only when every component unit resolves to the `descoped` disposition.
234
+ - `units[].status` — compatibility/progress state: `queued | in-progress | merge-ready | blocked | skipped-already-done`; per-unit `pr`/`branch`/`lastVerdict`/`reviewRounds` are pointers into the real records. The two legacy terminal spellings still read, but consumers do not branch on them directly.
235
+ - `components[].delivery` / `units[].deliveryRef` — the **canonical component exit gate**. Terminal component authorization initializes one record bound to the candidate's current `generation`, frozen component HEAD, combined/component PR, and the run's delivery mode/provider. `record-component-delivery-attempt`, `record-component-delivery-observation`, `record-component-delivery-nudge`, and `record-component-delivery-outcome` all require that exact authorized generation and HEAD; a unit branch HEAD or stale generation is refused. Attempts and observations are stored once here, including prior nonterminal generations, and one enqueue action per generation prevents duplicate enqueue. A successful queue outcome validates the required-check plan's synthetic queue-head evidence before writing `outcome`, `outcomeAt`, `mergedSha`, and provider `mergedAt`; direct delivery rejects queue evidence. The terminal transition validates every declared member as unique, resolved, implementation-owned, merge-ready, and completion-unblocked, then atomically stamps only `{ disposition, deliveryRef }` on every member. Readers resolve those references back to this record, so progress, resume/next, postmortem, finalization, and workspace reap see one delivery lifecycle and one merge claim.
236
+ - `components[].delivery.reconciliations[]` — append-only pre-finalization observations for distinct unit PRs explicitly preserved in the frozen component publication evidence and linked through the same delivered generation. `reconcile-contained-unit-prs` fetches the target, live-verifies the combined PR at `delivery.mergedSha`, reads every linked unit PR head before mutation, proves open exact reviewed heads are ancestors of the fetched target, and re-reads each head immediately before closure. The close comment names all four identities. Closed/merged PRs record terminal no-ops; drift, absent ancestry, unreadable state, or a non-matching component merge records a refusal and leaves that PR open. Generic writers cannot alter these rows because they are part of protected component delivery state. The rows make the terminal state reachable; they do not authorize completion, and `finalize` re-establishes every live completion fact independently.
237
+ - **Compatibility policy for manifests predating component delivery.** Absence of `components[].delivery` remains readable through the historical `units[].delivery` contract, regardless of whole-manifest migration: #1009 migration must not invent delivery facts. This preserves singleton behavior and permits old shared runs to be inspected/finalized as recorded. The next terminal component authorization creates the canonical record; from that point component transitions are mandatory and any member `units[].delivery` duplication is refused. Generic writers cannot create, rewrite, or erase the component record or member `deliveryRef`.
238
+ - Legacy `deliveryMode` / `units[].delivery` — the **pre-component merge-ready exit gate**. `merge-ready` used to be terminal with no transition out of it, so nothing could be refused and a unit could sit there forever with the manifest still valid — epic-986 recorded `mergeShippable: true` and four units `merge-ready` with `lastVerdict: PASS`, their PR refs, and `mergedSha: null` on every one. `deliveryMode` (`direct` | `queue`, settled at [pre-flight step 3a](pre-flight.md) by the mechanized probe [`detect-delivery-mode.mjs`](../scripts/detect-delivery-mode.mjs) — **never read off repo files**, since queue config commonly lives dashboard-side, outside the repo; an absent field on an older manifest reads as `direct`, which is a *legacy* read and not a licence for the probe to guess) decides which action is legal, and `record-delivery-attempt` **refuses an action that does not belong to the mode** — choosing wrong fails silently in both directions, so it is enforced rather than recorded. **`queueProvider`** (`mergify` | `github`) is the second half of that answer, from the same probe: the mode picks the state machine, the provider picks the *mechanics*, and `queue` is two flows sharing almost none of them. It is an error alongside `direct`, a `validate` **warning** when absent on a queue run — so a legacy manifest still loads and resumes — and a **refusal** at the moment a provider-specific action is taken, since without it the enqueue command itself is unknown. `run-state.mjs delivery-flow <slug>` renders the resolved flow and its exact ops (exit 2 when unresolved). `delivery` is `{ attempts[], outcome, mergedSha, blockedOn, watch }`: each attempt carries `at`/`action`/`headSha`/`outcome`; the legal fields are **per flow**, so a queue field on a `direct` attempt is an error rather than noise. A `dequeued`/`rejected` attempt owes a `reason` — one of `checks-failed | conflict | conditions-unmet | frozen | manual | pull-request-updated`, which are **routing classes** — plus the queue's own string verbatim in **`rawReason`**, and a verbatim `detail`. The classes are deliberately fewer than the vocabulary (Mergify's `queue-dequeue-reason` alone carries ~40 values), so `dequeueRouting()` owns the mapping, a `reason` contradicting its `rawReason` is refused, and **an unmapped reason routes to a hand-back** rather than being guessed into a fix round. A Mergify enqueue recorded as `waiting` also owes **`ack`** (`{kind: reaction|payload, ref}`): its enqueue is a PR comment, so a command nobody read and a queue actively holding the PR are otherwise the same record — epic-986's shape one layer up. GitHub's native enqueue is an API call that returns its own receipt and owes none. Terminal `outcome: 'merged'` requires `mergedSha` and at least one recorded attempt (a hand-back requires neither — it is the honest exit for a delivery that could never be attempted, e.g. a first observation of `frozen`) — proved contained in the fetched target by [`combine-and-verify.mjs delivered`](../scripts/combine-and-verify.mjs), because a merge tool's return code and a queue acknowledgement are *requests*, not results — and `handed-back` requires `blockedOn`. A `checks-failed` dequeue **moves the unit back to `in-progress`**: the queue tested PR-merged-with-base, a tree per-PR CI never saw, so it is a round of the loop owing a fresh verdict, not a retry. A second attempt at an unchanged `headSha` is refused; the skill never retries the merge path because the queue already retries what should be (`bisecting` resolves a red batch itself) and deliberately does not retry what should not. A `merge-ready` unit with no terminal outcome **warns as undelivered** — legal mid-run, a finding at handoff. `delivery.watch` (`record-delivery-observation`) bounds the *watching* in `queue` mode — and is refused in `direct` mode, where the merge is synchronous and a watch means the run believes it is enqueueing. It keeps the last observed `queueState`/`position` plus the queue's own `unmetConditions` and `lastChangeAt`, and **only a change to that triple restarts the clock**, so a repeat poll reads as a stall rather than as life (a condition going green is progress even while the state string does not move). `queueState` includes the **pre-admission** phase the model did not name until PR #529 spent minutes in it: `waiting-for-queue-conditions` (the queue accepted the request and is holding the PR) versus `not-enqueued` (nothing is holding it — the request never landed), which read identically in the queue CLI and have opposite remedies. Past `deliveryWatchBoundMinutes` (default 10 — the same stall bound the watcher scripts enforce, since a manifest bound the watcher hands back before is never reached) the CLI exits **4** and `validate` warns; `frozen`/`waiting_schedule` are self-explaining blocks that hand back on first sight rather than waiting out the bound. Exit **5** is the other kind of actionable — a cheap action rather than a hand-back: pre-admission unchanged past 5 minutes with nothing listed unmet earns **one** `record-delivery-nudge` (`@mergifyio refresh`, mergify only), which restarts the stall clock once and is capped there, since an uncapped nudge keeps a wedged unit looking alive. It is not a retry of the merge path — it attempts nothing and touches no HEAD. The bound is on **stall, not elapsed time** — a unit can sit in `waiting_for_previous_batches` for an hour while genuinely advancing, and a flat timeout would hand back healthy units. The observation write is refusable only on **its own shape** (a missing `queueState`, or a delivery record already invalid for the run's mode) — never on unrelated unit state, for the same reason `record-round` is not.
239
+ - `units[].dependsOn` / `units[].sharedSurfaces` — **the interference the run schedules and delivers on.** `dependsOn` carries the **blocking** edges, each `{ unit, source }` with `source` in `symbol | premise`; a bare string reads as `symbol`, which is the safe legacy interpretation, and an unrecognized source is refused at the write rather than coerced (a typo'd `premis` would take the co-delivering reading silently). `sharedSurfaces` carries the **assembly** ones — the surface ids two units both touch — which ADR 0001 noted the model named but had no field for. Both grades block *delivery*; **only `symbol` blocks scheduling** (2026-08-04 — a premise dependent compiles, so it is built concurrently and carries the edge's `invariant` into its spawns, while `combine-and-verify.mjs mergeable` keeps it from shipping first); and only `symbol` + assembly co-deliver, so a premise edge orders two components rather than bundling them. A premise edge also carries an optional **`invariant`** — the specific wrong behavior that would be live if the dependent shipped alone — which `runnable` prints under the admitted unit and the producer spawn quotes verbatim. Validation refuses a **dangling** edge (a dependent forks its dependency's branch, so an edge pointing at a descoped unit sends it off the wrong base) and a **cycle** (each unit waits on another, so the component silently stops progressing while nothing is invalid). → [interference.md](interference.md)
240
+ - `units[].workspacePath` / `units[].pushedSha` / `inFlightCap` — **the workspace a unit owns and the evidence that releases its dependents.** A workspace belongs to one unit from its first producer spawn until the unit is delivered or handed back, so `validate` refuses two units sharing a path **and** refuses a unit pointed at the run's own `workspacePath` — the orchestrator's tree belongs to no unit ([why](why.md#the-orchestrator-is-a-writer-too)). `pushedSha` is what makes a unit `runnable`'s dependents runnable: the bar is **pushed, not merged**, so an unrecorded push strands them while the branch they need is already on the remote (a recorded `pr` counts too — a PR cannot exist over an unpushed head). `inFlightCap` (**4**, a positive integer, refused rather than coerced) caps how many units may hold a workspace at once; it bounds disk and dependency-install cost, never correctness, and **1 is the old strictly-serial behaviour**. **The loop never writes this field** — 4 is the default and the answer on every repo, so a recorded value is a human's deliberate override and `validate` warns when one is below the default (this line said "default 2" for nine days after the default became 4, and `epic-563-admin-transactions` set 2). Every recorded tree path — this field, the run-level `workspacePath`, and `workspaceRoot` — must be **absolute and not the filesystem root**, because each is a path the reap decides against: a relative one resolves against whatever directory the reap happens to run from, and `/` is not a tree this loop owns at all. `validate` holds them to exactly what the reap's guard accepts, untrimmed — `" /repo"` and `"/repo"` are two different directories, so a validator that quietly trims blesses a path the guard will then refuse. Read the schedule with `run-state.mjs runnable <slug>`; reap the trees with `workspaces.mjs reap <slug>`.
241
+
242
+ `delivery` is `{ attempts[], outcome, mergedSha, blockedOn, watch }`; each attempt carries `at`/`action`/`headSha`/`outcome`, and the legal fields are **per flow** — a queue field on a `direct` attempt is an error, not noise. A `dequeued`/`rejected` attempt owes a `reason` — `checks-failed | conflict | conditions-unmet | frozen | manual | pull-request-updated`, **routing classes** deliberately fewer than the queue vocabulary, mapped by `dequeueRouting()` from the queue's own string kept verbatim in **`rawReason`**, plus a verbatim `detail`. A `reason` contradicting its `rawReason` is refused, and **an unmapped reason routes to a hand-back** rather than being guessed into a fix round. A Mergify enqueue recorded as `waiting` also owes **`ack`** (`{kind: reaction|payload, ref}`): its enqueue is a PR comment, so an unread command and a queue actively holding the PR are otherwise the same record. GitHub's native enqueue returns its own receipt and owes none.
243
+
244
+ Terminal `outcome: 'merged'` requires `mergedSha` and at least one recorded attempt, proved contained in the fetched target by [`combine-and-verify.mjs delivered`](../scripts/combine-and-verify.mjs) — a merge tool's return code and a queue acknowledgement are *requests*, not results. `handed-back` requires `blockedOn` and neither of the others; it is the honest exit for a delivery that could never be attempted. A `checks-failed` dequeue **moves the unit back to `in-progress`**: the queue tested PR-merged-with-base, a tree per-PR CI never saw, so it is a round owing a fresh verdict, not a retry. A second attempt at an unchanged `headSha` is refused — the queue already retries what should be retried. A `merge-ready` unit with no terminal outcome **warns as undelivered**: legal mid-run, a finding at handoff.
245
+
246
+ `delivery.watch` (`record-delivery-observation`) bounds the *watching* in `queue` mode and is **refused in `direct`**, where a watch means the run believes it is enqueueing. It keeps the last `queueState`/`position` plus the queue's own `unmetConditions` and `lastChangeAt`, and **only a change to that triple restarts the clock**, so a repeat poll reads as a stall rather than as life. `queueState` separates the two pre-admission states that read identically in the queue CLI and have opposite remedies: **`waiting-for-queue-conditions`** (the queue is holding the PR) vs **`not-enqueued`** (nothing is). Past `deliveryWatchBoundMinutes` (default 10) the CLI exits **4** and `validate` warns; `frozen`/`waiting_schedule` hand back on first sight. Exit **5** is the cheap-action case: pre-admission unchanged past 5 minutes with nothing listed unmet earns **one** `record-delivery-nudge` (`@mergifyio refresh`, mergify only), capped there, attempting nothing and touching no HEAD. The bound is on **stall, not elapsed time**. An observation write is refusable only on **its own shape**, never on unrelated unit state.
247
+ - `units[].dependsOn` / `units[].sharedSurfaces` — **the interference the run schedules and delivers on.** `dependsOn` carries the **blocking** edges, each `{ unit, source }` with `source` in `symbol | premise`; a bare string reads as `symbol`, which is the safe legacy interpretation, and an unrecognized source is refused at the write rather than coerced (a typo'd `premis` would take the co-delivering reading silently). `sharedSurfaces` carries the **assembly** ones — the surface ids two units both touch — which ADR 0001 noted the model named but had no field for. Both grades block *delivery*; **only `symbol` blocks scheduling** (2026-08-04 — a premise dependent compiles, so it is built concurrently and carries the edge's `invariant` into its spawns, while `combine-and-verify.mjs mergeable` keeps it from shipping first); and only `symbol` + assembly co-deliver, so a premise edge orders two components rather than bundling them. A premise edge also carries an optional **`invariant`** — the specific wrong behavior that would be live if the dependent shipped alone — which `runnable` prints under the admitted unit and the producer spawn quotes verbatim. Validation refuses a **dangling** edge (a dependent forks its dependency's branch, so an edge pointing at a descoped unit sends it off the wrong base) and a **cycle** (each unit waits on another, so the component silently stops progressing while nothing is invalid). → [interference.md](interference.md)
248
+ - `units[].workspacePath` / `units[].pushedSha` / `inFlightCap` — **the workspace a unit owns and the evidence that releases its dependents.** A workspace belongs to one unit from its first producer spawn until the unit is delivered or handed back, so `validate` refuses two units sharing a path **and** refuses a unit pointed at the run's own `workspacePath` — the orchestrator's tree belongs to no unit ([why](why.md#the-orchestrator-is-a-writer-too)). `pushedSha` is what makes `runnable`'s dependents runnable: the bar is **pushed, not merged**, so an unrecorded push strands them while the branch they need is already on the remote (a recorded `pr` counts too — a PR cannot exist over an unpushed head). `inFlightCap` (**4**, a positive integer, refused rather than coerced) caps how many units may hold a workspace at once; it bounds disk and install cost, never correctness, and **1 is the old strictly-serial behaviour**. **The loop never writes this field** — a recorded value is a human's deliberate override, and `validate` warns when one is below the default. Every recorded tree path — this field, the run-level `workspacePath`, and `workspaceRoot` — must be **absolute and not the filesystem root**, because each is a path the reap decides against. `validate` holds them to exactly what the reap's guard accepts, **untrimmed**: a validator that quietly trims blesses a path the guard will then refuse. Read the schedule with `run-state.mjs runnable <slug>`; reap the trees with `workspaces.mjs reap <slug>`.
249
+
250
+ - `workspaceRoot` — **the orphan sweep's declared scope**, optional and absolute. `workspaces.mjs reap` collects trees on disk that no unit claims, and it needs a directory to look in. **A declaration that cannot be read is refused, never inferred around:** "undeclared" is precisely absent, `null`, or an empty string; anything else present is a value somebody set, so a non-string, a slashes-only `/`, or a path that will not resolve yields exit 4 rather than a scope the manifest never named. Undeclared, the scope is inferred from the recorded `units[].workspacePath`s, which must all agree on one parent tree — a disagreement yields **no** scope and exit 4 rather than an arbitrary one. Either way a root that is, contains, or sits inside a protected tree is refused: `dirname` of a unit mis-recorded as the checkout itself is the repo's *parent*, and other checkouts' worktrees beside it are not this run's orphans. Set it when a run's workspaces cannot agree on a parent, or when its paths came from an older naming scheme.
251
+ - `deferrals` — the decomposition gate's output — `[{ requirement, trackedIn }]`, both required: an untracked deferral is a requirement owned by nobody, which is the epic-848 shape and reads exactly like a requirement nobody needed. Rendered by [`plan`](../scripts/report.mjs), which prints `deferred: none recorded` rather than omitting the section, so "nothing was deferred" and "nobody ran the gate" stay distinguishable.
252
+ - `units[].gateResults` — **the run-local record that makes the [removal path](../SKILL.md#the-removal-path-keep-this-skill-small)'s rule 2 measurable.** One append-only entry per observation: `{ gate, ran, result, round?, headSha?, findings?, fixed?, findingDetails?, durationMs?, reason?, at }`, written by `record-gate-result`. Generic `set`, `merge`, and `upsert-unit` may preserve an existing unit's byte-identical history but cannot create the field on a new unit or append, rewrite, or erase it on an existing one. `findingDetails` entries are `{ class, locator, blocking, outcome }`, where outcome is `open | fixed | noise`; `class + locator` is the stable fingerprint across rounds and units. Legacy numeric `findings` remains raw volume and `fixed[]` remains attributable-fix evidence, but neither fabricates a unique identity. `durationMs` is optional telemetry copied only when the harness supplies it.
253
+
254
+ **`ran: false` or `result: 'skipped'` owes a `reason`**, refused otherwise. They report differently: `ran:false` is `not run`; `ran:true, result:skipped` is `skipped`. A non-execution must use `result: 'skipped'`, while positive `findings`, non-empty `findingDetails`, or non-empty `fixed` evidence require `result: 'findings'`; contradictory states are refused instead of being mislabeled or discarded. A malformed present record is `unreadable`, never clean. Every committed artifact being green is survivorship, not a result — structured findings and fixes break that tie.
255
+
256
+ **Retirement is cross-run.** `gate-audit` appends one snapshot to `$RESOLVER_GATE_VALUE_DIR/index.jsonl`, or `$RESOLVER_RUN_DIR/gate-value/index.jsonl` when a scoped run directory is configured, otherwise `${XDG_STATE_HOME:-~/.local/state}/resolver-gate-value/index.jsonl`. It takes the latest snapshot per run slug, reports unique/blocking/repeated/fixed/noise separately, and recommends retirement only when the trailing per-gate zero-yield streak reaches `RESOLVER_GATE_RETIREMENT_MIN_RUNS` (default 10). `not run`, `skipped`, `unreadable`, a rejection, or any finding resets the streak. Narrowing and deduplication are independent recommendations.
257
+
258
+ **Refusable only on its own shape** — never on unrelated unit state and never by the breaker, the same discipline as `record-round` and `record-delivery-observation`: a logging call that can hard-fail is one an orchestrator learns to stop making, and non-adoption is precisely the failure this ends. Write it **in the same turn the gate runs**.
259
+
260
+ **The consumer ships with it, deliberately.** From this manifest set: `units[].rounds` went 0 → 83% adoption (the breaker reads it), `skillsRoot` 0 → 90% (`validate` reads it), `contractRevision` 0 → 57% (`contract-revision.mjs` reads it) — and `delivery`, fully mechanized with dedicated commands, was written **0 times in 522 units**, because nothing consumes it. The distinguishing property is never mechanization; it is whether a later gate reads the value. So `gate-audit` (also rendered by `progress`, hence in the handoff) is the reader, and `validate` warns on a `merge-ready` unit with no gate results at all.
261
+
262
+ - `workspaceMode` / `workspacePath` — `shared` (default; every spawn works in the current checkout) | `worktree` (the run gets a checkout of its own and never touches the human's tree), probed at [pre-flight step 5](pre-flight.md) by [`detect-workspace-mode.mjs`](../scripts/detect-workspace-mode.mjs). A **probed setting, not another pre-flight question** — the neutral batch already occupies the selected adapter's capacity, and the answer turns on tree state a human cannot recall at a prompt. A **dirty tree recommends `worktree`**, which replaces the old dirty-tree stop rather than blocking the run; an already-isolated checkout stays `shared`, since nesting buys nothing and costs a second dependency install. `worktree` owes `workspacePath` (a `validate` warning otherwise): the handoff removes the worktree **by path**, so an unrecorded one is left behind. **This is the coordinator's tree only** — every code-writing spawn works in its unit's own `units[].workspacePath`, and pointing a unit at this path is a validation error rather than a shortcut.
263
+ - `enqueueTrigger` — `manual` | `auto` | `hybrid`, probed at [pre-flight](pre-flight.md) by [`detect-delivery-mode.mjs`](../scripts/detect-delivery-mode.mjs). Whether the **repo** can merge a PR with no further action from the loop — not how the loop enqueues, since manual enqueue stays available everywhere. Where an auto-merge rule's conditions include a review clause, **posting the verdict as an approval IS the merge**, so that act inherits guarantee 4: ask `run-state.mjs approval-gate <slug> [componentId]` first (exit 1 = post a comment instead). A preliminary unit review omits the id and cannot approve an auto-merge PR; only the terminal review of an authorized frozen component supplies it. Absent on a `queue` run is a `validate` warning and makes the gate fail closed to comment-only; `auto`/`hybrid` alongside `mergeShippable: false` warns, because that is precisely the configuration in which a routine review merges a PR the run meant to hand back. See [why.md](why.md#the-enqueue-trigger).
264
+ - `autonomy` — `autonomous` (what pre-flight **recommends**) | `supervised` (what an **unset** field resolves to). The difference is load-bearing: a recommendation governs what a human at the gate is offered first, while the unset-resolution governs a manifest nobody was asked about, where the fail-safe answer is the strict one — resolving absent to `autonomous` would retroactively flip `mergeShippable` on for every legacy run. Set once at [pre-flight](pre-flight.md) step 4. It **subsumes** the old `mergeShippable` ask (that field still exists, and an explicitly-set one still wins in both directions — the level only supplies its default). Rejected outside the enum **at the write**, not just at `validate`: a typo'd level resolves to `supervised`, so the run keeps stopping at gates the human believes they lifted while the manifest looks configured. Read it back with `run-state.mjs autonomy <slug>` (exit 1 = never set), which returns the resolved policy and the parks that remain. **No level lifts** the design gate, the breaker's `descope`, or its round ceiling; `autonomous` *does* pre-authorize the breaker's `split`. → [why](why.md#pre-flight)
265
+ - `breakerAutonomy` — `auto` (default) | `ask`. Whether the loop may take a fired circuit-breaker's decision itself — the reversible ones (`continue`, `design`, and `split` under `autonomy: autonomous`); `ask` restores a stop-and-ask on **every** firing, and `run-state.mjs autonomy` reports those extra parks rather than describing only the ones the level creates. Deliberately **not** another pre-flight question — [pre-flight.md](pre-flight.md) step 3 defines the complete neutral batch, and another slot would overflow the common plan — so it is a setting with a default, overridable by the human naming it. See [breaker.md](breaker.md).
266
+ - `components[].candidate` / `components[].authorizationBoundary` — the protected progressive assembly and terminal authorization record. `record-component-candidate` appends `unit-discovery` or integration-owned `integration-fix` snapshots while copying each included unit's exact preliminary PASS evidence; included units never shrink. `freeze-component-candidate` accepts only the complete component at a clean/green latest head. `authorize-component-candidate` requires integrated CI, code review, checklist/scan, and smoke all bound to that frozen SHA; high-risk membership requires the high-risk review marker. `reopen-component-candidate` preserves prior authorizations, increments the generation, and accepts only #888's typed reopen reasons with a changed matching boundary. Generic writers cannot add, alter, or erase candidate history or component authorization. `combine-and-verify.mjs mergeable --component <id>` is the reader that makes this the final delivery boundary.
267
+
268
+ Preliminary candidate assembly remains compatible with historical unit evidence: prefer a typed `rounds[]` PASS at the exact `pushedSha`; otherwise an exact-head legacy `rounds[]` or deep `reviewHistory[]` PASS is copied as an explicit `legacy:true` projection with `reviewSubject` and `authorizationBoundary` set to `unknown` and its source named. This projection is historical evidence only: it does not migrate or rewrite unit history, and it never relaxes terminal component authorization, which still requires typed `reviewSubject:"code"` and an exact `integration` boundary on the frozen component head.
269
+ - `epic` / `components` / `mergeShippable` — *(epic runs only)* an epic hands back **one deliverable per [component](deliverables.md#deliverables-the-shippable-component-not-the-whole-epic)** (a shared-surface cluster or dependency chain), not one epic-wide PR, so `components[]` replaces the old single `epicPr`. `mergeShippable` (default false) is the only thing that lets this skill merge into `targetBranch`; production promotion is never here regardless. It is **written by the `autonomy` level at pre-flight** (`autonomous` → true) rather than derived at read: [`combine-and-verify.mjs mergeable`](../scripts/combine-and-verify.mjs) reads this stored field straight off disk to authorize a merge, so guarantee 4 gets exactly one source of truth. An explicitly-set value is never overwritten by the level.
270
+ - `visualEvidence` — *(optional)* for a `presentation:visual` surface, the SHA-pinned committed-baseline links plus the ephemeral diff URL — **returned** by `e2e-test`'s `post-visual-evidence.mjs` (stdout `visual-evidence:` / `--evidence-out`) and written here by the orchestrator's `upsert-unit`, never by the CI job itself; a pointer, not a copy of the PNGs.
271
+
272
+ ## First-pass rate — a spec-maturity signal, not a quality score
273
+
274
+ First-pass rate is an **informal** read off the round log across units — the fraction whose first review round returned PASS **and whose PASS held to merge**. No script computes or enforces it; it is a number a human reads from `rounds`/handoffs, not a mechanized gate. Two rules keep it from lying:
275
+
276
+ - **Count a PASS that held, never a PASS that merely occurred.** A PASS a later round reverses is *not* a first-pass success — #848's round-6 PASS was overturned by four subsequent rounds ([the record](incidents/848/README.md#the-pass-reversal)). Crediting the premature PASS would let a shallow verdict game the metric upward.
277
+ - **It measures intake / spec maturity, not code or reviewer quality.** A reversed PASS is a **serial-invariant PASS**: a single reviewer certifying an *unwritten* governing contract one invariant at a time, so a mid-sequence PASS means "none found at this round's depth," not "done." The evidence is the #848/#849 contrast — #849's *written* contract passed in one round and held; #848's *unwritten* contract ground through nine. Units that pass first were well-specified; units that grind had a contract nobody wrote down. So reading raw first-pass rate as a "done / quality" score rewards an under-probing reviewer — the opposite of the intent.
278
+
279
+ Making a terminal PASS *reliable* (a second, diverse-model confirmation on high-risk or long-`NEEDS_CHANGES` units) is deferred to **#425**; this note fixes only the metric's definition and framing, not the exit bar.
280
+
281
+ ## Rules
282
+
283
+ 1. **Write it at pre-flight** (models confirmed) and **update it on every state transition** through `run-state.mjs`, which stamps `updatedAt` for you. It is one small file; write it eagerly.
284
+ 2. **Read it first on resume.** Inherit the confirmed models, rebuild the roster from `units[]`, and apply the skill's own staleness checks (compare `auditBaseSha` against HEAD by hand — it is a recorded key, not an enforced gate) before trusting any cached analysis. The skill's resume/entry-points table still governs *where* to re-enter.
285
+ 3. **The manifest is an index, never the source of truth.** Verdicts live in reviews, coverage in audits, decisions in issue bodies. On any contradiction, the artifact wins and the manifest gets corrected — a unit is merge-ready because a fresh independent review said so, not because the JSON says so.
286
+ 4. **One skill owns the file per run.** `resolve-issues` owns its delivery manifest; `resolve-release` is a **separate run** (its own `<release-slug>.json`) — it consumes the handoff but does not share the delivery manifest. If an outer orchestrator ever wraps `resolve-issues`, the outermost one owns the file and `resolve-issues` reports state up rather than writing a second manifest.
287
+
288
+ One validation nuance worth stating: `validate` emits the same-model review as a **warning, not a failure** (the doctrine records `NOT INDEPENDENT`; it does not forbid a one-model run).
@@ -0,0 +1,48 @@
1
+ # Testing this skill from a sandboxed copy
2
+
3
+ Mutation testing — inverting an invariant (flip a predicate, delete a bound, revert a guard) to confirm the suite actually notices — must never run against this skill's live working tree. A corruption you forget to revert ships. (Named incident: during the #387 audit, an agent mutation-testing in place left `PRUNE_AFTER_DAYS = 6000` behind in an uncommitted tree; had it survived, catalog pruning would have shipped disabled for roughly 16 years.) The safe method is a scratch copy, and copying `resolve-issues` alone does not run clean — this page is the recipe, and `scripts/sandbox-selftest.mjs` performs it.
4
+
5
+ ## Do this
6
+
7
+ ```sh
8
+ node ~/.agents/skills/resolve-issues/scripts/sandbox-selftest.mjs # sandbox resolve-issues, run the suites, verify the baseline
9
+ node ~/.agents/skills/resolve-issues/scripts/sandbox-selftest.mjs --skill review-pr # a different skill under test
10
+ node ~/.agents/skills/resolve-issues/scripts/sandbox-selftest.mjs --keep # leave the sandbox on disk to inspect
11
+ node ~/.agents/skills/resolve-issues/scripts/sandbox-selftest.mjs --help # usage + exit codes
12
+ ```
13
+
14
+ It copies the skill into an OS temp dir, symlinks the sibling skills beside it, runs `node --test` over `scripts/*.test.mjs` + `workflows/*.test.mjs`, and asserts the **only** failures are the known repo-root-dependent tests — naming which test moved on any mismatch. It never touches the installed skill tree; every file operation lands in the temp dir. Exit `0` = baseline held, `1` = anomaly (a real regression, or a known test that moved — named either way), `2` = usage/setup error. Run `node ~/.agents/skills/resolve-issues/scripts/sandbox-selftest.mjs --help` for the exact contract.
15
+
16
+ The rest of this page is the *why* — the judgment the script encodes, so a change to the layout or the known set is made deliberately, not blindly.
17
+
18
+ ## Why a bare copy fails
19
+
20
+ Copy `skills/engineering/resolve-issues` to a scratch directory and run its suite and it does not come back clean. The failures fall into two families — a missing sibling, and a missing repo root — and within them, four distinct causes that surface differently enough that fixing one looks like fixing all of them when it isn't:
21
+
22
+ 1. **Cross-skill relative import, dies at load.** `scripts/fix-rounds.mjs` imports `../../review-pr/scripts/theme-contract.mjs` (and `finding-contract.mjs`); `scripts/run-state-review6.test.mjs` and `workflows/workflows.test.mjs` import the same sibling directly. A bare copy has no sibling `review-pr` beside it, so the import fails with `ERR_MODULE_NOT_FOUND`, and every file that touches it — directly or transitively through `fix-rounds.mjs`/`run-state.mjs` — dies at load. This is deliberate given the symlink-farm distribution model (this skill is installed as a sibling of `review-pr`, not standalone) — not a bug to fix, a layout to reproduce. **Symlinking the siblings fixes it.**
23
+ 2. **Same cause, via subprocess — doesn't die at load.** `scripts/run-state-review2.test.mjs` has no static import of the sibling, so the file itself loads fine; but several of its cases `spawnSync` `run-state.mjs` as a child process, and that child hits the same missing-`fix-rounds.mjs` import, so its assertions fail without the file ever showing up as a load-time death. This mode is invisible in a bare copy — you only notice it's a separate thing once the file-level deaths in cause 1 stop masking it. **The same sibling symlink fixes it.**
24
+ 3. **Repo-root-relative fixture.** `scripts/run-state-review6.test.mjs`'s 42-cell executor test reads `docs/evidence/809-runtime-smoke.json` by walking up four levels from the script to a repo root that doesn't exist in a scratch copy. Symlinking `review-pr` fixes cause 1's import, but this one test still fails on `ENOENT`. **Unfixable in an isolated sandbox** — the fixture lives above the copy.
25
+ 4. **Repo-root tree-walk.** `scripts/artifact-audit.test.mjs` (issue #379, #397) walks `../../../..` to the repo root to read `skills/.../SKILL.md`, `CLAUDE.md`, and `references/run-state.md`, and to scan the whole `skills/` tree for readers of a deleted field. Five of its tests do this; a scratch copy has no repo root above it, so they `ENOENT` — the same class as cause 3, arriving after it (the recipe predates these tests, which is exactly how the old "total minus one" baseline went stale). **Also unfixable in an isolated sandbox**, and reconstructing the whole `skills/` tree to satisfy it would defeat the point of an isolated copy.
26
+
27
+ So causes 1 and 2 are *fixed* by the sandbox layout (symlink the siblings); causes 3 and 4 are the irreducible cost of running above no repo root, and they define the baseline.
28
+
29
+ ## The layout the script builds
30
+
31
+ From the copy's parent directory it symlinks the sibling skills beside the copy — `review-pr` is the one actually imported by the test suite; the others round out parity with the skills this one orchestrates (`implement-and-pr`, `ensure-coverage`, `e2e-test`, `smoke` — enumerated alongside `review-pr` in SKILL.md's frontmatter `dependencies:`), in case a broader sandbox session touches them too:
32
+
33
+ ```sh
34
+ mkdir -p /tmp/sandbox
35
+ cp -R skills/engineering/resolve-issues /tmp/sandbox/resolve-issues
36
+ cd /tmp/sandbox
37
+ for s in review-pr implement-and-pr ensure-coverage e2e-test smoke; do
38
+ ln -s /path/to/repo/skills/engineering/"$s" "$s"
39
+ done
40
+ ```
41
+
42
+ **Symlink read-only in intent: mutate only files inside the copy.** A symlink is a live pointer, not a snapshot — a write through `resolve-issues/../review-pr/...` (or a mutation test that reaches sideways) lands in the real sibling skill, on the real branch, not in your sandbox. If a mutation genuinely needs to touch a sibling's file, copy that sibling too instead of symlinking it. (`sandbox-selftest.mjs` copies the skill under test and only ever symlinks its siblings, so its own runs are safe by construction.)
43
+
44
+ ## The baseline: total minus the known repo-root set, not a magic count
45
+
46
+ With the symlinks in place, the only failures left are the repo-root-dependent tests from causes 3 and 4 — the ones that read files *above* the copy. The baseline is the suite **total minus that named set**, and `sandbox-selftest.mjs` verifies it as a set, not a count: it knows the members (`KNOWN_FAILING_TESTS`), asserts every failure is one of them (anything else is a real regression) and every one of them actually failed (a member that *passes* means it stopped depending on the repo root — the environment changed, and the script says so, telling you to remove it from the set).
47
+
48
+ As of #406 the resolve-issues set has six members: the one cause-3 fixture test in `run-state-review6.test.mjs`, plus five cause-4 tests in `artifact-audit.test.mjs`. **Don't hardcode "minus one" or any bare number** — that is precisely the claim that went stale when #379 added the artifact-audit tests: a fixed count can't tell a new repo-root test apart from a regression, and it silently mis-baselines the moment the suite grows. Adding or removing a repo-root-dependent test is a one-line edit to `KNOWN_FAILING_TESTS`, visible in the diff; a count in prose is not. If the script reports a member that unexpectedly passed, or a failure outside the set, read the name it prints before treating it as a signal — that name is the whole point.
@@ -0,0 +1,96 @@
1
+ # The leaf-spawn contract — the five clauses, and why each one exists
2
+
3
+ This is the full contract behind SKILL.md's [leaf-spawn rule](../SKILL.md#how-to-invoke-me). Read it when you are about to spawn — every producer, every reviewer, every fix round, inline or fanned out.
4
+
5
+ **The premise the whole contract rests on: a spawned agent does not inherit your loaded skills.** It starts with nothing you have read. Everything it must know has to be *in the spawn*, and every clause below is a different way that fails silently when it is not.
6
+
7
+ > **Do not hand-assemble these clauses — render them: [`run-state.mjs spawn-contract <slug> <unit> --kind producer|fix|review`](../scripts/run-state.mjs).** It fills every clause below from the run's own state and prints a block to paste. Read this file to understand *why* a clause exists, or when the renderer reports a gap it cannot fill (exit 4) — not to rebuild the contract by hand each time.
8
+ >
9
+ > The reason is measured rather than stylistic. A hand-assembled contract is composed once per run and then repeated: over 33 sessions and 163 producer spawns, **10 of 17 sessions with 4+ spawns varied by at most one gate across the entire run**, and where the template moved it decayed rather than improved. The clauses below do not fail because an orchestrator disagrees with them; they fail because the template drifts free of this file after the first unit. → [why.md](why.md#the-spawn-contract-is-rendered-not-composed)
10
+
11
+ ## (a) Tell it to read `<skillsRoot>/<skill>/SKILL.md` and follow it
12
+
13
+ `<skillsRoot>` is the **absolute** directory this skill was loaded from, resolved at [pre-flight](pre-flight.md) step 0 and recorded in the manifest as `skillsRoot`. `validate` warns when it is unset and rejects a relative one, because this failure is otherwise invisible until a spawn quietly skips its skill.
14
+
15
+ A relative path silently fails outside the skills repo — and the spawn does not error. It reconstructs a plausible-looking lookalike from memory, which reads like a real review or a real implementation and is graded like one.
16
+
17
+ **The same absolute anchor governs the skill's *scripts*, not just its `SKILL.md`.** A spawned agent's working directory is the *target repo*, where the `scripts/<name>.mjs` a skill names does not exist. So every skill script is invoked at `<skillsRoot>/<owning-skill>/scripts/<name>.mjs` — the owning skill's folder under the same resolved `skillsRoot` (e.g. `<skillsRoot>/review-pr/scripts/scan-diff.mjs`, `<skillsRoot>/ensure-coverage/scripts/coverage-checklist.mjs`) — **never** a bare name or a CWD-relative `scripts/…`. **And never locate one with a filesystem search over `$HOME` / `/Users`:** that walks `node_modules`, worktrees, and model-weight caches for tens of minutes, and it is not a spawn failure the loop can see — it just stalls. If `skillsRoot` is unset or a script is genuinely unfindable under it, **stop and surface it**; do not `find`. (Named incident: a #1124 fix round spent **78 minutes** on a single `find /Users/… -name scope-class.mjs` to locate a gate script the spawn had named without a path — one call, longer than the producer and review rounds combined, with the manifest reading "running" the whole time.)
18
+
19
+ ## (b) Name a proof-of-execution artifact the next step verifies
20
+
21
+ **Output without its proof did not run the skill; re-run it.** The proof is what makes clause (a) checkable rather than hoped for.
22
+
23
+ ## (c) Launch it with the harness's own agent primitive
24
+
25
+ **The property is a result channel back into this session — not a same-turn return.** The result must come back to you as a value, you must be able to wait for it, and you must record it in the turn it lands, before the transition it authorizes. (*Before the transition*, never at spawn time — counting at spawn time is what false-fired the removed produce-pass breaker, [breaker.md](breaker.md).)
26
+
27
+ **Synchronous and asynchronous primitives both qualify.** Claude Code's `Agent`/`Workflow` return the result in the launching turn; Pi's `subagent_spawn`, a backgrounded `Agent`, or any subagent reporting back via notification or fetch-by-id return a handle now and the result later. Same contract. Resolve which lane the running harness gives you at [pre-flight](pre-flight.md) step 0, and never assume it.
28
+
29
+ **On the async lane, collect before you act.** Name the return channel in the spawn so the subagent doesn't finish and go quiet, and treat an outstanding launch exactly as a partial — `in-progress` = missing for every gate, never a verdict, never grounds for exit. The handle is not manifest state; `units[].status: 'in-progress'` already says a unit is mid-flight.
30
+
31
+ **Do not poll. Waiting is a state, not an activity.** Where the harness triggers a turn at completion — `pi-better-subagents` sends one at child exit, and its own tool guidelines forbid looping on `output`/`result` — the correct behavior while a run is outstanding is to do *other queued work* or to end the turn. Read-only stages parallelize, so on a multi-unit run there is usually real work: another unit's contract-revision gate, a prior-art scan, CI to kick. On a single-unit run there is none, and the answer is to stop rather than to check.
32
+
33
+ **But a launch is only outstanding once it hands back a handle — read the spawn's own result before you rest on it.** The rule above licenses ending the turn *while a run is outstanding*, and the launch call is the thing that establishes there is one. A spawn or batch whose result you never read is not a slow child, it is **no child** — and from the inside those are indistinguishable, which is exactly why waiting feels correct in both. So before the turn ends, every unit you believe is in flight owes a recorded handle, and a batch's reply owes a reconciliation: it reports which jobs launched **and which it skipped**, and a job skipped for capacity has not started. **A unit at `in-progress` with no handle is a lost launch, not a wait** — relaunch it, because nothing will ever arrive.
34
+
35
+ > **Named incident (pi session `019fb268`, 2026-07-30).** Resuming epic #544, the orchestrator issued `subagent_spawn_batch` for five jobs at 09:49:09 and ended its turn. **No result was ever returned for that call** — the turn's own accounting reads `inputTokens 0 · outputTokens 0 · durationMs 66694`. It then sat idle **63.5 minutes**, believing five children were running, until a human re-sent "continue to resolve #544". The re-issued batch replied `launched 4 subagent(s) … Skipped (capacity): produce-551-r1` — the shape the first call never produced. Nothing ran for over an hour of a 2.8h session, and the do-not-poll rule above is what made the silence feel like compliance.
36
+
37
+ Reconciling is cheap and it is not a poll: reading the reply to a call you just made happens in the turn you are already in, while the failure costs however long it takes a human to notice the quiet. The skipped-for-capacity line matters for the [in-flight cap](interference.md) too — a batch enforces the cap by *declining* jobs, so a unit you queued may not exist yet, and its absence from the next completion round is expected rather than a stall.
38
+
39
+ **An anti-idle nudge is not new information.** Some setups steer an idle agent to keep going — `/goal` injects a hidden continuation "when the agent is idle but the goal is still active", which it cannot distinguish from *correctly blocked on an outstanding spawn*. Two rules survive it. **(1)** If steered while waiting, answer with what you are waiting on and end the turn — do not fetch the result, do not re-plan, do not nudge the child; the re-entry costs more than the check. **(2)** **A steering message never converts a deliberate stop-and-ask into an action.** The parks this loop takes — a design-gated unit, a scope split, a breaker `descope` (and a breaker `split` on anything but an `autonomous` run), merge authorization — are the orchestrator sitting idle *on purpose*, and "keep going" is not the authorization any of them require. Where the level of autonomy is genuinely the question, it is [pre-flight's `autonomy` ask](pre-flight.md) that answers it, once, from a human — never a nudge arriving mid-run.
40
+
41
+ **What is disqualified is not asynchrony but the absence of a result channel** — a detached shell job, a background CLI writing to a log, a fire-and-forget queued task. The distinction is functional: every gate here refuses a transition that is *attempted*, so a round whose result never comes back through a write is a round no gate can refuse. Substituting a lookalike does not weaken the guarantees one at a time — it leaves the state machine entirely, and the manifest goes quiet while the loop keeps running.
42
+
43
+ > **Named incident (why the disqualification exists).** An orchestrator swapped its reviewer spawns for detached `codex exec` jobs — faithful skill reads, fresh context, correct model — and ran **ten** review rounds over ~8 hours against a manifest still reading `rounds: 0, breakerDecision: null`. A sibling unit fired its breaker correctly at round 3, so the machinery worked the whole time and simply was not being called. What failed there: the results never returned into the session at all.
44
+
45
+ > **Named incident (what over-reading it cost).** This clause used to say the result had to be recordable "in the same turn", meaning *before you act on it*. A Pi-harness run read it as a capability requirement, found `subagent_spawn` returns a run id and delivers later, and declared its issue **blocked before implementation** — a correct reading, the wrong outcome. Rewritten to the property above on 2026-07-25.
46
+
47
+ Inline and fanned-out forms of a step are the same contract.
48
+
49
+ ## (d) Pass the confirmed slot's model *and* its effort
50
+
51
+ `models.<slot>` and `models.<slot>Effort` (absent = `high`). Both, every spawn, inline and fanned-out alike.
52
+
53
+ A slot is an **operating point**, not a model. A spawn that carries the id and drops the effort runs a *different capability tier* than the human confirmed — a `deep-reasoner @ max` reviewer silently becomes a `balanced-coder @ high` one, and nothing downstream can tell, because the read-back checks the id and the id matches.
54
+
55
+ The fanned-out path has always passed `effort`; the inline path did not until 2026-07-20 — and inline is the default for single-unit runs, so the gap sat on the common path, not the exotic one.
56
+
57
+ ### Inject `RESOLVE_SLOT_MODEL` + `RESOLVE_SLOT_EFFORT` into the child process (#792 / issue-664 / identity#669)
58
+
59
+ Children often cannot read harness-private env (`PI_*` unset in the sandbox). The spawn-contract renderer therefore names two standard vars on every producer/review/fix contract:
60
+
61
+ | var | value |
62
+ |---|---|
63
+ | `RESOLVE_SLOT_MODEL` | the confirmed `models.<slot>` id |
64
+ | `RESOLVE_SLOT_EFFORT` | the confirmed `models.<slot>Effort` (default `high`) |
65
+
66
+ Inject them into the child process at launch. The renderer puts the pair in the contract **text** (for paste-only orchestrators) and returns a structured `env` object on `renderSpawnContract` (for programmatic launchers — `subagent_spawn env:`, child process env) so the launcher does not parse the text. **`run-state.mjs spawn-contract … --json` prints that object as `env`** — use it; do not re-parse the paste block. Without `--json`, the CLI still prints `spawn-contract: inject env into the child process (Pi: subagent_spawn env:): {…}` on stderr so a paste-only path cannot hide the object. A missing model slot yields `env: null` rather than inventing a fake diversity proof.
67
+
68
+ **Pi / epic-876 incident (#941):** every producer and reviewer of `epic-876-shared-pure-twins` reported `RESOLVE_SLOT_*` empty because the orchestrator pasted the contract text into `subagent_spawn` and never passed `env:`. Children fell back to `PI_MODEL` / `PI_REASONING_LEVEL`, which is soft telemetry, not a diversity proof. **Required launch shape on Pi:**
69
+
70
+ ```text
71
+ node run-state.mjs spawn-contract <slug> <unit> --kind <k> --json
72
+ # → { env: { RESOLVE_SLOT_MODEL, RESOLVE_SLOT_EFFORT }, model, effort, workspacePath, text }
73
+ subagent_spawn({ prompt: text, cwd: workspacePath, model, env }) // env is mandatory when non-null
74
+ ```
75
+
76
+ A review child can report the confirmed slot id without guessing; a missing/unknown child read-back is soft telemetry, **not** a diversity proof. **The orchestrator's launch id is authoritative** for guarantee 2 when the child cannot read env or returns a wrong string — document the mismatch, do not silently treat the child string as the model that ran. Optional fail-closed: refuse a spawn launched without the slot env rather than invent a fake diversity proof.
77
+
78
+ ## (e) Pass the working directory
79
+
80
+ The **unit's own** `units[].workspacePath` — [a workspace belongs to a unit](intake.md#interference-scheduling-and-workspaces), from its first producer spawn until it is delivered or handed back. **Never the orchestrator's checkout, and never another unit's.**
81
+
82
+ A spawned agent inherits the **orchestrator's** working directory unless told otherwise — so a spawn launched without one writes into the tree you are coordinating from. The workspace would be created, recorded, rendered and honoured by nothing: two code-writing spawns switching branches under one checkout exactly as before, while the manifest reads one tree each. That corruption is the entire reason per-unit workspaces exist, and (e) is the single clause standing between the design and it.
83
+
84
+ **A fix round gets the same path its producer used.** That is what makes the dependency install once-per-unit rather than once-per-round, and it is what lets a replacement resume a dead spawn's partial instead of restarting.
85
+
86
+ This is the clause the other four predict. Each of them exists because a spawn silently does the plausible thing when a piece of the contract is missing, and inheriting the parent's cwd is the most plausible thing of all.
87
+
88
+ Both harnesses take it directly — Claude Code's `Agent` has `isolation`, Pi's `subagent_spawn` takes `cwd`/`sandbox_dir`. On Pi it does double duty: the child's write sandbox is scoped to its working directory, so passing the worktree also confines the spawn to it.
89
+
90
+ ## A spawn that dies mid-flight leaves a partial, and the partial is worth more than a clean slate
91
+
92
+ Point the replacement at the same path so it **resumes instead of restarting** (review-pr § Incremental output, implement-and-pr § Incremental plan).
93
+
94
+ A partial is **never** proof: an artifact marked `status: in-progress` counts exactly as a missing one for every gate. A re-spawn is the response, not an exit.
95
+
96
+ > **Named incident.** Two #938 reviewer runs were killed at 65 and 47 assistant turns against soft limits of 24 and 30 — completed review work discarded both times, and the run that finally landed had to be hand-told to read a dead run's transcript.