---
name: execute
description: "Implements a plan step by step, verifies named tests or explicit manual scenarios, enforces the product-behavior guardrail and five-attempt retry limit, and completes with the plan's automated regression gate or validated manual evidence. Use when executing a plan that plan-the-work already wrote."
disable-model-invocation: true
---

# Execute

## Usage

```
/make-it-work:execute [TICKET-ID | path/to/plan.md] [--autopilot]
```

- Pass a ticket key (e.g. `PROJ-123`), an explicit path to a plan file, or nothing (the skill derives the key from the current branch). `--autopilot` may appear anywhere in the invocation — strip it from the argument before Phase 0 point 2's ticket/path resolution runs, so it is never mistaken for the ticket key or the plan path.
- **No `--autopilot`** — interactive. Every `AskUserQuestion` and checkpoint below pauses for a human, exactly as documented.
- **`--autopilot`** — unattended. At every interactive point below, apply the Autopilot Mode policy instead of pausing.

## Autopilot Mode

When invoked with `--autopilot`, still **construct** every question/options payload exactly as the interactive path below would — option counts, labels, and the `(Recommended)` rule all still apply and get exercised on every run — just don't call `AskUserQuestion` or wait at a checkpoint. Auto-resolve per the table below instead.

**Hard-stop exception:** no destructive action exists in this skill — `execute` never deletes or overwrites user content beyond the plan file's own `## Execution Status` bookkeeping, and it never runs `git commit` (Phase 1's "Never git-commit" rule, unaffected by `--autopilot`). Five sites nonetheless remain unconditional stops under `--autopilot`, identical to the interactive path, because autopilot cannot safely infer an answer for any of them — these are missing-input or malformed-plan stops, not a destructive-action analog, but are listed here for completeness per this section's own disclosure requirement:
- Phase 0 point 1's ambiguous repo/workspace selection among unrelated clones with no unifying doc — there is no way to infer which of several unrelated repos is the right one, so this stays a stop under both modes.
- Phase 0 point 1's "Could not identify the project root" message.
- Phase 0 point 2's underivable `<TICKET>` key / plan path.
- Phase 0 point 2's "No plan found at `make-it-work/<TICKET>/<TICKET>-plan.md`..." message.
- Phase 2's inconsistent dependency ordering (a step's `**Depends on:**` line names a later-numbered step) — the plan itself is malformed; autopilot does not attempt to reorder execution to satisfy it.

Separately, the Execution Mode question's "review the plan first" alternative (Phase 0 point 3) is never auto-selected under `--autopilot` — autopilot always resolves Mode via the `(Recommended)`-label rule below instead, so in practice this path is structurally unreachable under autopilot, the same way `go-deep`'s destructive "Run fresh onboarding" path becomes unreachable once its own Recommended option is always chosen. If some caller nonetheless forces a pause here under `--autopilot`, do not resolve it by treating silence as "review the plan first" — stop and require a human. The fresh-Inline-choice follow-up question (Phase 0 point 3) is similarly unreachable under `--autopilot` — Mode never freshly resolves to Inline there, so that specific follow-up never fires from a fresh choice. It is reachable, and resolved, only via the two sites the table below names separately: the Phase 0 legacy backfill (`inline-pause-mode-backfill`, for a plan already recording `Inline` from an earlier interactive run) and the Phase 2 per-step override (`inline-step-pause-override`, for a plan that also already recorded "Stop after each step").

**Not autopilot-governed at all:** the guardrail and the 5-attempt retry limit (Phase 1) are correctness halts built into this skill, not interactive points — they fire identically with or without `--autopilot`, and when either fires the run ends with Phase 3's fixed report exactly as documented; autopilot never retries further, guesses an answer, or suppresses the report. Likewise, `run-regression`'s own stop-and-ask (e.g. "Could not find a full-suite test command for `<repo>`...") is not resolved here either — Phase 4 treats it as a non-interactive FAIL-equivalent stop. When this skill itself runs with `--autopilot`, it forwards that flag to `run-regression` as well so the nested run is auditable. `execute` makes one `run-regression` call whose explicit argument — `full`, or the mixed token string Phase 4 builds — plus the forwarded `--autopilot` means no mode-selection prompt is reached.

**Decision log:** write `make-it-work/<TICKET>/execute-autopilot-log.jsonl` at repo root. Initialize it fresh (truncate/overwrite) the first time this run resolves any site — it describes this run only, never a prior one — then **append one line each time a further site is resolved later in the same run**: do not write it once near the start and leave it there unchanged. Subagent-Driven mode's per-step continuation (Phase 2) is no longer a distinct autopilot resolution — it behaves identically with or without `--autopilot` (see Phase 2's own Dispatch mechanics) — so it produces no log line of its own. Two newer sites can still produce lines over the course of a run: a resumed `Inline`-mode plan missing the `**Inline pause mode:**` line produces exactly one `inline-pause-mode-backfill` line (Phase 0, once); and an `Inline` + `Stop after each step` plan run under `--autopilot` produces one `inline-step-pause-override` line *per step* (Phase 2, since the override fires every time it actually overrides a recorded pause) — both described in the table below. If a run ends up resolving zero sites at all (e.g. Mode was already recorded with its `**Inline pause mode:**` line intact and reading 'Run straight through,' or Mode was freshly recorded as Subagent-Driven and every step completed normally), the file is still written, with zero lines. Field shape follows the shared schema in `docs/autopilot-log-schema.md` — this skill uses only `"askUserQuestion"` and `"checkpoint"` (it has no non-enumerable `open_text` sites), `multiSelect` is always `false` (every question this skill asks is single-select), so `chosen` is only ever a label or `null` — never an array or free text. Every line also still includes `rationale` (one sentence), per the shared schema's core fields. `phase` examples: `"Phase 0"`, `"Phase 2"`. `site` examples: `"mode-choice"`, `"inline-pause-mode-backfill"`, `"inline-step-pause-override"`.

When Bash is permitted, use the shared writer in `docs/autopilot-log-schema.md` with `--ticket "<TICKET>"` for this log: `write` at the first resolved site, `append` for later sites, or `init` if no site resolves. Invoke each writer command in its own Bash tool call, separately from any call to the plan-status script. If Bash is unavailable, use Write/Edit for the same log contract. Do not invoke the Bash writer after a Write/Edit denial or try another path to bypass a denied log write; report the denial while continuing the otherwise valid execution workflow.

A hard-stop site that actually fires is still logged, per the shared schema's `chosen: null` convention — this is distinct from a site that's merely moot this run: a site skipped because Mode was already recorded, or a step/phase never reached because an earlier stop condition halted the plan before reaching it, is not logged at all.

**Resolution table** (one row per interactive site, in the order they appear):

| Phase | Site | `kind` | Autopilot resolution |
|---|---|---|---|
| Phase 0 | ambiguous repo/workspace selection (unrelated clones, no unifying doc) | `checkpoint` | Unconditional stop, unaffected by autopilot — see Hard-stop exception above. |
| Phase 0 | "Could not identify the project root" | `checkpoint` | Unconditional stop, unaffected by autopilot. |
| Phase 0 | underivable `<TICKET>` key / plan path | `checkpoint` | Unconditional stop, unaffected by autopilot. |
| Phase 0 | "No plan found at `make-it-work/<TICKET>/<TICKET>-plan.md`..." | `checkpoint` | Unconditional stop, unaffected by autopilot. |
| Phase 0 | Execution Mode choice (`AskUserQuestion`, `multiSelect: false`, 2 options: Subagent-Driven / Inline) | `askUserQuestion` | Choose the option labeled `(Recommended)` — today "Subagent-Driven". The "review the plan first" free-text alternative is never auto-selected (hard-stop exception above) — it is not one of the 2 enumerated options to begin with. Write the plan file's `## Execution Status → Mode` line exactly as the chosen branch already specifies. |
| Phase 0 | Mode already recorded from a prior run | — | Not a decision site this run — proceed under the recorded mode without asking, and log nothing for it. **Exception:** when the recorded mode is Inline and its `**Inline pause mode:**` line is missing, this is not this row's case at all — see the `inline-pause-mode-backfill` row immediately below instead. |
| Phase 0 | Mode already recorded as Inline, but `**Inline pause mode:**` line is missing (site slug: `inline-pause-mode-backfill`) | `askUserQuestion` | Choose the option labeled `(Recommended)` — "Run straight through". Write the `**Inline pause mode:**` line with that value, and log it. This site *is* reachable under `--autopilot`, unlike a fresh Inline choice (Mode never freshly resolves to Inline under autopilot) — a plan can already carry `Mode: Inline` from an earlier interactive run before being resumed under `--autopilot` later. |
| Phase 2 | a step's `**Depends on:**` line names a later-numbered step | `checkpoint` | Unconditional stop, unaffected by autopilot — see Hard-stop exception above. The plan's dependency ordering is inconsistent; name the two step numbers involved rather than guessing at a fix. |
| Phase 2 (Inline mode, "Stop after each step" recorded) | the per-step pause that mode would otherwise take (site slug: `inline-step-pause-override`) | `checkpoint` | Auto-confirm: relay the step's outcome to the user as chat text, append one `inline-step-pause-override` line to the decision log for this step, then continue to the next step's implementation within that same response (or proceed to Phase 3/4 if this was the last step, or a stop condition fired), without ending the turn to wait for a reply — identical reasoning to Subagent-Driven's own unconditional non-pause. This fires on every step of such a run, not once; a plan recording "Run straight through" never reaches this row at all, since there is no pause to override. |

Subagent-Driven mode's per-step continuation is no longer listed above because it is no longer an autopilot-specific resolution — Phase 2's own Dispatch mechanics now relay-and-continue automatically under interactive use too, identically with or without `--autopilot`. Nothing is logged for it.

At the end of an autopilot run that reaches a terminal report (Phase 3's report, Phase 4's FAIL stop, or Phase 5's success report), print a short human-readable summary of every auto-resolved decision and the log file's path, so someone can audit the run afterward.

## Phase 0 — Locate the plan and resolve execution context

1. **Repo/workspace detection** — reuse `plan-the-work`'s Step 1a logic verbatim to decide whether this is a **single repo** or a **coordinated multi-repo workspace**, since it determines which repo's `Affected Code` table (and, later, where each repo's test commands come from — its `.claude/skills/test-strategy/SKILL.md` when present) this run applies to. The distinction is not "does the parent hold other repos" — a bare folder of unrelated clones is not a workspace. It is "are these repos documented as one system": a **workspace-root orientation file** (a top-level `CLAUDE.md` / service map describing the sibling repos and how they call each other) is the signal that turns a folder of repos into a workspace.
   - **`.git` exists here.** This repo is a project root. Then:
     - If the **parent** holds a workspace-root orientation file that describes this repo as one service among siblings → you are inside one service of a multi-repo workspace; the **workspace root** is the parent (`..`).
     - Otherwise → **single-repo project**, root is here — even if the parent happens to contain other, unrelated repos.
   - **No `.git` here, but subdirectories have their own `.git`.** If a workspace-root orientation file ties them together → multi-repo workspace, root is here. If they are just unrelated clones with no unifying doc → ask the user which repo (or workspace) to execute against, rather than guessing (autopilot: see Autopilot Mode — this is an unconditional stop).
   - **None of these resolve** → tell the user: "Could not identify the project root. Please launch from the repo root, a service subdirectory, or the workspace root." and stop (autopilot: see Autopilot Mode — this is an unconditional stop).

   All paths below are relative to the root identified here. In a single-repo project, "each affected repo" simply means the one repo. When unsure between single and multi, prefer single-repo.

2. **Locate the plan** — resolve the plan file from the invocation argument, adapting `plan-the-work`'s Step 1b spec-resolution logic to `-plan.md` files instead of `-spec.md` files:
   - **If the argument is an explicit path to a file**, use it directly and skip the rest of this resolution.
   - **Otherwise, determine the `<TICKET>` key:**
     - If the argument looks like a ticket key, use it.
     - If the argument is empty, derive the key from `git branch --show-current` in the current (or most recently modified) repo, e.g. `feature/PROJ-123-add-x` → `PROJ-123`.
     - If no argument was given and no key can be derived from the branch (e.g. on `main` or a branch that doesn't encode a key), do not proceed with an undefined `<TICKET>`: ask the user for the ticket key or an explicit plan path, and stop until they answer (autopilot: see Autopilot Mode — this is an unconditional stop).
   - Once a `<TICKET>` is known, resolve `make-it-work/<TICKET>/<TICKET>-plan.md`. If it does not exist, tell the user: "No plan found at `make-it-work/<TICKET>/<TICKET>-plan.md`. Run `/make-it-work:plan-the-work` first." and stop (autopilot: see Autopilot Mode — this is an unconditional stop).
   - Read the resolved plan file in full before proceeding. If it has a concrete `## Verification Policy` table, read `<base>/references/verification-policy.md` and validate it before making changes. Its explicit gate/evidence rules replace the legacy gate selection below; retry, guardrail, ordering and Progress rules still apply.

3. **Resolve Execution Status → Mode** — read the plan file's `## Execution Status → Mode` line.
   - **If it reads "Not yet chosen"**, ask the user to choose, before doing anything else — even if you were only handed this file with no memory of it being created — using the same two options `plan-the-work`'s own Step 6 offers. Call `AskUserQuestion` with `multiSelect: false` and exactly these two options (autopilot: see Autopilot Mode):

     1. `{ label: "Subagent-Driven (Recommended)", description: "Dispatch a fresh subagent per step (via the Agent tool), reviewed between steps. Best for complex multi-repo plans; keeps each step's context clean." }`
     2. `{ label: "Inline Execution", description: "Execute steps in this session with a checkpoint after each step's Verify." }`

     The question text itself may also invite reviewing the plan first ("Which approach? (or: review the plan first, then decide)") — this is a free-text alternative reply the user can give instead of picking an option, not a third enumerated option in the `AskUserQuestion` call.

     - If the user picks **Subagent-Driven**, run the `set-mode --mode subagent-driven` command below; it replaces the "Not yet chosen" line and its two bullet options with `**Mode:** Subagent-Driven — dispatch a fresh subagent per step (via the Agent tool), reviewed between steps.` Then proceed to point 4.
     - If the user picks **Inline**, run `set-mode --mode inline` below; it replaces that same block with `**Mode:** Inline — execute steps in this session, checkpointed after each step's Verify.` Then ask one follow-up `AskUserQuestion` (`multiSelect: false`): *'Inline mode: stop after each step for review, or run straight through?'*, with exactly these two options: `{ label: "Run straight through (Recommended)", description: "No pause between steps — the same behavior Inline already has today." }` and `{ label: "Stop after each step", description: "Relay each step's outcome and wait for your go-ahead before starting the next one." }`. Run the matching `set-pause` command below; it inserts the chosen pause line immediately after `**Mode:**`.
     - If the user asks to review the plan first, stop here and wait — write nothing back until they come back with one of the two choices above (autopilot: see Autopilot Mode — never auto-selected).
   - **If a mode is already recorded** (the line already reads `Subagent-Driven` or `Inline` rather than "Not yet chosen" — set by a prior `plan-the-work` or `execute` run), proceed under that mode without asking again (autopilot: nothing to resolve or log here when Mode is Subagent-Driven, or when Mode is Inline with its pause-mode line already present — see the one exception immediately below, and Autopilot Mode). When the recorded mode is Inline, also check for an existing `**Inline pause mode:**` line immediately after it. If present, proceed under that stored choice without asking again — same treatment as Mode itself. **If absent** (a plan recorded `Mode: Inline` before this line existed): this is a newly-added decision point being resolved for the first time on an existing plan, not a fresh Inline choice — ask the same follow-up question as above before proceeding to point 4 (autopilot: see Autopilot Mode — this specific site, named `inline-pause-mode-backfill`, auto-resolves to the Recommended default rather than stopping, since it is reachable under `--autopilot` whenever a plan already recorded `Inline` from an earlier **interactive** run).

4. **Resolve Progress / resume point** — parse the plan file's `## Execution Status → Progress` line ("Step N of M complete").
   - If `N` equals `M`, every implementation/test step is already done — skip directly to Phase 4 (the completion gate); only the gate remains, or needs re-running.
   - Otherwise, resume from step `N+1` once Phase 2 begins working through the plan's steps.

**Execution Status bookkeeping is scripted.** Resolve `<base>` to this skill's directory. Use `node "<base>/scripts/plan-status.mjs" inspect --plan "<plan path>"` to read Mode, Inline pause mode, completed steps, and total steps as JSON. For every later write to this section, invoke the same script rather than editing Markdown by hand:

| When | Command after `node "<base>/scripts/plan-status.mjs"` |
| --- | --- |
| Mode choice | `set-mode --plan "<plan path>" --mode subagent-driven` or `--mode inline` |
| Inline pause choice or legacy backfill | `set-pause --plan "<plan path>" --pause straight-through` or `--pause after-each-step` |
| One step's Verify passed | `complete-step --plan "<plan path>" --step <N>` |
| Every member of a real concurrent batch passed | `complete-batch --plan "<plan path>" --through <highest step number>` |
| A mistaken Progress claim must be rolled back | `correct-progress --plan "<plan path>" --completed <last verified step>` |

The script changes only `## Execution Status`, writes atomically, and rejects skipped steps, conflicting choices, malformed status, or an invalid correction. Its command does **not** decide whether Verify passed, whether a batch was eligible, or whether a rollback is justified; apply this skill's rules first. A nonzero exit leaves the plan unchanged: investigate the discrepancy before dispatching the next step. When invoked by `implement` with a dashboard state path, append `--dashboard-state "<state path>"` to `complete-step` or `complete-batch`; the command then renders the dashboard as part of that successful Progress update. If the option is omitted, the command also finds and refreshes a matching active Execute dashboard beside the plan. Pass the same script path, command, and dashboard state path to a single-step subagent when it owns the Progress write; batch subagents still never write Progress themselves.

Invoke each status-script command in its own Bash tool call. Do not join it with an autopilot decision-log write: a denied log write must not prevent the status update from running. If the log write is denied, handle that separately; it must not suppress a valid plan-status update.

5. **Re-derive the recommended executor tier** — `plan-the-work`'s own Step 6 computes a "Recommended executor tier" (low/standard/high) but only prints it in chat; it is not persisted as a field in the plan file. Re-derive it yourself, directly against the plan file Phase 0 point 2 resolved, using the exact same criteria `plan-the-work`'s Step 6 documents:
   - **low** — mechanical, few files, additive, no data-migration / state-transition / security risk, steps fully specified.
   - **standard** — moderate: a few domains or repos, some risk, mostly-specified steps.
   - **high** — multiple repos with logic changes, security / state transitions / data migrations / cross-service flows, or steps that still need judgment during execution.

   Read this off the plan file's own sections only — no new investigation of the target codebase: the **Affected Code** table (repo/file count), the **Risks** table (severity surface — the Overall risk values), and the **Steps** (count, and whether they read as additive or invasive). Under **Subagent-Driven** mode, pass a model matching this tier as the `model` argument on every subsequent `Agent` dispatch in Phase 2 (Work through the plan's steps), so every step runs at the recommended level. Under **Inline** mode, the current session's model can't be changed programmatically — note the tier for the user, but take no further action here.

## Phase 1 — Guardrail and retry-limit policy

Every step in Phase 2 applies the two stop conditions defined here, plus the one standing rule at the end of this section. Do not proceed past either stop condition on your own judgment — both hand control to Phase 3, which owns how the halt is reported.

### Retry limit

A step's own named test(s) — the `**Tests:**` field's command(s), each run from its own repo root, or (when that repo has no test-strategy location and no configured framework) the corresponding row(s) in the plan's shared `## Test Plan` table — are that step's sole success criterion. A Tests line recorded as `not runnable locally` is never run, retried, or counted as an attempt; it is reported in the step's checkpoint instead. When a fix attempt is made and the test(s) are re-run:

- Count every attempt to change the code in pursuit of making that step's failing test(s) pass as one "attempt," starting from 1.
- If the test(s) still fail after **5** such attempts, stop working on that step immediately. Do not make a 6th attempt, and do not fall back to a "best effort, moving on anyway" outcome — a step whose test still fails is not done, regardless of how close the 5th attempt looked.
- Reaching the retry limit is a distinct stop condition from the guardrail below: it fires when the code itself simply isn't passing the test after genuine fix attempts, with no indication the test or the plan's intent is in question. If, during those attempts, it becomes clear the disagreement is actually about what the test (or the code) *should* be doing rather than a plain bug, stop counting retries and apply the guardrail below instead — the two conditions are not both charged against the same step for the same discrepancy.

### Guardrail (test bug vs. product-behavior question)

This check applies specifically when fixing a step's failing test appears to require changing the test itself (its assertions, fixtures, or setup) rather than only the implementation code. Work through it in this order, every time:

1. **First, check for a genuine test bug — but never on pattern-matching alone.** A test assertion that merely *looks* mechanically wrong (an apparently off-by-one or inverted value, a suspicious-looking fixture) is not yet confirmed as a genuine test bug — it only becomes one once it's actually checked against what the plan's own `## Goal`/`## Requirement Summary` document as the intended behavior for this case (the same source point 2 below consults). Before concluding "this is just a mechanical bug in the test" and fixing it, briefly confirm the plan's documented intent doesn't actually match what the test currently asserts — if it does match (the test was "wrong-looking" but is in fact what's documented), this is not a mechanical bug at all; skip straight to point 2's classification instead of fixing it here. Only once that check comes back clean — the documented intent doesn't call for what the test currently asserts, and the test's flaw is narrow and mechanical (a bad assertion, e.g. it asserts the wrong value, checks the wrong field, or has an off-by-one/inverted condition; or a wrong fixture, e.g. stale test data, a setup step that doesn't match what the step under test actually needs) — fix the test, and never in a way that weakens or deletes what the test was actually trying to verify (e.g. do not loosen an assertion, delete a check, or broaden a match just to make it pass). Then continue implementing the step normally: re-run the corrected test and proceed as usual (including still being subject to the retry limit above if further fix attempts are needed).
2. **If it is not a mechanical test bug**, apply this operationalized check to classify the discrepancy — do not skip straight to a guess:
   - Locate what the plan's own `## Goal` and `## Requirement Summary` sections say about the behavior in question. If those sections are silent or ambiguous about this specific behavior, also read the spec's Acceptance Criteria they trace to (the spec file's path is given in the plan's own header, e.g. `> **Spec:** ...`) before drawing any conclusion — do not stop at "the plan doesn't say" without checking the spec it was built from.
   - Compare three things: (i) what the failing test expects, (ii) what the code currently does, and (iii) what the Goal/Requirement Summary (and, where consulted, the spec's Acceptance Criteria) documents as the intended behavior.
   - **If the code's behavior contradicts that documented intent, while the test's expectation matches it** — this is an ordinary bug, not a product-behavior question: the code is the side that's wrong. Fix the code; leave the test's expectation as it is. Then continue implementing the step as normal.
   - **If the test's own expectation contradicts that documented intent** — e.g. the test asserts something the Goal/Requirement Summary (or the spec's AC) explicitly says should not happen, or asserts the opposite of what an AC scenario describes — this is a real product-behavior question, not a test bug. Do not silently rewrite the test to match the code, and do not silently change the code to match the test's expectation either. Stop and hand off to Phase 3.
   - **If neither the test nor the code looks wrong relative to what's documented (having checked both the plan and, where the plan was silent, the spec's AC), yet the two still disagree with each other** — this, too, is a real product-behavior question. Stop and hand off to Phase 3.
   - **Whenever this comparison is genuinely uncertain** — the documented intent (plan and, where consulted, spec) is ambiguous, silent on the specific case, or could reasonably be read either way — resolve the uncertainty toward treating it as a real product-behavior question, never toward picking a side and continuing. It is always acceptable to hand off to Phase 3 when unsure; it is never acceptable to guess and keep going.

In short: the classification hinges entirely on matching each side (test, code) against the plan's (and, when needed, the spec's) own documented intent, not on which side is more convenient to change, which side was written first, or which side is easier to fix.

### Halt scope

Both stop conditions above — the retry limit and the guardrail — halt the **entire remaining plan**, not only the current step or that step's dependents. Once either condition fires:

- Do not attempt any later step in the plan, including one that has no dependency at all on the flagged/stalled step and could technically run on its own.
- Do not continue working step-by-step on the theory that the flagged step can be revisited later — the whole plan pauses in place, and only resumes via the handling Phase 3 defines (a fresh decision from the user).
- This applies identically under both execution modes: under Subagent-Driven mode, do not dispatch the next step's subagent once a stop condition has fired inside the current step's subagent; under Inline mode, do not proceed to the next step's implementation in this same session.

### Never git-commit

`execute` never runs `git commit` on the user's behalf, at any point in this process:

- Not after any individual step's tests turn green.
- Not after the guardrail or retry-limit stop conditions fire.
- Not at the end of the plan, and not even after the completion gate (Phase 4) passes.

All implemented code, fixed tests, and any other changes made while working through the plan are left uncommitted in the working tree throughout — for the user to review and commit themselves, on their own schedule and in whatever grouping they choose. This rule governs every step in Phase 2 and every phase of this skill; nothing later in this skill overrides it.

## Phase 2 — Work through the plan's steps

This phase does the actual implementation work. It drives the plan forward from the resume point Phase 0 point 4 established, through the plan's own **last** step, **inclusive**.

### Scope: resume point through the last step, inclusive — no exceptions

The plan's `## Steps` section numbers its steps 1 through `M`, where `M` is the same `M` that appears in `## Execution Status → Progress` ("Step N of M complete"). This phase's job is not finished, and control does not pass to **Phase 4**, until step `M` itself — the highest-numbered step in the plan, whatever its own heading calls it — has been implemented, had its tests confirmed passing, and had Progress updated to read "Step M of M complete." The only way to leave this phase before that point is the early exit described in the per-step procedure below: a Phase 1 stop condition (guardrail or retry limit) firing on some step, which hands control to Phase 3 instead — never a routine step completion, and never simply reaching a step that looks like a wrap-up.

This holds regardless of what kind of step `M` is. A plan with manual verification ends with "Verify manual scenarios" (older plans may call it "Write tests"). This is a numbered execution step: perform its Test Plan walkthroughs against actual behavior, run its Verify checks, record observed evidence, and then update Progress. It cannot be skipped or treated as a wrap-up. Do not claim an automated test suite passed when the step verifies manual scenarios.

Concretely: if Phase 0 point 4 determined the resume point is step `N+1`, this phase's loop begins at step `N+1` and continues, step by step, up to and including step `M`. If `N+1` already equals `M` (only the last step remains), this phase still runs — it performs step `M` itself, the same as any other step; it is never skipped just because it is also the final step. The loop only ends, successfully, once step `M`'s own Progress update ("Step M of M complete") has been written to the plan file. Ending the loop earlier — for any reason other than a Phase 1 stop condition firing — is not a valid outcome of this phase. Once Progress reads "Step M of M complete," this phase's work is done — proceed to Phase 4 (the completion gate).

### Working order: respecting each step's own dependency markers

Work through the steps in the numeric order the plan lists them. Progress is a single linear counter ("Step N of M complete"), so this loop never actually reorders steps at runtime — reordering would let a resumed run silently skip whatever was jumped ahead of. Each step's own `**Depends on:**` and `**Can run in parallel with:**` markers are honored as follows:

- Before starting any step, confirm every step named in its `**Depends on:**` line has a number less than or equal to `N` (i.e. it is already recorded as complete in Progress, either from an earlier step in this same run or from an earlier resumed run). In a well-formed plan this is always true by the time numeric order reaches that step, because a step cannot depend on a later-numbered step. If a step's `**Depends on:**` line ever names a step whose number is greater than the current step's own number, the plan itself is malformed — do not attempt to reorder execution to satisfy it; stop and tell the user the plan's dependency ordering is inconsistent (naming the two step numbers involved) rather than guessing at a fix.
- A step's `**Can run in parallel with:**` line names another step that has no ordering constraint against it: neither depends on the other, so either could validly come first. By default this still means only that the two steps' relative order is unconstrained, not that they run concurrently — take them in the plan's listed numeric order, like any other adjacent pair. **Exception — true concurrent batching, Subagent-Driven mode only, when this run was given a `dispatch order` input of `parallel`** (see `## When run by implement`'s Inputs — this never applies to a standalone run, which has no such input, or to the original plan's own steps, which always dispatch one at a time regardless): before dispatching the next not-yet-done step, compute the largest batch of contiguous, not-yet-done steps starting at the current resume point that satisfies **all four** of: (1) every step in the batch is the next contiguous not-yet-done step in numeric order (never skip ahead over an undone lower-numbered step); (2) every pair within the batch is mutually marked `**Can run in parallel with:**` each other; (3) every step's own `**Depends on:**` line is already satisfied (at or below the current Progress watermark); (4) every step's own path set — the union of its `**Files:**` line and, when present, its `**Tests:**` field's own file path(s) — is disjoint from every other batched step's own same union. This file-and-test-disjointness check is independent of, and in addition to, the plan's own marker, since that marker has only ever meant "order-unconstrained" and was never authored with true concurrency in mind; a step whose `**Files:**` line reads `none` contributes only its `**Tests:**` paths (if any) to this union, and a step with neither contributes nothing — trivially disjoint from every other step, same as it is harmless today. Any not-yet-done step that fails any of these four is dispatched alone (a batch of one), exactly as every step is dispatched today.

### Per-step procedure

For every step from the resume point through step `M`, inclusive, perform these four actions in order:

1. **Implement.** Make the code change(s) the step's own **What to do** field describes. When planned tests change, follow `<base>/../../docs/test-map-contract.md` to update their identities, evidence and relationships in the product repo's map. Save only reviewed metadata updates named in the plan, preserving user decisions; mapping work never adds/changes source/test annotations. Before the scoped completion gate inspect/reassess affected map inputs and retain unresolved portions. Touch only the files listed on that step's own **Files:** line — do not edit a file that isn't listed there, even if it seems related, and do not fold in work that belongs to a different, later step.
2. **Verify.** Run the step's **Verify** check.
   - If the step has its own `**Tests:**` field (meaning the target repo has a configured test framework and `plan-the-work`'s per-step test-writing sub-phase recorded a scoped command for this step), run the exact scoped test command that field records, and confirm the specific named test(s) it identifies now pass — not merely that some tests somewhere pass. This field lists one line per in-scope repo, test-scope repos included (`<repo>: <file path(s)> [<layer>], <command>, <state>`) — run each line's command from its own repo root and confirm each one's named test(s) pass. Find that root the same way `run-regression`'s "Finding a token's repo" does: cwd's git toplevel when its basename matches `<repo>`, otherwise a same-named subdirectory of cwd, otherwise one of the workspace root Phase 0 point 1 detected. A line with no `<repo>:` prefix runs from Phase 0's root. A line whose state is `regression not runnable locally — <reason>` or `progression written — not runnable locally (<reason>)` is not run or retried: list it in the step's report/checkpoint as `not run locally — <reason>`; the step still needs its runnable lines and Verify to pass. A repo omitted from this field has no test-strategy location and no configured framework and is covered by the no-`**Tests:**` case below instead, for that repo only.
   - If the step has no `**Tests:**` field (meaning that repo has no configured test framework), it has no scoped command to run. In addition to running the step's own **Verify** line as written, locate the row(s) in the plan's shared `## Test Plan` table that correspond to this step (by scenario description or by the file/command column referencing this step's own changes) and manually confirm each identified scenario behaves as that row describes. A step with no `**Tests:**` field is not exempt from verification — its corresponding Test Plan row(s) are its test, and they must be walked through and confirmed exactly as the row describes before the step counts as passing.
3. **On failure, apply Phase 1's policy before re-attempting.** If the Verify check (the scoped test command, or the manual Test Plan walkthrough) fails, apply the retry-limit and guardrail policy defined in Phase 1 — do not simply try again ad hoc. Specifically: check whether fixing the failure requires changing the test/scenario itself (triggering the guardrail's test-bug-vs-product-behavior check) or only the implementation code (counting as one retry-limit attempt); keep re-attempting only within whichever of those two policies applies, exactly as Phase 1 defines. The instant either policy's stop condition fires — the guardrail identifies a real product-behavior question, or the 5th attempt still fails — stop working on this step immediately and proceed to Phase 3. Do not attempt any later step (including one satisfying "Can run in parallel with" this one) once a stop condition has fired; Phase 1's "halt scope" rule governs here without exception.
4. **Update Progress immediately once the step passes.** As soon as this step's Verify check is confirmed passing (per point 2), update `## Execution Status → Progress` in the plan file to read "Step N of M complete" (substituting this step's own number for `N`) before doing anything else — in particular, before starting the next step's implementation. Do not batch Progress updates, and do not defer this update until later steps also finish; each step's own completion is written to the plan file the moment that step is done, so a resumed run always has an accurate resume point even if the session ends unexpectedly right after this step. **Exception — a step dispatched as part of a real batch** (more than one step, per Working order's batching exception above): this step does **not** write Progress itself at all. The orchestrating session owns writing Progress once for the whole batch, only after every batched sibling has reported, per the batch-dispatch bullet in Dispatch mechanics below — never derived from, or overwritten by, any individual batched subagent's own write. A step dispatched alone (a batch of one — the ordinary case, and every case before this item existed) is unaffected by this exception and still writes its own Progress exactly as this point already describes.

**Implement dashboard checkpoint.** When this run received an `implement` dashboard state path (see **When run by implement**), append `--dashboard-state "<dashboard state path>"` to the `plan-status.mjs complete-step` command that a single-step subagent runs, or to the orchestrator's `complete-batch` command for a real batch. The status command writes Progress and renders the dashboard in one required checkpoint; do not run a separate best-effort render afterward. If that command fails — including a renderer failure — do not relay completion, dispatch another step, or proceed to the completion gate; return `EXECUTE_STOPPED` with the exact error so `implement` can checkpoint the stop. A standalone `execute` run, and an older `implement` run which did not supply a dashboard state path, has no dashboard to refresh and omits this option.

For an `implement` run carrying `verification_version: 1`, or any plan with a concrete verification policy, read `../implement/references/verification.md` before dispatching the first step. Its one-step evidence write and validator call sit between passing Verify and the Progress update in point 4; "before doing anything else" means before the next implementation step, not before recording required evidence. On resume, validate that each already-complete step has an entry before dispatch. Pass the artifact root, ledger path, and contract to a single-step subagent so it records and validates its own entry before Progress. For a true concurrent batch, subagents report the actual checks but do not write the shared ledger; after all pass, the orchestrating session records and validates all batch entries before its one Progress update. On batch failure, leave Progress and the ledger at their pre-batch values. Legacy runs without either opt-in keep their original reports.

### Dispatch mechanics, by mode

How points 1–4 above are actually carried out differs by the `Mode` Phase 0 point 3 resolved:

**Subagent-Driven mode.** For each numbered step, dispatch a single fresh subagent via the Agent tool to perform that one step. This includes a trailing manual verification or "Write tests" step with `**Files:** none`: its Test Plan walkthrough and Verify still belong to its own fresh subagent. The orchestrating session must not perform that step itself or mark it complete after inspecting an earlier subagent's work; only Inline mode executes a step in this session. Before Phase 4, confirm every step newly completed in this run has its own Agent dispatch (or belongs to an eligible concurrent batch of Agent dispatches). Then follow these dispatch rules:
- Pass the executor tier Phase 0 point 5 computed for this plan as the subagent dispatch's `model` argument, so every step's subagent runs at the plan's recommended tier.
- Give the subagent, as its prompt, everything it needs to complete points 1–4 above without needing to ask this session anything mid-step:
  - this step's own fields verbatim — **What to do**, **Files:**, **Verify**, and, when present, the step's own **Tests:** field (the exact test command(s), with each line's resolved repo root); when the step has no **Tests:** field, the relevant row(s) of the plan's shared `## Test Plan` table instead;
  - Phase 1's policy **in full**, including the retry limit, the guardrail's operationalized check, the halt-scope rule, and the never-git-commit rule — not a paraphrase or a subset of it, since a subagent working alone is exactly where a stray `git commit` or an uncounted retry would otherwise happen;
  - Phase 3's two fixed report shapes (Case 1 — Guardrail fired; Case 2 — Retry limit reached), verbatim, so the subagent already knows exactly what shape to return, with every field filled in from what it actually observed, the instant either of Phase 1's stop conditions fires inside it — rather than reporting back in free-form prose the orchestrating session would then have to reconstruct into shape after the fact;
  - the plan file's own path, this step's number `N`, and the total step count `M`, together with an explicit instruction that the subagent itself is responsible for updating `## Execution Status → Progress` in that plan file to "Step N of M complete" the moment its Verify (and, where applicable, Test Plan row(s)) pass — per point 4 above — before it returns its report — **except when this step is being dispatched as part of a real batch** (see the batch-dispatch bullet below): in that case, the prompt instead explicitly tells the subagent **not** to write `## Execution Status → Progress` itself under any circumstance. Everything else about the report is unchanged — the subagent still returns its full account of what it implemented on a pass, or the full Case 1/Case 2 shape (per the bullet below) the instant a Phase 1 stop condition fires; "not under any circumstance" governs only the Progress claim, never the rest of the report's own content. The orchestrating session owns the Progress write for the whole batch.
- The dispatched subagent is responsible for performing points 1–4 above on its own: implementing the change, running Verify, retrying internally (up to Phase 1's 5-attempt limit) on an ordinary failure, applying the guardrail check itself if a fix looks like it needs to change the test, writing the Progress update itself once it passes, and reporting back once the step either passes or hits a Phase 1 stop condition — **except when dispatched as part of a real batch** (see the batch-dispatch bullet below), where it does everything in this list except the Progress write, which it never performs under any circumstance; the orchestrating session owns that write for the whole batch instead. Do not re-dispatch a new subagent mid-step for a retry — the same subagent iterates internally.
- Once the subagent returns its report, review it before doing anything else: read what it implemented, then re-read the plan file's own `## Execution Status → Progress` line directly (not merely the subagent's prose claim) to confirm it now reads "Step N of M complete" for this step, or that a Phase 1 stop condition fired per the report. The subagent is the one that writes Progress; only if the file's Progress line was not actually updated despite the subagent reporting success does this session write it directly, as a correction, before proceeding. **Exception for a batch step** (see the batch-dispatch bullet below): this per-step correction does not apply at all. A batched subagent never writes Progress, by design (per its own prompt instruction above), so the file correctly shows no update for it the whole time its batch is in flight — this is expected, not something to correct, and Progress for that step is owned entirely by the batch-dispatch bullet's own single, whole-batch write (or, on a partial failure, its own deliberate no-write). Once Progress is confirmed, either continue to the next step (if this step passed) or proceed to Phase 3 (if a stop condition fired). This review happens for every step, interactive or `--autopilot` alike — but it is no longer a stopping point: once the report is reviewed, relayed to the user as chat text, and Progress is confirmed, dispatch the next step's subagent **within that same response**, without ending the turn to wait for a reply (the same mechanics the Autopilot Mode section previously described only for `--autopilot` now apply unconditionally). Never dispatch two steps' subagents with no relayed report in between — the review and relay still happen for every step — but never end the turn waiting for the user's go-ahead before dispatching the next one either — **unless dispatching a real batch per Working order's exception** (more than one step, genuinely eligible to run concurrently): there, every batch member's subagent is intentionally dispatched together in one response, with their reports relayed together once every one of them has arrived, per the batch-dispatch bullet immediately below. This rule still means exactly what it says for any two steps that are *not* part of the same eligible batch.
- **When dispatching a real batch** (Working order's exception above determined more than one not-yet-done step is eligible to batch together): construct each batched step's own self-contained prompt exactly as the bullets above describe (including the no-self-written-Progress instruction), one per step, and dispatch all of them as separate `Agent` tool calls within the same response — never one at a time with an intervening wait. Then wait for **every** subagent in the batch to return its own report before acting on any of them; `Agent` dispatch in this harness is asynchronous, so a report arriving does not mean the batch is done — do not relay, write Progress, or dispatch anything further until every batched subagent has reported. Once all have reported: **if every one passed**, review and relay each report, in the batch's own ascending step-number order (for a stable, readable narrative), then the orchestrating session itself writes `## Execution Status → Progress` to the batch's own highest step number, exactly once — never read back or trust any individual subagent's own claim about Progress, since none of them wrote it — and continue to the next not-yet-done step or batch within that same response. **If any one subagent's report shows a Phase 1 stop condition fired:** let every other already-dispatched sibling in this same batch finish and report in before doing anything else (they cannot be recalled mid-flight); **before stopping, re-read `## Execution Status → Progress` directly** — never trust any batched subagent's own prose claim — to confirm it still reads exactly its pre-batch value; a subagent is instructed never to write Progress inside a batch, but if one did so anyway despite that instruction, correct the file back to the batch's actual pre-batch value now, the same self-healing role the single-step "only if the file's Progress line was not actually updated... does this session write it directly, as a correction" rule already plays outside a batch. Do **not** write Progress to any step's own number for this batch, regardless of how many siblings individually passed — Progress must read exactly its pre-batch value, corrected if necessary, before this run stops; then stop the entire run — do not dispatch any further step or batch, in this round or any other — and proceed to Phase 3, whose report must list every sibling's own individual outcome (which passed, which hit a stop condition, and how), per Phase 3's own extended report shape below, not only the one that stopped. A batch of exactly one step (the common case when dispatch order is `sequential`, or when a step failed the eligibility check above) is handled by the existing per-step bullets, unchanged — this bullet only applies when the batch actually contains more than one step.

**Inline mode.** Perform points 1–4 above directly in this session, for each step in turn:
- Implement the step's change, run its Verify check, and apply Phase 1's policy on failure, all within this same session — no subagent dispatch.
- Phase 0 point 3 records Inline mode's Mode line as 'checkpointed after each step's Verify' — that phrase refers only to point 4's Progress write (the plan file gets an accurate, durable checkpoint after every step), not to a pause for user review on its own. Whether a routine step completion is *also* a stopping point now depends on the plan file's own `**Inline pause mode:**` line (set at Mode-selection time, Phase 0 point 3): **Run straight through** — proceed immediately and directly to the next step's implementation once Progress is updated, exactly as Inline has always behaved; a routine step completion is never a stopping point, and (together with Phase 3's two stop conditions) this remains the only way this session stops mid-plan. **Stop after each step** — once Progress is updated for a step, relay a short summary of what that step did to the user in chat, then end the turn and wait for the user's go-ahead before starting the next step's implementation; this intentional, per-step stop is distinct from, and in addition to, Phase 3's two stop conditions, and is not an early exit from this phase's 'no exceptions' scope rule above — it is simply where one step's own per-step procedure ends and the next one's begins. **Under `--autopilot`, this pause is always overridden** (autopilot: see Autopilot Mode — this per-step override is its own named site, `inline-step-pause-override`, distinct from the Phase 0 `inline-pause-mode-backfill` site): relay the step's outcome and continue within the same response, exactly like Subagent-Driven's own unconditional behavior, regardless of what `**Inline pause mode:**` records — an unattended run must never actually wait, no matter what an earlier interactive session recorded.

## Phase 3 — Guardrail / retry-limit stop handling

Phase 2 hands control here the instant either of Phase 1's two stop conditions fires while working a step — the guardrail identifying a real product-behavior question (Phase 1, "Guardrail"), or that step's test(s) still failing after the 5th fix attempt (Phase 1, "Retry limit"). Per Phase 1's "Halt scope," reaching this phase means the entire remaining plan pauses in place: no later step is attempted, including one with no dependency on the flagged/stalled step, and this step itself is not retried any further once this phase is reached. This phase does exactly one thing — assemble and deliver whichever of the two fixed reports below applies — and the run ends there. Both stop conditions get the same halt scope and the same reporting treatment, per Phase 1's Halt scope: there is no third, lesser halt behavior for either condition, and nothing here resumes automatically. The only way the plan continues is a fresh invocation of `execute`, after the user has reviewed the report and supplied whatever guidance resolves it (e.g. an edited plan step, an updated spec, or an explicit call on which side — test or code — was actually wrong).

### Precedence when both conditions could apply to the same step

Phase 1's "Retry limit" section already states this, and it governs here too: if, at any point during a step's retry attempts — including as early as the very first attempt, well before a 5th attempt is ever reached — the guardrail's test-bug-vs-product-behavior check identifies a real product-behavior question, stop counting retries immediately and apply the guardrail instead. In that situation this phase always uses **Case 1 — Guardrail fired** below, never Case 2, even though fewer than 5 attempts occurred. The two conditions are never both charged against the same step for the same discrepancy, and a step is never reported under both formats.

### Which side detects the stop condition and originates the report

Phase 2's dispatch mechanics differ by mode, and so does which side of the run actually notices the stop condition first and is responsible for producing the report:

- **Subagent-Driven mode.** The dispatched subagent working the stalled/flagged step is the one applying Phase 1's policy internally (Phase 2, "Dispatch mechanics, by mode"), so it is the subagent — not the orchestrating session — that first detects the stop condition and is the only party that actually knows the discrepancy details, the attempts tried, and the last failure observed. Phase 2 already requires that subagent's dispatch prompt to include Phase 1's policy in full; in addition to that, the dispatch prompt must also include this section's two fixed report shapes (Case 1 and Case 2 below) verbatim, so the subagent knows exactly what shape to return the moment either stop condition fires inside it, rather than reporting back in free-form prose that the orchestrating session would then have to reconstruct into shape after the fact. The subagent's final report back to the orchestrating session must already be filled in to one of these two shapes, with every field populated from what it actually observed while working the step. On receiving that report, the orchestrating session's job is to re-read the plan file's own `## Execution Status → Progress` line directly (never trusting the subagent's prose for this one field — the same rule Phase 2 already applies when reviewing any subagent report) to fill in the `Progress` field, then relay the rest of the subagent's report into the fixed shape verbatim — never omitting, paraphrasing away, or re-deriving a field the subagent already determined — and deliver it to the user as this phase's report. **Exception for a real batch:** when the stopped step was dispatched as part of a real batch (Phase 2's batch-dispatch bullet), the stopped subagent ran concurrently with its siblings and has no visibility into their outcomes, so whatever it wrote in `Batch siblings` is not trustworthy and is never relayed verbatim for that one field. Instead, once every batched sibling has reported (per the batch-dispatch bullet's own wait-for-all-reports rule), the orchestrating session itself fills in `Batch siblings` from what those other reports actually showed — each other step's own number and title, plus its own outcome — overriding whatever the stopped subagent's report said there. When more than one sibling stopped, the precedence rule below also governs which stopped sibling's own report supplies this phase's other fields. Every field besides `Progress` and `Batch siblings` is still relayed from the originating (stopped) subagent's own report, verbatim, exactly as before.
- **Inline mode.** This session is executing the step directly (no subagent), so it is the one that detects the stop condition itself, mid-step, while applying Phase 1's policy. It assembles the same fixed report shape directly from what it just did and observed while working the step, reading `## Execution Status → Progress` from the plan file for that one field the same as above, and delivers it to the user itself.

In both modes, the report that ultimately reaches the user has the identical shape and carries the identical required information — only which side originates it, and how the `Progress` field (and, for a real batch in Subagent-Driven mode, `Batch siblings`) is filled in, differs.

### Case 1 — Guardrail fired

Print, verbatim in shape, filling in every bracketed field:

```
Stop condition: Guardrail — test vs. product-behavior discrepancy
Plan: <resolved plan path>
Step: <N> — <step title, exactly as it appears in the plan's ## Steps section>
Test expectation: <exactly what the failing test asserts, or — for a step with no Tests: field — what the corresponding ## Test Plan row describes as the expected/scenario outcome>
Code behavior: <exactly what the code currently does for the same case>
Documented intent: <what the plan's ## Goal / ## Requirement Summary say about this specific behavior; when those sections were silent or ambiguous and the spec's Acceptance Criteria were consulted per Phase 1, what those AC say instead — name the spec file (from the plan's own header) in that case>
Discrepancy: <name exactly which one of Phase 1's guardrail-triggering outcomes applied — "the test's own expectation contradicts the documented intent"; "neither the test nor the code contradicts the documented intent, yet they still disagree with each other"; or "the documented intent is ambiguous/silent on this specific case, so the disagreement is being treated as a product-behavior question per Phase 1's uncertainty rule">
Attempts tried before the guardrail fired: <a short line per fix attempt tried before the discrepancy was recognized, naming what changed each time, or "None — the discrepancy was apparent without any code fix attempt" when the guardrail fired on inspection alone>
Files touched by this step so far: <the file(s) actually edited while working this step, from its own Files: line> — left exactly as they are, uncommitted, in the working tree
Batch siblings: <none — this step was dispatched alone | for each other step dispatched in the same batch: its own number and title, plus its own outcome — "passed, <files touched>" if it passed, or its own short stop-condition summary if it also stopped>
Progress: <the plan file's ## Execution Status → Progress line, read fresh, exactly as it reads> — unchanged; step <N> is not recorded as done
Status: The rest of the plan is on hold pending your decision. This run ends here — Phase 4 (the completion gate) is never reached, and no completion-gate report is printed for this run. Nothing resumes automatically: re-invoke /make-it-work:execute (with your guidance incorporated, e.g. an updated plan or spec resolving this discrepancy) to continue.
```

Phase 1's outcome where "the code's behavior contradicts documented intent while the test's expectation matches it" is, by Phase 1's own definition, an ordinary bug — Phase 1 has the step fix the code and continue normally rather than handing off here, so that outcome never produces a Case 1 report; it never reaches this phase at all.

### Case 2 — Retry limit reached

Print, verbatim in shape, filling in every bracketed field:

```
Stop condition: Retry limit reached
Plan: <resolved plan path>
Step: <N> — <step title, exactly as it appears in the plan's ## Steps section>
Attempts made: 5
Attempts tried: <a short line per attempt (1 through 5) naming what changed and what the resulting failure was, so the user can see the fix history, not just the final one>
Last failure observed: <the exact failure from the 5th attempt — the failing test's output/assertion, or the manual Test Plan scenario's observed mismatch, whichever applied to this step>
Files touched by this step so far: <the file(s) actually edited while working this step, from its own Files: line> — left exactly as they are, uncommitted, in the working tree
Batch siblings: <none — this step was dispatched alone | for each other step dispatched in the same batch: its own number and title, plus its own outcome — "passed, <files touched>" if it passed, or its own short stop-condition summary if it also stopped>
Progress: <the plan file's ## Execution Status → Progress line, read fresh, exactly as it reads> — unchanged; step <N> is not recorded as done
Status: The rest of the plan is on hold pending your guidance. This run ends here — Phase 4 (the completion gate) is never reached, and no completion-gate report is printed for this run. Nothing resumes automatically: re-invoke /make-it-work:execute (with your guidance incorporated, e.g. an updated plan or spec resolving this failure) to continue.
```

**Precedence when more than one sibling in the same batch stops.** If every stopped sibling in the batch hit the *same* kind of stop condition, use that Case's own shape and describe every stopped sibling in `Batch siblings`. If siblings stopped on *different* conditions within the same batch (one guardrail, one retry-limit), use Case 1's shape — a product-behavior question takes precedence for the user to resolve first — and fold the retry-limit sibling's own outcome into `Batch siblings` instead of omitting it. Either way, the report's own `Step:`/`Test expectation:`/etc. fields describe exactly one sibling (the one chosen by this precedence rule); every other stopped or passed sibling's own detail lives in `Batch siblings`, never silently dropped.

### Progress is read here, essentially never written

Both cases above read `## Execution Status → Progress` to fill in one field — they do not write it, with one narrow exception. Per Phase 2 point 4, Progress is updated only when a step's own Verify passes; a step that hit either stop condition, by definition, never passed Verify, so in the ordinary case Phase 2 never wrote a Progress update for it, and this phase leaves it exactly as it already reads. The one exception mirrors Phase 2's own correction rule in the opposite direction: when this phase re-reads Progress fresh (per "Which side detects the stop condition" above) and finds the flagged/stalled step's own number already recorded as complete — e.g. a subagent mistakenly wrote it despite the stop condition firing — correct the file back to the prior value (the last step that actually passed Verify) before filling in the `Progress` field and delivering the report, rather than reporting a Progress value known to be wrong. Outside that narrow correction, nothing here ever advances Progress. Either way, the flagged/stalled step's own partial history — its fix attempts, its specific failure or discrepancy, and the files it touched — lives only in the chat report above, never folded into the Progress line itself, so the plan file never records a mid-attempt state. This is deliberate: a resumed run (the next `execute` invocation) must find an accurate resume point in the file, resuming at the same flagged step `N` on top of whatever files it already edited, not a half-finished step recorded as if it were further along than it is. A batch-dispatched step (see Phase 2's batching exception) is not corrected by this section at all — the orchestrating session, not any individual subagent, owns that batch's Progress write, and the analogous correction for a non-compliant batched subagent (one that wrote Progress despite being told not to) already happens earlier, inside Phase 2's own batch-dispatch bullet, before this phase is ever reached; by the time a batch's partial-failure stop reaches this phase, Progress has already been confirmed or corrected back to its pre-batch value there.

### This is a terminal outcome for this run

Once either report above has been delivered, this run of `execute` is finished — not paused mid-phase, finished. Phase 4 (the completion gate) is never reached following a Phase 3 report, no matter which step in the plan was flagged or stalled, and Phase 5's terminal success report is never printed in the same run as a Phase 3 report — the two are mutually exclusive, distinct terminal outcomes: a run either ends here, in Phase 3, or it ends later in Phase 5, never both.

## Phase 4 — Completion gate

**Resolved-policy path:** when the plan has a concrete `## Verification Policy` table, follow `references/verification-policy.md` for scope and completion. All-manual plans can finish with `VERIFIED_MANUALLY` and validated observed evidence; mixed plans require both their selected automated suites and manual scenarios. The rest of this phase is the legacy path for plans without an explicit policy.

Phase 4 is reached in exactly two ways: normally, once Phase 2's loop finishes step `M` and writes "Step M of M complete" to `## Execution Status → Progress`; or directly, on a fresh invocation of `execute`, when Phase 0 point 4 finds Progress already reading "Step M of M complete" — every implementation/test step was already done by an earlier run — and routes straight here without re-running Phase 2 at all. Either way, this phase runs exactly once per invocation of `execute` that reaches it: it is a single, whole-plan-level check, not a per-step action, and it is never reached following a Phase 3 report (per Phase 3's own "terminal outcome" rule).

### Where this runs: never dispatched, mode-independent

Unlike Phase 2's per-step work, Phase 4 always runs in whichever session is currently executing `execute` — it is never dispatched to a fresh subagent via the Agent tool, regardless of which `Mode` the plan recorded in `## Execution Status → Mode` for Phase 2's own per-step dispatch. Subagent-Driven mode dispatches a fresh subagent per *step*; the completion gate is not a step, has no entry in the plan's `## Steps` section, and is never counted in "Step N of M." It is a single check performed once, after every step is done, so it stays in this session even when every individual step above it ran inside a dispatched subagent. Do not dispatch a subagent for this phase under Subagent-Driven mode — a reader should not assume that mode's per-step dispatch pattern extends here.

### Resolving scope: scoped+full vs. full-suite

Use the **scoped+full** gate only when **both** of the following hold; otherwise fall back to full-suite mode:

(a) The plan's `## Domains/UCs Touched` section lists at least one token. A `` `<repo>`: None — <reason> `` line contributes none; a missing section, or one where every line is `None`, fails this check.
(b) At least one repo named by those tokens' prefixes has `.claude/skills/test-strategy/SKILL.md` (find each repo the same way Phase 2 point 2 finds a Tests line's repo root).

- **Both hold:** the argument is every listed token (any number of prefixes), followed by `full:<repo>` for every product repo in `## Affected Code` — each `` ### `<repo>` `` section heading not marked `(test scope only)`. The gate value is `scoped+full`. Tokens for a repo without a strategy are still passed; `run-regression` lists them under `Unmapped scope (not run)`, never as FAIL.
- **Otherwise:** the argument is `full`, and the gate value is `full-suite`.

The full suite of every product repo the plan changes always runs, so this gate never drops below a full-suite safety net; current test-map relationships add tests in other repos (such as a QA repo) that the full suite alone would miss. Test-scope repos run only their mapped scoped tests. The maintained map does not broaden the existing full-suite policy.

### Invoking `run-regression`

However scope resolved, invoke `run-regression` via the `Skill` tool — the same mechanism used anywhere else in this plugin that one skill's own instructions call another:

Inside an `implement` run, carry the supplied workflow state path and workflow-decision audit contract into this same-session invocation (including the resolved-policy path). Any workflow choices made there are checkpointed by the main session before dependent work; do not introduce a new command flag or another state file.

- **Scoped+full mode** (conditions (a) and (b) both hold): `Skill({skill: "make-it-work:run-regression", args: "<every token from the plan's ## Domains/UCs Touched> <full:<repo> per product repo> [--autopilot]"})` — append `--autopilot` exactly when this `execute` invocation has it; e.g. `Skill({skill: "make-it-work:run-regression", args: "payments-api:UC-08 ledger-api:UC-03 full:payments-api full:ledger-api --autopilot"})`.
- **Full-suite mode** (either condition fails): `Skill({skill: "make-it-work:run-regression", args: "full [--autopilot]"})` — append the flag only when this invocation has it.

This call requires `skills/run-regression/SKILL.md` to not carry a `disable-model-invocation: true` frontmatter line — it does not, as shipped. Without that, the `Skill` tool refuses the call outright with "Unknown skill" — it does not run `run-regression` in some degraded form or fall back to anything else; the call simply fails to resolve.

`run-regression`'s own frontmatter carries no subagent-dispatch directive, so invoking it via the `Skill` tool loads its instructions into this same session's current turn rather than handing the work to a separate subagent: this session itself then works through `run-regression`'s own Phase 0 through Phase 5 exactly as that skill's `SKILL.md` describes, using the argument just passed (the token string, or `full`), and it is this session that ends up printing `run-regression`'s fixed Phase 5 report block(s) directly in the chat. Once that report has been printed, control returns here, to `execute`'s own Phase 4, to read it — `run-regression`'s own Phase 5 is not itself the end of this run; `execute` still has to act on what it produced.

### Reading the result

`run-regression`'s Phase 5 report takes one of these shapes, and which one applies is a property of the report itself — not of how many repos this plan's own `## Affected Code` table lists (a single-repo plan can still resolve, inside `run-regression`, to a detected multi-repo workspace, since `run-regression` does its own independent repo/workspace detection whenever it's given `full`):

- **No leading `Workspace:` line** — a single-repo bare `full` run. Read that one block's own `Gate result:` field.
- **A leading `Workspace: <n> repos` line** (a bare `full` in a detected workspace) **or `Workspace: <n> runs` line** (any token run, followed by a leading `Mode: Scoped + full` or `Mode: Scoped` line), then one block per executed run. Read the closing `Overall gate result:` line, never any individual block's own `Gate result:` line — some blocks can PASS while others FAIL, and `Overall gate result` is the single line that already folds that all together correctly.

The closing `Not run:` and `Unmapped scope (not run)` lines list suites and tokens that did not execute. Report them (see Phase 5's optional `Not run:` line), but never treat them as FAIL.

**If the result reads `PASS`** (`Gate result: PASS` for a single-repo run, or `Overall gate result: PASS` for a workspace or token run): proceed to Phase 5.

**If the result reads `FAIL`** (`Gate result: FAIL` for a single-repo run, or `Overall gate result: FAIL` for a workspace or token run — regardless of which specific block(s) actually failed): stop. Print `run-regression`'s full report verbatim to the user — every block, in full, exactly as `run-regression` produced it, including any `Reason:` string, its `Not run:` and `Unmapped scope (not run)` lines, and (for a workspace or token run) every block plus the `Workspace:`/`Overall gate result:` lines — and state plainly that `execute` does not attempt to fix a completion-gate failure automatically. This is a deliberate difference from a step-level test failure in Phase 2: there is no retry here (Phase 1's 5-attempt retry limit governs step-level test failures only), no guardrail check (Phase 1's guardrail is about a step's own failing test conflicting with the plan's documented intent — it has no bearing on a regression-suite result), and no dispatch to Phase 3 (Phase 3 exists specifically to report the two step-level stop conditions Phase 1 defines — the guardrail and the retry limit — and neither of those fired here; a completion-gate FAIL is a third, distinct kind of stop that this phase reports on its own, in its own way, never by routing through Phase 3's machinery). Leave `## Execution Status → Progress` exactly as it already reads ("Step M of M complete") — this phase never rewrites Progress, since every step did in fact pass; only the plan-level regression gate failed on top of that. Do not print Phase 5's terminal success report in this same run. The only way to continue is a fresh invocation of `execute` after the user has triaged the regression failure (fixed the underlying break, or otherwise addressed it) — that fresh invocation's own Phase 0 point 4 will find Progress already reading "Step M of M complete" and route straight back to this same Phase 4 to re-run the gate.

**If `run-regression` never produces a `Gate result` / `Overall gate result` line at all** — this happens when nothing executed (a token report with no `Overall gate result:` line, or a single-repo bare `full` that prints only `Not run: <repo> — <reason>`), or when one of `run-regression`'s own stop-and-ask conditions fires instead of a normal report, e.g. its Phase 0's "Could not identify the project root," or (for a single-repo full-suite run — the outcome this very plugin repo would hit today, having no configured test framework of its own) its Phase 1's "Could not find a full-suite test command for `<repo>`... Specify one directly, or run `/make-it-work:define-test-strategy` first." — treat this the same as a FAIL, never as a PASS, and never as something to silently skip past into Phase 5: relay `run-regression`'s own stop message (or its `Not run:`/`Unmapped scope (not run)` lines) to the user verbatim and stop here, in Phase 4, exactly as the FAIL case above does (Progress left unchanged, no Phase 5 report this run, only a fresh `execute` invocation resumes it). The one exception is Phase 1's stop-and-ask itself asking the user for a command: if the user supplies one and `run-regression` goes on, in that same turn, to actually run it and print a real Phase 5 block with a `Gate result`/`Overall gate result` line, read that line per the rules above instead — the stop-and-ask is a pause within `run-regression`'s own run, not automatically a hard stop of this phase, provided it resolves into an actual block. A `Gate result` line must never be assumed or defaulted to `PASS`: the absence of one is itself treated as not-a-pass.

## Phase 5 — Final report

Phase 5 is reached only when Phase 4's automated completion gate reads `PASS` (`Gate result: PASS` for a single-repo run, or `Overall gate result: PASS` for a workspace or token run). Explicit all-manual plans finish with the separate report in `references/verification-policy.md`. For automated or mixed plans, print the fixed report block below and include a separate manual-evidence line when applicable.

Print, verbatim in shape, filling in every bracketed field:

```
Plan: <resolved plan path>
Mode: <Subagent-Driven | Inline>
Steps completed: <M> of <M>
Completion gate: <Full suite | Scoped + full (<repos>)> — <PASS>
[Not run: <entries>]
Changes are uncommitted in the working tree — review and commit when ready.
```

- **`Plan:`** — the plan file path Phase 0 point 2 resolved (`make-it-work/<TICKET>/<TICKET>-plan.md`, or the explicit path argument), exactly as it was used throughout this run.
- **`Mode:`** — the `Mode` Phase 0 point 3 resolved for this run, printed exactly as one of the two literal values `Subagent-Driven` or `Inline` (not the longer descriptive sentence recorded in the plan file's `## Execution Status → Mode` line — just the mode name).
- **`Steps completed:`** — `<M> of <M>`, where `M` is the plan's own total step count, the same `M` that appears throughout `## Execution Status → Progress` ("Step N of M complete"). By the time this phase runs, Progress reads "Step M of M complete," so both numbers here are that same `M` — every step, not merely the ones this particular invocation itself executed (a resumed run that only executed the tail of the plan still reports the plan's true total here).
- **`Completion gate:`** — first `Full suite` or `Scoped + full (<repos>)`, matching whichever branch Phase 4's "Resolving scope" section actually took for this run (conditions (a) and (b) both holding → `Scoped + full`, with `<repos>` the comma-separated product repos passed as `full:<repo>`, e.g. `Scoped + full (payments-api, ledger-api)`; either failing → `Full suite`), then ` — PASS` (this line is only ever printed once the gate has already been confirmed to read PASS, so the result half of it is always `PASS`, never `FAIL`).
- **`Not run:`** — printed only when `run-regression`'s report listed any entry on its `Not run:` or `Unmapped scope (not run)` line; omit the line entirely when both read `None`. Copy those entries, joined with `; `, each with its reason (e.g. `Not run: payments-api: ../qa-automation/tests/e2e — ci-only; ledger-api:UC-03 — no test strategy`). These never affect the PASS on the line above.
- **`Changes are uncommitted in the working tree — review and commit when ready.`** — printed verbatim, unchanged, every time: this skill never runs `git commit` on the user's behalf, per Phase 1's "Never git-commit" rule, so this line is a constant, not a field to fill in.

### This is the terminal, successful-completion message

This report is one of exactly three distinct, mutually exclusive ways a run of `execute` can end — never more than one of them in the same run:

1. **A Phase 3 report** (Case 1 — Guardrail fired, or Case 2 — Retry limit reached) — printed when a stop condition fires mid-plan, in Phase 2. Per Phase 3's own "terminal outcome" rule, a run that ends this way never reaches Phase 4, and never reaches this Phase 5 report either.
2. **Phase 4's completion-gate FAIL report** — printed when every step passed but `run-regression`'s gate itself comes back FAIL (or never produces a result line at all). Per Phase 4's own instructions, a run that ends this way prints `run-regression`'s full report verbatim and stops there; it never falls through to this Phase 5 report in the same run.
3. **This Phase 5 report** — printed only when every step passed *and* the completion gate came back PASS. This is the sole successful, fully-terminal outcome of a run of `execute`.

The explicit-policy manual terminal report is a fourth successful terminal path, with outcome `VERIFIED_MANUALLY`. Print only the applicable terminal report, never an automated PASS for an all-manual plan.

## When run by implement

**Workflow decisions** — follow [implement's workflow-decision audit contract](../implement/references/workflow-decisions.md). Report explicit workflow choices to the main session as they resolve, before dependent work; keep product answers in their existing deliverables. Use the supplied state path, and preserve the distinction between user answers and automatic resolutions.

This section applies only when `/make-it-work:implement` runs this skill; a standalone run ignores it entirely. Everything above still applies unchanged — Phases 0–5, the retry limit, the guardrail, the halt scope, and the never-git-commit rule.

**Inputs** — the plan path (always passed explicitly, so Phase 0 point 2 uses it directly — it may be a versioned `make-it-work/<TICKET>/<TICKET>-plan-v<N>.md`) and the run's autonomy level (Guided, Autonomous, or Autopilot). When the run has an existing participating dashboard, also pass the exact state-file path `make-it-work/<TICKET>/<TICKET>-state.md` as the **dashboard state path**; do not pass it for an older run whose dashboard is absent, because `implement`'s no-backfill rule still applies. When this invocation is resuming a fix-plan round's own added steps, also: the round's dispatch order (`sequential` or `parallel`) — omitted for the original plan's own execute invocation, which always dispatches sequentially regardless of this input's absence.

**Per-step dashboard contract** — every single-step or completed-batch Progress advance carries the dashboard state path into `plan-status.mjs`, so it updates the active Execute dashboard before reporting or continuing. `implement` must not defer this to its terminal Execute handling: it still owns state mutations, phase-transition renders, and an `EXECUTE_STOPPED` checkpoint when the command fails, but the active Execute dashboard is owned by this per-step command.

**Live autonomy** — the caller also supplies the **workflow state path**, even when no dashboard exists. Follow [implement's chat autonomy contract](../implement/references/autonomy-changes.md) in this inline session. Before every question/default, next step/batch dispatch, inline pause decision, and completion-gate invocation, use the current saved mode instead of the entry `--autopilot` flag. Finish/checkpoint an in-flight step or batch before applying a delivered request; preserve Progress, retry counts, execution mode, and inline pause mode. In Guided/Autonomous the stored inline pause choice applies again; Guided alone does not introduce per-step stops. Pass the workflow state path as context to nested `run-regression`, appending `--autopilot` only if the current mode is Autopilot. Per-step subagents do not handle chat changes or mutate workflow autonomy; this main session owns them. The workflow state path alone never authorizes dashboard creation.

**Mode (Phase 0 point 3)** — when the Mode line reads "Not yet chosen":

- **Guided** — ask the user exactly as in a standalone run. If they choose to review the plan first, do not wait inside this run: end it with the `EXECUTE_STOPPED` outcome below (reason: user reviewing the plan).
- **Autonomous** — do not ask. Record `Subagent-Driven`, the recommended option, in exactly the format Phase 0 point 3 prescribes, and proceed.
- **Autopilot** — invoke this skill with `--autopilot`; its existing Autopilot Mode resolution table selects `Subagent-Driven`, suppresses every safe prompt, and forwards the flag to `run-regression`.

A Mode line that already records a mode is used as-is, in both levels.

**Completion gate questions** — Guided and Autonomous handle `run-regression`'s own stop-and-ask for a full-suite command as usual. Under Autopilot it remains a hard stop, returned as `GATE_NO_RESULT` for `implement` to checkpoint without a prompt.

**Discoveries under Subagent-Driven mode** — add one item to every per-step dispatch prompt: "End your report with a `Discoveries:` line listing reusable facts about the existing system you noticed (an undocumented caller, an invariant the code enforces), or `none`." Collect those lines from each step's report for the final `Discoveries:` line below.

**Stop reports point back to `implement`** — keep every field of Phase 3's Case 1 and Case 2 reports and of Phase 4's FAIL / no-result report, but wherever they tell the user to re-invoke `/make-it-work:execute` to continue, say instead: "`implement` will decide the next step." Phase 5's report is unchanged.

**Outcome lines** — after whichever terminal report this run printed, end the output with:

```
Execute outcome: PASSED | VERIFIED_MANUALLY | GUARDRAIL | RETRY_LIMIT | GATE_FAILED | GATE_NO_RESULT | EXECUTE_STOPPED
Discoveries: <reusable facts about the existing system noticed while implementing | none>
Failing tests: <<repo>: <file> / test names from run-regression's captured output tail — <repo> from the failing block's Repo: line | unknown>   ← GATE_FAILED only
```

Map the run's terminal report to exactly one value:

| Terminal report | `Execute outcome` |
| --- | --- |
| Phase 5 final report | `PASSED` |
| Explicit all-manual policy, manual terminal report with validated evidence | `VERIFIED_MANUALLY` |
| Phase 3, Case 1 — Guardrail fired | `GUARDRAIL` |
| Phase 3, Case 2 — Retry limit reached | `RETRY_LIMIT` |
| Phase 4, gate result `FAIL` | `GATE_FAILED` |
| Phase 4, no `Gate result` / `Overall gate result` line at all | `GATE_NO_RESULT` |
| Any other stop, outside Phase 3 and Phase 4 — Phase 0 (plan not found, project root not identified), Phase 2's inconsistent-dependency check, or the Guided review-first choice above | `EXECUTE_STOPPED` |

`Discoveries` records facts about the system *as it already was* — for example an undocumented caller or an invariant the code enforces — never the changes this run made; `implement` uses them in its final context sync.

**Version 1 handoff** — when the caller's workflow state contains `handoff_version: 1`, save the complete terminal report and outcome lines to `make-it-work/<TICKET>/<TICKET>-execute.md` (the path `implement` already uses), then read `../implement/references/handoffs.md` and write a new `execute-<N>.json` under `make-it-work/<TICKET>/<TICKET>-handoffs/`. Its `report` artifact is that saved report. Include the actual gate mode (`data.gate`: `full-suite`, `scoped+full`, or `none` for `VERIFIED_MANUALLY`), discoveries, and identified failing test paths/names. If a `GATE_FAILED` report cannot identify any failing test, emit `needs_input` with the missing-evidence question instead of a false completed result. Do not write a handoff for an older run. End the chat output with `Handoff: <path>`; `implement` reads the saved report rather than overwriting it in this mode.

**Verification evidence** — for `verification_version: 1`, maintain the versioned ledger described in `../implement/references/verification.md`. At Phase 4's terminal gate result, record its actual mode/result without rerunning it (`gate.mode`: `full-suite`, or `scoped+full` for Phase 4's tags + full gate). At any terminal Execute outcome, map every row in the plan's existing AC traceability table to actual passing step evidence or mark it unverified, then run the verification helper with `--plan` and `--outcome`. Do this before writing the handoff. Include `artifacts.verification: make-it-work/<TICKET>/<TICKET>-verification-v<plan_version>.json` in a `done` Execute handoff. A missing or invalid ledger is a stopped run to repair on resume, never an inferred pass.
