You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The change-authoring skills (ratchet-propose-batch, ratchet-propose, ratchet-decompose-phase) have no step that reconciles authored work against the originating GitHub issue, no rule governing Closes #N claims, and no mechanism that carries deferred scope forward between phases. The result, demonstrated end to end by the #80 → PR #97 → PR #98 chain below: a security-relevant half of an issue was silently dropped, the issue was claimed Closesd anyway, and the next phase — the one the deferral prose said would "revisit" it — never saw the deferral at all. Nothing in the process caught it; it was found by manual audit.
Three structural gaps, one per skill:
propose-batch hard-codes Closes #N before the work is scoped..claude/skills/ratchet-propose-batch/SKILL.md requires per-phase goal/success/done but never mentions originating issues at all — so nothing stops a manifest author from writing "the phase PR MUST link Closes #80" into a phase contract while the change-level done paraphrases only a subset of the issue. The Closes claim is then locked in before anyone has decided what will actually be built.
propose treats the manifest's paraphrased done as ground truth..claude/skills/ratchet-propose/SKILL.md derives features and plan from the user's description / the injected done criterion. It never fetches the originating issue, never diffs the authored scope against the issue's stated requirements, and never surfaces omissions to the user. A propose agent can therefore self-approve a scope reduction in a plan-prose bullet ("Out of scope: …") with no reviewer ever asked.
decompose-phase grounds only in shipped done criteria — plan prose evaporates..claude/skills/ratchet-decompose-phase/SKILL.md step 1 says to ground in "the injected prior-phase results: which change intents shipped and what each one's done criterion was." It never reads the prior phase's plan.md (where deferrals live as prose) and never verifies that a prior phase's Closes #N was actually earned. A deferral written as "revisit in phase 2" is invisible at phase-2 decomposition.
Each skill is mirrored in .claude/skills/ and .opencode/skills/ (content-identical apart from slash-command naming), so every fix must land in both trees.
Worked example (do not repeat)
Issue #80 ("RATCHET_BATCH_AGENT_CMD / RATCHET_EVAL_AGENT_CMD silently replace the agent in production — no gating, no notice, no journal marker, permissions bypassed") proposed four fix items: (1) a loud notice, (2) journal provenance stamping, (3) "Consider requiring an explicit opt-in pairing flag (--allow-agent-override) … or gating the seam on NODE_ENV", (4) a shared buildAgentSpawnRequest helper. It also named a distinct problem in its Why section: the override path never consults an adapter, so the resolved permission posture is voided while batch config still displays it as enforced.
PR Phase 1: spawn/env plumbing — thread env through rex runtimes + gate agent-cmd override (#89, #80) #97 shipped items 1, 2, 4 and claimed Closes #80. The new buildAgentSpawnRequest override branch returns a bare bash -c <override> request — no adapter, no permission flags — so the permission posture is still voided under an override, while batch config (src/core/batch/config.ts) remains override-unaware and reports the posture as enforced.
Net loss, still untracked at filing time: the ungated override seam and the permissions-posture bypass, on an issue GitHub will auto-close as fully fixed when the stack merges. The original issue's own hedged wording ("Consider requiring…") is what handed the propose agent its de-scope justification — which is why every requirement below is imperative.
What must change
Harden the three skills so this failure chain is structurally impossible. All requirements below are MUST-level; none are suggestions.
ratchet-propose and ratchet-propose-batch — issue reconciliation
When the work being proposed originates from one or more GitHub issues (referenced by the user, the manifest, or the injected done), the skill MUST fetch each originating issue (e.g. gh issue view <n>) and reconcile the authored scope (done criteria, features, plan) against the issue's stated requirements — both enumerated fix items and problems named in its Why/body.
Any material requirement of the issue that the authored scope omits MUST be surfaced to the user as an explicit decision point (enumerated: "issue asks X, this proposal does not include X") before artifacts are finalized. Skills MUST NOT self-approve an omission by writing it into plan prose.
Scope reductions touching security, permissions, or data integrity are NON-NEGOTIABLE: they MUST NOT be deferred or dropped without an explicitly filed, linked tracking issue that has an owner. A prose bullet in plan.md is not a deferral mechanism. If the user approves a de-scope, the skill MUST file (or require) the tracking issue and link it from the plan before proceeding.
ratchet-propose-batch — no premature Closes
The manifest MUST NOT hard-code Closes #N (in goal, success, or done) for work that has not yet been scoped and verified. Phase contracts reference issues as "targets #N" / "addresses #N"; the Closes #N linkage is earned at PR-authoring time only after the issue's material requirements are confirmed implemented.
A change-level done that covers only part of an issue MUST say "partially addresses #N" and MUST NOT say "Fixes #N" or "Closes #N".
Decomposition MUST read the prior phase(s)' plan.md files — not only the injected done criteria — and extract every ## Out of scope, "deferred", "revisit", or equivalent item. Each extracted item MUST be either (a) carried forward as a change intent in the phase being decomposed, (b) matched to an existing open tracking issue and reported as tracked, or (c) surfaced to the user as an explicit drop decision. Silently ignoring one is not an outcome.
Before treating an issue as shipped, decomposition MUST verify that a prior phase's Fixes/Closes #N claim was actually earned: compare the issue's material requirements against what the prior phase's done and plan describe as implemented. An unearned Closes MUST be surfaced (and the remaining scope carried forward), not inherited as fact.
Cross-cutting
Any de-scope of security-, permission-, or integrity-relevant work is a stop-and-surface event: the skill halts and asks the user, it never proceeds on momentum. This rule MUST appear verbatim (or equivalent) in the guardrails of all three skills.
A Fixes #N / Closes #N claim — in a manifest done, a plan, or a PR body — is permitted only when the issue's material requirements are actually implemented. Partial work MUST use "partially addresses #N".
All skill edits MUST land in BOTH .claude/skills/<name>/SKILL.md and .opencode/skills/<name>/SKILL.md, and in whatever generator/template produces them (the files carry generatedBy metadata), so regeneration does not revert the hardening.
Acceptance criteria
ratchet-propose/SKILL.md and ratchet-propose-batch/SKILL.md (both trees) contain an explicit step that fetches every originating GitHub issue and reconciles authored scope against it, and a guardrail forbidding self-approved omissions of material issue requirements.
ratchet-propose-batch/SKILL.md (both trees) forbids hard-coding Closes #N in manifest goal/success/done for unscoped work, and requires "targets #N" / "partially addresses #N" phrasing instead.
ratchet-decompose-phase/SKILL.md (both trees) requires reading prior phases' plan.md for out-of-scope/deferred/revisit items and mandates the carry-forward / tracked / explicit-drop trichotomy for each.
ratchet-decompose-phase/SKILL.md (both trees) requires verifying a prior phase's Fixes/Closes #N was earned before treating the issue as shipped.
All three skills (both trees) contain the stop-and-surface guardrail for security/permission/integrity de-scopes, requiring a filed, linked, owned tracking issue for any approved deferral.
If this issue is itself proposed via these skills before they are hardened: none of the seven criteria above may be dropped, deferred, or reworded to "consider"; any reduction requires a filed, linked tracking issue and explicit user approval.
Why
The change-authoring skills (
ratchet-propose-batch,ratchet-propose,ratchet-decompose-phase) have no step that reconciles authored work against the originating GitHub issue, no rule governingCloses #Nclaims, and no mechanism that carries deferred scope forward between phases. The result, demonstrated end to end by the #80 → PR #97 → PR #98 chain below: a security-relevant half of an issue was silently dropped, the issue was claimedClosesd anyway, and the next phase — the one the deferral prose said would "revisit" it — never saw the deferral at all. Nothing in the process caught it; it was found by manual audit.Three structural gaps, one per skill:
propose-batchhard-codesCloses #Nbefore the work is scoped..claude/skills/ratchet-propose-batch/SKILL.mdrequires per-phasegoal/success/donebut never mentions originating issues at all — so nothing stops a manifest author from writing "the phase PR MUST linkCloses #80" into a phase contract while the change-leveldoneparaphrases only a subset of the issue. TheClosesclaim is then locked in before anyone has decided what will actually be built.proposetreats the manifest's paraphraseddoneas ground truth..claude/skills/ratchet-propose/SKILL.mdderives features and plan from the user's description / the injecteddonecriterion. It never fetches the originating issue, never diffs the authored scope against the issue's stated requirements, and never surfaces omissions to the user. A propose agent can therefore self-approve a scope reduction in a plan-prose bullet ("Out of scope: …") with no reviewer ever asked.decompose-phasegrounds only in shippeddonecriteria — plan prose evaporates..claude/skills/ratchet-decompose-phase/SKILL.mdstep 1 says to ground in "the injected prior-phase results: which change intents shipped and what each one'sdonecriterion was." It never reads the prior phase'splan.md(where deferrals live as prose) and never verifies that a prior phase'sCloses #Nwas actually earned. A deferral written as "revisit in phase 2" is invisible at phase-2 decomposition.Each skill is mirrored in
.claude/skills/and.opencode/skills/(content-identical apart from slash-command naming), so every fix must land in both trees.Worked example (do not repeat)
Issue #80 ("
RATCHET_BATCH_AGENT_CMD/RATCHET_EVAL_AGENT_CMDsilently replace the agent in production — no gating, no notice, no journal marker, permissions bypassed") proposed four fix items: (1) a loud notice, (2) journal provenance stamping, (3) "Consider requiring an explicit opt-in pairing flag (--allow-agent-override) … or gating the seam onNODE_ENV", (4) a sharedbuildAgentSpawnRequesthelper. It also named a distinct problem in its Why section: the override path never consults an adapter, so the resolved permission posture is voided whilebatch configstill displays it as enforced.What the process did with that:
propose-batchbaked the scope reduction into the manifest before implementation..ratchet/batches/engine-runtime-hardening/batch.yamlphase 1 hard-codes "the phase PR MUST linkCloses #89andCloses #80" ingoalandsuccess, and thegate-and-mark-agent-cmd-overridechange'sdonecovers only notice + provenance + shared helper, ending "Fixes engine: RATCHET_BATCH_AGENT_CMD / RATCHET_EVAL_AGENT_CMD silently replace the agent in production — no gating, no notice, no journal marker, permissions bypassed #80." The gate and the permission bypass were already gone — andCloses #80was already mandatory.proposeself-approved the de-scope in plan prose. PR Phase 1: spawn/env plumbing — thread env through rex runtimes + gate agent-cmd override (#89, #80) #97'sgate-and-mark-agent-cmd-override/plan.mdcontains the bullet: "Out of scope (kept thin per the vertical-slice strategy): the issue's 'consider an explicit opt-in flag / NODE_ENV gate' (proposal item 3) — … an opt-in gate would break every existing e2e/eval harness invocation; revisit if engine: step completion is self-attested — 'ratchet batch report --complete' advances any transition with zero evidence, and a crash after reporting is invisible #78's corroboration work (phase 2) still needs it." Only the gating half was even noted as deferred; the permissions-bypass half was never mentioned as deferred anywhere. No tracking issue was filed; no human was asked.Closes #80. The newbuildAgentSpawnRequestoverride branch returns a barebash -c <override>request — no adapter, no permission flags — so the permission posture is still voided under an override, whilebatch config(src/core/batch/config.ts) remains override-unaware and reports the posture as enforced.Closes #78 #82 #81) never picked the deferral up. Its diff contains no mention of engine: RATCHET_BATCH_AGENT_CMD / RATCHET_EVAL_AGENT_CMD silently replace the agent in production — no gating, no notice, no journal marker, permissions bypassed #80,agentOverride, an override gate, or the permission bypass. Its engine: step completion is self-attested — 'ratchet batch report --complete' advances any transition with zero evidence, and a crash after reporting is invisible #78 corroboration work mitigated the audit harm (a synthetic stub can no longer drive a change todonewithout disk evidence) but did not gate the seam and did not fix the bypass.decompose-phasegrounded phase 2 in phase 1's shippeddonecriteria — which said "Fixes engine: RATCHET_BATCH_AGENT_CMD / RATCHET_EVAL_AGENT_CMD silently replace the agent in production — no gating, no notice, no journal marker, permissions bypassed #80" — so the "revisit in phase 2" prose was never read.Net loss, still untracked at filing time: the ungated override seam and the permissions-posture bypass, on an issue GitHub will auto-close as fully fixed when the stack merges. The original issue's own hedged wording ("Consider requiring…") is what handed the propose agent its de-scope justification — which is why every requirement below is imperative.
What must change
Harden the three skills so this failure chain is structurally impossible. All requirements below are MUST-level; none are suggestions.
ratchet-proposeandratchet-propose-batch— issue reconciliationdone), the skill MUST fetch each originating issue (e.g.gh issue view <n>) and reconcile the authored scope (donecriteria, features, plan) against the issue's stated requirements — both enumerated fix items and problems named in its Why/body.plan.mdis not a deferral mechanism. If the user approves a de-scope, the skill MUST file (or require) the tracking issue and link it from the plan before proceeding.ratchet-propose-batch— no prematureClosesCloses #N(ingoal,success, ordone) for work that has not yet been scoped and verified. Phase contracts reference issues as "targets #N" / "addresses #N"; theCloses #Nlinkage is earned at PR-authoring time only after the issue's material requirements are confirmed implemented.donethat covers only part of an issue MUST say "partially addresses #N" and MUST NOT say "Fixes #N" or "Closes #N".ratchet-decompose-phase— deferrals survive phase boundariesplan.mdfiles — not only the injecteddonecriteria — and extract every## Out of scope, "deferred", "revisit", or equivalent item. Each extracted item MUST be either (a) carried forward as a change intent in the phase being decomposed, (b) matched to an existing open tracking issue and reported as tracked, or (c) surfaced to the user as an explicit drop decision. Silently ignoring one is not an outcome.Fixes/Closes #Nclaim was actually earned: compare the issue's material requirements against what the prior phase'sdoneand plan describe as implemented. An unearnedClosesMUST be surfaced (and the remaining scope carried forward), not inherited as fact.Cross-cutting
Fixes #N/Closes #Nclaim — in a manifestdone, a plan, or a PR body — is permitted only when the issue's material requirements are actually implemented. Partial work MUST use "partially addresses #N"..claude/skills/<name>/SKILL.mdand.opencode/skills/<name>/SKILL.md, and in whatever generator/template produces them (the files carrygeneratedBymetadata), so regeneration does not revert the hardening.Acceptance criteria
ratchet-propose/SKILL.mdandratchet-propose-batch/SKILL.md(both trees) contain an explicit step that fetches every originating GitHub issue and reconciles authored scope against it, and a guardrail forbidding self-approved omissions of material issue requirements.ratchet-propose-batch/SKILL.md(both trees) forbids hard-codingCloses #Nin manifestgoal/success/donefor unscoped work, and requires "targets #N" / "partially addresses #N" phrasing instead.ratchet-decompose-phase/SKILL.md(both trees) requires reading prior phases'plan.mdfor out-of-scope/deferred/revisit items and mandates the carry-forward / tracked / explicit-drop trichotomy for each.ratchet-decompose-phase/SKILL.md(both trees) requires verifying a prior phase'sFixes/Closes #Nwas earned before treating the issue as shipped.Closes #80.batch config's override-unaware enforcement display) is tracked in a dedicated issue with an owner, and engine: RATCHET_BATCH_AGENT_CMD / RATCHET_EVAL_AGENT_CMD silently replace the agent in production — no gating, no notice, no journal marker, permissions bypassed #80'sCloseslinkage in the open PR stack is corrected to reflect partial implementation.If this issue is itself proposed via these skills before they are hardened: none of the seven criteria above may be dropped, deferred, or reworded to "consider"; any reduction requires a filed, linked tracking issue and explicit user approval.