Execute Plan
When to use
YES: meta/specs/NNN-slug/ has a plan.md with wave-grouped [ ] tasks (from write-plan) ready to execute; resuming a partially executed plan.
NO: no waves yet (use write-plan); design undecided (use tech-design); plan Status is already FROZEN.
Protocol
Input
- Spec folder:
meta/specs/NNN-slug/ (or a path to either file in it). Reads both plan.md (waves, log) and spec.md (ACs, D-NNN-XX decisions, Structure Outline).
Execution model
Parent agent (orchestrator):
- Reads plan + spec, dispatches subagents, runs review gates, commits.
- Never reads source code files or writes code itself (the Step 5 docs sync is the exception — durable-docs-update runs inline and manages its own reading).
- Edits
spec.md ONLY in Step 2.5 (promotion) and Step 6 (ship gate).
Use the model the user requests. Otherwise, choose the implementer model per logical task:
- Sonnet — only when every condition holds:
- The edit is fully specified and follows an existing pattern.
- Its assigned files are known and bounded.
- It requires no unresolved choice about behavior, architecture, or contract.
- It touches no schema, migration, auth, security, concurrency, payments, destructive data, or public/shared/external interface.
- The dispatch names a check that can verify the result.
- Opus — otherwise. Use Opus when any Sonnet condition fails or is unclear.
- Grouped work: classify all work assigned to one subagent together; any Opus condition selects Opus.
- Escalation: when the orchestrator selected Sonnet, upgrade to Opus if new scope, coupling, or ambiguity appears. Never downgrade during the same task.
- Authority: model choice never bypasses decision gates or reduces review and verification.
Subagents (implementers):
- Receive: plan file path + their assigned task IDs; the
AC-NNN-XX texts their tasks cite and the relevant Structure Outline excerpt (both copied from spec.md into the dispatch — they don't hunt the spec); any prior [Implementation] log entries touching their files (the outline is frozen — the log is where reality lives).
- Before the first write, resolve each target path and read its governing repository instructions and Claude path rules in
.claude/rules/ whose quoted paths: globs match it; use the intended path for a new file.
- Implement the assigned work; read existing code in affected areas.
- Code comments and test names:
- Write a comment only for what the code can't say — a constraint, assumption, or coupling; the comment carries the fact in prose.
- The dispatch's
D-NNN-XX/AC-NNN-XX ids may label a comment beside its fact.
- Never cite task ids, wave numbers, or finding ids in code — use a date if "when" matters.
- A test that satisfies an AC carries the id in its name:
test_acNNN_XX_....
- Return:
{ files_changed: [paths], summary: string, discoveries: [{ type: "[Implementation]" | "[AC-affecting]" | "[Future]", note: string }] | null }
- A deviation from the Structure Outline IS an
[Implementation] discovery — there is no separate channel. If the task body conflicts with a copied current AC-NNN-XX text, the AC text is authoritative: implement to the AC and return the conflict as an [AC-affecting] discovery — never silently reconcile it.
- A file assigned to another subagent in the same wave must NOT be edited — return
{ needs_scope_expansion: true, additional_files: [paths], justification: string } instead; the parent reassigns and re-dispatches. Once per wave: a second needs_scope_expansion in the same wave stops the reshuffle — collapse the colliding tasks into ONE subagent and run them serially (the same escape wave rule 3 uses for declared overlap).
- Keep Git mutations scoped to assigned files: never run
git stash, git checkout -- ., git reset, or another command that changes the whole tree.
- Scope every Git read to assigned paths.
- Read a committed baseline without changing shared state with
git show HEAD:<path>.
- No file contents in returns — paths and summaries only.
Autonomy gate — resolve before asking
This gate governs any mid-run AskUserQuestion on a reversible code decision. Out of scope (always ask): crash/timeout retry, verification-fail, contract amendment (→ Step 2.5), new-feature placement (→ Step 6.2), any destructive act. Auto-resolve only when the decision is grounded — it traces to a named source (a D-NNN-XX, AC-NNN-XX, cited spec line, or existing code at a file:line), never your reasoning alone — and you are ≥ 0.80 confident it fits this case. Then apply the disposition you'd otherwise recommend — the spec-mandated action (Tier 1) or the solver's fix (Tier 2) — and log it (below). A human-gated or not-diff-provable concern (a visual D-NNN-XX) never auto-fixes: log it as a - P2/P3 [deferred]: F-NNN-XX — ... entry in ## Wave Reviews (the anchor form on the P2/P3 row of Step 2) with the recommendation — Step 6.2 triages it at the ship gate.
Ground the decision in tiers; stop at the first that resolves:
- Tier 1 — Spec (parent, no subagent). The answer sits in a cited
AC-NNN-XX, locked D-NNN-XX, plan task, or the frozen Structure Outline. A literal match is ~1.0 confident; applying a principle to this case is a judgment — score it honestly. ≥ 0.80 → proceed; below it, fall to Tier 2, don't ask yet.
- Tier 2 — Investigation (two read-only subagents, serial). Dispatch a finder (Sonnet): "Does a source directly answer this — a
D-NNN-XX/AC-NNN-XX, another spec line, or existing code? Return { source, excerpt } only if it directly answers; merely related → source: none." source: none → escalate. Else dispatch a solver (Opus): "From that source + the spec, return { fix, confidence, needs_decision_change } — the simplest fix consistent with the locked decisions. Set needs_decision_change if the fix contradicts the D-NNN-XX's rationale, needs a decision changed, re-architects, or invents a default for behavior no source specifies." confidence ≥ 0.80 and not needs_decision_change → proceed; else escalate. The solver only proposes — the fix runs through the normal wave / fix-verify-loop path.
- Tier 3 — Escalate. The step's
AskUserQuestion, options with a recommendation, carrying the spec ref + finder/solver notes so the user decides fast.
Log every auto-resolve to ## Execution Log under the wave's ### Wave N — [date] heading: - [auto-resolved]: <decision> — per <source>, conf 0.NN. These are code-only and still pass Step 2/4 review — the backstop for a mis-scored proceed.
Review policy — choose the smallest safe gate
The orchestrator chooses each review unit without asking. A review unit changes review timing, not execution state — every wave keeps its own dispatch, checkbox flips, and commit.
- One wave — default. Use when any two-wave condition fails or risk is unclear.
- Two waves — use only when all conditions hold:
- Both adjacent waves are low-risk and reversible.
- Together they name no more than 4 files.
- Any dependency between them is local and explicit.
- Neither touches schema, migrations, concurrent writes, auth, permissions, security boundaries, payments, destructive data paths, or a public/shared/external interface.
- No earlier review debt is pending.
Before dispatch:
- Marker: append
- Review pending: Waves N–M — base <SHA> under ## Wave Reviews; use N–N for one wave.
- Base: use
HEAD before the unit's first implementation commit.
- Size: count implementation files and lines; exclude spec-folder bookkeeping unless it changes the contract.
After each wave in a two-wave unit:
- Close early: shorten the marker to the completed prefix and review now when the implementation diff exceeds 4 files or 200 changed lines, or the wave produces an AC-affecting discovery, decision/outline drift, scope expansion into the next wave, or any high-risk surface above.
- Continue: otherwise execute the second wave before reviewing the unit.
Step 1 — Wave execution loop
- Read the plan fresh — fix-verify-loop or a promotion may have changed it. Extract
PLAN_SLUG from the folder name (meta/specs/014-daily-digest/ → 014-daily-digest). If the plan header's **Base SHA:** is already set (a resume), adopt it as PLAN_BASE_SHA and skip the rest of this item. Fresh start only: first the staleness check — LAST=$(git log -1 --format=%H -- meta/specs/<slug>/plan.md); skip it if LAST is empty (plan never committed), else run git diff $LAST -- meta/specs/<slug>/spec.md (working tree included, so uncommitted spec edits count); any output means the plan was sequenced against an older spec — stop and route to write-plan. Then check git status --porcelain excluding the spec folder's files (they fold into the Wave 1 commit); if dirty, AskUserQuestion: "Stash and proceed (Recommended)" / "Commit and proceed" / "Abort". Then record PLAN_BASE_SHA=$(git rev-parse HEAD) and set the plan header's **Base SHA:** line.
- On session re-entry, resolve any
Review pending: marker before new implementation:
- Completed wave exists: shorten the marker to the completed prefix and review it through Step 3.5.
- No completed wave; assigned files clean: resume its first unchecked wave.
- No completed wave; assigned files dirty:
AskUserQuestion: "Resume from the partial changes (Recommended)" / "Stash them and restart the wave" / "Abort plan". On Resume, dispatch one recovery implementer with the unchecked task IDs and existing diff to reconcile and finish the wave; use the user-requested model, or Opus by default.
- Find the next
### Wave N with any [ ] tasks. Resuming mid-wave → dispatch only unchecked tasks. No unchecked tasks anywhere → resolve any pending review, then run Step 4; during a Step 6.2 ship-debt phase, return to its Review coverage item instead.
- With no pending unit, choose one or two waves by the Review policy and append its pending marker. With a pending unit, use its first unchecked wave.
- Launch one subagent per logical task in the wave, in parallel, using the model selected above.
Must land together with: tasks go to one subagent and are classified together.
- Collect results. Crash/timeout →
AskUserQuestion: "Retry this item (Recommended)" / "Skip and mark dependents blocked" / "Abort plan". Don't commit a partial wave.
- Append each returned discovery to the plan's
## Execution Log under a ### Wave N — [date] heading, with its type tag ([Future] entries take the next F-NNN-XX — Plan anchors, skills/write-plan/SKILL.md). Any [AC-affecting] discovery → run Step 2.5 now, before committing the wave. Other blocking issues → run the Autonomy gate; on escalation, AskUserQuestion: "Resolve and retry (Recommended)" / "Skip and mark dependents blocked" / "Override and proceed" / "Abort plan".
- Flip the wave's tasks to
[x] — the flip must land IN the wave commit (it's the resume state).
- Stage and commit:
git add [wave files + plan] && git commit -m "plan(<PLAN_SLUG>): Wave N complete — [brief summary]". On Wave 1, also git add any uncommitted spec.md (Step 1.1's fold-in); if git status --porcelain on the spec folder shows anything but spec.md/plan.md, leave those unstaged and tell the user.
- If the review unit is complete or an early-close condition fired, run Steps 2–3.5. Otherwise return to Step 1 for its second wave.
- Return to Step 1 after the review unit closes.
Step 2 — Review unit + Drift check
Read REVIEW_BASE from the pending marker, set REVIEW_HEAD=$(git rev-parse HEAD), and spawn every code-reviewer against git diff $REVIEW_BASE..$REVIEW_HEAD. Review the whole unit, never task or commit slices, so cross-task and cross-wave bugs stay visible. Reviewer count scales with the unit's actual size and risk:
- R1 — contract & correctness — always. Criteria below.
- R2 — cross-task & regression — add for every Step 6.2 ship-debt unit, when the unit spans two waves, or when its implementation diff exceeds 4 files or 200 changed lines, counting size by the Review policy. Charter: "Find bugs from how this review unit's changes interact — a signature, shared state, or config one task changed that another task or an existing caller now depends on. An empty result is valid."
- R3 — data integrity — add whenever the diff touches schema, migrations, or concurrent writes (any size). Charter: transactions, races, partial writes, migration reversibility — Step 4's data-integrity seat runs these plan-wide.
Merge findings (dedup by file + line-span + root cause, keep max severity) before the table below; at most three reviewers.
- Criteria (R1): the code-gated
AC-NNN-XX texts cited by the unit's tasks (copied from the spec). [human-gated:] ACs are excluded — they can't be verified against a diff (the ship gate routes them to Post-ship verification). Plus standard correctness/security/edge-case analysis.
- Drift question (posed to R1, whose dispatch also carries the unit's Structure Outline excerpts — the same ones the implementers got): "Does this diff contradict any locked
D-NNN-XX in spec.md, or deviate from the Structure Outline excerpt? Cite the decision ID or outline element and the contradicting hunk." The outline half is the independent net — implementers self-report only the deviations they notice.
- Scope: this review unit's diff only, not the whole plan. Single pass, no verifier; findings have
verdict: null and validated_by: "reviewer".
| Finding |
Action |
| None |
Record 0 findings — clean beside the pending marker; continue to Step 3.5. |
Drift hit (diff contradicts a D-NNN-XX) |
Run the Autonomy gate. Grounded + reversible (the D-NNN-XX is the source) → conform without asking: confirmed P1 with validated_by: "reviewer" → Step 3, log [auto-resolved]. A human-gated/visual D-NNN-XX isn't diff-provable → log it as a - P2/P3 [deferred]: entry (P2/P3 row below), don't ask. Only if the gate escalates (not confident, or the reviewer challenges the decision) → AskUserQuestion: "Fix code to conform to the D-NNN-XX (Recommended)" / "The decision is wrong — supersede it" (→ Step 2.5) / "Accept with risk note in Wave Reviews". |
Outline-drift hit (diff deviates from the outline; no D-NNN-XX or AC contradicted) |
A detail delta the implementer didn't self-report: append it as an [Implementation] entry to the Execution Log and continue — no pause. (A deviation that also contradicts an AC-NNN-XX or locked D-NNN-XX takes the Drift-hit / Step 2.5 path instead.) |
| P0/P1 |
Set verdict: "confirmed", validated_by: "reviewer", and evidence from the review unit → fix-verify-loop (Step 3). |
| P2/P3 not fixed |
Log in ## Wave Reviews as - P2 [deferred]: F-NNN-XX — ... / - P3 [deferred]: F-NNN-XX — ... with the why — line-leading - required: the ship-gate anchor is ^- P[0-9]+ \[deferred\]:, and the F id follows the colon (Plan anchors, skills/write-plan/SKILL.md). |
Write the unit's findings tally and Drift result beside its pending marker once Step 3 outcomes are known. Step 3.5 replaces that marker with the completed review record. Only pause where the table says so.
Step 2.5 — Promote an [AC-affecting] discovery (user-gated)
Triggered the moment an [AC-affecting] discovery is logged (Step 1.7) or a Drift hit resolves to "the decision is wrong" (Step 2). Never auto-apply — this amends the contract.
Log first: write the [AC-affecting] Execution Log entry if none exists — the Drift path arrives without one, and the marker must have an entry to count against. It states the contradiction and evidence.
Present via AskUserQuestion: the contradiction, the evidence, the proposed spec change (revised AC-NNN-XX text and/or D-NNN-XX supersession with new decision block). Also grep plan.md for unchecked - [ ] tasks citing the revised AC-NNN-XX or the superseded old id and list each (title + first body line) in the same question with a disposition: keep / amend / drop — re-pointing a citation updates a label, not the task's instructions. Apply amend/drop edits to plan.md as part of the promotion commit. Options: "Promote to spec (Recommended)" / "Adjust the proposal" / "Abort plan".
On approval, edit the spec(s) (AC line / decision block formats are canonical in skills/product-interview/SKILL.md's spec template). Worked example: old id D-014-03, new id D-014-11.
- Revise the
AC-NNN-XX in place, appending *(revised per D-NNN-XX)* — ACs are the live contract, one current truth; the why lives in the decision trail.
- Supersede the old decision in the spec file that owns its id — a cross-spec supersession flips a prior spec's block: set
Status: superseded, add Superseded-by: <new id>. Touch nothing else in the block.
- Append the new block to the current spec's spec.md, with the current spec's
NNN and the next XX (highest existing XX in this spec + 1) — Supersedes: <old id>, rationale citing the evidence and plan Wave N. Heading type marker: inherit the superseded block's [product]/[tech], or [tech] if the change is build-originated (marker is advisory — see the canonical Decisions comment).
Classify the supersession, then re-point. Additive = every claim under the old id stays true; behavior-changing = some claim is now false. Either way, grep plan.md for the old id and re-point citations to the new id. A behavior-changing supersession also sweeps the repo: grep the old id across code and docs, dispatch ONE subagent with the hit list and the implementers' comment rules; per hit —
- still true → leave it (the id resolves through the Status line);
- now false → rewrite the prose to the current fact and re-point the label to the new id;
- pointless → delete the comment.
The subagent returns files_changed to stage in the promotion commit.
Close the log entry: append promoted-to-spec [date]: AC-NNN-XX revised, <old id> superseded by <new id>. — ALWAYS lowercase and hyphenated; this is the ship gate's count-compare anchor (Plan anchors, skills/write-plan/SKILL.md). Never write the hyphenated token outside a real marker (unhyphenated prose is safe — the hyphen is what the gate counts).
Commit: git add [spec folder(s)] [swept files] && git commit -m "plan(<PLAN_SLUG>): promote [AC-affecting] — <old id> superseded by <new id>". Resume where execution stopped.
Fix-loop packet
Every fix-verify-loop invocation in Steps 3–4 passes:
- Findings: Confirmed P0/P1 findings with their
validated_by value and verdict evidence.
- Artifact paths: The call's approved base paths below. A finding or its evidence may identify another path, but editing it requires the fix-loop scope-expansion gate.
- Criteria: The call's governing criteria below plus each finding's criterion.
| Call |
Base artifact paths |
Governing criteria |
| Review unit — Step 3 |
Review-unit files |
ACs cited by the unit |
| Regression review — Step 3.5 |
Review-unit files plus files in the reviewed fix commit |
ACs cited by the unit |
| Final review — Step 4 |
Files changed in $PLAN_BASE_SHA..HEAD |
Code-gated ACs relevant to the findings |
| Verification failure — Step 4 |
Files changed in $PLAN_BASE_SHA..HEAD |
The expected project-verification result and relevant code-gated ACs |
Step 3 — Review-unit fix-verify-loop
P0/P1 findings (incl. confirmed Drift fixes) → invoke the fix-verify-loop skill with the Fix-loop packet. On a returned escalation, AskUserQuestion: "Retry with guidance (Recommended)" / "Accept and defer" (→ log [deferred] in Wave Reviews) / "Skip finding" / "Abort plan".
Commit fixes separately: plan(<PLAN_SLUG>): Waves N-M fixes — [summary] (use Wave N for a one-wave unit).
Step 3.5 — Review fixes commit (regression check)
If Step 3 produced a fixes commit, spawn code-reviewer scoped to its diff when the fix reached outside the review unit's files (git show --name-only --format= HEAD vs the unit file-set) or the diff is sizeable — directionally 2+ files or ~50 lines; otherwise skip the review. Clean or P2/P3-only → continue (deferred entries logged as in Step 2). P0/P1 → set verdict: "confirmed", validated_by: "reviewer", and evidence from the regression review → fix-verify-loop with the Fix-loop packet → commit as Waves N-M regression fixes (Wave N for one wave). Regression-fix commits are not re-reviewed here; Step 4 therefore selects Full.
Set Fix coverage to none when Step 3 made no commit, reviewed through <SHA> when every fix commit received this regression check, and unreviewed when any fix or regression-fix commit did not.
Close the unit by replacing its pending marker and adjacent provisional lines with:
### Review unit: Waves N–M
- Range: <REVIEW_BASE>..<REVIEW_HEAD>
- Seats: R1[, R2, R3]
- AC evidence: <AC-NNN-XX PASS — file:line; ... | none>
- Findings: <N findings: M fixed, D dropped by pre-gate, E demoted | 0 findings — clean>
- Drift: <none | disposition>
- Fix coverage: <none | reviewed through <SHA> | unreviewed>
Keep every anchored deferred entry directly below the completed block; marker replacement never removes deferred findings.
Step 4 — Final review
Land Step-4 fixes. After any Step-4 fix-verify-loop invocation:
- Resolve. Resolve every escalation and staged-change choice.
- Match. When accepted staged changes remain, confirm the path set from
git diff --staged --name-only exactly matches the accepted files_changed; resolve any mismatch before continuing.
- Commit. Before the next review or verification step, commit the matched paths as
plan(<PLAN_SLUG>): final review fixes — [summary] or plan(<PLAN_SLUG>): verification fixes — [summary]. With no accepted staged changes, continue without a commit.
Review Step-4 fixes. After Land Step-4 fixes, continue when no fix was committed; otherwise classify the commit from its diff:
| Gate |
Use when |
Action |
| Small |
Every condition holds: at most 2 files and 100 changed lines; one code path; no Review-policy high-risk surface; clear affected criteria, callers, and consumers. |
Invoke two-pass-review over the fix commit, its affected callers and consumers, and only the ACs or decisions the fix can change. |
| Medium |
Small does not fit; at most 3 affected final-review seats, including Seat B, can be named; no Full condition holds. |
Run the affected seats in parallel over the fix commit and affected surrounding code. Merge P0/P1 findings, then verify them once under the final-review Verify rule. |
| Full |
Any condition holds: more than 5 files or 400 changed lines; a Review-policy high-risk surface; a contract, decision, or outline change; 4 or more affected seats; unclear evidence or blast radius. |
Re-run Full over the updated $PLAN_BASE_SHA..HEAD diff. |
Small and Medium report only regressions caused by the fix, reuse unaffected final-review evidence, and return confirmed P0/P1 findings to the final-review fix rule below.
After all waves and pending reviews close, select code-gated ACs with grep -E '^- \*\*AC-[0-9]+' spec.md | grep -F '[code-gated]', then choose the final mode over git diff $PLAN_BASE_SHA..HEAD:
Use Integration only when all conditions hold:
- Every wave belongs to a completed review unit.
- Every fix commit has review coverage.
- Every confirmed P1 was fixed; none was deferred or skipped.
- No P0 occurred; at most two confirmed P1s occurred, all in one review unit.
- No regression review found another P1.
- No decision or outline drift occurred.
- No AC-affecting promotion occurred.
- The build touched none of the Review policy's high-risk surfaces.
- The spec has no more than 11 code-gated ACs.
- The blast radius is clear.
Use Full when any Integration condition fails or its evidence is unclear, including any deferred or skipped P1, unreviewed fix, P0, more than two P1s, P1s across units or in regression review, drift, promotion, high-risk work, or unclear blast radius.
Integration review: spawn one code-reviewer over the full diff, licensed to inspect unchanged callers and consumers. Give it every code-gated AC-NNN-XX, every D-NNN-XX block, and the Structure Outline. Charter: "Return per-AC PASS/FAIL evidence, then find cross-wave or caller regressions and whole-build decision/outline drift that review-unit passes could not see. Do not repeat isolated implementation commentary already settled in completed review units. An empty finding set is valid."
Full review: run the panel below. For either mode, the two-pass-review protocol rules apply: zero P0/P1 across all seats → skip the verifier and present the clean result with checks_run. If the verifier rejects every finding, record the disagreement and continue with zero confirmed P0/P1 findings; do not start another review automatically.
Dispatch in parallel — every seat is a code-reviewer agent receiving the full $PLAN_BASE_SHA..HEAD diff:
- Seat A — contract. Criteria: every code-gated
AC-NNN-XX (mechanical selection grep above) + standard correctness/security/edge-case analysis.
- Seat B — regression / blast radius. Scope: the changed files PLUS their unchanged callers/consumers — explicitly licensed to read outside the diff. Criteria: "Find behavior outside this feature that the diff breaks — callers and consumers of changed signatures, shared state or config, existing behavior no AC describes. Whether the feature's own ACs pass is Seat A's job, not yours. An empty result is a valid result."
- Seat C — decision & outline drift. Receives ALL
D-NNN-XX blocks from spec.md (including superseded, to catch reversion) + the frozen Structure Outline. Criteria: "Does the whole diff contradict any locked D-NNN-XX or deviate from the frozen Structure Outline? Cite the decision or outline element and the contradicting hunk. A contract-level contradiction is a Step 2.5 promotion, not just a fix. An empty result is a valid result."
- Conditional — AC clusters. If code-gated ACs ≥ 12: partition them into clusters of ≤ 8 and dispatch one Seat-A-style reviewer per cluster (its AC subset + the full diff); Seat A then carries only the correctness/security mandate, no ACs.
- Conditional — data integrity. If the diff touches schema, migrations, or concurrent writes: one more reviewer chartered on transactions, races, partial writes, and migration reversibility.
Merge (parent): dedup by file + line-span + root cause; keep the max severity; note which seats flagged each finding.
Verify: ONE verifier agent over the merged finding set — never one per seat. Set every adjudicated finding's validated_by to verifier. If the deduped P0/P1 findings exceed 4, batch the verification by relatedness (shared files, symbols, or call chains — never split findings that reference the same code path) and stitch the verdicts back into one envelope.
Confirmed P0/P1 → fix-verify-loop with the Fix-loop packet. A finding that contradicts an AC-NNN-XX or locked D-NNN-XX (not just fails it) is a contract break: log it as an [AC-affecting] Execution Log entry and run Step 2.5 — final review has no wave commit, but promotion works the same.
- Fix: apply Land Step-4 fixes, then Review Step-4 fixes.
- Promotion: any Step-2.5 promotion forces the post-fix gate to Full because Integration requires a stable contract.
- Retry limit: run one post-fix gate automatically. If resolving that gate changes code or the contract again, finish the resolution, then
AskUserQuestion: "Run another post-fix review (Recommended)" / "Abort plan".
- Completion: Small or Medium merges its evidence with the unaffected prior evidence; Full replaces the prior result. Record only a final state covered by that evidence. A later Step 6.2 ship-debt phase keeps the record valid only by merging review evidence for every added code change.
Verification run (conditional). After final-review fixes pass their post-fix gate, the parent runs the project's test/verification command once over the final state, if one exists — reading PASS/FAIL only, never source.
- No command → skip.
- Pass → note
verification: passed.
- Fail, or can't run →
AskUserQuestion: "Fix" / "Accept (pre-existing or intended)" / "Abort". You classify; the parent never reads the test to guess why. "Fix" → create a confirmed finding with validated_by: "machine" and evidence naming the exact command and observed failure; state only what the result proves, invoke fix-verify-loop with the Fix-loop packet, apply Land Step-4 fixes and Review Step-4 fixes, then run verification again. "Accept" → log an accepted risk in the ### Final review block, carried into the completion record.
Record the selected mode, per-AC PASS/FAIL evidence, and the verification-run outcome in a ### Final review block appended to ## Wave Reviews — file-backed so it survives a session boundary; Step 6.3 copies it into the spec.
Step 5 — Comments and durable docs
Route before the sweep:
- Already complete. If the
### Final review block contains **Durable-docs phase:** complete, continue to Step 6 without rerunning the sweep.
- Untriaged ship debt. If any
[Future] or [deferred] entry lacks a **Ship-debt triage:** disposition, write **Durable-docs phase:** pending in the ### Final review block and enter Step 6.2. Return here after the ship-debt phase closes.
- Ready. Otherwise, write
**Durable-docs phase:** pending unless it already exists, then run one final sweep over the full plan diff.
Invoke the durable-docs-update skill via the Skill tool inline. It sweeps the comments, syncs the docs, and reports both. Pass:
- scope —
$PLAN_BASE_SHA..HEAD (Mode B);
- discoveries — the typed Execution Log entries;
- context — the spec's Background + ACs;
- spec — the
spec.md path, so it mines the locked D-NNN-XX decisions as candidates.
Commit only the files durable-docs-update changed: git add [those paths] && git commit -m "plan(<PLAN_SLUG>): durable docs sync" — plan.md may hold unstaged Wave-Review text that must not ride along. Replace the pending marker with **Durable-docs phase:** complete. This step runs once after the last code phase and before the Completion record.
Step 6 — Ship gate
Run the plan's ## Ship Gate checklist; every box must be resolved before freezing.
Promotion check (count-compare, Execution-Log-scoped): sed -n '/^## Execution Log/,/^## Wave Reviews/p' plan.md | grep -c '^- \[AC-affecting\]' must equal the same slice piped to grep -ci 'promoted-to-spec'. Any shortfall → run Step 2.5 for the unmarked entries now; an unpromoted contract break fails the gate.
Triage every untriaged [Future] and [deferred] entry:
Analyze. An entry is triaged when its F-NNN-XX id has a recorded disposition under **Ship-debt triage:** in the ### Final review block. Before asking, write **Ship-debt phase:** triage there so an interruption resumes this item. Use one read-only subagent per four untriaged entries, capped at four subagents: min(4, ceil(entry_count / 4)). Split the entries evenly. Each subagent verifies its entries against the final code, spec, and review evidence, then returns one ShipDebtAssessment per entry. With no untriaged entries and no recorded fix-now disposition awaiting a task, replace a triage marker with closed; a pending durable-docs phase returns to Step 5, otherwise continue to item 3.
ShipDebtAssessment {
id: "F-NNN-XX",
status: "valid" | "stale" | "unclear",
evidence: string,
status_confidence: 0.0-1.0,
recommendation: "fix-now" | "defer" | "future" | "drop",
reason: string,
recommendation_confidence: 0.0-1.0
}
Ask. Present the assessments in as few AskUserQuestion batches as the tool allows, with one independently selectable question per assessment. Put each recommended choice first and record every disposition in the ### Final review block:
**Ship-debt triage:**
- <id> — <status> (<status_confidence>): <evidence>
Recommendation: <recommendation> (<recommendation_confidence>) — <reason>
Disposition: <fix-now | defer | future: destination | drop>
| Choice |
Use when |
Result |
fix-now |
A valid defect or shipped hole fits the current contract and approved scope. |
Add it to the ship-debt phase. |
defer |
A valid shipped limitation will not be fixed now. |
Record it under "Deferred / what this does NOT close". |
future |
The item is a separate feature outside the current contract. |
Ask the user where to place it; keep it visible and record its destination. |
drop |
The item is stale or noise. |
Let it die with the plan. |
Record each answer immediately. After every entry has a disposition, enter the fix-now phase when any recorded fix-now item lacks a task; otherwise replace the phase marker with **Ship-debt phase:** closed; a pending durable-docs phase returns to Step 5, otherwise continue to item 3.
Fix-now phase. Run at most one. If it has already run, omit fix-now from later questions.
- Plan. Set
SHIP_DEBT_BASE_SHA=$(git rev-parse HEAD) and replace the phase marker directly with **Ship-debt phase:** build — base <SHA>. Append every recorded fix-now item that lacks a task using the canonical task format, the next stable T id, its existing F-NNN-XX id, and its governing AC-NNN-XX or D-NNN-XX citations; cite every AC whose outcome the fix can change. Group the tasks into dependency-ordered ### Wave N: Ship debt — <summary> waves of at most five tasks; run independent tasks in parallel.
- Build. Run the normal wave dispatch, commit, and Steps 2–3.5 review rules through every appended wave; when no unchecked tasks remain, continue to Review coverage instead of Step 4.
- Review coverage. Re-run Step 4 in Full mode after any Step 2.5 promotion or decision/outline drift; otherwise re-run Step 4 only when a ship-debt review unit ends with
Fix coverage: unreviewed.
- Verify. If Step 4 reran, use its verification result; otherwise run the project verification command with Step 4's no-command/pass/fail handling.
- Close. If Step 4 reran, replace the earlier
### Final review block with its new record while preserving the phase marker and triage dispositions. Otherwise merge the ship-debt review units' evidence for every cited AC into that block and append the phase's verification result. Replace the phase marker with **Ship-debt phase:** closed; a pending durable-docs phase returns to Step 5, otherwise restart Step 6 at item 1. Later questions offer only defer, future, or drop.
When a future item is manually placed in a text home, begin its copied text with promoted from F-NNN-XX.
Write the spec's Completion record (format canonical in skills/product-interview/SKILL.md's spec template; copy, don't move — the plan keeps its log):
Shipped: [date], Status Complete/Partial.
- Criteria results: per-AC PASS/PARTIAL/FAIL with 1-line evidence from the
### Final review block, updated after any Step 6.2 ship-debt phase. Honest — FAIL/PARTIAL when warranted.
- Post-ship verification: manual test cases covering the whole feature (happy path, edges, error/empty states), derived from the spec's
## UX section + ACs, each an unchecked - [ ] line written steps → expected result. Every human-gated AC-NNN-XX MUST appear as a steps → expected line led by AC-NNN-XX: — owed, not orphaned (the diff never verified them). Confirm coverage mechanically: grep -E '^- \*\*AC-[0-9]+' spec.md | grep -F '[human-gated:' (grep the open [human-gated: form — it carries the inline "how" text; a closed bracket matches nothing and silently drops every human-gated AC) — every hit needs a matching AC-NNN-XX: line. If nothing is human-observable: write None — nothing manually observable.
- Deferred / what this does NOT close: every item selected
defer in Step 6.2, with severity.
- Review filter stats: one line aggregating the Wave Reviews tallies — findings dropped by fix-verify-loop's pre-gate and findings demoted, across all review units — so what the filter rejected stays visible.
Run one orchestration-prose pass. Invoke the tighten-instruction and structure-prose skills via the Skill tool, then relay both lenses to one Sonnet subagent. Run this pass once, after all parent-authored prose exists and before changing ship state.
- Scope: only parent-authored prose in the plan's
## Execution Log and ## Wave Reviews (including ### Final review), plus the spec's new Completion record.
- Shape only: improve clarity and structure without changing meaning, evidence, decisions, statuses, or task state. Preserve every ID and checkbox line verbatim.
- Anchors: record each count before the pass and verify it afterward; discard a file's edits if any count or form changes.
[Implementation], [AC-affecting], [Future], and [auto-resolved] entries must still start - [Tag].
[deferred] entries must still start - P<severity> [deferred]:.
- Promotion markers must remain lowercase
promoted-to-spec.
- Ship-debt state must retain
**Ship-debt phase:** triage, **Ship-debt phase:** build — base <SHA>, or **Ship-debt phase:** closed, plus each Disposition: line.
- Durable-docs state must retain
**Durable-docs phase:** pending or **Durable-docs phase:** complete.
Confirm every review, verification, docs, and ship-debt decision is resolved; run every applicable project check not already passed on the current state.
Flip spec Status: → Shipped. Check the plan's Ship Gate boxes, set plan Status: FROZEN [date].
Commit: git add [spec folder] && git commit -m "plan(<PLAN_SLUG>): ship — completion record, plan frozen".
Step 7 — Report
The Completion record in spec.md is the durable summary — don't duplicate it. Report in this exact shape — a scan of this block is how the user learns what happened, so give substance to what they're knowingly carrying and counts to what was routinely handled:
**Build complete: [NNN-slug]**
- Built: [what shipped, one line]
- Tests: [passed | failed — accepted: why | no command]
- ACs: [n] PASS, [m] FAIL/PARTIAL — [name each non-pass | all pass]
- Spec changed mid-build: [old id → new id — what changed, one line each | none]
- Accepted risks (carried, not fixed): [one line each — see Wave Reviews | none]
- Deferred debt: [one line each, with severity | none]
- Handled autonomously: [N] outline deviations, [M] auto-resolved decisions (see Execution Log)
- Docs: [files touched | none needed]
- Post-ship verification (you verify): [each item, one per line | none]
(Counts write 0 when empty — a zero is information, not noise. A field with two or more items nests them as sub-bullets.)
Resumability
- Wave-granular via
[x] checkboxes — on resume, find the first wave with [ ] tasks, dispatch only those.
- Ship-debt resume. A
**Ship-debt phase:** triage marker resumes Step 6.2 from the first entry without a recorded disposition. A build — base <SHA> marker restores SHIP_DEBT_BASE_SHA, materializes any recorded fix-now item without a task, then resumes the first unchecked Ship debt wave or Review coverage. A closed marker never offers another fix-now phase.
- Durable-docs resume. A `*
…(truncated)
1---2name: execute-plan3description: Implement a feature by executing its wave-grouped plan.md. TRIGGER when: user says 'run the plan', 'execute the plan', or 'implement it'; a plan.md has unchecked waves ready to build.4---56# Execute Plan78## When to use910YES: `meta/specs/NNN-slug/` has a `plan.md` with wave-grouped `[ ]` tasks (from write-plan) ready to execute; resuming a partially executed plan.1112NO: no waves yet (use `write-plan`); design undecided (use `tech-design`); plan Status is already FROZEN.1314## Protocol1516### Input1718- **Spec folder**: `meta/specs/NNN-slug/` (or a path to either file in it). Reads both `plan.md` (waves, log) and `spec.md` (ACs, D-NNN-XX decisions, Structure Outline).1920### Execution model2122**Parent agent (orchestrator):**23- Reads plan + spec, dispatches subagents, runs review gates, commits.24- Never reads source code files or writes code itself (the Step 5 docs sync is the exception — durable-docs-update runs inline and manages its own reading).25- Edits `spec.md` ONLY in Step 2.5 (promotion) and Step 6 (ship gate).2627**Use the model the user requests. Otherwise, choose the implementer model per logical task:**2829- **Sonnet — only when every condition holds:**30 - The edit is fully specified and follows an existing pattern.31 - Its assigned files are known and bounded.32 - It requires no unresolved choice about behavior, architecture, or contract.33 - It touches no schema, migration, auth, security, concurrency, payments, destructive data, or public/shared/external interface.34 - The dispatch names a check that can verify the result.35- **Opus — otherwise.** Use Opus when any Sonnet condition fails or is unclear.36- **Grouped work:** classify all work assigned to one subagent together; any Opus condition selects Opus.37- **Escalation:** when the orchestrator selected Sonnet, upgrade to Opus if new scope, coupling, or ambiguity appears. Never downgrade during the same task.38- **Authority:** model choice never bypasses decision gates or reduces review and verification.3940**Subagents (implementers):**41- Receive: plan file path + their assigned task IDs; the `AC-NNN-XX` texts their tasks cite and the relevant Structure Outline excerpt (both copied from spec.md into the dispatch — they don't hunt the spec); any prior `[Implementation]` log entries touching their files (the outline is frozen — the log is where reality lives).42- Before the first write, resolve each target path and read its governing repository instructions and Claude path rules in `.claude/rules/` whose quoted `paths:` globs match it; use the intended path for a new file.43- Implement the assigned work; read existing code in affected areas.44- Code comments and test names:45 - Write a comment only for what the code can't say — a constraint, assumption, or coupling; the comment carries the fact in prose.46 - The dispatch's `D-NNN-XX`/`AC-NNN-XX` ids may label a comment beside its fact.47 - Never cite task ids, wave numbers, or finding ids in code — use a date if "when" matters.48 - A test that satisfies an AC carries the id in its name: `test_acNNN_XX_...`.49- Return: `{ files_changed: [paths], summary: string, discoveries: [{ type: "[Implementation]" | "[AC-affecting]" | "[Future]", note: string }] | null }`50- A deviation from the Structure Outline IS an `[Implementation]` discovery — there is no separate channel. If the task body conflicts with a copied current `AC-NNN-XX` text, the AC text is authoritative: implement to the AC and return the conflict as an `[AC-affecting]` discovery — never silently reconcile it.51- A file assigned to another subagent in the same wave must NOT be edited — return `{ needs_scope_expansion: true, additional_files: [paths], justification: string }` instead; the parent reassigns and re-dispatches. Once per wave: a second `needs_scope_expansion` in the same wave stops the reshuffle — collapse the colliding tasks into ONE subagent and run them serially (the same escape wave rule 3 uses for declared overlap).52- Keep Git mutations scoped to assigned files: never run `git stash`, `git checkout -- .`, `git reset`, or another command that changes the whole tree.53- Scope every Git read to assigned paths.54- Read a committed baseline without changing shared state with `git show HEAD:<path>`.55- No file contents in returns — paths and summaries only.5657### Autonomy gate — resolve before asking5859This gate governs any mid-run `AskUserQuestion` on a **reversible code decision**. Out of scope (always ask): crash/timeout retry, verification-fail, contract amendment (→ Step 2.5), new-feature placement (→ Step 6.2), any destructive act. Auto-resolve only when the decision is **grounded** — it traces to a named source (a `D-NNN-XX`, `AC-NNN-XX`, cited spec line, or existing code at a `file:line`), never your reasoning alone — and you are **≥ 0.80 confident** it fits this case. Then apply the disposition you'd otherwise recommend — the spec-mandated action (Tier 1) or the solver's fix (Tier 2) — and log it (below). A human-gated or not-diff-provable concern (a visual `D-NNN-XX`) never auto-fixes: log it as a `- P2`/`P3 [deferred]: F-NNN-XX — ...` entry in `## Wave Reviews` (the anchor form on the P2/P3 row of Step 2) with the recommendation — Step 6.2 triages it at the ship gate.6061Ground the decision in tiers; stop at the first that resolves:6263- **Tier 1 — Spec (parent, no subagent).** The answer sits in a cited `AC-NNN-XX`, locked `D-NNN-XX`, plan task, or the frozen Structure Outline. A literal match is ~1.0 confident; applying a *principle* to this case is a judgment — score it honestly. ≥ 0.80 → proceed; below it, fall to Tier 2, don't ask yet.64- **Tier 2 — Investigation (two read-only subagents, serial).** Dispatch a **finder** (Sonnet): *"Does a source directly answer this — a `D-NNN-XX`/`AC-NNN-XX`, another spec line, or existing code? Return `{ source, excerpt }` only if it directly answers; merely related → `source: none`."* `source: none` → escalate. Else dispatch a **solver** (Opus): *"From that source + the spec, return `{ fix, confidence, needs_decision_change }` — the simplest fix consistent with the locked decisions. Set `needs_decision_change` if the fix contradicts the `D-NNN-XX`'s rationale, needs a decision changed, re-architects, or invents a default for behavior no source specifies."* `confidence ≥ 0.80` and not `needs_decision_change` → proceed; else escalate. The solver only proposes — the fix runs through the normal wave / fix-verify-loop path.65- **Tier 3 — Escalate.** The step's `AskUserQuestion`, options with a recommendation, carrying the spec ref + finder/solver notes so the user decides fast.6667Log every auto-resolve to `## Execution Log` under the wave's `### Wave N — [date]` heading: `- [auto-resolved]: <decision> — per <source>, conf 0.NN`. These are code-only and still pass Step 2/4 review — the backstop for a mis-scored proceed.6869### Review policy — choose the smallest safe gate7071The orchestrator chooses each review unit without asking. A review unit changes review timing, not execution state — every wave keeps its own dispatch, checkbox flips, and commit.7273- **One wave — default.** Use when any two-wave condition fails or risk is unclear.74- **Two waves — use only when all conditions hold:**75 - Both adjacent waves are low-risk and reversible.76 - Together they name no more than 4 files.77 - Any dependency between them is local and explicit.78 - Neither touches schema, migrations, concurrent writes, auth, permissions, security boundaries, payments, destructive data paths, or a public/shared/external interface.79 - No earlier review debt is pending.8081Before dispatch:8283- **Marker:** append `- Review pending: Waves N–M — base <SHA>` under `## Wave Reviews`; use `N–N` for one wave.84- **Base:** use `HEAD` before the unit's first implementation commit.85- **Size:** count implementation files and lines; exclude spec-folder bookkeeping unless it changes the contract.8687After each wave in a two-wave unit:8889- **Close early:** shorten the marker to the completed prefix and review now when the implementation diff exceeds 4 files or 200 changed lines, or the wave produces an AC-affecting discovery, decision/outline drift, scope expansion into the next wave, or any high-risk surface above.90- **Continue:** otherwise execute the second wave before reviewing the unit.9192### Step 1 — Wave execution loop93941. Read the plan fresh — fix-verify-loop or a promotion may have changed it. Extract `PLAN_SLUG` from the folder name (`meta/specs/014-daily-digest/` → `014-daily-digest`). If the plan header's `**Base SHA:**` is already set (a resume), adopt it as `PLAN_BASE_SHA` and skip the rest of this item. Fresh start only: first the staleness check — `LAST=$(git log -1 --format=%H -- meta/specs/<slug>/plan.md)`; skip it if `LAST` is empty (plan never committed), else run `git diff $LAST -- meta/specs/<slug>/spec.md` (working tree included, so uncommitted spec edits count); any output means the plan was sequenced against an older spec — stop and route to write-plan. Then check `git status --porcelain` excluding the spec folder's files (they fold into the Wave 1 commit); if dirty, `AskUserQuestion`: "Stash and proceed (Recommended)" / "Commit and proceed" / "Abort". Then record `PLAN_BASE_SHA=$(git rev-parse HEAD)` and set the plan header's `**Base SHA:**` line.952. On session re-entry, resolve any `Review pending:` marker before new implementation:96 - **Completed wave exists:** shorten the marker to the completed prefix and review it through Step 3.5.97 - **No completed wave; assigned files clean:** resume its first unchecked wave.98 - **No completed wave; assigned files dirty:** `AskUserQuestion`: "Resume from the partial changes (Recommended)" / "Stash them and restart the wave" / "Abort plan". On Resume, dispatch one recovery implementer with the unchecked task IDs and existing diff to reconcile and finish the wave; use the user-requested model, or Opus by default.993. Find the next `### Wave N` with any `[ ]` tasks. Resuming mid-wave → dispatch only unchecked tasks. No unchecked tasks anywhere → resolve any pending review, then run Step 4; during a Step 6.2 ship-debt phase, return to its **Review coverage** item instead.1004. With no pending unit, choose one or two waves by the Review policy and append its pending marker. With a pending unit, use its first unchecked wave.1015. Launch one subagent per logical task in the wave, in parallel, using the model selected above. `Must land together with:` tasks go to one subagent and are classified together.1026. Collect results. Crash/timeout → `AskUserQuestion`: "Retry this item (Recommended)" / "Skip and mark dependents blocked" / "Abort plan". Don't commit a partial wave.1037. Append each returned discovery to the plan's `## Execution Log` under a `### Wave N — [date]` heading, with its type tag (`[Future]` entries take the next `F-NNN-XX` — Plan anchors, skills/write-plan/SKILL.md). **Any `[AC-affecting]` discovery → run Step 2.5 now, before committing the wave.** Other blocking issues → run the **Autonomy gate**; on escalation, `AskUserQuestion`: "Resolve and retry (Recommended)" / "Skip and mark dependents blocked" / "Override and proceed" / "Abort plan".1048. Flip the wave's tasks to `[x]` — the flip must land IN the wave commit (it's the resume state).1059. Stage and commit: `git add [wave files + plan] && git commit -m "plan(<PLAN_SLUG>): Wave N complete — [brief summary]"`. On Wave 1, also `git add` any uncommitted spec.md (Step 1.1's fold-in); if `git status --porcelain` on the spec folder shows anything but spec.md/plan.md, leave those unstaged and tell the user.10610. If the review unit is complete or an early-close condition fired, run Steps 2–3.5. Otherwise return to Step 1 for its second wave.10711. Return to Step 1 after the review unit closes.108109### Step 2 — Review unit + Drift check110111Read `REVIEW_BASE` from the pending marker, set `REVIEW_HEAD=$(git rev-parse HEAD)`, and spawn every `code-reviewer` against `git diff $REVIEW_BASE..$REVIEW_HEAD`. Review the whole unit, never task or commit slices, so cross-task and cross-wave bugs stay visible. Reviewer count scales with the unit's actual size and risk:112113- **R1 — contract & correctness** — always. Criteria below.114- **R2 — cross-task & regression** — add for every Step 6.2 ship-debt unit, when the unit spans two waves, or when its implementation diff exceeds 4 files or 200 changed lines, counting size by the Review policy. Charter: *"Find bugs from how this review unit's changes interact — a signature, shared state, or config one task changed that another task or an existing caller now depends on. An empty result is valid."*115- **R3 — data integrity** — add whenever the diff touches schema, migrations, or concurrent writes (any size). Charter: transactions, races, partial writes, migration reversibility — Step 4's data-integrity seat runs these plan-wide.116117Merge findings (dedup by file + line-span + root cause, keep max severity) before the table below; at most three reviewers.118119- **Criteria (R1)**: the code-gated `AC-NNN-XX` texts cited by the unit's tasks (copied from the spec). `[human-gated:]` ACs are excluded — they can't be verified against a diff (the ship gate routes them to Post-ship verification). Plus standard correctness/security/edge-case analysis.120- **Drift question** (posed to R1, whose dispatch also carries the unit's Structure Outline excerpts — the same ones the implementers got): *"Does this diff contradict any locked `D-NNN-XX` in spec.md, or deviate from the Structure Outline excerpt? Cite the decision ID or outline element and the contradicting hunk."* The outline half is the independent net — implementers self-report only the deviations they notice.121- **Scope**: this review unit's diff only, not the whole plan. Single pass, no verifier; findings have `verdict: null` and `validated_by: "reviewer"`.122123| Finding | Action |124|---|---|125| None | Record `0 findings — clean` beside the pending marker; continue to Step 3.5. |126| **Drift hit** (diff contradicts a `D-NNN-XX`) | Run the **Autonomy gate**. Grounded + reversible (the `D-NNN-XX` is the source) → conform without asking: confirmed P1 with `validated_by: "reviewer"` → Step 3, log `[auto-resolved]`. A human-gated/visual `D-NNN-XX` isn't diff-provable → log it as a `- P2`/`P3 [deferred]:` entry (P2/P3 row below), don't ask. Only if the gate escalates (not confident, or the reviewer challenges the decision) → `AskUserQuestion`: "Fix code to conform to the D-NNN-XX (Recommended)" / "The decision is wrong — supersede it" (→ Step 2.5) / "Accept with risk note in Wave Reviews". |127| **Outline-drift hit** (diff deviates from the outline; no `D-NNN-XX` or AC contradicted) | A detail delta the implementer didn't self-report: append it as an `[Implementation]` entry to the Execution Log and continue — no pause. (A deviation that also contradicts an `AC-NNN-XX` or locked `D-NNN-XX` takes the Drift-hit / Step 2.5 path instead.) |128| P0/P1 | Set `verdict: "confirmed"`, `validated_by: "reviewer"`, and evidence from the review unit → fix-verify-loop (Step 3). |129| P2/P3 not fixed | Log in `## Wave Reviews` as `- P2 [deferred]: F-NNN-XX — ...` / `- P3 [deferred]: F-NNN-XX — ...` with the why — line-leading `- ` required: the ship-gate anchor is `^- P[0-9]+ \[deferred\]:`, and the F id follows the colon (Plan anchors, skills/write-plan/SKILL.md). |130131Write the unit's findings tally and Drift result beside its pending marker once Step 3 outcomes are known. Step 3.5 replaces that marker with the completed review record. Only pause where the table says so.132133### Step 2.5 — Promote an [AC-affecting] discovery (user-gated)134135Triggered the moment an `[AC-affecting]` discovery is logged (Step 1.7) or a Drift hit resolves to "the decision is wrong" (Step 2). Never auto-apply — this amends the contract.1361371. **Log first**: write the `[AC-affecting]` Execution Log entry if none exists — the Drift path arrives without one, and the marker must have an entry to count against. It states the contradiction and evidence.1382. **Present** via `AskUserQuestion`: the contradiction, the evidence, the proposed spec change (revised `AC-NNN-XX` text and/or `D-NNN-XX` supersession with new decision block). Also grep `plan.md` for unchecked `- [ ]` tasks citing the revised `AC-NNN-XX` or the superseded old id and list each (title + first body line) in the same question with a disposition: keep / amend / drop — re-pointing a citation updates a label, not the task's instructions. Apply amend/drop edits to `plan.md` as part of the promotion commit. Options: "Promote to spec (Recommended)" / "Adjust the proposal" / "Abort plan".1393. **On approval, edit the spec(s)** (AC line / decision block formats are canonical in `skills/product-interview/SKILL.md`'s spec template). Worked example: old id `D-014-03`, new id `D-014-11`.140 - Revise the `AC-NNN-XX` in place, appending `*(revised per D-NNN-XX)*` — ACs are the live contract, one current truth; the why lives in the decision trail.141 - Supersede the old decision in the spec file that owns its id — a cross-spec supersession flips a prior spec's block: set `Status: superseded`, add `Superseded-by: <new id>`. Touch nothing else in the block.142 - Append the new block to the current spec's spec.md, with the current spec's `NNN` and the next `XX` (highest existing `XX` in this spec + 1) — `Supersedes: <old id>`, rationale citing the evidence and `plan Wave N`. Heading type marker: inherit the superseded block's `[product]`/`[tech]`, or `[tech]` if the change is build-originated (marker is advisory — see the canonical Decisions comment).1434. **Classify the supersession, then re-point.** Additive = every claim under the old id stays true; behavior-changing = some claim is now false. Either way, grep `plan.md` for the old id and re-point citations to the new id. A behavior-changing supersession also sweeps the repo: grep the old id across code and docs, dispatch ONE subagent with the hit list and the implementers' comment rules; per hit —144 - still true → leave it (the id resolves through the Status line);145 - now false → rewrite the prose to the current fact and re-point the label to the new id;146 - pointless → delete the comment.147148 The subagent returns `files_changed` to stage in the promotion commit.1495. **Close the log entry**: append `promoted-to-spec [date]: AC-NNN-XX revised, <old id> superseded by <new id>.` — ALWAYS lowercase and hyphenated; this is the ship gate's count-compare anchor (Plan anchors, skills/write-plan/SKILL.md). Never write the hyphenated token outside a real marker (unhyphenated prose is safe — the hyphen is what the gate counts).1506. Commit: `git add [spec folder(s)] [swept files] && git commit -m "plan(<PLAN_SLUG>): promote [AC-affecting] — <old id> superseded by <new id>"`. Resume where execution stopped.151152### Fix-loop packet153154Every `fix-verify-loop` invocation in Steps 3–4 passes:155156- **Findings:** Confirmed P0/P1 findings with their `validated_by` value and verdict evidence.157- **Artifact paths:** The call's approved base paths below. A finding or its evidence may identify another path, but editing it requires the fix-loop scope-expansion gate.158- **Criteria:** The call's governing criteria below plus each finding's criterion.159160| Call | Base artifact paths | Governing criteria |161|---|---|---|162| Review unit — Step 3 | Review-unit files | ACs cited by the unit |163| Regression review — Step 3.5 | Review-unit files plus files in the reviewed fix commit | ACs cited by the unit |164| Final review — Step 4 | Files changed in `$PLAN_BASE_SHA..HEAD` | Code-gated ACs relevant to the findings |165| Verification failure — Step 4 | Files changed in `$PLAN_BASE_SHA..HEAD` | The expected project-verification result and relevant code-gated ACs |166167### Step 3 — Review-unit fix-verify-loop168169P0/P1 findings (incl. confirmed Drift fixes) → invoke the **fix-verify-loop** skill with the [Fix-loop packet](#fix-loop-packet). On a returned escalation, `AskUserQuestion`: "Retry with guidance (Recommended)" / "Accept and defer" (→ log `[deferred]` in Wave Reviews) / "Skip finding" / "Abort plan".170171Commit fixes separately: `plan(<PLAN_SLUG>): Waves N-M fixes — [summary]` (use `Wave N` for a one-wave unit).172173### Step 3.5 — Review fixes commit (regression check)174175If Step 3 produced a fixes commit, spawn `code-reviewer` scoped to its diff when the fix reached outside the review unit's files (`git show --name-only --format= HEAD` vs the unit file-set) or the diff is sizeable — directionally 2+ files or ~50 lines; otherwise skip the review. Clean or P2/P3-only → continue (deferred entries logged as in Step 2). P0/P1 → set `verdict: "confirmed"`, `validated_by: "reviewer"`, and evidence from the regression review → fix-verify-loop with the [Fix-loop packet](#fix-loop-packet) → commit as `Waves N-M regression fixes` (`Wave N` for one wave). Regression-fix commits are not re-reviewed here; Step 4 therefore selects Full.176177Set `Fix coverage` to `none` when Step 3 made no commit, `reviewed through <SHA>` when every fix commit received this regression check, and `unreviewed` when any fix or regression-fix commit did not.178179Close the unit by replacing its pending marker and adjacent provisional lines with:180181```markdown182### Review unit: Waves N–M183- Range: <REVIEW_BASE>..<REVIEW_HEAD>184- Seats: R1[, R2, R3]185- AC evidence: <AC-NNN-XX PASS — file:line; ... | none>186- Findings: <N findings: M fixed, D dropped by pre-gate, E demoted | 0 findings — clean>187- Drift: <none | disposition>188- Fix coverage: <none | reviewed through <SHA> | unreviewed>189```190191Keep every anchored deferred entry directly below the completed block; marker replacement never removes deferred findings.192193### Step 4 — Final review194195**Land Step-4 fixes.** After any Step-4 `fix-verify-loop` invocation:196197- **Resolve.** Resolve every escalation and staged-change choice.198- **Match.** When accepted staged changes remain, confirm the path set from `git diff --staged --name-only` exactly matches the accepted `files_changed`; resolve any mismatch before continuing.199- **Commit.** Before the next review or verification step, commit the matched paths as `plan(<PLAN_SLUG>): final review fixes — [summary]` or `plan(<PLAN_SLUG>): verification fixes — [summary]`. With no accepted staged changes, continue without a commit.200201**Review Step-4 fixes.** After **Land Step-4 fixes**, continue when no fix was committed; otherwise classify the commit from its diff:202203| Gate | Use when | Action |204|---|---|---|205| **Small** | Every condition holds: at most 2 files and 100 changed lines; one code path; no Review-policy high-risk surface; clear affected criteria, callers, and consumers. | Invoke `two-pass-review` over the fix commit, its affected callers and consumers, and only the ACs or decisions the fix can change. |206| **Medium** | Small does not fit; at most 3 affected final-review seats, including Seat B, can be named; no Full condition holds. | Run the affected seats in parallel over the fix commit and affected surrounding code. Merge P0/P1 findings, then verify them once under the final-review **Verify** rule. |207| **Full** | Any condition holds: more than 5 files or 400 changed lines; a Review-policy high-risk surface; a contract, decision, or outline change; 4 or more affected seats; unclear evidence or blast radius. | Re-run Full over the updated `$PLAN_BASE_SHA..HEAD` diff. |208209Small and Medium report only regressions caused by the fix, reuse unaffected final-review evidence, and return confirmed P0/P1 findings to the final-review fix rule below.210211After all waves and pending reviews close, select code-gated ACs with `grep -E '^- \*\*AC-[0-9]+' spec.md | grep -F '[code-gated]'`, then choose the final mode over `git diff $PLAN_BASE_SHA..HEAD`:212213Use **Integration** only when all conditions hold:214215- Every wave belongs to a completed review unit.216- Every fix commit has review coverage.217- Every confirmed P1 was fixed; none was deferred or skipped.218- No P0 occurred; at most two confirmed P1s occurred, all in one review unit.219- No regression review found another P1.220- No decision or outline drift occurred.221- No AC-affecting promotion occurred.222- The build touched none of the Review policy's high-risk surfaces.223- The spec has no more than 11 code-gated ACs.224- The blast radius is clear.225226Use **Full** when any Integration condition fails or its evidence is unclear, including any deferred or skipped P1, unreviewed fix, P0, more than two P1s, P1s across units or in regression review, drift, promotion, high-risk work, or unclear blast radius.227228**Integration review:** spawn one `code-reviewer` over the full diff, licensed to inspect unchanged callers and consumers. Give it every code-gated `AC-NNN-XX`, every `D-NNN-XX` block, and the Structure Outline. Charter: *"Return per-AC PASS/FAIL evidence, then find cross-wave or caller regressions and whole-build decision/outline drift that review-unit passes could not see. Do not repeat isolated implementation commentary already settled in completed review units. An empty finding set is valid."*229230**Full review:** run the panel below. For either mode, the two-pass-review protocol rules apply: zero P0/P1 across all seats → skip the verifier and present the clean result with `checks_run`. If the verifier rejects every finding, record the disagreement and continue with zero confirmed P0/P1 findings; do not start another review automatically.231232Dispatch in parallel — every seat is a `code-reviewer` agent receiving the full `$PLAN_BASE_SHA..HEAD` diff:233234- **Seat A — contract.** Criteria: every code-gated `AC-NNN-XX` (mechanical selection grep above) + standard correctness/security/edge-case analysis.235- **Seat B — regression / blast radius.** Scope: the changed files PLUS their unchanged callers/consumers — explicitly licensed to read outside the diff. Criteria: "Find behavior outside this feature that the diff breaks — callers and consumers of changed signatures, shared state or config, existing behavior no AC describes. Whether the feature's own ACs pass is Seat A's job, not yours. An empty result is a valid result."236- **Seat C — decision & outline drift.** Receives ALL `D-NNN-XX` blocks from spec.md (including superseded, to catch reversion) + the frozen Structure Outline. Criteria: "Does the whole diff contradict any locked `D-NNN-XX` or deviate from the frozen Structure Outline? Cite the decision or outline element and the contradicting hunk. A contract-level contradiction is a Step 2.5 promotion, not just a fix. An empty result is a valid result."237- **Conditional — AC clusters.** If code-gated ACs ≥ 12: partition them into clusters of ≤ 8 and dispatch one Seat-A-style reviewer per cluster (its AC subset + the full diff); Seat A then carries only the correctness/security mandate, no ACs.238- **Conditional — data integrity.** If the diff touches schema, migrations, or concurrent writes: one more reviewer chartered on transactions, races, partial writes, and migration reversibility.239240**Merge** (parent): dedup by file + line-span + root cause; keep the max severity; note which seats flagged each finding.241242**Verify**: ONE `verifier` agent over the merged finding set — never one per seat. Set every adjudicated finding's `validated_by` to `verifier`. If the deduped P0/P1 findings exceed 4, batch the verification by relatedness (shared files, symbols, or call chains — never split findings that reference the same code path) and stitch the verdicts back into one envelope.243244Confirmed P0/P1 → **fix-verify-loop** with the [Fix-loop packet](#fix-loop-packet). A finding that *contradicts* an `AC-NNN-XX` or locked `D-NNN-XX` (not just fails it) is a contract break: log it as an `[AC-affecting]` Execution Log entry and run Step 2.5 — final review has no wave commit, but promotion works the same.245246- **Fix:** apply **Land Step-4 fixes**, then **Review Step-4 fixes**.247- **Promotion:** any Step-2.5 promotion forces the post-fix gate to **Full** because Integration requires a stable contract.248- **Retry limit:** run one post-fix gate automatically. If resolving that gate changes code or the contract again, finish the resolution, then `AskUserQuestion`: "Run another post-fix review (Recommended)" / "Abort plan".249- **Completion:** Small or Medium merges its evidence with the unaffected prior evidence; Full replaces the prior result. Record only a final state covered by that evidence. A later Step 6.2 ship-debt phase keeps the record valid only by merging review evidence for every added code change.250251**Verification run (conditional).** After final-review fixes pass their post-fix gate, the parent runs the project's test/verification command once over the final state, if one exists — reading PASS/FAIL only, never source.252253- **No command** → skip.254- **Pass** → note `verification: passed`.255- **Fail, or can't run** → `AskUserQuestion`: "Fix" / "Accept (pre-existing or intended)" / "Abort". You classify; the parent never reads the test to guess why. "Fix" → create a confirmed finding with `validated_by: "machine"` and evidence naming the exact command and observed failure; state only what the result proves, invoke fix-verify-loop with the [Fix-loop packet](#fix-loop-packet), apply **Land Step-4 fixes** and **Review Step-4 fixes**, then run verification again. "Accept" → log an accepted risk in the `### Final review` block, carried into the completion record.256257Record the selected mode, per-AC PASS/FAIL evidence, and the verification-run outcome in a `### Final review` block appended to `## Wave Reviews` — file-backed so it survives a session boundary; Step 6.3 copies it into the spec.258259### Step 5 — Comments and durable docs260261Route before the sweep:262263- **Already complete.** If the `### Final review` block contains `**Durable-docs phase:** complete`, continue to Step 6 without rerunning the sweep.264- **Untriaged ship debt.** If any `[Future]` or `[deferred]` entry lacks a `**Ship-debt triage:**` disposition, write `**Durable-docs phase:** pending` in the `### Final review` block and enter Step 6.2. Return here after the ship-debt phase closes.265- **Ready.** Otherwise, write `**Durable-docs phase:** pending` unless it already exists, then run one final sweep over the full plan diff.266267Invoke the **durable-docs-update** skill via the Skill tool inline. It sweeps the comments, syncs the docs, and reports both. Pass:268- **scope** — `$PLAN_BASE_SHA..HEAD` (Mode B);269- **discoveries** — the typed Execution Log entries;270- **context** — the spec's Background + ACs;271- **spec** — the `spec.md` path, so it mines the locked `D-NNN-XX` decisions as candidates.272273Commit only the files durable-docs-update changed: `git add [those paths] && git commit -m "plan(<PLAN_SLUG>): durable docs sync"` — `plan.md` may hold unstaged Wave-Review text that must not ride along. Replace the pending marker with `**Durable-docs phase:** complete`. This step runs once after the last code phase and before the Completion record.274275### Step 6 — Ship gate276277Run the plan's `## Ship Gate` checklist; every box must be resolved before freezing.2782791. **Promotion check (count-compare, Execution-Log-scoped)**: `sed -n '/^## Execution Log/,/^## Wave Reviews/p' plan.md | grep -c '^- \[AC-affecting\]'` must equal the same slice piped to `grep -ci 'promoted-to-spec'`. Any shortfall → run Step 2.5 for the unmarked entries now; an unpromoted contract break fails the gate.2802. **Triage every untriaged `[Future]` and `[deferred]` entry:**281282 **Analyze.** An entry is triaged when its `F-NNN-XX` id has a recorded disposition under `**Ship-debt triage:**` in the `### Final review` block. Before asking, write `**Ship-debt phase:** triage` there so an interruption resumes this item. Use one read-only subagent per four untriaged entries, capped at four subagents: `min(4, ceil(entry_count / 4))`. Split the entries evenly. Each subagent verifies its entries against the final code, spec, and review evidence, then returns one `ShipDebtAssessment` per entry. With no untriaged entries and no recorded `fix-now` disposition awaiting a task, replace a `triage` marker with `closed`; a pending durable-docs phase returns to Step 5, otherwise continue to item 3.283284 ```285 ShipDebtAssessment {286 id: "F-NNN-XX",287 status: "valid" | "stale" | "unclear",288 evidence: string,289 status_confidence: 0.0-1.0,290 recommendation: "fix-now" | "defer" | "future" | "drop",291 reason: string,292 recommendation_confidence: 0.0-1.0293 }294 ```295296 **Ask.** Present the assessments in as few `AskUserQuestion` batches as the tool allows, with one independently selectable question per assessment. Put each recommended choice first and record every disposition in the `### Final review` block:297298 ```299 **Ship-debt triage:**300 - <id> — <status> (<status_confidence>): <evidence>301 Recommendation: <recommendation> (<recommendation_confidence>) — <reason>302 Disposition: <fix-now | defer | future: destination | drop>303 ```304305 | Choice | Use when | Result |306 |---|---|---|307 | `fix-now` | A valid defect or shipped hole fits the current contract and approved scope. | Add it to the ship-debt phase. |308 | `defer` | A valid shipped limitation will not be fixed now. | Record it under "Deferred / what this does NOT close". |309 | `future` | The item is a separate feature outside the current contract. | Ask the user where to place it; keep it visible and record its destination. |310 | `drop` | The item is stale or noise. | Let it die with the plan. |311312 Record each answer immediately. After every entry has a disposition, enter the fix-now phase when any recorded `fix-now` item lacks a task; otherwise replace the phase marker with `**Ship-debt phase:** closed`; a pending durable-docs phase returns to Step 5, otherwise continue to item 3.313314 **Fix-now phase.** Run at most one. If it has already run, omit `fix-now` from later questions.315316 1. **Plan.** Set `SHIP_DEBT_BASE_SHA=$(git rev-parse HEAD)` and replace the phase marker directly with `**Ship-debt phase:** build — base <SHA>`. Append every recorded `fix-now` item that lacks a task using the canonical task format, the next stable `T` id, its existing `F-NNN-XX` id, and its governing `AC-NNN-XX` or `D-NNN-XX` citations; cite every AC whose outcome the fix can change. Group the tasks into dependency-ordered `### Wave N: Ship debt — <summary>` waves of at most five tasks; run independent tasks in parallel.317 2. **Build.** Run the normal wave dispatch, commit, and Steps 2–3.5 review rules through every appended wave; when no unchecked tasks remain, continue to **Review coverage** instead of Step 4.318 3. **Review coverage.** Re-run Step 4 in Full mode after any Step 2.5 promotion or decision/outline drift; otherwise re-run Step 4 only when a ship-debt review unit ends with `Fix coverage: unreviewed`.319 4. **Verify.** If Step 4 reran, use its verification result; otherwise run the project verification command with Step 4's no-command/pass/fail handling.320 5. **Close.** If Step 4 reran, replace the earlier `### Final review` block with its new record while preserving the phase marker and triage dispositions. Otherwise merge the ship-debt review units' evidence for every cited AC into that block and append the phase's verification result. Replace the phase marker with `**Ship-debt phase:** closed`; a pending durable-docs phase returns to Step 5, otherwise restart Step 6 at item 1. Later questions offer only `defer`, `future`, or `drop`.321322 When a `future` item is manually placed in a text home, begin its copied text with `promoted from F-NNN-XX`.3233. **Write the spec's Completion record** (format canonical in `skills/product-interview/SKILL.md`'s spec template; copy, don't move — the plan keeps its log):324 - `Shipped: [date]`, Status Complete/Partial.325 - **Criteria results**: per-AC PASS/PARTIAL/FAIL with 1-line evidence from the `### Final review` block, updated after any Step 6.2 ship-debt phase. Honest — FAIL/PARTIAL when warranted.326 - **Post-ship verification**: manual test cases covering the whole feature (happy path, edges, error/empty states), derived from the spec's `## UX` section + ACs, each an unchecked `- [ ]` line written `steps → expected result`. Every human-gated `AC-NNN-XX` MUST appear as a `steps → expected` line led by `AC-NNN-XX:` — owed, not orphaned (the diff never verified them). Confirm coverage mechanically: `grep -E '^- \*\*AC-[0-9]+' spec.md | grep -F '[human-gated:'` (grep the open `[human-gated:` form — it carries the inline "how" text; a closed bracket matches nothing and silently drops every human-gated AC) — every hit needs a matching `AC-NNN-XX:` line. If nothing is human-observable: write `None — nothing manually observable`.327 - **Deferred / what this does NOT close**: every item selected `defer` in Step 6.2, with severity.328 - **Review filter stats**: one line aggregating the Wave Reviews tallies — findings dropped by fix-verify-loop's pre-gate and findings demoted, across all review units — so what the filter rejected stays visible.3294. **Run one orchestration-prose pass.** Invoke the `tighten-instruction` and `structure-prose` skills via the Skill tool, then relay both lenses to one **Sonnet** subagent. Run this pass once, after all parent-authored prose exists and before changing ship state.330 - **Scope:** only parent-authored prose in the plan's `## Execution Log` and `## Wave Reviews` (including `### Final review`), plus the spec's new Completion record.331 - **Shape only:** improve clarity and structure without changing meaning, evidence, decisions, statuses, or task state. Preserve every ID and checkbox line verbatim.332 - **Anchors:** record each count before the pass and verify it afterward; discard a file's edits if any count or form changes.333 - `[Implementation]`, `[AC-affecting]`, `[Future]`, and `[auto-resolved]` entries must still start `- [Tag]`.334 - `[deferred]` entries must still start `- P<severity> [deferred]:`.335 - Promotion markers must remain lowercase `promoted-to-spec`.336 - Ship-debt state must retain `**Ship-debt phase:** triage`, `**Ship-debt phase:** build — base <SHA>`, or `**Ship-debt phase:** closed`, plus each `Disposition:` line.337 - Durable-docs state must retain `**Durable-docs phase:** pending` or `**Durable-docs phase:** complete`.3385. Confirm every review, verification, docs, and ship-debt decision is resolved; run every applicable project check not already passed on the current state.3396. Flip spec `Status:` → `Shipped`. Check the plan's Ship Gate boxes, set plan `Status: FROZEN [date]`.3407. Commit: `git add [spec folder] && git commit -m "plan(<PLAN_SLUG>): ship — completion record, plan frozen"`.341342### Step 7 — Report343344The Completion record in `spec.md` is the durable summary — don't duplicate it. Report in this exact shape — a scan of this block is how the user learns what happened, so give substance to what they're knowingly carrying and counts to what was routinely handled:345346```347**Build complete: [NNN-slug]**348- Built: [what shipped, one line]349- Tests: [passed | failed — accepted: why | no command]350- ACs: [n] PASS, [m] FAIL/PARTIAL — [name each non-pass | all pass]351- Spec changed mid-build: [old id → new id — what changed, one line each | none]352- Accepted risks (carried, not fixed): [one line each — see Wave Reviews | none]353- Deferred debt: [one line each, with severity | none]354- Handled autonomously: [N] outline deviations, [M] auto-resolved decisions (see Execution Log)355- Docs: [files touched | none needed]356- Post-ship verification (you verify): [each item, one per line | none]357```358359(Counts write `0` when empty — a zero is information, not noise. A field with two or more items nests them as sub-bullets.)360361### Resumability362363- **Wave-granular via `[x]` checkboxes** — on resume, find the first wave with `[ ]` tasks, dispatch only those.364- **Ship-debt resume.** A `**Ship-debt phase:** triage` marker resumes Step 6.2 from the first entry without a recorded disposition. A `build — base <SHA>` marker restores `SHIP_DEBT_BASE_SHA`, materializes any recorded `fix-now` item without a task, then resumes the first unchecked Ship debt wave or **Review coverage**. A `closed` marker never offers another fix-now phase.365- **Durable-docs resume.** A `*366367…(truncated)