@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.
- package/LICENSE +3 -0
- package/README.md +90 -0
- package/bin/1aboveio-skills.mjs +18 -0
- package/package.json +28 -0
- package/runtime/skills/distribution/generated/recipes.json +1189 -0
- package/runtime/skills/distribution/scripts/bundles.mjs +280 -0
- package/runtime/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
- package/skills/backend/airflow-dag-develop/LICENSE +3 -0
- package/skills/backend/airflow-dag-develop/SKILL.md +111 -0
- package/skills/backend/app-debug/LICENSE +3 -0
- package/skills/backend/app-debug/SKILL.md +109 -0
- package/skills/backend/app-debug/references/common-errors.md +128 -0
- package/skills/backend/python-backend/LICENSE +3 -0
- package/skills/backend/python-backend/SKILL.md +326 -0
- package/skills/cicd-pipeline/cloud-build/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-build/SKILL.md +707 -0
- package/skills/cicd-pipeline/cloud-debug/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-debug/SKILL.md +316 -0
- package/skills/cicd-pipeline/cloud-debug/references/build-failures.md +238 -0
- package/skills/cicd-pipeline/cloud-debug/references/deploy-failures.md +376 -0
- package/skills/cicd-pipeline/cloud-debug/references/pipeline-failures.md +378 -0
- package/skills/cicd-pipeline/cloud-deploy/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-deploy/SKILL.md +229 -0
- package/skills/cicd-pipeline/cloud-deploy/references/config-templates.md +257 -0
- package/skills/cicd-pipeline/docker/LICENSE +3 -0
- package/skills/cicd-pipeline/docker/SKILL.md +126 -0
- package/skills/cicd-pipeline/google-cloud/LICENSE +3 -0
- package/skills/cicd-pipeline/google-cloud/SKILL.md +118 -0
- package/skills/cicd-pipeline/google-cloud/references/gcs.md +469 -0
- package/skills/cicd-pipeline/google-cloud/references/iam.md +451 -0
- package/skills/cicd-pipeline/google-cloud/references/project.md +349 -0
- package/skills/cicd-pipeline/google-cloud/references/secrets.md +336 -0
- package/skills/cicd-pipeline/google-cloud/references/vpc.md +312 -0
- package/skills/cicd-pipeline/google-cloud/scripts/create-sa.sh +36 -0
- package/skills/cicd-pipeline/google-cloud/scripts/gcp-config.sh +31 -0
- package/skills/cicd-pipeline/google-cloud/scripts/grant-iap.sh +41 -0
- package/skills/cicd-pipeline/google-cloud/scripts/setup-secrets.sh +48 -0
- package/skills/cicd-pipeline/mergify/LICENSE +3 -0
- package/skills/cicd-pipeline/mergify/SKILL.md +138 -0
- package/skills/cicd-pipeline/mergify/assets/templates/mergify.yml +237 -0
- package/skills/cicd-pipeline/mergify/assets/templates/ruleset.json +46 -0
- package/skills/cicd-pipeline/mergify/references/branch-protection.md +277 -0
- package/skills/cicd-pipeline/mergify/references/configuration.md +183 -0
- package/skills/cicd-pipeline/mergify/references/diagnosis.md +73 -0
- package/skills/cicd-pipeline/mergify/references/traps.md +78 -0
- package/skills/cicd-pipeline/mergify/references/watch-contract.md +218 -0
- package/skills/cicd-pipeline/mergify/scripts/audit-core.mjs +131 -0
- package/skills/cicd-pipeline/mergify/scripts/audit.mjs +4 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +663 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery.mjs +4 -0
- package/skills/cicd-pipeline/podman/LICENSE +3 -0
- package/skills/cicd-pipeline/podman/SKILL.md +70 -0
- package/skills/cicd-pipeline/podman/agents/openai.yaml +4 -0
- package/skills/cicd-pipeline/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
- package/skills/cicd-pipeline/podman/assets/templates/podman-service-override.conf +3 -0
- package/skills/cicd-pipeline/podman/references/compose-compatibility.md +70 -0
- package/skills/cicd-pipeline/podman/references/networking-and-ports.md +74 -0
- package/skills/cicd-pipeline/podman/references/rootless-services-and-sockets.md +156 -0
- package/skills/cicd-pipeline/podman/references/troubleshooting.md +98 -0
- package/skills/engineering/e2e-test/LICENSE +3 -0
- package/skills/engineering/e2e-test/SKILL.md +156 -0
- package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +272 -0
- package/skills/engineering/e2e-test/assets/ci-gates.github.yml +451 -0
- package/skills/engineering/e2e-test/assets/e2e-workflow.yml +282 -0
- package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +71 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +219 -0
- package/skills/engineering/e2e-test/references/authoring/test-skipping.md +44 -0
- package/skills/engineering/e2e-test/references/ci-integration.md +121 -0
- package/skills/engineering/e2e-test/references/ci-playwright-container.md +280 -0
- package/skills/engineering/e2e-test/references/debugging.md +36 -0
- package/skills/engineering/e2e-test/references/presentation-sweep.md +131 -0
- package/skills/engineering/e2e-test/references/reviewing.md +39 -0
- package/skills/engineering/e2e-test/references/route-discovery.md +50 -0
- package/skills/engineering/e2e-test/references/route-manifest.md +44 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-fastapi.py +290 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
- package/skills/engineering/e2e-test/scripts/post-visual-evidence.mjs +158 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +148 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
- package/skills/engineering/e2e-test/scripts/presentation-visual.mjs +84 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +75 -0
- package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
- package/skills/engineering/engineering-runtime/LICENSE +3 -0
- package/skills/engineering/engineering-runtime/SKILL.md +10 -0
- package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/engineering-runtime/coherence/workflow.json +553 -0
- package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
- package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
- package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
- package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
- package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +576 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +166 -0
- package/skills/engineering/ensure-coverage/LICENSE +3 -0
- package/skills/engineering/ensure-coverage/SKILL.md +136 -0
- package/skills/engineering/ensure-coverage/evals/evals.json +125 -0
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +91 -0
- package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +83 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
- package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +25 -0
- package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +87 -0
- package/skills/engineering/ensure-coverage/references/depth/test-smells.md +23 -0
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +164 -0
- package/skills/engineering/ensure-coverage/references/enforcement/hooks.md +85 -0
- package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +109 -0
- package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +33 -0
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +78 -0
- package/skills/engineering/ensure-coverage/references/presentation/runner-contract.md +74 -0
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +33 -0
- package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
- package/skills/engineering/ensure-coverage/references/process/review-contract-template.md +119 -0
- package/skills/engineering/ensure-coverage/references/process/scope-class.md +178 -0
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +55 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +45 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +93 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +178 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +101 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +358 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-checklist.mjs +494 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +663 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
- package/skills/engineering/ensure-coverage/scripts/evidence-block.mjs +367 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +269 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/ensure-coverage/scripts/package-lock.json +76 -0
- package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
- package/skills/engineering/ensure-coverage/scripts/scope-class.mjs +554 -0
- package/skills/engineering/harness-runtime/LICENSE +3 -0
- package/skills/engineering/harness-runtime/SKILL.md +18 -0
- package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
- package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
- package/skills/engineering/harness-runtime/contracts.md +15 -0
- package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
- package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
- package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
- package/skills/engineering/harness-runtime/index.mjs +767 -0
- package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
- package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
- package/skills/engineering/harness-runtime/references/model-catalog-seed.json +159 -0
- package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
- package/skills/engineering/implement-and-pr/LICENSE +3 -0
- package/skills/engineering/implement-and-pr/SKILL.md +176 -0
- package/skills/engineering/implement-and-pr/references/ci-iteration.md +10 -0
- package/skills/engineering/implement-and-pr/references/closeout.md +27 -0
- package/skills/engineering/implement-and-pr/references/contract-complete-fix-rounds.md +34 -0
- package/skills/engineering/implement-and-pr/references/evidence-rules.md +39 -0
- package/skills/engineering/implement-and-pr/references/incremental-plan.md +16 -0
- package/skills/engineering/implement-and-pr/references/self-review.md +23 -0
- package/skills/engineering/implement-and-pr/references/tdd-mode.md +18 -0
- package/skills/engineering/resolve-issues/LICENSE +3 -0
- package/skills/engineering/resolve-issues/SKILL.md +167 -0
- package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +448 -0
- package/skills/engineering/resolve-issues/references/breaker.md +82 -0
- package/skills/engineering/resolve-issues/references/deliverables.md +27 -0
- package/skills/engineering/resolve-issues/references/delivery.md +108 -0
- package/skills/engineering/resolve-issues/references/evidence-lane.md +21 -0
- package/skills/engineering/resolve-issues/references/exact-head-ci.md +287 -0
- package/skills/engineering/resolve-issues/references/fan-out.md +33 -0
- package/skills/engineering/resolve-issues/references/finalization.md +68 -0
- package/skills/engineering/resolve-issues/references/guarantees.md +10 -0
- package/skills/engineering/resolve-issues/references/high-risk.md +29 -0
- package/skills/engineering/resolve-issues/references/incidents/848/README.md +156 -0
- package/skills/engineering/resolve-issues/references/intake.md +86 -0
- package/skills/engineering/resolve-issues/references/integration-gate.md +53 -0
- package/skills/engineering/resolve-issues/references/interference.md +87 -0
- package/skills/engineering/resolve-issues/references/loop.md +134 -0
- package/skills/engineering/resolve-issues/references/model-catalog.md +9 -0
- package/skills/engineering/resolve-issues/references/postmortem.md +27 -0
- package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +41 -0
- package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +48 -0
- package/skills/engineering/resolve-issues/references/pre-flight.md +41 -0
- package/skills/engineering/resolve-issues/references/regression-checklist.md +26 -0
- package/skills/engineering/resolve-issues/references/run-state.md +288 -0
- package/skills/engineering/resolve-issues/references/sandboxed-testing.md +48 -0
- package/skills/engineering/resolve-issues/references/spawn-contract.md +96 -0
- package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +40 -0
- package/skills/engineering/resolve-issues/references/why.md +653 -0
- package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +49 -0
- package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +721 -0
- package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +962 -0
- package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +220 -0
- package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +420 -0
- package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +256 -0
- package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +168 -0
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/doctrine.mjs +62 -0
- package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +191 -0
- package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +413 -0
- package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +332 -0
- package/skills/engineering/resolve-issues/scripts/finalize.mjs +488 -0
- package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +3307 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +16 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +51 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +17 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +166 -0
- package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +92 -0
- package/skills/engineering/resolve-issues/scripts/guide-index.mjs +73 -0
- package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +159 -0
- package/skills/engineering/resolve-issues/scripts/interference.mjs +427 -0
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/next-operations.mjs +419 -0
- package/skills/engineering/resolve-issues/scripts/postmortem.mjs +909 -0
- package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +322 -0
- package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +415 -0
- package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +697 -0
- package/skills/engineering/resolve-issues/scripts/report.mjs +494 -0
- package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +172 -0
- package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +79 -0
- package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +334 -0
- package/skills/engineering/resolve-issues/scripts/run-state.mjs +4784 -0
- package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +395 -0
- package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +290 -0
- package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +170 -0
- package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +293 -0
- package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +197 -0
- package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +127 -0
- package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +893 -0
- package/skills/engineering/resolve-issues/scripts/workspaces.mjs +829 -0
- package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +290 -0
- package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +80 -0
- package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +102 -0
- package/skills/engineering/resolve-release/LICENSE +3 -0
- package/skills/engineering/resolve-release/SKILL.md +112 -0
- package/skills/engineering/resolve-release/references/assembly.md +137 -0
- package/skills/engineering/resolve-release/references/auto-when-green.md +56 -0
- package/skills/engineering/resolve-release/references/candidate.md +167 -0
- package/skills/engineering/resolve-release/references/exposure.md +178 -0
- package/skills/engineering/resolve-release/references/handoff.md +24 -0
- package/skills/engineering/resolve-release/references/postmortem.md +230 -0
- package/skills/engineering/resolve-release/references/preflight.md +207 -0
- package/skills/engineering/resolve-release/references/principles.md +94 -0
- package/skills/engineering/resolve-release/references/regression-checklist.md +36 -0
- package/skills/engineering/resolve-release/references/related-skills.md +12 -0
- package/skills/engineering/resolve-release/references/routing.md +149 -0
- package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +285 -0
- package/skills/engineering/resolve-release/references/versioning.md +202 -0
- package/skills/engineering/resolve-release/references/why.md +53 -0
- package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +389 -0
- package/skills/engineering/resolve-release/scripts/build-changes.mjs +209 -0
- package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +407 -0
- package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +904 -0
- package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +81 -0
- package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +612 -0
- package/skills/engineering/resolve-release/scripts/close-attempt.mjs +135 -0
- package/skills/engineering/resolve-release/scripts/closeout-release.mjs +161 -0
- package/skills/engineering/resolve-release/scripts/doctrine.mjs +106 -0
- package/skills/engineering/resolve-release/scripts/durable-processing.mjs +522 -0
- package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +659 -0
- package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +1014 -0
- package/skills/engineering/resolve-release/scripts/finalize-release.mjs +526 -0
- package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +169 -0
- package/skills/engineering/resolve-release/scripts/green-gate.mjs +599 -0
- package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +752 -0
- package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +56 -0
- package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +1538 -0
- package/skills/engineering/resolve-release/scripts/postmortem.mjs +381 -0
- package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +498 -0
- package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +326 -0
- package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +272 -0
- package/skills/engineering/resolve-release/scripts/report.mjs +417 -0
- package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +114 -0
- package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +238 -0
- package/skills/engineering/resolve-release/scripts/review-packet.mjs +503 -0
- package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +263 -0
- package/skills/engineering/resolve-release/scripts/version-assert.mjs +339 -0
- package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +485 -0
- package/skills/engineering/resolve-release/scripts/version.mjs +1199 -0
- package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +449 -0
- package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/README.md +60 -0
- package/skills/engineering/resolve-release/vendor/acorn.mjs +6233 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +341 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +70 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +7 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +2033 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +2033 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +7 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +49 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +5 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +549 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +549 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +36 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +47 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +82 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +22 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +25 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +85 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +85 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +20 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +20 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +61 -0
- package/skills/engineering/review-pr/LICENSE +3 -0
- package/skills/engineering/review-pr/SKILL.md +123 -0
- package/skills/engineering/review-pr/references/adversarial-reviewer-prompt.md +42 -0
- package/skills/engineering/review-pr/references/code-correctness.md +5 -0
- package/skills/engineering/review-pr/references/contract-freshness.md +9 -0
- package/skills/engineering/review-pr/references/coordination.md +18 -0
- package/skills/engineering/review-pr/references/domain-hazards.md +123 -0
- package/skills/engineering/review-pr/references/finding-themes.md +7 -0
- package/skills/engineering/review-pr/references/github-posting.md +98 -0
- package/skills/engineering/review-pr/references/golden-path-smoke.md +5 -0
- package/skills/engineering/review-pr/references/incremental-output.md +16 -0
- package/skills/engineering/review-pr/references/inputs-and-discovery.md +31 -0
- package/skills/engineering/review-pr/references/output-format.md +99 -0
- package/skills/engineering/review-pr/references/over-mock-screen.md +7 -0
- package/skills/engineering/review-pr/references/promotion-prs.md +16 -0
- package/skills/engineering/review-pr/references/re-review.md +18 -0
- package/skills/engineering/review-pr/references/review-method.md +199 -0
- package/skills/engineering/review-pr/references/review-mode.md +30 -0
- package/skills/engineering/review-pr/references/review-posture.md +53 -0
- package/skills/engineering/review-pr/references/round1-depth.md +62 -0
- package/skills/engineering/review-pr/references/scripts.md +17 -0
- package/skills/engineering/review-pr/references/workflow.md +16 -0
- package/skills/engineering/review-pr/schemas/findings.schema.json +282 -0
- package/skills/engineering/review-pr/scripts/finding-contract.mjs +285 -0
- package/skills/engineering/review-pr/scripts/post-review.mjs +405 -0
- package/skills/engineering/review-pr/scripts/pr-context.mjs +207 -0
- package/skills/engineering/review-pr/scripts/scan-diff.mjs +365 -0
- package/skills/engineering/review-pr/scripts/theme-contract.mjs +57 -0
- package/skills/engineering/smoke/LICENSE +3 -0
- package/skills/engineering/smoke/SKILL.md +131 -0
- package/skills/engineering/smoke/assets/smoke.manifest.example.json +53 -0
- package/skills/engineering/smoke/references/manifest.md +192 -0
- package/skills/engineering/smoke/scripts/smoke.mjs +713 -0
- package/skills/fullstack/better-auth/LICENSE +3 -0
- package/skills/fullstack/better-auth/SKILL.md +601 -0
- package/skills/fullstack/better-auth/references/feishu-api.md +270 -0
- package/skills/fullstack/monorepo/LICENSE +3 -0
- package/skills/fullstack/monorepo/SKILL.md +465 -0
- package/skills/fullstack/nextjs-fullstack/LICENSE +3 -0
- package/skills/fullstack/nextjs-fullstack/SKILL.md +210 -0
- package/skills/fullstack/nextjs-fullstack/conventions.md +318 -0
- package/skills/fullstack/nextjs-fullstack/frontend-conventions.md +61 -0
- package/skills/fullstack/nextjs-fullstack/nextjs16.md +287 -0
- package/skills/fullstack/nextjs-fullstack/server-actions.md +409 -0
- package/skills/fullstack/prisma-setup/LICENSE +3 -0
- package/skills/fullstack/prisma-setup/SKILL.md +180 -0
- package/skills/fullstack/prisma-setup/nextjs.md +258 -0
- package/skills/fullstack/prisma-setup/turborepo.md +301 -0
- package/skills/fullstack/shadcn/LICENSE +3 -0
- package/skills/fullstack/shadcn/SKILL.md +119 -0
- package/skills/fullstack/shadcn/assets/shadcn-small.png +0 -0
- package/skills/fullstack/shadcn/assets/shadcn.png +0 -0
- package/skills/fullstack/shadcn/cli.md +411 -0
- package/skills/fullstack/shadcn/customization.md +224 -0
- package/skills/fullstack/shadcn/evals/evals.json +90 -0
- package/skills/fullstack/shadcn/mcp.md +101 -0
- package/skills/fullstack/shadcn/rules/base-vs-radix.md +323 -0
- package/skills/fullstack/shadcn/rules/component-selection.md +67 -0
- package/skills/fullstack/shadcn/rules/composition.md +195 -0
- package/skills/fullstack/shadcn/rules/data-table.md +201 -0
- package/skills/fullstack/shadcn/rules/forms.md +255 -0
- package/skills/fullstack/shadcn/rules/icons.md +103 -0
- package/skills/fullstack/shadcn/rules/styling.md +167 -0
- package/skills/fullstack/zod-v4/LICENSE +3 -0
- package/skills/fullstack/zod-v4/SKILL.md +287 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# The loop, per unit: produce -> review || CI -> fix
|
|
2
|
+
|
|
3
|
+
The three steps run per unit and repeat until the review passes. Kept in one file
|
|
4
|
+
because a unit *iterates* between review and fix — splitting them would cost a
|
|
5
|
+
second read on every round. Previous: [intake.md](intake.md) · next:
|
|
6
|
+
[delivery.md](deliverables.md#deliverables-the-shippable-component-not-the-whole-epic).
|
|
7
|
+
|
|
8
|
+
## The loop (per unit)
|
|
9
|
+
|
|
10
|
+
This loop applies only to units whose confirmed `unitKind` is `implementation`.
|
|
11
|
+
`external-verification`, `human-decision`, and `prerequisite` remain in their recorded
|
|
12
|
+
non-code protocols; neither a prepared artifact nor a harness `PASS` routes them here.
|
|
13
|
+
|
|
14
|
+
### 1 — Produce (one spawn: implement + e2e + gates + PR)
|
|
15
|
+
|
|
16
|
+
**One producer spawn per unit** — before rendering it, a unit whose intake set `evidenceLifecycle.required: true` must carry `units[].evidenceLifecycleContract`; `spawn-contract` validates the complete artifact and refuses before implementation when it is missing or invalid. The rendered producer and reviewer prompts carry the same validated artifact. The reviewer checks implementation against it, but it never replaces independent code review or live provider evidence. Then read `<skillsRoot>/implement-and-pr/SKILL.md` and follow it end-to-end: implement to the work item, test to the criteria (TDD for criteria-backed work, `@covers`/`@level` tags), browser surfaces per its e2e-test step (route manifest + presentation sweep), run the ensure-coverage gates (`lint-tests --diff`, `coverage-ledger validate`, checklist generate/validate), and open/update the PR with the full **Review Contract** (including the **`Implementation Model`** line — the read-back). It works in **the unit's own workspace** (clause (e); a fix round reuses the same one); branch off the fetched `targetBranch` head (`origin/<targetBranch>`, never a stale local branch), or the dependency's branch when it blocking-interferes with one; never a protected branch. **Derive `units[].pushedSha` — never remember it.** In the same turn the producer returns, read the head off the remote and record it, without waiting to be told a push happened:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
gh pr view <pr> --json headRefOid -q .headRefOid # or: git ls-remote origin <branch> | cut -f1
|
|
20
|
+
run-state.mjs upsert-unit <slug> '{"id":"<unit>","pushedSha":"<sha>","pr":"#<n>"}'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This is what makes the unit's dependents runnable, and an unrecorded push strands them. It is stated as a derivation rather than an obligation because the obligation already existed and was still missed on **every unit of a four-unit epic** (`epic-563-admin-transactions`: `pushedSha` null ×4, ten hours, [why](why.md#the-in-flight-cap-and-its-default)). A field the loop must remember to write at a moment it is not otherwise stopping is a field that does not get written; a field read off the remote in a turn that is already happening does. `unitPushed` also accepts a recorded `pr` as proof — a PR cannot exist over an unpushed head — so recording the PR number covers the same ground, which is why both go in one write. Before spawning, verify the branch will contain `units[].contractRevision.sha`; a contract-revision re-entry is a whole-contract reconciliation, not an incremental repair of findings derived from the superseded design. High-risk units carry the [high-risk](high-risk.md) producer additions. **Proof:** the Review Contract, tagged tests, and SHA-stamped gate results — the Contract's `Implementation Model` line is the read-back for clause (d), and a substitution recorded there goes to `units[].implementationModel` so the diversity guard compares the pair that actually ran. → [why one spawn](why.md#one-producer-spawn-per-unit)
|
|
24
|
+
|
|
25
|
+
**Do not compose the spawn prompt — render it: `run-state.mjs spawn-contract <slug> <unit> --kind producer|fix`, and paste what it prints.** It fills in the absolute `<skillsRoot>` read, the unit's own `workspacePath`, the slot's model **and** effort, the round conditionals `implement-and-pr` routes its heavier material behind (terminal round, `highRisk`, scope class, contract revision), any `orderedAfter` invariant, and the gate list **with its flags**. Exit 4 means state is missing a clause the spawn needs — fix the state, don't hand-fill it.
|
|
26
|
+
|
|
27
|
+
Why a command and not a paragraph, since this used to be one: measured over 33 sessions and 163 producer spawns, the prompt is composed **once per run and then repeated**, never re-derived from this file. **10 of 17 sessions with 4+ producer spawns varied by at most one gate across the entire run** — one sat at 2 of 5 gates for 27 consecutive spawns, another named all 5 eighteen times, another named none nine times. Where it moved it more often decayed than improved (7 down, 3 up), and the decays were on the longest runs. So the whole run inherits whatever the first composition happened to contain, and the flag that makes the checklist *decide* (`--diff`) reached **10%** of spawns — which is what a producer's green turning red under the reviewer's run costs, one evidence round at a time. A rendered contract is identical on spawn 1 and spawn 33 and cannot decay. → [why](why.md#the-spawn-contract-is-rendered-not-composed)
|
|
28
|
+
|
|
29
|
+
**And pass every unmet `orderedAfter` invariant, verbatim** — `run-state.mjs runnable` prints them under the admitted unit. A unit with a premise dependency is scheduled **ahead of** the unit it rests on (since 2026-08-04 a premise edge orders delivery, not the build — [interference.md](interference.md)), so its producer is writing against an assumption that is *not true in the tree yet*. Say so in the spawn: "you are building against the assumption that X; #579 establishes X and has not landed." That sentence is the entire safety mechanism — it is what makes the dependent's premise **declared** rather than silent, which is the hazard the old scheduling block was defending against and the only part of it worth keeping. The **reviewer** gets it too, so it verifies the code against a named assumption instead of inferring one. A premise dependent whose spawn did not carry its invariant has been built blind, and the round is not trustworthy: re-spawn it with the invariant rather than reviewing what came back.
|
|
30
|
+
|
|
31
|
+
**Record what the spawn returns — you are the manifest's only writer.** No spawn writes the run manifest; each returns its data as a value and you record it in the turn the result lands, exactly as you already do for `record-round` and `record-gate-result`. Three values arrive this way, and a returned value nobody records is a lost field, not a deferred one:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
run-state.mjs record-scope-class <slug> <unit> --stdin # producer's `scopeClass` (the classifier's JSON)
|
|
35
|
+
run-state.mjs record-review-round <slug> <unit> --stdin # lean: {round,verdict,headSha,scope?,themeIds?,findings?} — headSha accepted (#792)
|
|
36
|
+
run-state.mjs record-fix-round <slug> <unit> --stdin # lean: {reviewRound,headSha,themeIds,changedSurfaces?,classesClosed?}; CLI derives/validates surfaces
|
|
37
|
+
# deep-audit matrix only when high-risk deep protocol is active
|
|
38
|
+
run-state.mjs upsert-unit <slug> '{"id":"<unit>","visualEvidence":{…}}' # post-visual-evidence's returned URLs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**The visual one is not a paste — the key is renamed on the way in.** `post-visual-evidence.mjs` returns `{ unit, visual: { durableBaselines, diffArtifact } }`; the manifest field is `units[].visualEvidence`, and it takes the **value of `visual`**, not the whole returned object. So `visualEvidence` ← `returned.visual`. Pasting the returned object whole nests it as `visualEvidence.visual.durableBaselines` and every reader of the field silently sees nothing.
|
|
42
|
+
|
|
43
|
+
Why here rather than in the spawn that produced it: `writeManifest` is atomic per write but nothing guards the read-modify-write around it, so two spawns finishing together silently drop one's changes — harmless only while code-writing spawns are serialized, which is the very thing #553 removes. Correct by construction, not by mutual exclusion (ADR 0001 decision 5 (`docs/adr/0001-interference-is-the-scheduling-primitive.md`)).
|
|
44
|
+
|
|
45
|
+
### 2 — Review ∥ CI (same breath, same HEAD)
|
|
46
|
+
|
|
47
|
+
**Pre-spawn check (decidable, no review spent):** the handoff carries the **screens** green — `scan-diff.mjs`'s findings channel empty and `coverage-checklist.mjs validate` passing — plus the contract with its `Implementation Model` line. Anything missing or red → bounce straight to step 3, taking the **evidence-only lane** there when the production diff hasn't moved.
|
|
48
|
+
|
|
49
|
+
**Pass the checklist validate its `--diff <merge-base>`.** Without it the check degrades to *shape*: it asks whether a row looks like it cites something, not whether the citation is true, and a row citing a file that no longer exists passes. With it the validator resolves every cited `file:line` against the tree, exempts paths this PR deletes, and warns on locators that sit entirely outside the net diff. That difference is most of the evidence lane's remaining volume — a stale locator caught here costs seconds; caught by the reviewer it costs a round. → [why](why.md#the-checklist-screens-resolve-locators)
|
|
50
|
+
|
|
51
|
+
**The one exception, and it is the manifest's to grant, not the producer's:** accept an **absent** coverage checklist only when `units[].scopeClass === 'no-surface'` is recorded on the manifest (`run-state.mjs record-scope-class`, written from `ensure-coverage`'s `scope-class.mjs classify` — deny-by-default over the net diff). Never on the producer's say-so, and never on an absent field: absent means *not classified yet*, which is not `no-surface`. → [why](why.md#the-no-surface-checklist-exception) On a `no-surface` unit the handoff instead carries the **matched class's declared oracle and its result** — the oracle replaces the checklist, it is not a waiver, so a matched class with no oracle is a blocking finding and bounces like any other red screen. **Everything else in this step is unchanged**: same reviewer spawn, same model-diversity rule, same verdict bar, `scan-diff`'s findings channel still zero-tolerance, CI still green on the exact head. An inferred scope class never lightens the review — and it is orthogonal to `highRisk`, which merge/CI/deploy/IAM paths *raise* while classifying `no-surface` ([scope-class.md](../../ensure-coverage/references/process/scope-class.md)).
|
|
52
|
+
|
|
53
|
+
**Record every gate result as it happens — `run-state.mjs record-gate-result`, in the same turn the gate runs.** A gate that ran clean and one that did not run are otherwise indistinguishable, which makes [the removal path](../SKILL.md#the-removal-path-keep-this-skill-small)'s rule 2 unrunnable. `ran: false` and `result: skipped` each owe a `reason`; they remain distinct report states. When a gate reports findings, include `findingDetails: [{class, locator, blocking, outcome}]` so rounds/units deduplicate by stable class+locator; include `durationMs` only when the harness already exposes it. → [why](why.md#the-removal-path) The write is refused only on its own shape, never on unit state. `progress` renders this run; `gate-audit` also appends/reads the durable cross-run series and is the only retirement recommendation surface.
|
|
54
|
+
|
|
55
|
+
**The screens gate every round; the stamped attestation is owed only by the round that requests the terminal review — and on *that* round it is a pre-spawn screen too.** `evidence-block.mjs validate` is deliberately *not* a per-round precondition: it asserts a whole generated block still matches HEAD, a claim the next fix commit voids, so demanding it every round buys a document rewrite per round. But "not every round" is not "never". On the round you flag terminal, run it **before** the reviewer spawn, at the SHA you are about to have reviewed, and treat red exactly like a red screen — bounce to step 3's evidence lane. Otherwise the one round whose stamp is actually owed is the one round nobody checks it on, and a stale stamp surfaces as an evidence-class finding on the *terminal* review: the most expensive round in the unit to spend on paperwork, and one that then needs its own re-review to exit. It costs seconds and you are already running `collect`. → [why](why.md#the-screens-and-the-terminal-round-attestation)
|
|
56
|
+
|
|
57
|
+
Kick CI and spawn the reviewer **together** — they consume the same pushed HEAD. **Don't block the fix on CI:** the moment the review verdict returns, start the fix on its findings; CI keeps running in parallel and its failures fold into whichever fix round is live when they land. What this does **not** move is the exit bar: the loop still ends only on CI honestly green **and** an independent APPROVE **on the same final HEAD** (guarantee 3), so a review APPROVE with CI still pending or red is not terminal — you wait out that one CI run, once, at the end. → [why](why.md#review--ci-and-not-blocking-the-fix-on-ci) The reviewer spawn: **fresh context, the confirmed review model (assert the read-back)**, and this contract — never a paraphrase:
|
|
58
|
+
|
|
59
|
+
Use the [exact-head CI adapter](exact-head-ci.md) for either an existing provider run
|
|
60
|
+
on the current PR head or temporary PR retarget/close/reopen plus workflow dispatch.
|
|
61
|
+
Never hand-author the mutation sequence. Feed its mode-declared SHA-bound artifact to
|
|
62
|
+
`evidence-block.mjs collect --exact-head`; skipped jobs remain skipped, observed-run
|
|
63
|
+
head drift blocks, and choreographed runs additionally require proved restoration.
|
|
64
|
+
**Name review-pr's conditional references and their triggers in the spawn contract** — it routes round-2+, promotion, high-risk and contract-freshness material behind caller-computed conditions, and you are the caller: pass `lastReviewedSha` (⇒ round ≥ 2 re-review), the `highRisk` flag (round-1 depth, finding themes), the contract-revision SHA, and whether `pr-context.mjs` reports `promotion: true`. A reviewer that is not told cannot know, and silently reviews at the wrong depth rather than failing.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
> Read `<skillsRoot>/review-pr/SKILL.md` (absolute) and follow it; do not improvise. Subject: the net merge-base...HEAD diff of `<prRef>` (compute it with `<skillsRoot>/review-pr/scripts/pr-context.mjs`), read-only. Run the four-axis adversarial scan; return schema'd findings, each with a real `file:line`, a confidence, and a stable `theme` id. Run `<skillsRoot>/ensure-coverage/scripts/coverage-checklist.mjs validate` and report the result. Run the mechanized over-mock screen (`<skillsRoot>/review-pr/scripts/scan-diff.mjs`) and report its decidable `findings` channel **verbatim** (resolve every skill script at `<skillsRoot>/<owning-skill>/scripts/…`, never a CWD-relative `scripts/…` and never by searching `$HOME` — see [spawn-contract.md](spawn-contract.md) clause (a)) — every hit is a zero-tolerance blocker. Hunt over-mocks, skip-to-green, weakened assertions, fixed timeouts, and degraded-page assertions — these fail regardless of CI color. Verdict is calibrated: a blocker must map to a named blocking class (review-pr § Verdicts and the blocking bar); everything else is a note inside a PASS. Classify every finding `subject: code|evidence` — `evidence` only when the fix would touch no source file (contract wording, checklist rows, evidence locators); omitting it means `code`. **The caller routes an unmoved-diff round on this**, so misclassifying a code defect as evidence skips its adversarial re-review — when unsure, leave it `code`. Report back the **model id and effort you actually ran on**: the orchestrator asserts them against the confirmed review slot, and a read-back that does not match means the verdict does not count toward guarantee 2. **If you post the verdict to GitHub, post it as the caller instructs — approval or comment — and never upgrade a comment to an approval on your own judgement.**
|
|
68
|
+
|
|
69
|
+
**Before that spawn, resolve how its verdict may be posted — `run-state.mjs approval-gate <slug> [componentId]` — and tell it which.** Omit the component id for preliminary unit review; it must remain comment-only on auto/hybrid repos even when mergeShippable is on. Supply the id only for the terminal frozen-component review. On a repo that auto-merges once its conditions hold, an approving review satisfies one of them, so **posting the approval is the merge** and it inherits guarantee 4: exit 1 means the reviewer posts a **comment**, carrying the full verdict, and merges nothing. This is the counterintuitive case — the review can PASS and the approval still be withheld, because `mergeShippable` off means hand back. Deciding this in the reviewer spawn instead of here would put the merge authorization in the hands of the agent least able to see it. → [why](why.md#the-enqueue-trigger)
|
|
70
|
+
|
|
71
|
+
**Exit 0 on an `auto`/`hybrid` trigger is not "post it" — it is "this approval is the merge, so it owes the merge's bar."** A preliminary unit review therefore posts as a comment: no component candidate is authorized yet. Only the terminal component review may become an approval, and only after [`combine-and-verify.mjs mergeable --component <id>`](../scripts/combine-and-verify.mjs) exits 0 against the live frozen HEAD, exactly as an enqueue would. The gate's own answer says this in its `reason`; it is repeated here because the reason string is read by whoever ran the command, while the act of posting happens one spawn away. Note which way the exposure runs: under `supervised` this branch is rare, so an approval posted the moment the verdict landed usually merged nothing. Under the recommended `autonomous` it is the **common** path — the same shortcut now merges, and the loop's own review is what trips it. → [why](why.md#the-enqueue-trigger)
|
|
72
|
+
|
|
73
|
+
Append the unit's `contractRevision` SHA + refs to that spawn contract. The reviewer first verifies that PR HEAD contains that target-branch revision and treats it as the source authority; ancestry failure is `NEEDS_CHANGES` before any approval can count. When the revision differs from `units[].reviewedContractSha`, withhold `lastReviewedSha` and require a full-scope review.
|
|
74
|
+
|
|
75
|
+
High-risk units append the [high-risk reviewer additions](high-risk.md). Collect the verdict, the review model used, the findings, and the **two proof artifacts** (checklist validate result + scan-diff channel) — a verdict arriving without them is rejected before it is read.
|
|
76
|
+
|
|
77
|
+
**Re-reviews (round ≥ 2) are delta-scoped by default** (review-pr § Re-review): reconcile every prior finding against the current tree (Previous Findings — Resolution Status; claimed-fixed without a locator stays Unresolved), and run the fresh scan on `lastReviewedSha..HEAD` only — **two dots, and the count matters.** `lastReviewedSha` is a prior *head* of this branch, not a base, so three-dot resolves to `merge-base(lastReviewedSha, HEAD)`. While a branch only ever gains commits those are the same commit and either spelling works; the moment it is **rewritten** — squash, amend, rebase, `mergify stack squash` — the two heads become siblings off the original base, and three-dot silently widens to the *full* net diff. The re-review then runs full scope while recording `scope: "delta"`, so the lane's entire saving disappears and nothing fails to say so. (`review-pr`'s `<merge-base>...HEAD` is a different range and is correct — there the left side really is the base.) Reconciliation is against the invariant *class* each fix names, not the line originally cited (review-pr § Re-review). Force full scope — by withholding the SHA — when the unit is high-risk, on round 3 and every third, when the delta leaves the original diff's files, after a rebase, or when the authoritative contract revision changed. **Record `units[].lastReviewedSha` and `units[].reviewedContractSha` after every verdict — and log the round itself:** `run-state.mjs record-round <slug> <unit> '{"verdict":…,"headSha":…,"reviewSubject":"code|evidence","themeIds":[…],"authorizationBoundary":{"kind":"head|ci|contract|integration","value":…},"scope":"delta|full"}'`. The CLI derives `changedSurfaces` from Git between the prior reviewed HEAD (or recorded audit/base boundary) and `headSha`; a supplied override must match. **Write it in the same turn the verdict lands, before the fix spawn.** An evidence subject also requires `evidenceClasses`. After PASS, add a matching typed `reopenReason` and change the authorization boundary. → [why](why.md#delta-re-reviews-and-the-round-log)
|
|
78
|
+
|
|
79
|
+
### 3 — Fix, then loop
|
|
80
|
+
|
|
81
|
+
**After a preliminary unit PASS: record the unit-discovery candidate update in the same turn; do not launch delivery for the unit PR.** The per-unit CI result still belongs to that preliminary evidence. Delivery begins only after the complete component candidate is frozen and terminally authorized. Then launch the single CI→delivery background pipeline against the component PR and its authorized component HEAD (`watch-delivery.mjs --pr <n> --repo <owner/name> --head <componentHeadSha>`). See [delivery.md](delivery.md) (#792 / issue-664 / identity#669; hybrid observation from #791). The orchestrator records and routes the terminal JSON:
|
|
82
|
+
|
|
83
|
+
| exit | reason | meaning | next |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| 0 | — | merged (`mergedSha` + `mergedAt`) | `combine-and-verify.mjs delivered`/`queue-delivered` → one `record-component-delivery-attempt` + atomic `record-component-delivery-outcome` |
|
|
86
|
+
| 5 | `ci-failed` | CI failed on exact HEAD | fold into fix round (existing doctrine) |
|
|
87
|
+
| 4 | **`stall-while-queued`** | watch stall while the queue still holds the PR (frozen picture under Preparing checks / similar) | **not a unit hand-back.** Same turn: `gh pr view --json state,mergedAt,mergeCommit` once; if MERGED, record delivery + ancestry; if still OPEN, **relaunch** the same `--head` watch. Never `outcome: handed-back` for the unit and never re-enqueue the same HEAD. (issue-799-800 #807 / PR #810; [delivery.md](delivery.md)) |
|
|
88
|
+
| 4 | `head-drift` | tip ≠ `--head` | re-review the new head (never treat as merged/ci-failed for the old SHA) |
|
|
89
|
+
| 4 | `dequeued` / `conditions-unmet` / `unreadable` / closed | queue exit or real unmet condition | hand-back / dequeue routing per [delivery.md](delivery.md); do not re-enqueue an unchanged HEAD |
|
|
90
|
+
|
|
91
|
+
Exit 4 is the watch process ending without a merge — **route on `reason`, not on the exit code alone.** Collapsing every exit 4 into unit hand-back is what turned a healthy Preparing-checks stall into multi-hour `outcome-write-lag` on #807.
|
|
92
|
+
|
|
93
|
+
On `enqueueTrigger ∈ {hybrid, auto}` do **not** wait for an explicit enqueue — the repo may already be auto-merging. Pure `manual` still enqueues first, then launches the same `--head` watch. Never poll CI or the queue in the foreground.
|
|
94
|
+
|
|
95
|
+
**A PASS ends the unit loop and becomes preliminary component evidence. Notes inside a PASS do not buy a unit round.** The verdict is calibrated by the reviewer, and it already separates the two: a blocker maps to a named blocking class, and *everything else is a note inside a PASS* (step 2's contract says this to the reviewer in those words). File notes as `deferrals[]` with tracking issues; preserve the exact passed unit head and review record, then immediately feed it to the component candidate (`record-component-candidate`, round class `unit-discovery`). You may not spend a unit fix round on a P2 the reviewer declined to block on, and you may not re-review that unit head merely because assembly is still moving. A genuine unit-owned defect may reopen with `ci-red`, `head-rewritten`, `contract-revised`, `integration-finding`, or `external-review` plus a changed matching boundary. **`external-review`** (epic-876 / #941): after independent PASS, before enqueue, check open non-self `CHANGES_REQUESTED` reviews — if one names a real AC/code gap, reopen with `reopenReason: external-review` and `authorizationBoundary: {kind: head, value: <new-head>}` rather than treating it as note-chasing or as a probable-rebase postmortem demotion. A component-only conflict or integrated-test fix belongs to the integration candidate (`integration-fix`), not a rewrite of an already-passed unit branch.
|
|
96
|
+
|
|
97
|
+
The measured cost of the other habit: `epic-563-admin-transactions` logged **8 review rounds across 4 units and 3 of them re-reviewed an already-PASSed head**. `#572` passed independent review at minute 220 and merged at minute 367 — 147 minutes, of which one full fix-plus-re-review cycle was spent on two findings the reviewer had labelled non-blocking. Only one of the four units' extra rounds followed an actual `NEEDS_CHANGES`. A run that treats PASS as provisional has no exit condition except the orchestrator's taste, and taste does not converge. → [why](why.md#a-pass-is-terminal)
|
|
98
|
+
|
|
99
|
+
The fix spawn is a producer spawn (step 1's contract) pointed at the review findings **plus every CI failure known at spawn time** — including one carried from an earlier round whose CI landed after that round's fix had already started (the decoupling in step 2): fix **causes** — never by skipping, weakening, or asserting on a degraded page — and re-run the step-1 close-out on the fix diff before requesting re-review (a fix that clears old findings while adding an unscreened new blocker is the classic round-3 cause). A finding with a `hazard_candidate` is fixed in two parts: code + the hazards-file row, same commit.
|
|
100
|
+
|
|
101
|
+
- **Proof budget:** demonstrating any finding, fix, or CI claim gets **at most one reproduction artifact per round, inside the unit's branch/PR** — never a proof-only PR, never proof iteration across rounds. Undemonstrable within budget → a framed decision for the human, not another spawn wave.
|
|
102
|
+
- **A fix never changes the PR's scope class.** When the blocker turns out to be a **pipeline gap** — CI structurally cannot pass this *class* of PR (docs-only, generated-only, config-only) — that is an infrastructure unit of its own: route it to a new issue/PR and pause this unit on it if truly blocked; never append workflow/CI-policy commits to a content PR. → [why](why.md#a-fix-never-changes-the-scope-class)
|
|
103
|
+
- **Every fix round closes the invariant class, not the counterexample.** A finding is an *instance*; what you fix is the rule it violates, across every path, field, state, and interleaving that rule covers. The fix spawn names, in the commit and in the Review Contract, **the class it closed and the adjacent members it checked** — an unstated class is an unclosed one. With a design input, the ADR's invariant list *is* the class boundary; without one — the common case — derive the class the finding implies, state it, and close it. **Size the naming to the finding:** most findings *are* their own class (a typo, a null check on the only field that has one), and there the class is one clause; the rule earns its keep on findings whose rule has siblings — orderings, concurrency, immutability, permission checks. Demanding an enumeration on a CRUD fix is the same over-triggering failure as demanding a design brief for one. → [why](why.md#every-fix-closes-the-invariant-class)
|
|
104
|
+
- **Is this round even about the code?** Two independent signals must both hold, and neither is your judgment about code you did not read. **(a) The production diff did not move** since `lastReviewedSha` — read from `evidence-block.mjs`, never a hand-rolled `git diff`. **(b) The reviewer classed every surviving finding `subject: evidence`** — it read the diff and you did not, so this is read, never inferred. **Either signal absent → ordinary round.** With both, spend a narrow **evidence-fix spawn** rather than a producer spawn plus re-review — and note what that is *not*: it is not you editing the files. You coordinate, never implement, and that rule does not lapse because the diff is small.
|
|
105
|
+
|
|
106
|
+
The spawn contract, the touch-no-source constraint, the one-round budget and the rebase case: [references/evidence-lane.md](evidence-lane.md). **This lane should now be rare** — if it is the common path, the question is why the screens are not catching what the reviewer is catching. → [why](why.md#the-evidence-lanes-two-signals)
|
|
107
|
+
|
|
108
|
+
- **Name the class when you record the round** — `record-round` requires `evidenceClasses` whenever `reviewSubject: evidence`, one or more of `stale-locator` · `unrun-gate-row` · `stale-stamp` · `contract-drift` · `checklist-row` · `other`. It costs a word and it is the only thing that makes the question above answerable: `reviewSubject: evidence` records what was reviewed independently of which surfaces changed, and the loop has been unable to tell the two repairs apart. The first three are **already screened**, so a recurring one means an existing screen was skipped or run without `--diff` — fix the call, do not add a gate. The rest recurring means nothing mechanizes that class yet, and those rounds are the named incident a new screen would be added with ([the removal path](../SKILL.md#the-removal-path-keep-this-skill-small), rule 1). `run-state.mjs evidence-audit <slug>` is what reads it. → [why](why.md#the-checklist-screens-resolve-locators)
|
|
109
|
+
**When a unit isn't converging, the escalation is the circuit-breaker — one rung, and the loop takes only the reversible half of it.** It does not lower the exit bar: a unit still ends only on guarantee 3's independent verdict against its final HEAD. There is deliberately no cheaper advisory rung above it. → [why](why.md#the-circuit-breaker-and-bounded-autonomy)
|
|
110
|
+
|
|
111
|
+
**One threshold — the 3rd completed *review* round with no PASS verdict** (`firedOn: review-rounds` — the code keeps failing review). The breaker counts *completed* review rounds only: a producer/fix spawn that dies with zero code never advances it. (A second, produce-pass threshold that counted spawns at spawn time was removed — it false-fired when early-death spawns produced nothing before any review ran. → [why](why.md#the-circuit-breaker-and-bounded-autonomy))
|
|
112
|
+
|
|
113
|
+
**The diagnosis is computed, never written from memory** — `run-state.mjs diagnose-breaker <slug> <unit>` reads the round log's `themeIds` and returns the signal, the recommendation, and the verbatim text to pass through unaltered. **Exit 0 = the loop takes this decision itself; exit 1 = it owes the human an answer.** `record-breaker-decision --auto` applies it. The routing that matters here:
|
|
114
|
+
|
|
115
|
+
- **`continue` and `design` are the loop's to take** (`breakerAutonomy: auto`, the default). `continue` spends one bounded round; `design` routes to `/grill-with-docs`, which is itself a human interview, so automating the decision stops asking permission to ask them.
|
|
116
|
+
- **`split` is the loop's under `autonomy: autonomous`, the human's under `supervised`; `descope` is always the human's.** Both refused in state rather than by convention, and an auto-applied split must stamp `autonomyAtDecision` on its own record. The asymmetry is real and measured: a split *re-slices* and shrinks the per-round context on a unit already carrying the largest diff in the run (5 uses in 602 units), while a descope *delivers less than was asked* — the one decision that leaves no trace in the handoff (0 uses). A split that drops a slice owes a tracked `deferrals[]` entry, or it is a descope wearing another label.
|
|
117
|
+
- **A recurring theme buys a mandated class-complete round before it buys a human** — the remedy this skill already prescribes. If the theme survives that round, the next firing takes the split/descope decision on the rule above.
|
|
118
|
+
- **Nothing is auto-decided at or above the 8-round ceiling.** Past it the breaker is a hard stop-and-ask whatever the diagnosis says.
|
|
119
|
+
|
|
120
|
+
Full procedure, the audit behind it, and the re-entry rules: [references/breaker.md](breaker.md).
|
|
121
|
+
|
|
122
|
+
Loop 2→3 until, for the current HEAD: CI honestly green, checklist validates, every prior finding genuinely Resolved, and the independent verdict is APPROVE (or PASS with only notes) — or the breaker stops the unit for a human decision.
|
|
123
|
+
|
|
124
|
+
**"CI honestly green" is a question about the SHA, not about the checks you named — ask it with [`head-check-set.mjs`](../scripts/head-check-set.mjs).** A required-check plan asks whether the checks it *names* are green; it never asks what else is red, and #1081 is the seven-hour bill for that. Two release workflows were rejected by GitHub at validation time and executed **zero jobs on every push across fourteen commits**, while the unit earned an independent PASS and was marked merge-ready — because `skill-script-tests`, the named required check, was genuinely green. The subtlety that defeats the obvious fix: a workflow GitHub cannot parse produces **no check-run at all**, so "read every check-run instead of the named ones" answers green too. Run `collect --repository <owner/name> --head <sha> [--plan required-check-plan.json]` in the same turn you record a CI result. It reads check-runs, legacy commit statuses **and Actions runs including ones with zero jobs**, and separates three states the loop used to blur: required-and-red, **not-required-and-red** (informational — the #1081 case), and never-ran-at-all, which in turn distinguishes a missed event from a pending job from an out-of-band dispatch (#1058). It exits 1 on the required set only, exactly as today's contract does: whether an undeclared red should stop a merge belongs to `.mergify.yml` and the human, never to a reporting script. Silence is the one outcome that is not allowed. → [exact-head-ci.md § the full check set](exact-head-ci.md#the-full-check-set-at-a-head)
|
|
125
|
+
|
|
126
|
+
**When a unit leaves the loop, render `run-state.mjs progress <slug>` — and ask `run-state.mjs runnable <slug>` in the same breath.** Every stop or terminal disposition: undelivered `merge-ready`, `delivered`, `handed-back`, `already-done`, `descoped`, `blocked`, or a breaker stop. Record human descopes only through `record-scope-decision`; it refuses automation and unreconciled dependencies. `progress` reports each disposition separately, so a descope never enters delivered or already-done totals. `runnable` is the *decision*, and it is the one that must not be improvised.
|
|
127
|
+
|
|
128
|
+
**`runnable` is the scheduler. You do not have a second one.** Ask it at every milestone a unit passes — a push, a verdict, a delivery, a hand-back — and spawn exactly what its `ADMIT NOW` block names, carrying each `orderedAfter` invariant verbatim into the spawn. Do not derive the next unit from your own reading of the dependency graph, and above all **do not schedule on "merged."** The bar is *pushed*, and `runnable` already applies it (`pushedSha`, or a recorded `pr`, or a resolved unit); a premise edge does not hold a dependent back at all since 2026-08-04, it only orders delivery.
|
|
129
|
+
|
|
130
|
+
This is stated imperatively because the failure is not disagreement, it is **omission under load**. `epic-563-admin-transactions` called `runnable` **zero times in 626 minutes** across 45 other `run-state.mjs` invocations, and hand-scheduled its two UI units on the backend's *merge* instead of its push: `#573` was admittable from minute ~15 and was spawned at minute **347**. The orchestrator was not wrong about the graph — it wrote the correct rule into its own narration at minute 447 ("the skill's rule is *pushed*, not merged") after applying the wrong one for six hours. Prose it agrees with is not the mechanism; the command is. → [why](why.md#the-in-flight-cap-and-its-default)
|
|
131
|
+
|
|
132
|
+
It is a report, not a gate — it stops nothing. But it is written *here*, in the file the loop reads every round, and that placement is the entire fix. Measured over the runs of 2026-07-31 → 08-03: `epic-544` resolved **13 units across ~24 hours and rendered `progress` once**, at the very end; `epic-25-proposal-generator` and `epic-31-bilingual-site` rendered once each, also at handoff.
|
|
133
|
+
|
|
134
|
+
What makes that worth a paragraph is that the rule already existed — in three places, none of them here. [`report.mjs`](../scripts/report.mjs) has said since it was written that PROGRESS is "rendered after each unit reaches a terminal state," but that is a *code comment*. [regression-checklist](regression-checklist.md) row 10a grades for it — "PROGRESS as each unit reaches a terminal state" — but that file is read when someone edits or grades this skill, not when the loop runs. SKILL.md's [handoff](../SKILL.md#definition-of-done-handoff) mandates it at the *end*. So the only mandate that ever fired was the one at the end, and it fired exactly once per run. A rule stated everywhere except where the work happens is a rule that does not happen; this render exists because the facts got "reported when the run was short and attentive and quietly skipped when it was long — which is exactly when the human has lost track."
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Model catalog compatibility reference
|
|
2
|
+
|
|
3
|
+
The canonical model catalog doctrine, implementation, and team seed are owned by [`harness-runtime`](../../harness-runtime/references/model-catalog.md).
|
|
4
|
+
|
|
5
|
+
Resolve Issues continues to expose its established `scripts/model-catalog.mjs` command and import path as a compatibility wrapper for one release. New consumers import the canonical runtime package. Run `model-catalog.mjs --help` for the compatible command surface.
|
|
6
|
+
|
|
7
|
+
## Team seed (`references/model-catalog-seed.json`) — read-only, ships with the skill
|
|
8
|
+
|
|
9
|
+
The seed now ships installation-relative to [`harness-runtime`](../../harness-runtime/references/model-catalog-seed.json), where the canonical doctrine defines its read-only and precedence invariants. This heading remains as a compatibility anchor for existing Resolve Issues references.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Optional run profile diagnostic
|
|
2
|
+
|
|
3
|
+
`run-state.mjs postmortem <slug> [--json]` computes the existing timing/round profile from
|
|
4
|
+
the run manifest when a human explicitly asks for it.
|
|
5
|
+
|
|
6
|
+
It is read-only and non-blocking. It does not run automatically from `progress` or
|
|
7
|
+
`finalize`; it does not save a cross-run series; and it creates no obligation to adjudicate
|
|
8
|
+
findings, file an issue, or include the profile in the handoff. Its output never authorizes
|
|
9
|
+
completion. The correctness transition is [finalization.md](finalization.md).
|
|
10
|
+
|
|
11
|
+
The profiler can still help investigate rounds after PASS, staggered starts, a cap below
|
|
12
|
+
the default, unrecorded pushed SHAs, component delivery wait, and delayed outcome recording.
|
|
13
|
+
Delivery wait is measured once per deliverable: a singleton starts at its first PASS; a co-delivery component starts at its component-ready PASS — the first terminal PASS of every member, advanced only when a typed or reconstructable reopen legitimately re-enters one. Current runs read queue request/observation, provider merge, and outcome-write clocks directly from `components[].delivery`; historical runs fall back to member `units[].delivery`. Earlier members were not independently deliverable, so charging each one until the shared merge multiplies one integration interval by the component size (epic-892). Where candidate timestamps exist, split that interval at update/freeze/authorization to distinguish assembly and terminal review from queue time.
|
|
14
|
+
|
|
15
|
+
Each component timeline preserves the established `members: string[]` normalized-ID
|
|
16
|
+
projection and also exposes `declaredMembers`, one stable diagnostic record per declared
|
|
17
|
+
slot: `{ index, id, valid, resolved, duplicate }`. `id` is either a non-empty declared
|
|
18
|
+
string ID or `null`; invalid declarations never receive invented IDs. A duplicate is a
|
|
19
|
+
malformed membership declaration, not another delivery-evidence-bearing member. Invalid,
|
|
20
|
+
unresolved, or duplicate slots keep component readiness, candidate-completeness, queue,
|
|
21
|
+
merge/outcome, aggregate, and delivery-wait clocks unknown; independently recorded
|
|
22
|
+
freeze-to-authorization evidence remains visible. Text output renders every slot with its
|
|
23
|
+
index and `resolved`, `invalid`, `missing`, or `duplicate` status.
|
|
24
|
+
|
|
25
|
+
These are diagnostic hypotheses derived from manifest telemetry, not delivery facts. When
|
|
26
|
+
a profile matters, read its evidence against the unit rounds, component candidate history,
|
|
27
|
+
and live repository state.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Pre-flight steps 1–2 — discovering models and settling both slots
|
|
2
|
+
|
|
3
|
+
Split out of [pre-flight.md](pre-flight.md), which was 38.6KB in 94 lines (410 bytes per line) —
|
|
4
|
+
the densest file in this skill and, like the SKILL.md it was carved from, big enough to be
|
|
5
|
+
truncated by a harness with nothing warning you. Step 2 alone was 40% of it.
|
|
6
|
+
|
|
7
|
+
Read this when pre-flight reaches step 1. The other steps stay in the index.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
1. **Discover the available models — don't guess names. Run `scripts/discover-models.mjs`, don't enumerate by hand.** This remains the Resolve Issues compatibility command while `harness-runtime` owns its implementation. It unions configured or credentialed evidence with model ids explicitly advertised by the current turn, so discovery stops being an agent reading prose (which drifts into proposing models that don't exist):
|
|
11
|
+
|
|
12
|
+
**Run `discover-models.mjs --harness <pi|codex|claude-code>`**, passing the spawn primitive's advertised model ids unchanged through `--available <comma-separated-ids>` when it exposes an enum. It emits `{ harness, completeness, discovered: [{id, source}], notes }` on stdout; **feed the ids straight to `model-catalog.mjs tiers --seen <id,id,...> --harness <h>`** (step 2). A model the human explicitly names as runnable can be included with `--human-named <ids>`; that is valid evidence but does not turn a partial inventory into a full one. See `scripts/discover-models.mjs --help` for flags and exit codes (`0` = discovery ran, JSON emitted; `2` = usage error). Per harness:
|
|
13
|
+
- **Pi — FULL mechanization.** The script reads Pi's curated `enabledModels` **and** credentialed-but-uncurated remainder (custom models whose provider `apiKey` resolves; credentialed providers with no `enabledModels` entry, listed at provider level only, e.g. `google/*`). The judgment to keep: `enabledModels` is a picker *filter*, not the full runnable set. Recommend slots from that curated set; provider-level `provider/*` and custom entries are the remainder a human pulls in by naming a model.
|
|
14
|
+
- **Codex — PARTIAL from config; FULL with current-turn ids.** `~/.codex/config.toml` contains defaults and profiles, not the complete set the current spawn primitive can launch. Pass the primitive's advertised model override enum through `--available`; without it, retain `completeness: partial` and do not reject a human-named runnable model merely because it is absent from config.
|
|
15
|
+
- **Claude Code — PARTIAL from settings; FULL with current-turn ids.** `settings.json` may name configured defaults but not the complete built-in `Agent` model enum. Pass that enum through `--available` when advertised. The script deliberately does **not** read `~/.claude/model-catalog.json`: the banked catalog is classification evidence, never availability.
|
|
16
|
+
|
|
17
|
+
The load-bearing rules the script enforces and you must keep applying:
|
|
18
|
+
- **Never-a-source.** Pi's built-in model registry, `pi --models` pattern expansion, a models-API dump, or a harness's full known-model catalog are **never** a source — they enumerate every model the harness *knows a definition for*, not what this user can run; that is training-data-shaped noise with extra steps. The script enforces this by construction (it reads only enabled/credentialed models); when you discover Claude Code by hand, hold the same line.
|
|
19
|
+
- **Propose only models that appeared in a discovery source or that the user named.** If discovery yields nothing, the proposal block must contain the *question* — "list the models available here" — with those slots left empty, not filled with plausible names: a guessed model (e.g. a Claude model in a harness that only runs one provider) is worse than no suggestion, because a confirmed-but-unrunnable model resurfaces mid-run as the silent-fallback failure the [no-silent-fallback guard](../SKILL.md#pre-flight-once-before-intake--never-mid-run) exists to catch. Your training-data knowledge of what models exist is not a discovery source.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
2. **Classify the discovered models into capability tiers, then settle both slots in this gate.** The slots are **implementer · reviewer**. The **implementer is always asked** — the strength call, made per run against the run's risk profile; there is no pre-packaged profile. **The reviewer is never asked:** it is filled from a ranking (team default, then the diversity ladder), resolved against the answered implementer — `reviewer ≠ implementer` is the only possible collision and the ranking just moves down one. So the gate is **three questions on every run**: implementer, target branch, autonomy. A harness that discovered a single model is still not asked (nothing to pick); it takes that id, recorded `NOT INDEPENDENT`. **Filled is not silent** — state the reviewer, its operating point, its rank and any `reduced diversity` flag in the pre-flight summary, as with `workspaceMode` and `deliveryMode`, so an override costs one message. → [why](why.md#the-reviewer-slot-is-filled-not-asked)
|
|
23
|
+
|
|
24
|
+
**Mechanized, not described:** `preflight-questions.mjs` plans no `review` question in any shape it accepts and resolves the fill at `record`, reporting `reviewFill: { id, reason }` (`team-default` · `ladder` · `human-named` · `no-distinct-candidate`). Asking the reviewer is off-contract, not judgment.
|
|
25
|
+
|
|
26
|
+
**First, tier the discovered models** into the [capability bands](model-catalog.md) (`frontier` · `deep-reasoner` · `balanced-coder` · `scoped-coder`) — by *capability class*, never a hardcoded name list, and per **operating point** (a model at an effort). **`scoped-coder` fills no slot and is never offered as a candidate** — tag it so the classification is banked and pre-flight stops re-asking, then leave it out of both slot lists. Don't classify from scratch when the answer is already banked: run **`model-catalog.mjs tiers --harness <this harness> --seen <discovered ids>`**, which composes the banked catalog, another harness's catalog, and the [team seed](model-catalog.md#team-seed-referencesmodel-catalog-seedjson--read-only-ships-with-the-skill) with the precedence applied *inside* the command (the composition, the citations, and the staleness signals to surface are [model-catalog.md](model-catalog.md)'s — this step just consumes the one decided answer per model). The catalog is a cache of *confirmations*, never an availability source — a cataloged model discovery didn't yield stays unproposable (step 1). For what the catalog doesn't cover, **tier from discovery-source evidence, not name intuition:** a name your training data has never seen is tiered from the harness's model metadata or docs, the provider's model pages, pricing (a strong tier signal), or what the user has said — and when no evidence settles it, tag the model **`tier: unconfirmed — please classify`** and slot it into **no** role until the human confirms (a confidently-guessed tag is the failure here: a balanced-coder mis-tagged deep-reasoner and recommended as the implementer for a risk-heavy run silently hands the hardest work to the weakest model). Show the tags so the human can correct a misclassification; proposing an *undiscovered* model is still forbidden.
|
|
27
|
+
|
|
28
|
+
**Then present both slots — the implementer as a question with its recommended pick and every eligible alternate, the reviewer as a stated fill.** Per-slot recommendation guidance:
|
|
29
|
+
- **Implementer** — the **one** model that writes every unit's diff; the strength call is made here, per run, and **a frontier model is never recommended for it**: the choice tracks the run's **risk profile**, not raw strength, so a human who wants a frontier model in the loop names it for the reviewer slot. **Recommend by risk profile.** Routine feature work → a **balanced-coder**: round cost is dominated by review+fix and routine units land in ~1–2 rounds (measured against a *frontier* reviewer, so treat it as an estimate now that the default reviewer is a deep-reasoner — climbing rounds on routine units are the first thing to suspect, and naming a frontier reviewer for one run is the cheapest test). Predominantly [high-risk units](intake.md#intake--scheduling), a cross-cutting refactor, an epic with cross-cutting surfaces, or work the user called complex → a **deep-reasoner**: on auth/money/tenancy/migration surfaces a balanced-coder implementer reliably misses the domain-semantic bug and costs 2–3 recovery rounds, and naming a frontier reviewer is the other half of that fix. Must differ from the reviewer. → [why](why.md#the-reviewer-slot-is-filled-not-asked)
|
|
30
|
+
- **Reviewer** — **≠ the implementer, different family preferred** (same-family is `reduced diversity`: flagged and recorded, never a reason to ask). **Independence, not superiority** — the slots are not a strength ladder, so a **frontier implementer is not a rule violation** and does not leave this slot unfillable; pair it with another family's frontier. **Fill order — diversity first, tier second:** another family's frontier → another family's deep-reasoner → the *same* family's deep-reasoner (`reduced diversity — same family`) → the same model id with fresh context and an adversarial prompt, which is **not** independent and is declared as such. Never trade cross-family diversity for a tier, and the ranking **never reaches balanced-coder**, whatever the family — capacity is a threshold, diversity the tiebreaker. **This is the fill order, not a question's option list:** it goes to `preflight-questions.mjs` as `review.candidates` (behind `review.default`), and the first candidate that is not the answered implementer takes the slot. → [why](why.md#the-reviewer-slot-is-filled-not-asked)
|
|
31
|
+
|
|
32
|
+
**Team default, recorded 2026-08-02: when discovery yields `openai/gpt-5.5` and it is not the implementer, this slot is filled with it at `high` — no question.** (Seeded `deep-reasoner` in all three harnesses; against the usual Anthropic implementer it is rank 2 on the ladder, no flag.) **The default outranks the ladder whenever it applies**; when it cannot, the ladder fills the slot — still without a question.
|
|
33
|
+
|
|
34
|
+
**Two situations retire the default, and neither turns the slot into a question** — both hand it to the ladder. **Discovery didn't yield it and the human didn't name it** → step 1's rule 3 outranks this line (a partial Codex/Claude config read doesn't satisfy that premise; a human-named model is itself valid discovery evidence). **`gpt-5.5` is the implementer** → the next ranked candidate takes the slot, which is why the ladder always rides *behind* the default: a human who overrides the implementer *to* `gpt-5.5` gets the fill moved down and restated, at no interruption. **Nothing else retires it** — not a discovered frontier, not a `reduced diversity` flag. Both were tried, both were wrong (2026-08-03 and 2026-08-16, [measured](why.md#the-reviewer-slot-is-filled-not-asked)), and the planner now emits no reviewer question either could justify.
|
|
35
|
+
|
|
36
|
+
Naming a model here is a deliberate exception to [model-catalog.md](model-catalog.md)'s "ship the schema and lifecycle, never the data" rule, taken on the user's explicit instruction, and it carries that rule's cost: **this name will go stale — re-check this paragraph whenever OpenAI ships a successor.** It is a *slot fill*, not a tier claim; the tier still comes from the catalog, nothing downstream reads the name, so a stale one costs one override.
|
|
37
|
+
- **Visible-option invariant:** when discovery yields a slot-eligible frontier point, include it in the implementer option list as an alternate even though it is not the recommendation. For Pi, `openai/gpt-5.6-sol @ high (frontier)` is the canonical current example; show it whenever discovery yields that id, and let the human choose it explicitly.
|
|
38
|
+
- **A slot is a model *and its operating point*** — each banked point is offered as its own slot candidate (`example-coder-2 @ high (balanced-coder)` · `example-coder-2 @ max (deep-reasoner)`), and the effort is **read from the catalog, never asked per run** (the effort rule and `high`-is-the-floor doctrine live in [model-catalog.md](model-catalog.md)). Record the picked effort next to the picked id (`models.<slot>Effort`) so a resume spawns at the same point.
|
|
39
|
+
- **Hard rules hold whatever the human picks:** reviewer **≠** implementer; the family preference never licenses an undiscovered model — a **single-provider harness** (e.g. Codex with only GPT-family models) picks a different model *within* the family and flags `reduced diversity — same family`; only one model available → the review is *not* independent, say so. A selection that would break a hard rule is **bounced back to the human with the conflict named — never silently repaired.** A model the human names that discovery didn't yield is taken as the human's own discovery source.
|
|
40
|
+
- **What the recommendation is based on (pre-intake):** a quick skim of the named issue(s) — title, labels, body — is enough to tell an auth/money/migration-heavy run or a declared refactor from routine feature work; cheap, and it doesn't move this gate after intake. If full intake later contradicts the confirmed implementer tier (a run confirmed on a balanced-coder implementer turns out predominantly high-risk once the sub-issues are enumerated), **surface a one-time re-confirm of the implementer slot then** — don't silently proceed on the wrong pick, and don't silently upgrade either; re-confirmation is the only strength lever, so a mis-called run gets exactly one deliberate correction.
|
|
41
|
+
- **Build one neutral question batch and let the shared runtime plan it.** Use [`scripts/preflight-questions.mjs`](../scripts/preflight-questions.mjs): the implementer question listing every eligible discovered **operating point**, followed by target branch and autonomy — three questions, on every run and every adapter, in one call. The reviewer ranking rides the same input (`review: { default?, candidates: [...] }`) and produces **no** question; the planner returns `reviewRanking` and `defaulted.review` for the summary, and `record` returns the resolved `reviewFill`. Pass the exact `currentTurnCapabilities` from step 0; invoke only the native payload call(s) the returned `interaction.calls` plans, in order, and normalize the responses before recording. Recommended options stay first with one-line rationales. **Listing the alternates is load-bearing** — without them the human cannot see what discovery found and can only rubber-stamp; for the filled reviewer the alternates are the ranking, printed in the summary rather than as choices. Never drop or combine a slot to hide overflow.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Pre-flight steps 4–6 — recording the answers, autonomy, and preparing the checkout
|
|
2
|
+
|
|
3
|
+
Split out of [pre-flight.md](pre-flight.md) alongside [the model-slot chapter](pre-flight-model-slots.md).
|
|
4
|
+
Read this once the human has answered: it owns how the batch is normalized and recorded atomically,
|
|
5
|
+
what each `autonomy` level pre-authorizes, and the checkout/`workspaceMode` preparation that must
|
|
6
|
+
happen before intake.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
4. **Normalize, confirm or override, then record atomically** to the **run manifest** via `run-state.mjs merge` using `recordPreflightAnswers(...).manifestPatch` — `currentTurnCapabilities`, both model slots and their explicit families (plus each non-`high` effort), `targetBranch`, and `autonomy` — then add step 3a's `deliveryMode` (+ `queueProvider` in queue mode). Read back the manifest; do not hand-roll or partially bank the answer. Cancellation yields no patch and records nothing. A resumed run inherits the completed pre-flight instead of re-prompting. Identical model ids remain `NOT INDEPENDENT`; different ids in the same explicit family remain independent but are recorded as `reduced diversity`. **`autonomy`** is one question that pre-authorizes as much of the loop's stop-and-ask surface as the human wants to spend up front, when they have the context, instead of mid-run when they don't. Two levels, and **`autonomous` is the recommended pick** — present it first and marked "(Recommended)":
|
|
10
|
+
|
|
11
|
+
| level | pre-authorizes | still stops and asks |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `autonomous` **(recommended)** | the intake **scope split**, the **breaker's `split`**, and merging a shippable component into `targetBranch` | a missing design or test criteria, and the breaker's `descope` |
|
|
14
|
+
| `supervised` | nothing | every park |
|
|
15
|
+
|
|
16
|
+
**Why `autonomous` is the recommendation and not merely an option.** The three things it pre-authorizes are all *reversible and traceable*: a scope split and a breaker `split` re-slice the work rather than shipping less of it, and a merge into `targetBranch` lands a reviewed, CI-green component that git records permanently. What stays parked is the irreversible or unevidenced half — a missing contract, and `descope`, the one decision that quietly ships less than was asked for. Spending the human's attention on parks that a manifest already records, on a loop whose exit bar is an independent APPROVE plus honestly-green CI, buys confirmation rather than safety. Choose `supervised` when the run is exploratory, the target branch is shared and busy, or the human wants to see each component before it lands.
|
|
17
|
+
|
|
18
|
+
Four things no level lifts: the **design gate** and the **missing-test-criteria** gate (both **hand back** — no level drafts a contract in-run; a third `autonomous+design` level that would have was cut before it shipped, [why](why.md#the-design-gate-hands-back)), the **breaker's round ceiling**, and the breaker's **`descope`** (refused in state at every level — it decides that less ships than was asked for, the one autonomous decision that leaves no trace, and it only arises on an already-stuck unit). The breaker's **`split`** is the one park `autonomous` lifts on that list: a split *re-slices* rather than shipping less, and it fires where the loop hurts most — [breaker.md](breaker.md), [why](why.md#pre-flight). Don't re-derive any of this from the table: `run-state.mjs autonomy <slug>` answers it, deriving the split entry from the same predicate the state validator applies.
|
|
19
|
+
|
|
20
|
+
**`enqueueTrigger` comes from the same probe as the mode and provider, and it is the one guarantee 4 actually rests on.** Mode and provider answer *how you enqueue*; the trigger answers **whether this PR can reach `targetBranch` with no further action from the loop at all**. A repo carrying an auto-merge rule merges the moment its conditions hold — and the loop's ordinary acts (marking a PR ready, pushing the commit that turns CI green, posting the review verdict as an approval) are exactly what satisfies them. Where that is true, `mergeShippable: false` is unenforceable: the loop never *decides* to merge, it merges as a side effect of reviewing.
|
|
21
|
+
|
|
22
|
+
Note what the trigger is **not**: it is not manual-versus-auto as alternatives. Manual enqueue stays available on an auto repo, so the loop never loses a path. `hybrid` — both paths live — is the common real shape. What the trigger records is that a *second* path exists which the loop does not drive, and for authorization `auto` and `hybrid` are identical.
|
|
23
|
+
|
|
24
|
+
`detect-delivery-mode.mjs` reports it with the conditions it read and which of them **this loop can trip through its own work** (exit 3 = trigger UNKNOWN). It fails closed toward the hazard: a probe that could not read the config reads as UNKNOWN, never as `manual`, because assuming `manual` on an auto-merge repo is how a run configured to merge nothing merges anyway with nothing reporting it. Record it (`set <slug> enqueueTrigger manual|auto|hybrid`), then ask **`run-state.mjs approval-gate <slug> [componentId]`** before any review verdict is posted to GitHub. Preliminary unit reviews omit the id and post as comments; only the terminal authorized component review supplies it. Exit 1 means **comment**, never approval.
|
|
25
|
+
|
|
26
|
+
Record it (`set <slug> autonomy <level>`) and ask the loop what it resolved to rather than re-deriving it — **`run-state.mjs autonomy <slug>`** returns the decided policy and the parks that remain (exit 1 = never set, so "nobody chose" stays distinguishable from "chose supervised"). `mergeShippable` is still a real field and an explicitly-set one still wins in both directions; the level only supplies its default. **Bank any model classified for the first time this run into the [model catalog](model-catalog.md)** via `model-catalog.mjs bank` so the next run reads it instead of re-asking.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
5. **Prepare the checkout** — now that the target branch is settled. `workspaceMode` settles where **the coordinator** works; every implement/fix spawn gets [a workspace of its own](intake.md#interference-scheduling-and-workspaces), handed out per unit at intake rather than here. Three things before intake: **(a)** `git fetch origin <targetBranch>`, so every branch forks from the **freshly fetched remote head** (`origin/<targetBranch>`), never the local branch, which may sit days behind — a run based on a stale head reviews against an outdated tree and manufactures avoidable merge conflicts at integration (re-fetch here if any time has passed since step 3). **(b)** Record the currently checked-out branch (`set <slug> originalBranch <branch>`) — the run switches branches under the human's checkout, and the handoff restores this branch on done. **(c)** Settle **`workspaceMode`** with [`detect-workspace-mode.mjs`](../scripts/detect-workspace-mode.mjs) — `shared` (every spawn works in the current checkout) or `worktree` (the run gets a checkout of its own and never touches the human's tree).
|
|
30
|
+
|
|
31
|
+
This is a **probed setting with a default, not another question**: the complete neutral batch already uses the selected adapter's capacity, and the answer turns on tree state (dirty? already a linked worktree?) that a human cannot recall at a prompt but a probe reads exactly — the same reasoning as `deliveryMode`, the same shape as `breakerAutonomy`. State the result in the pre-flight summary so a wrong guess is correctable before any work runs, and honour the human naming either mode outright.
|
|
32
|
+
|
|
33
|
+
What it recommends, and why it is not simply "always a worktree": a fresh worktree has no `node_modules`, no `.env`, no build cache, so on a product repo it owes an install before the first test can run. That cost is real and paid every run, so `shared` stays the default for a clean tree.
|
|
34
|
+
|
|
35
|
+
- **Dirty tree → `worktree`.** This **replaces the old dirty-tree stop** rather than blocking the run. The stop existed because a branch switch can fail on uncommitted changes or silently carry them into a unit's diff; a worktree dissolves the dilemma instead of handing it back. Never commit or stash the human's work for them — leave it exactly where it is.
|
|
36
|
+
- **Already isolated** (a linked worktree, a disposable CI clone) → `shared`; nesting buys nothing and costs a second install.
|
|
37
|
+
- **Clean tree → `shared`**, unless the human wants the checkout kept free while the run works.
|
|
38
|
+
|
|
39
|
+
On `worktree`, record the path too (`set <slug> workspaceMode worktree`, `set <slug> workspacePath <abs-path>`) — the handoff removes it by path, and an unrecorded one is left behind for a human to find. Create it off the fetched target head (`git worktree add <path> <targetBranch>`) and remove it at the handoff, **after** the unit workspaces are reaped and every branch is pushed.
|
|
40
|
+
|
|
41
|
+
**This path is the coordinator's, and it is never a unit's.** Do not pass it as a spawn's working directory — `validate` refuses a unit whose `workspacePath` equals it, and the reap refuses to remove it. The rule and its dated incident: [why.md](why.md#the-orchestrator-is-a-writer-too).
|
|
42
|
+
|
|
43
|
+
**The in-flight cap is not settled here, and it is not an ask.** It is **4**, always, on every repo. Do not `set <slug> inFlightCap`, do not estimate this repo's install cost to justify a smaller number, and do not raise it with the human as a choice — a cap the loop is invited to pick is a cap the loop picks too low, and the one measured instance of that cost five hours ([why](why.md#the-in-flight-cap-and-its-default)). It bounds disk and dependency-install cost, never correctness, so the wrong-but-higher answer costs a bounded number of extra installs while the wrong-but-lower answer costs the parallelism the scheduler exists to provide. A human who has *measured* a slow-install repo may write the field themselves; that is their decision to make, not one you surface.
|
|
44
|
+
|
|
45
|
+
**No structured tool available.** Keep the runtime's `textual-multiple-choice-forbidden` decision intact. Ask only the returned `freeTextQuestions`, one concise prompt at a time, with no numbered or lettered choices and no optional/defaulted slot. Record only after every required free-text answer is complete; cancellation records no partial gate.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
6. **Only then start intake.** Carry the confirmed models into *every* spawn — each implementer, reviewer, and fix round, and into the [fan-out workflows](fan-out.md) as `implementationModel` / `reviewModel`, at the effort of the banked point picked (`models.<slot>Effort`, **high** when none). **A unit whose spawn read-back recorded a substitute passes its own `implementationModel` (the model that actually wrote its diff) as a per-unit override**, so the diversity guard compares the right pair. Carry the confirmed **`targetBranch`** into every implementer (the branch base), the integration gate (the fork point), and promotion detection (a unit whose base is a production branch is a [promotion, not a feature PR](../SKILL.md#promotion--release-lane)). Run the orchestrator's git work in the step-5 checkout, and restore its recorded branch on done. Do not re-ask the models/branch at the loop's review or fix steps; both were settled here. If the human changes a model or the branch mid-run, re-confirm once, update the manifest, and carry the new value forward.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Pre-flight gate — the full procedure (models + target branch + checkout prep)
|
|
2
|
+
|
|
3
|
+
This is the complete seven-step procedure (0–6) behind SKILL.md's [pre-flight gate](../SKILL.md#pre-flight-once-before-intake--never-mid-run). Read it when the gate runs — the first thing the skill does, before intake. The gate's non-negotiables live in SKILL.md; this file is *how* to satisfy them: per-harness discovery sources, tier classification and the banked catalog, per-slot recommendation guidance, branch detection from remote heads, and the checkout-preparation mechanics. The tier vocabulary itself (the capability bands, the effort rule, the catalog/seed precedence) lives in [model-catalog.md](model-catalog.md) and is mechanized in `model-catalog.mjs`; this file consumes it and does not restate it.
|
|
4
|
+
|
|
5
|
+
If the prompt already named the models / base branch, skip discovery + proposal for whatever it named and go straight to recording and confirming (steps 4–6); the remaining slots are still asked explicitly.
|
|
6
|
+
|
|
7
|
+
**This file is the index of the seven steps.** Two chapters live beside it, because at 38.6KB this
|
|
8
|
+
file carried the same truncation risk the SKILL.md it serves was refactored to escape — and a
|
|
9
|
+
reference is read into the same context window, so moving a chapter out of SKILL.md into a file
|
|
10
|
+
this size only relocates the hazard:
|
|
11
|
+
|
|
12
|
+
| Steps | Read |
|
|
13
|
+
|---|---|
|
|
14
|
+
| **1–2** — discover models, tier them, settle **both slots** (the largest chapter by far) | [pre-flight-model-slots.md](pre-flight-model-slots.md) |
|
|
15
|
+
| **4–6** — record the answers atomically, `autonomy`, prepare the checkout | [pre-flight-recording-and-checkout.md](pre-flight-recording-and-checkout.md) |
|
|
16
|
+
|
|
17
|
+
Steps 0, 3 and 3a stay here: step 0 produces the values every later step consumes, and 3/3a are
|
|
18
|
+
short probes the whole run rests on.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
0. **Resolve and record the three inputs every later step consumes — `<skillsRoot>`, current-turn capabilities, and the harness's spawn primitive.** Numbered 0 because it produces values steps 1–6 and the whole loop *consume*; nothing here asks the human anything, so it costs no question budget.
|
|
22
|
+
|
|
23
|
+
- **`<skillsRoot>`** — the **absolute** directory this skill was loaded from, i.e. the parent of `resolve-issues/`. Derive it from the path you actually read this file from (in Claude Code, the skill's own base directory; elsewhere, `dirname` of the loaded `SKILL.md`, twice). Record it: `set <slug> skillsRoot <abs-path>`. **Verify before recording** — `test -f "<skillsRoot>/review-pr/SKILL.md"` — because a wrong root fails at *spawn* time, several steps later, as a subagent that quietly skipped its skill rather than as an error here. **That loaded installation is the run's lifecycle authority until finalization.** If this run edits `resolve-issues` itself, scripts in the candidate tree are test subjects, not upgraded orchestration commands: do not switch `run-state`, `combine-and-verify`, workspace cleanup, or finalization to the code under review mid-run. A schema added by the candidate cannot retroactively require state the run-start authority never recorded, and inventing that state after review is not migration. Test the candidate commands in isolation; drive the live run with `<skillsRoot>` throughout.
|
|
24
|
+
- **Current-turn capabilities** — copy the native tool names and the spawn primitive's advertised model ids exactly as exposed in this turn into `currentTurnCapabilities: { nativeTools, spawnModelIds }`, then record that object in the run manifest. Empty arrays are facts; never fill either array from static harness configuration or model knowledge. A resumed run inherits this record instead of reconstructing the old turn, while a genuinely new turn records its own capabilities before planning.
|
|
25
|
+
- **The spawn primitive** — the harness's own way to launch a subagent with a chosen model *and effort*. Resolve it here, beside the model read-back, and state it in the pre-flight summary so the human can correct a wrong guess before any work runs. It is deliberately **not** a manifest field: nothing reads it back, and adding a stored value nothing consumes is how this skill accumulated the dead constants the 2026-07-20 audit found.
|
|
26
|
+
- **Whether any unit already owes a design, before anything else runs.** Skim each issue for the [design gate](intake.md#intake--scheduling)'s two questions and the `high-risk` auto-flag (auth/authz, money/tax/pricing, tenancy/org-scope, DB migration). A high-risk issue that *describes* a change but enumerates no invariants — or any issue two reasonable implementers would build differently from — **owes a design, and the answer is to say so now and stop**, not to discover it after models, branch, delivery mode and a manifest have been settled. Hand it back naming `/grill-with-docs`; the human lands the design and re-runs. This is the cheapest possible place to find out, and the gate at intake stays as the backstop for what a skim misses.
|
|
27
|
+
- **Which lane that primitive is — sync or async — and, if async, how you collect a result.** [Both qualify](spawn-contract.md#c-launch-it-with-the-harnesss-own-agent-primitive); state which one and, on the async lane, the collection mechanism (notification, fetch-by-id, or the message the subagent sends back). A primitive with **no** way to collect is not a spawn — a stop-and-ask here, before any unit starts. Settling this at step 0 is what keeps an async harness from reading the leaf-spawn contract as a capability it lacks and blocking the run.
|
|
28
|
+
|
|
29
|
+
**Why this is step 0 rather than an assumption.** `SKILL.md`'s leaf-spawn contract requires every spawn to read `<skillsRoot>/<skill>/SKILL.md` at an absolute path, precisely because a relative `skills/engineering/...` path resolves to nothing once this skill is installed into a consumer repo by symlink — and the spawn then reconstructs a plausible-looking lookalike from memory instead of failing loudly. That contract had no step that ever produced the value: until 2026-07-20 `skillsRoot` appeared nowhere in this file, so every inline spawn's "absolute path" was aspirational and the orchestrator substituted the only path it had seen — the repo-relative one. The fan-out workflow hard-fails a relative path (`independent-review.workflow.js`); the inline path had no such guard, and the inline path is the default for single-unit runs.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
3. **Detect and confirm the source (target/base) branch** in the same neutral batch. Settle it here, not at the first PR: every unit rests on this one branch — independent units open their PR against it directly, a [stacked dependent unit](intake.md#intake--scheduling) rests on it transitively, and the [epic integration gate](deliverables.md#deliverables-the-shippable-component-not-the-whole-epic) forks its integration branch off it. **Run `scripts/detect-target-branch.mjs`.** It fetches `origin` and recommends the branch that holds the current development head — applying, internally, the GitFlow-`dev`-vs-trunk-`main` choice and a *content* check (`git cherry`, not commit counts, so a GitFlow repo's nominal merge-commit divergence isn't mistaken for a conflict), and picking **nothing** on a genuine conflict. So the agent's job is only: **confirm its recommendation in this gate; on a `conflict` result, present the candidates it lists (each with ahead/behind + last-commit date) and let the human name the branch** — the script never picks on a genuine conflict, so a `conflict` always routes to the human. See `scripts/detect-target-branch.mjs --help` for flags and exit codes (`0` = recommendation, `1` = conflict/human chooses, `2` = usage / no long-lived branches). Implementer, branch, and autonomy are answered individually inside the same planned batch, never as a defaulted bundle. The reviewer slot is filled rather than asked, so every run has exactly three questions — there is no worst case with four. `autonomy` remains one question precisely because it **subsumes** `mergeShippable` rather than joining it.
|
|
33
|
+
|
|
34
|
+
3a. **Probe the merge path — `scripts/detect-delivery-mode.mjs` — and record what it answers.** This is a **probe, not a fourth ask**: it costs no question budget and does not touch the one-interruption property step 3 just described. It settles two fields, because a queue is two different things: **`deliveryMode`** (`direct` | `queue`) picks the state machine that delivers a merge-ready unit, and **`queueProvider`** (`mergify` | `github`) picks the mechanics — the enqueue command, where queue state is read, what a dequeue reason is called, whether a re-evaluation nudge or an acknowledgement exists at all. Both fail silently in both directions when wrong, which is why they are probed rather than assumed and why the probe fails closed: **exit 2 is UNDETERMINED** — no probe could run, only file probes ran and were negative, or a queue whose provider is unknown/ambiguous — and *that* is the one case that becomes a human question, an exception path rather than a standing ask. A queue is a **runtime** fact whose config commonly lives dashboard-side, so never read either field off repo files.
|
|
35
|
+
|
|
36
|
+
**Why this step exists at all** — two docs described the probe as pre-flight's job while no step performed it, and `delivery` was written **0 times in 522 units**: [why](why.md#pre-flight).
|
|
37
|
+
|
|
38
|
+
4. **Normalize, confirm or override, then record atomically** — and steps 5–6 after it — are
|
|
39
|
+
[pre-flight-recording-and-checkout.md](pre-flight-recording-and-checkout.md). Do not stop here:
|
|
40
|
+
those steps settle `autonomy` (guarantee 4's authorization) and prepare the checkout, and a run
|
|
41
|
+
that skips them has recorded no human answer at all.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Regression checklist (editing this skill, or dry-run-evaluating an agent running it)
|
|
2
|
+
|
|
3
|
+
Every row must still hold after any edit to this skill; a transcript of an agent running it can be graded against the same rows. If an edit makes a row ambiguous, the edit is wrong. Release-lane invariants live in `resolve-release`'s checklist.
|
|
4
|
+
|
|
5
|
+
| # | Invariant | The failure it prevents | Graded by asking |
|
|
6
|
+
|---|---|---|---|
|
|
7
|
+
| 1 | **Main-loop only, depth-1 spawns; the orchestrator coordinates, never implements** — single-issue runs included. Heavy steps return compact schema'd results; state lives in the manifest. | The reviewer degrades to a nested same-context self-review; an inline-implemented unit makes the coordinator the author adjudicating its own review. | Any depth-2 spawn? Any unit implemented inline — including the evidence lane, where a small artifact-only fix is the tempting exception? Full transcripts held in the orchestrator's context? |
|
|
8
|
+
| 2 | **Model diversity is enforced via read-back, not assumed.** Reviewer ≠ the model that actually wrote the diff (per spawn read-back, recorded per unit); a same-model review is `NOT INDEPENDENT`, never presented as real. | Shared-blind-spot review; a silent spawn-time substitute poisoning the guard. | Are both models named in the handoff, from read-backs, and different? Same → flagged as a gap? |
|
|
9
|
+
| 3 | **Pre-flight once: two slots (implementer · reviewer) settled from discovered models — implementer always asked, reviewer never asked (filled from default → ladder, resolved against the answered implementer), every fill stated in the gate; branch from fetched remote heads; recorded to the manifest — never re-asked mid-run.** One implementer per run; strength picked from the run's risk profile. Codex/Claude config-only discovery is partial: current-turn spawn ids complete it, and a human-named runnable id is valid evidence. | Mid-run model prompts; guessed/undiscovered models; a configured-default list mistaken for a complete runnable inventory; feature work opened against production `main`; re-invented per-unit model escalation. | Any mid-run model/branch prompt, or a per-unit model switch? Implementer asked with alternates, reviewer **filled and stated** — never asked, whatever the ranking yielded — and `targetBranch` evidence-backed, all in the manifest before intake? On Codex/Claude, did discovery consume the current-turn spawn enum or report partial, rather than rejecting a human-named model? → [why](why.md#the-reviewer-slot-is-filled-not-asked) |
|
|
10
|
+
| 3a | **Pre-flight interaction is capability-driven through `harness-runtime`.** Step 0 records the exact current-turn native tools and spawn-model ids; one neutral batch owns implementer, target, and autonomy — three questions, the reviewer filled outside the batch. The agent invokes the planner's native calls in order. Every supported adapter takes the batch in one call; adapter-capacity overflow remains explicit and deterministic for any batch that grows past it. With no structured tool, only concise required free text is asked and textual multiple choice remains forbidden. Cancellation records no partial patch; resume inherits completed capabilities and answers. | One harness primitive becoming active doctrine; Codex planning a tool that is unavailable this turn; a slot silently dropped at a batch-capacity boundary; prose choices emitted where forbidden; a cancelled or resumed gate partially re-recorded. | Matrix: Pi · Codex-enabled · Claude Code each select their advertised adapter and carry the three questions in one call; Codex-unavailable returns free-text prompts with no choices; the reviewer is planned as no question in every ranking shape; cancellation records no patch; overflow reports ordered call groups without dropping ids; resume re-asks nothing. Does the conformance scan reject a new direct primitive, accepting only exact historical allowlist entries? |
|
|
11
|
+
| 4 | **The loop exits on a fresh independent verdict on the current HEAD, never a claim** — and the review is review-pr, proven by its two artifacts (verbatim `scan-diff` findings channel + `coverage-checklist validate` result); a verdict without them is rejected before it is read. | The producer self-clears its NEEDS_CHANGES; a review-shaped prose answer with no mechanized over-mock screen lets internal-seam mocks merge green. | Is the terminal evidence an APPROVE dated after the last commit, with both proof artifacts? Prior findings reconciled with locators? |
|
|
12
|
+
| 5 | **Rounds are priced.** Blockers map to review-pr's named blocking classes (else PASS notes, not escalated later unless the code changed); round 2+ is delta-scoped to `lastReviewedSha...HEAD` (full scope only: high-risk / round 3+ / delta outside original files / rebase); proof is one in-branch artifact per round — never a proof-only PR; a fix never changes the PR’s scope class (a pipeline gap routes to its own unit); `lastReviewedSha` lands in the manifest and the handoff's round profile comes from `units[].rounds` (`at`/`scope`). | Nitpicks buying full rounds; every round re-reviewing the whole reviewed diff; proof spirals (the observed 15-proof-PR day); no round record, so the next "why slow" starts from archaeology. | Any blocker without a class mapping? Round-2 full scan without a named trigger? Any proof-only PR? Round profile (from `rounds`) present in the handoff? Did a second consecutive same-theme NEEDS_CHANGES get carried into the breaker diagnosis as an open question — implementer circling *or* reviewer over-blocking — rather than silently resolved by the orchestrator? |
|
|
13
|
+
| 5a | **Rounds end for a reason: fixes close the class, and evidence-only rounds don't buy reviews.** **Every** fix round closes the invariant *class* — naming it and the adjacent members checked, ADR-bounded where a design input exists and derived from the finding where none does, **sized to the finding** (most findings are their own class; enumeration is owed only where the rule has siblings) — and the re-review reconciles against that class, marking an instance-only repair `Partially resolved`. A round takes the evidence lane only on **two** signals — production diff unmoved since `lastReviewedSha` (evidence paths excluded; restack and flaky-external-gate cases included) **and** every surviving finding classed `subject: evidence` by the reviewer — then: one batched commit, revalidate, no adversarial review on unmoved code. | Instance-then-class churn (one invariant re-raised wider each round), and rounds spent re-reading code that did not move. Mirror failure: enumeration demanded on a CRUD fix — ceremony, not rigor. → [why](why.md#every-fix-closes-the-invariant-class) | Fix names its invariant class + the adjacent members checked? Any later round re-raising it wider? Enumeration demanded on a sibling-less finding? Evidence lane entered on **both** signals (production diff unmoved **and** every surviving finding classed `subject: evidence`), and not run twice without fixing the validator gap? Its fix ran as the constrained evidence-fix spawn — no source file in the diff, both validators re-run at the new HEAD — falling back to fix + adversarial review when a finding needed source? Every round in `units[].rounds` (`headSha`, `changedSurfaces`, `reviewSubject`, `themeIds`, authorization boundary), round profile in the handoff? |
|
|
14
|
+
| 6 | **Honest green (guarantee 1).** No skip/guard/weaken/`.only`, no first-party internal-seam mocks or journey interception, no degraded-page assertions; missing state is seeded; the quarantine lane is the only non-blocking path; diff-discipline on `merge-base...HEAD`. | Manufactured green shipping as done. | Did any test get skipped/weakened to pass? Any internal seam mocked? Was missing state seeded rather than guarded around? |
|
|
15
|
+
| 7 | **Risk tiering routes process weight.** High-risk units (auth/money/tenancy/migration) run [high-risk.md](high-risk.md) — hazard hunt both sides, round-1 depth, theme-complete fixes, forced integration review. **Every other unit runs only the lean loop** — deep-lane obligations applied to a routine unit is a regression, not rigor. | The deep lane leaking into every unit (the process-weight failure this distillation removed); or a high-risk unit slipping through the lean lane. | Was the flag decided from surfaces touched? Did any routine unit get round-1 depth/hazard ceremony? Did any auth/money/tenancy/migration unit skip the deep lane? |
|
|
16
|
+
| 8 | **One producer spawn per unit** (implement + e2e + gates + PR via implement-and-pr), each spawn under the leaf-spawn contract: absolute `<skillsRoot>` path read + a named proof artifact. | Spawn-per-sub-step doctrine re-reading (the largest fixed cost); prose-paraphrased spawns silently dropping the Contract/tags/TDD. | Did implement/e2e/gates run as separate spawns without cause? Did every spawn force an absolute-path skill read and carry its proof? After a spawn died mid-flight, was the replacement pointed at the partial artifact to resume — and was any `status: in-progress` artifact ever accepted as proof, or a verdict read off one? |
|
|
17
|
+
| 9 | **Epics: unit PASSes are preliminary evidence; progressive candidates expose conflicts early; one frozen exact-head terminal authorization controls delivery.** `record-component-candidate` classifies `unit-discovery`/`integration-fix`; freeze precedes exact-head integrated CI + review + smoke; movement reopens with a typed reason; `combine-and-verify mergeable --component` checks the live authorized head. fmm-express #830 retains 26 unit rounds while requiring one terminal full component review. | Re-reviewing every moved unit head after PASS while the actual artifact is one combined PR; integration-only fixes rewritten onto unit branches; stale ALIVE verdict authorizing a moved head. | Were preliminary unit reviews preserved without authorizing delivery? Did assembly run as units became ready? Are integration-only fixes owned on the candidate? Was every target-applicable GitHub ruleset and every Mergify lifecycle source preserved and mapped before freeze? Are PR-head checks proven only on the frozen PR SHA, with publish-only provider evidence validated before exact-head pass/exit derivation? Are queue/batch checks retained as queue-head requirements and proven only by provider evidence on a distinct synthetic head, never by a PR check or omission? Was the complete candidate frozen before one terminal review/CI/smoke? Does any later movement carry a typed reopen and fresh authorization? Does postmortem delivery wait start once per deliverable — the component-ready PASS for a co-delivery component, advanced only by a legitimate reopen — rather than multiplying one integration interval by every preliminary unit PASS? |
|
|
18
|
+
| 9a | **Legacy combined delivery remains one PR per component.** `combine-and-verify.mjs` → `integration-verdict.json` `ALIVE` (assembly + combined CI + integrated review where owed + smoke) before done; every epic owes the closed-world source audit — against the PRD/spec when one exists, otherwise against the epic issue's own body. | Individually-green slices contradicting once combined; an epic "done" on per-unit green alone; a spec-bearing epic escaping the audit because its spec is the issue rather than a separate doc. | Did any stacked PR merge alone? Is there an ALIVE verdict + combined PR with CI green on its own HEAD? Is the source audit attached, and does it name what it audited against? |
|
|
19
|
+
| 9b | **An epic's children are proven to cover it — before any producer spawn, and again at exit.** Every parent requirement (stories, constraints, named buckets/enums/reason codes, testing decisions) maps to a child that owns it or to a tracked deferral named in the handoff; a surface disclaimed by two or more siblings gets an explicit owner. Fires **once per epic, never per unit**. | Children built faithfully to their own ACs while the epic goes unmet — every unit green, the missing requirement in no child and so invisible to producer, reviewer and CI alike until after merge (epic-848). Mirror failure: work vanishing between two children that each correctly excluded it. → [why](why.md#a-surface-every-sibling-disclaims) | Parent→child requirement diff run at intake and re-run at the exit audit? Every unowned requirement carrying a child AC or a tracked issue? Any surface disclaimed by every sibling that touches it? Gate applied once per epic rather than per unit? |
|
|
20
|
+
| 10 | **Completion is a correctness-only transition.** `run-state finalize` requires typed dispositions, freshly fetched ancestry, live issue/PR terminal state, original-branch restoration, and structured workspace cleanup; unpublished work is preserved and blocks completion. The handoff is rendered from immutable validated state, including deferrals and autonomous decisions. | Caller-authored completion claims; stale GitHub state; missing delivered ancestry; a run branch left checked out; unreaped or discarded work; diagnostic process work blocking delivery. | Did `finalize` pass at the recorded SHA, with a `completionAudit`? Does every delivered component descend from fetched target state, and every descope carry live human closure? Did the run keep its pre-flight `<skillsRoot>` as lifecycle authority through finalization, even when the candidate itself changed `resolve-issues`? Did cleanup preserve unpublished work and refuse completion rather than delete it — proving the workspace still shares the repo's Git common directory first, so a producer-converted standalone clone is named rather than found through a late removal failure? Did any post-mortem/adjudication/process issue become a completion obligation? |
|
|
21
|
+
| 10a | **The run reports itself: a rendered PLAN before the first producer spawn, and PROGRESS as each unit reaches a terminal state.** The plan (`run-state.mjs plan`) names every unit, its dependency order, its component, its risk tier, every deferral with the issue tracking it, and every open ask; progress (`run-state.mjs progress`) names what is resolved against the whole roster and flags any `merge-ready` unit with no terminal delivery outcome. Both are **rendered from the manifest**, so intake owes it `units[].dependsOn` and `deferrals[]` rather than holding them in context. Reports, not gates — they stop nothing. | A long run where the human has lost the thread: the plan narrated once and abridged thereafter, a deferred requirement mentioned in passing and never tracked (epic-848), and units sitting merge-ready-but-undelivered while every summary reads "done" (epic-986, twelve hours). | Was a plan reported before any code, naming every unit the run went on to build? Were deferrals recorded with tracking issues rather than mentioned in prose? Did the roster carry `dependsOn` and render the stacking order? Did progress get reported as units resolved, flagging undelivered merge-ready units? Was either report hand-written — and does it omit a field the renderer prints? **Was the merge path *probed* at pre-flight (`deliveryMode`, plus `queueProvider` on a queue) rather than assumed?** |
|
|
22
|
+
| 11 | **Design precedes code where it matters; rounds are capped.** Intake applies the two-questions test (two-implementers divergence; correctness-by-never-happens) **and the scope double-check** (subsystem / separable deliverables / far-beyond-routine diff → propose the split before any code, from the issue’s content, never inheriting the human’s sizing). A design-owing unit spawns no producer until a human-approved design/ADR exists (redirect: `/grill-with-docs`), and that doc rides into the producer and reviewer spawns as the contract. **A high-risk unit presumes the never-happens answer is yes and owes an enumerated invariant list** — a contract *pointer* is not one. After the 3rd completed review round (or 3rd PASS-less produce pass) the breaker fires on the **mechanized diagnosis** (`diagnose-breaker`), never on memory. **The breaker is the only escalation rung** — an advisory pre-breaker consult defers the decision a stuck unit needs. | Ten rounds re-deriving an unwritten contract one invariant at a time, ~6.5 unattended hours — or the mirror, a design brief demanded for a CRUD tweak. Plus the 127-run audit's two: **five of six design firings were high-risk units that had already cleared this gate**, and the recurring-theme branch was **never once taken in 522 units**. → [why](why.md#design-gate) | Did a unit with open design decisions spawn without an approved design input — or a **high-risk** unit spawn against an issue that describes the change but enumerates no invariants? Did a subsystem-sized unit spawn without a split proposal? Did any unit start round 4 without a decision **recorded via `record-breaker-decision`** (state, not prose: no `breaker` key after 3 rounds means it never fired)? Did the hand-off text come from `diagnose-breaker`, naming `/grill-with-docs` literally? Did a routine unit get blocked on a ceremony brief, or an advisory consult get introduced *ahead* of the breaker? |
|
|
23
|
+
| 11a2 | **The design gate hands back, and a prerequisite artifact never enters the loop.** A unit owing a design/ADR/test-criteria stops and names `/grill-with-docs` — the loop does not interview the human itself and does not produce the contract, at **any** `autonomy` level. A design/criteria document gets no producer spawn, no independent-review spawn, no PR of its own, no queue delivery and no ancestry gate: if it contains no code, it does not enter the loop. Pre-flight skims for design-owing units before models/branch/delivery are settled. | The measured incident (Pi session `019f9865`, issue #5): the gate fired correctly, then the run resolved the block in-session and banked the ADR through the whole pipeline — **64 minutes, 5 spawns, ~$2, zero lines of the feature**, including a **$1.07 review of a 91-line docs diff whose `scan-diff` was empty**. Every step followed from a rule; nothing scoped where it stopped. → [why](why.md#the-design-gate-hands-back) | Contract produced in-run instead of handed back? Orchestrator interviewing the human rather than routing to `/grill-with-docs`? Any docs-only artifact given a review spawn, its own PR, or a queue delivery? Design-owing unit discovered only after pre-flight settled models, branch and delivery? Any `autonomy` level offering to draft a contract? |
|
|
24
|
+
| 11b | **Autonomy is bounded by reversibility and by a ceiling.** The loop may take `continue` and `design` on the computed diagnosis (`breakerAutonomy: auto`), and **`split` under `autonomy: autonomous` only** — an auto-applied split must stamp `autonomyAtDecision` on its own breaker record or state refuses it. **`descope` is always the human's**, refused in state as `autoApplied` however it is stamped. A recurring theme buys one mandated class-complete round (`classCompleteFor`) before it buys a human. **Nothing is auto-decided at or above the 8-round ceiling.** Every autonomous decision is stamped `autoApplied` + `signal` and reported in the handoff. | The loop quietly deciding to build less — the one autonomous decision that leaves no trace, since every other shows up as rounds spent. Mirror: an autonomous loop grinding past where any observed unit converged (epic-848: nine rounds, ~6.5 unattended hours). → [why](why.md#the-circuit-breaker-and-bounded-autonomy) | Any `descope` stamped `autoApplied`, or auto-applied `split` without `autonomyAtDecision: autonomous` on its record? The `autonomy` command's parks disagreeing with what the loop took? Any auto-decision at or above the ceiling? A recurring theme escalated *before* its class-complete round was spent — or mandated twice? Handoff separating loop decisions from human ones, and surfacing any that contradicted the computed recommendation? |
|
|
25
|
+
| 11a | **The removal path is alive, and rule 2 is executable.** A new mechanized gate names the incident it would have caught in the same commit. Every observation is recorded with honest state and stable finding fingerprints. `gate-audit` appends/reads the durable cross-run series; retirement requires the configurable trailing zero-yield window, while narrowing and deduplication remain independent recommendations. | Incident-driven accretion with no removal; repeated locator noise overstating value; one clean run retiring a cheap safety screen; a rare high-value catch disappearing into raw counts. | Does the audit distinguish `ran clean`, `not run`, `skipped`, and `unreadable`? Are unique/blocking/repeated/fixed/noise counts separate? Does any retirement recommendation rest on fewer than the configured durable runs, or count a non-execution as clean? Can repeated warning noise recommend dedup/narrowing without retirement? |
|
|
26
|
+
| 12 | **Approved contract revisions invalidate old-contract authorization.** Before every producer/reviewer and on resume, fetch the target branch, record the authoritative contract SHA + refs, and verify unit HEAD contains it. A newer affected revision re-enters intake, forces rebase + whole-contract reconciliation + full review, and leaves pre-revision verdicts/CI/runtime evidence historical only. | Seven rounds polishing a route-based control plane after the human approved a different Cloud Run Job contract; stale PR narration and evidence kept the obsolete implementation alive. | Does `contractRevision.sha` name the approved target-branch commit? Does unit HEAD descend from it? Does `reviewedContractSha` equal it before merge-ready? After a revision, was `lastReviewedSha` withheld and the next review full-scope? Did the implementation PR weaken its own source criteria without explicit approval? |
|