Skip to content

Change-authoring skills let scope reductions and premature Closes #N claims propagate unverified (propose-batch / propose / decompose-phase) #100

Description

@joctaTorres

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 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:

  1. 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.
  2. 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.
  3. 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.

What the process did with that:

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".

ratchet-decompose-phase — deferrals survive phase boundaries

  • 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

  1. 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.
  2. 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.
  3. 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.
  4. ratchet-decompose-phase/SKILL.md (both trees) requires verifying a prior phase's Fixes/Closes #N was earned before treating the issue as shipped.
  5. 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.
  6. A test or checkable procedure demonstrates the reconciliation behavior on the worked example: given issue 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's text and phase 1's manifest/plan, the hardened skills flag (a) the unimplemented gate, (b) the unaddressed permission bypass, and (c) the premature Closes #80.
  7. The still-open remainder 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 (override gate + permission-posture bypass under override, including 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's Closes linkage 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions