/atdd-run
End-to-end driver for the ATDD pipeline. Chains every phase. Stops at two hard human checkpoints:
- Checkpoint #1 — post-spec. Before any code is written.
- Checkpoint #2 — final integration PR. When all scenario sub-PRs are merged into the integration branch and the final PR
integration → trunk is opened.
Every scenario sub-PR in between is handled autonomously by pr-auto-merge: CI watch, bot idle watch, /apply-pr-feedback on retours (bounded), then auto-merge into the integration branch. No per-scenario human prompt.
When to use
Trigger when the user provides a user-story slug (e.g. /atdd-run cart-checkout) or pastes a US with its business rules.
Inputs
us-slug — kebab-case identifier (used for filenames and GitHub labels).
- Optional flags:
--sequential — run reviewers serially instead of in parallel (Codex fallback).
--stage3=<sequential|workflow> — Stage 3 execution mode. Overrides .atdd-pipeline.json:stage3_mode. Default sequential. workflow is the opt-in parallel path and is ignored (falls back to sequential) when the Workflow tool is unavailable.
--dry-run — generate scenarios + show issue plan, do not create issues, do not write code.
--from-stage <spec|sync|red|green|auto-merge|final-pr> — resume from a specific phase.
--no-auto-merge — temporarily disable pr-auto-merge for this run; falls back to the legacy per-scenario human checkpoint #2 inside green-cycle.
Workflow
Stage 0 — Capture (skill: impact-map)
If no us-slug provided, run impact-map to elicit the story, actor, action, goal, and business rules. Emit specs/<us-slug>/context.md.
Stage 1 — Spec (skills: spec-generate, spec-review)
- Run
spec-generate. It MAY interview the user for ambiguities before producing Gherkin.
- Output:
specs/<us-slug>/*.feature files (one per scenario, tagged by test level).
- Run
spec-review. Read-only review across four axes: branches, coherence, gaps, triangulation.
- Output:
specs/<us-slug>/review.md.
- Checkpoint #1 — Human gate. Present the features + review report and ask:
OK → continue to Stage 2.
REGENERATE <reason> → loop back to step 1 with the reason as guidance.
Stage 2 — Sync (skill: to-issues-atdd)
Run to-issues-atdd. Idempotent. Creates:
- Parent issue (business goal aggregated from
context.md).
- User Story issue, linked to parent.
- One sub-issue per
.feature file, labelled by test level.
- Milestone for the target version (if provided in
context.md).
Output: a JSON manifest specs/<us-slug>/issues.json mapping scenario-slug → issue-number.
Stage 3 — Execute (skills: red-cycle, green-cycle, pr-auto-merge)
Stage 2 already provisioned the integration branch atdd/<us-slug>/integration and wrote it to issues.json.
Stage 3 has two execution modes. Pick with .atdd-pipeline.json:stage3_mode (sequential | workflow) or the --stage3=<mode> flag. Default is sequential — it is the only mode under Codex and the safe path everywhere.
Sequential mode (default)
For each sub-issue in issues.json.scenarios, iterate sequentially — sub-PRs target the same integration branch, so concurrency would race the merge queue:
- Run
red-cycle <issue>. Generates failing test + runs review-fidelity. Bounded auto-correct ×2 then escalate (comment on issue, skip to next scenario).
- Run
green-cycle <issue>. Generates minimal implementation + runs review-architecture and review-intent (parallel by default). Bounded auto-correct ×2 then escalate. On success: opens a draft PR targeting the integration branch.
- Hand the PR number to
pr-auto-merge <pr>. It will:
- Mark the PR ready.
- Watch CI to completion.
- Watch bot reviewers (CodeRabbit, codex, github-actions, etc.) until an
idle_window_minutes quiet period has elapsed.
- If actionable bot feedback exists, invoke
apply-pr-feedback (bundled with this plugin), push, and loop. Capped by max_fix_iterations.
- When CI is green AND no
CHANGES_REQUESTED AND no actionable bot comments remain: gh pr merge --squash --delete-branch.
- Escalates (comment on PR, leave open) on any timeout / exhausted fix iterations / failing CI it could not repair.
- After auto-merge succeeds, move to the next scenario. On escalation, record the PR number in
specs/<us-slug>/escalations.md and continue with remaining scenarios (do NOT abort the whole pipeline).
Workflow mode (opt-in, experimental — Claude Code only)
When stage3_mode == "workflow" and the Workflow tool is available (dynamic workflows are research-preview: a recent Claude Code, a paid plan, not org-disabled), produce all scenarios in parallel and serialize only the merge. This is the substrate that removes the merge-queue serialization from the per-scenario work while keeping the merge itself single-lane.
- Capability check. If the Workflow tool is unavailable (Codex, free plan,
disableWorkflows, older version), silently fall back to sequential mode above. Never hard-fail on a missing capability.
- Launch the shipped script. Call the Workflow tool with
scriptPath = ${CLAUDE_PLUGIN_ROOT}/workflows/atdd-stage3.workflow.mjs and args = { usSlug, integrationBranch, specsDir, scenarios, conventions } (flatten issues.json.scenarios to [{slug, issue, branch, level, rule, feature}]; conventions is the once-extracted shared language + relevant ADRs, passed so the N parallel scenario agents don't each re-discover them — a token cache, not a replacement for an agent consulting the ADRs its own diff touches). The script:
- runs
red-cycle + green-cycle per scenario in an isolated worktree (agentType atdd-scenario), each branch cut from the integration tip — parallel, no barrier;
- merges each draft PR through a single serialized lane (agentType
atdd-merge) that rebases onto the live integration tip, re-runs CI, then pr-auto-merges — so the merge queue never races.
- Consume the result. The script returns
{ merged: [slug], escalated: [{slug, issue, pr, reason}] }. Write each scenario's terminal phase into run-state.json and record escalations in escalations.md, exactly as sequential mode does.
The human gates stay OUTSIDE the workflow: checkpoint #1 (spec) already happened before Stage 3; checkpoint #2 (final PR) happens in Stage 4 after the workflow returns. Dynamic workflows take no mid-run human input, which is why the gates must bracket Stage 3, never sit inside it. This mode is experimental and opt-in; the sequential loop is the supported default until it has real-repo mileage.
Write run-state.json after every phase boundary of every scenario (after RED commits, after the draft PR opens, after merge, after escalation), in both modes. This is what makes a multi-hour run crash-resumable rather than restart-from-scratch — see Run state. The per-scenario phase transitions are the only durable record of where a fanned-out or interrupted run actually stopped.
There is no per-scenario human checkpoint in Stage 3. This is the explicit goal of auto_merge.enabled == true.
Stage 4 — Final integration PR (terminal stop)
After every scenario in issues.json.scenarios has either been merged into the integration branch or escalated:
- Classify every scenario from
run-state.json (see Run state) reconciled against GitHub into exactly one of merged, escalated, unmerged:
- If ANY scenario is
unmerged (neither merged nor escalated), REFUSE to proceed. The run is not finished; resume the unmerged scenarios first.
escalated scenarios do NOT block the final PR, but they MUST be surfaced — an escalated scenario is a hole in the user story, and shipping it silently into the trunk PR is the failure this step exists to prevent.
- Push the integration branch tip (it already has all merged scenario commits via squash merges).
- Open a single PR
atdd/<us-slug>/integration → trunk_branch:
Title: [US] <us-slug>: <Goal sentence>.
Draft status: open it as a draft when escalated.length > 0, otherwise ready. A draft can't be fast-merged, which keeps an incomplete US from slipping past the human gate (and dovetails with the trunk-merge guard hook).
Body: aggregated summary — goal, list of scenarios (each linking its sub-PR). When escalated.length > 0, the body MUST LEAD with a blocking section:
## ⚠️ Incomplete — <N> scenario(s) escalated, not implemented
This user story is NOT fully delivered. The following scenarios exhausted
auto-correction and were skipped:
- #<issue> <title> — see specs/<us-slug>/escalations.md
...
Resolve or consciously accept each before merging into <trunk_branch>.
Then the normal summary and a link to specs/<us-slug>/ artifacts.
Labels: atdd, us/<us-slug>, integration; add incomplete when escalated.length > 0.
- HARD STOP. Checkpoint #2 — Human gate on the trunk PR. Do NOT invoke
pr-auto-merge here. pr-auto-merge refuses to operate on PRs whose base is trunk_branch by contract, and the trunk-merge guard hook blocks it deterministically. Draft status is a guardrail, not the gate — the human still reviews and promotes.
- Print the PR URL (and, if drafted, the escalated-scenario list) and return.
Parallelism
When parallel: true (default), Stage 3 reviewers run via the Agent tool on Claude Code (formerly Task; the alias still works). With --sequential (or under Codex), reviewers are invoked in series within the same session.
Failure escalation
An escalation is a first-class signal, not a buried comment. In a sequential run the orchestrator sees each one inline; the moment Stage 3 fans out (workflow mode), a single blocked scenario is easy to miss, so escalation has one contract the orchestrator owns end to end.
Every escalation does four things:
Comment on the GitHub issue / PR (the sub-skill already does this) with: the failing skill name, the last reviewer report, the auto-correction attempt diffs, and the ESCALATED: phrase. GitHub stays the system of record (principle #5).
Append a structured entry to specs/<us-slug>/escalations.md — one block per escalation, machine-readable enough for Stage 4 to classify:
- scenario: <slug> · issue: #<n> · pr: #<n|—> · phase: red | green | auto-merge · at: <iso8601>
reason: <one line>
artifacts: specs/<us-slug>/.cycles/<n>/<report>.md
Mark it in run-state.json — set the scenario's status: "escalated" and phase to where it died, so resume and Stage 4 both read one source.
Emit a best-effort push — call PushNotification (Claude Code) so a human is actually told a scenario is blocked, e.g. ATDD <us-slug>: scenario <slug> (#<n>) escalated at <phase> — <reason>. This is best-effort and no-op under Codex (no such tool); it never gates the pipeline.
The pipeline does NOT continue past an escalated sub-issue's work; it moves to the next scenario. It does NOT abort the whole run. Stage 4 then refuses to ready the final PR while any scenario is unmerged, and surfaces every escalated one in the blocking PR header — so an escalation can't ship silently into the trunk PR.
Run state
specs/<us-slug>/run-state.json is the orchestrator's durable, per-scenario progress record. GitHub Issues remains the system of record (principle #5); this file is the local index that lets a crashed or interrupted run resume at the exact scenario+phase it stopped at, instead of replaying a whole stage. It is also what Stage 4 classifies on.
Shape:
{
"us_slug": "cart-checkout",
"integration_branch": "atdd/cart-checkout/integration",
"updated_at": "<iso8601>",
"scenarios": {
"<scenario-slug>": {
"issue": 130,
"branch": "atdd/cart-checkout/scenario-130",
"phase": "red | green | auto-merge | merged | escalated",
"pr": 142,
"status": "pending | in_progress | merged | escalated",
"attempts": { "red_fidelity": 0, "green_review": 0, "fix_iterations": 0 },
"updated_at": "<iso8601>"
}
}
}
Two rules:
- Write after every transition. The orchestrator rewrites the relevant scenario entry the moment a phase boundary is crossed (RED committed, draft PR opened, merged, escalated). Never batch the writes to the end — the value is entirely in surviving an interruption.
- Reconcile against GitHub on resume, never trust the file blindly. A crash can land between "merged on GitHub" and "wrote run-state.json". On resume, for each scenario re-derive ground truth from
gh (gh pr view <pr> --json state,mergedAt, gh issue view <issue> --json state, branch existence) and correct any drift before continuing. The file is a fast index; GitHub is the truth.
run-state.json is seeded from issues.json at the start of Stage 3 (every scenario pending).
Outputs
specs/<us-slug>/context.md
specs/<us-slug>/*.feature
specs/<us-slug>/review.md
specs/<us-slug>/issues.json (includes integration_branch)
specs/<us-slug>/run-state.json (per-scenario phase/status; the crash-resume index — see Run state)
specs/<us-slug>/escalations.md (only if any sub-issue / sub-PR escalated)
specs/<us-slug>/.cycles/<issue-number>/auto-merge.log per scenario (pr-auto-merge timeline).
- One scenario branch + auto-merged sub-PR per successfully completed scenario.
- ONE final PR
atdd/<us-slug>/integration → main, left OPEN for human review.
Resume semantics
Two granularities, coarse and fine:
- Coarse (
--from-stage) jumps directly to a stage and reuses the existing artifacts on disk. The skill is idempotent: rerunning a completed stage is a no-op when its outputs already exist (unless --force is passed).
- Fine (per-scenario, automatic). When Stage 3 is re-entered, the orchestrator reads
run-state.json, reconciles each scenario against GitHub (see Run state), and resumes each at its recorded phase: a scenario already merged is skipped, one stuck at auto-merge re-enters pr-auto-merge, one at green re-opens/repairs its PR, one escalated stays escalated. This is what makes an interrupted multi-hour run resumable at the scenario it died on rather than from the top of the stage.
Background watches (CI / bot-idle) are NOT restored across a session restart, so the resume path re-derives watch state from gh rather than any in-memory timer.
1---2name: atdd-run3description: End-to-end ATDD pipeline. Use when the user wants to take a user story from impact mapping all the way to merged code, or types /atdd-run.4---56# /atdd-run78End-to-end driver for the ATDD pipeline. Chains every phase. Stops at two hard human checkpoints:9101. **Checkpoint #1 — post-spec.** Before any code is written.112. **Checkpoint #2 — final integration PR.** When all scenario sub-PRs are merged into the integration branch and the final PR `integration → trunk` is opened.1213Every scenario sub-PR in between is handled autonomously by [`pr-auto-merge`](../../execute/pr-auto-merge/SKILL.md): CI watch, bot idle watch, `/apply-pr-feedback` on retours (bounded), then auto-merge into the integration branch. No per-scenario human prompt.1415## When to use1617Trigger when the user provides a user-story slug (e.g. `/atdd-run cart-checkout`) or pastes a US with its business rules.1819## Inputs2021- `us-slug` — kebab-case identifier (used for filenames and GitHub labels).22- Optional flags:23 - `--sequential` — run reviewers serially instead of in parallel (Codex fallback).24 - `--stage3=<sequential|workflow>` — Stage 3 execution mode. Overrides `.atdd-pipeline.json:stage3_mode`. Default `sequential`. `workflow` is the opt-in parallel path and is ignored (falls back to sequential) when the Workflow tool is unavailable.25 - `--dry-run` — generate scenarios + show issue plan, do not create issues, do not write code.26 - `--from-stage <spec|sync|red|green|auto-merge|final-pr>` — resume from a specific phase.27 - `--no-auto-merge` — temporarily disable `pr-auto-merge` for this run; falls back to the legacy per-scenario human checkpoint #2 inside `green-cycle`.2829## Workflow3031### Stage 0 — Capture (skill: `impact-map`)3233If no `us-slug` provided, run [`impact-map`](../../spec/impact-map/SKILL.md) to elicit the story, actor, action, goal, and business rules. Emit `specs/<us-slug>/context.md`.3435### Stage 1 — Spec (skills: `spec-generate`, `spec-review`)36371. Run [`spec-generate`](../../spec/spec-generate/SKILL.md). It MAY interview the user for ambiguities before producing Gherkin.38 - Output: `specs/<us-slug>/*.feature` files (one per scenario, tagged by test level).392. Run [`spec-review`](../../spec/spec-review/SKILL.md). Read-only review across four axes: branches, coherence, gaps, triangulation.40 - Output: `specs/<us-slug>/review.md`.413. **Checkpoint #1 — Human gate.** Present the features + review report and ask:42 - `OK` → continue to Stage 2.43 - `REGENERATE <reason>` → loop back to step 1 with the reason as guidance.4445### Stage 2 — Sync (skill: `to-issues-atdd`)4647Run [`to-issues-atdd`](../../sync/to-issues-atdd/SKILL.md). Idempotent. Creates:4849- Parent issue (business goal aggregated from `context.md`).50- User Story issue, linked to parent.51- One sub-issue per `.feature` file, labelled by test level.52- Milestone for the target version (if provided in `context.md`).5354Output: a JSON manifest `specs/<us-slug>/issues.json` mapping `scenario-slug → issue-number`.5556### Stage 3 — Execute (skills: `red-cycle`, `green-cycle`, `pr-auto-merge`)5758Stage 2 already provisioned the integration branch `atdd/<us-slug>/integration` and wrote it to `issues.json`.5960Stage 3 has two execution modes. Pick with `.atdd-pipeline.json:stage3_mode` (`sequential` | `workflow`) or the `--stage3=<mode>` flag. **Default is `sequential`** — it is the only mode under Codex and the safe path everywhere.6162#### Sequential mode (default)6364For each sub-issue in `issues.json.scenarios`, iterate **sequentially** — sub-PRs target the same integration branch, so concurrency would race the merge queue:65661. Run [`red-cycle <issue>`](../../execute/red-cycle/SKILL.md). Generates failing test + runs `review-fidelity`. Bounded auto-correct ×2 then escalate (comment on issue, skip to next scenario).672. Run [`green-cycle <issue>`](../../execute/green-cycle/SKILL.md). Generates minimal implementation + runs `review-architecture` and `review-intent` (parallel by default). Bounded auto-correct ×2 then escalate. On success: opens a **draft PR targeting the integration branch**.683. Hand the PR number to [`pr-auto-merge <pr>`](../../execute/pr-auto-merge/SKILL.md). It will:69 - Mark the PR ready.70 - Watch CI to completion.71 - Watch bot reviewers (CodeRabbit, codex, github-actions, etc.) until an `idle_window_minutes` quiet period has elapsed.72 - If actionable bot feedback exists, invoke [`apply-pr-feedback`](../../execute/apply-pr-feedback/SKILL.md) (bundled with this plugin), push, and loop. Capped by `max_fix_iterations`.73 - When CI is green AND no `CHANGES_REQUESTED` AND no actionable bot comments remain: `gh pr merge --squash --delete-branch`.74 - Escalates (comment on PR, leave open) on any timeout / exhausted fix iterations / failing CI it could not repair.754. After auto-merge succeeds, move to the next scenario. On escalation, record the PR number in `specs/<us-slug>/escalations.md` and continue with remaining scenarios (do NOT abort the whole pipeline).7677#### Workflow mode (opt-in, experimental — Claude Code only)7879When `stage3_mode == "workflow"` **and** the Workflow tool is available (dynamic workflows are research-preview: a recent Claude Code, a paid plan, not org-disabled), produce all scenarios in parallel and serialize only the merge. This is the substrate that removes the merge-queue serialization from the per-scenario *work* while keeping the merge itself single-lane.80811. **Capability check.** If the Workflow tool is unavailable (Codex, free plan, `disableWorkflows`, older version), **silently fall back to sequential mode above.** Never hard-fail on a missing capability.822. **Launch the shipped script.** Call the Workflow tool with `scriptPath = ${CLAUDE_PLUGIN_ROOT}/workflows/atdd-stage3.workflow.mjs` and `args = { usSlug, integrationBranch, specsDir, scenarios, conventions }` (flatten `issues.json.scenarios` to `[{slug, issue, branch, level, rule, feature}]`; `conventions` is the once-extracted shared language + relevant ADRs, passed so the N parallel scenario agents don't each re-discover them — a token cache, not a replacement for an agent consulting the ADRs its own diff touches). The script:83 - runs `red-cycle` + `green-cycle` per scenario in an **isolated worktree** (agentType `atdd-scenario`), each branch cut from the integration tip — parallel, no barrier;84 - merges each draft PR through a **single serialized lane** (agentType `atdd-merge`) that rebases onto the live integration tip, re-runs CI, then `pr-auto-merge`s — so the merge queue never races.853. **Consume the result.** The script returns `{ merged: [slug], escalated: [{slug, issue, pr, reason}] }`. Write each scenario's terminal phase into `run-state.json` and record escalations in `escalations.md`, exactly as sequential mode does.8687The human gates stay OUTSIDE the workflow: checkpoint #1 (spec) already happened before Stage 3; checkpoint #2 (final PR) happens in Stage 4 after the workflow returns. Dynamic workflows take no mid-run human input, which is why the gates must bracket Stage 3, never sit inside it. This mode is experimental and opt-in; the sequential loop is the supported default until it has real-repo mileage.8889**Write `run-state.json` after every phase boundary** of every scenario (after RED commits, after the draft PR opens, after merge, after escalation), in both modes. This is what makes a multi-hour run crash-resumable rather than restart-from-scratch — see *Run state*. The per-scenario phase transitions are the only durable record of where a fanned-out or interrupted run actually stopped.9091There is **no per-scenario human checkpoint** in Stage 3. This is the explicit goal of `auto_merge.enabled == true`.9293### Stage 4 — Final integration PR (terminal stop)9495After every scenario in `issues.json.scenarios` has either been merged into the integration branch or escalated:96971. **Classify every scenario** from `run-state.json` (see *Run state*) reconciled against GitHub into exactly one of `merged`, `escalated`, `unmerged`:98 - If ANY scenario is `unmerged` (neither merged nor escalated), REFUSE to proceed. The run is not finished; resume the unmerged scenarios first.99 - `escalated` scenarios do NOT block the final PR, but they MUST be surfaced — an escalated scenario is a hole in the user story, and shipping it silently into the trunk PR is the failure this step exists to prevent.1002. Push the integration branch tip (it already has all merged scenario commits via squash merges).1013. Open a single PR `atdd/<us-slug>/integration → trunk_branch`:102 - Title: `[US] <us-slug>: <Goal sentence>`.103 - **Draft status:** open it as a **draft** when `escalated.length > 0`, otherwise ready. A draft can't be fast-merged, which keeps an incomplete US from slipping past the human gate (and dovetails with the trunk-merge guard hook).104 - Body: aggregated summary — goal, list of scenarios (each linking its sub-PR). When `escalated.length > 0`, the body MUST LEAD with a blocking section:105106 ```text107 ## ⚠️ Incomplete — <N> scenario(s) escalated, not implemented108109 This user story is NOT fully delivered. The following scenarios exhausted110 auto-correction and were skipped:111 - #<issue> <title> — see specs/<us-slug>/escalations.md112 ...113 Resolve or consciously accept each before merging into <trunk_branch>.114 ```115116 Then the normal summary and a link to `specs/<us-slug>/` artifacts.117 - Labels: `atdd`, `us/<us-slug>`, `integration`; add `incomplete` when `escalated.length > 0`.1184. **HARD STOP. Checkpoint #2 — Human gate on the trunk PR.** Do NOT invoke `pr-auto-merge` here. `pr-auto-merge` refuses to operate on PRs whose base is `trunk_branch` by contract, and the trunk-merge guard hook blocks it deterministically. Draft status is a guardrail, not the gate — the human still reviews and promotes.1195. Print the PR URL (and, if drafted, the escalated-scenario list) and return.120121## Parallelism122123When `parallel: true` (default), Stage 3 reviewers run via the `Agent` tool on Claude Code (formerly `Task`; the alias still works). With `--sequential` (or under Codex), reviewers are invoked in series within the same session.124125## Failure escalation126127An escalation is a first-class signal, not a buried comment. In a sequential run the orchestrator sees each one inline; the moment Stage 3 fans out (workflow mode), a single blocked scenario is easy to miss, so escalation has one contract the orchestrator owns end to end.128129Every escalation does four things:1301311. **Comment on the GitHub issue / PR** (the sub-skill already does this) with: the failing skill name, the last reviewer report, the auto-correction attempt diffs, and the `ESCALATED:` phrase. GitHub stays the system of record (principle #5).1322. **Append a structured entry to `specs/<us-slug>/escalations.md`** — one block per escalation, machine-readable enough for Stage 4 to classify:133134 ```text135 - scenario: <slug> · issue: #<n> · pr: #<n|—> · phase: red | green | auto-merge · at: <iso8601>136 reason: <one line>137 artifacts: specs/<us-slug>/.cycles/<n>/<report>.md138 ```1391403. **Mark it in `run-state.json`** — set the scenario's `status: "escalated"` and `phase` to where it died, so resume and Stage 4 both read one source.1414. **Emit a best-effort push** — call `PushNotification` (Claude Code) so a human is actually told a scenario is blocked, e.g. `ATDD <us-slug>: scenario <slug> (#<n>) escalated at <phase> — <reason>`. This is best-effort and **no-op under Codex** (no such tool); it never gates the pipeline.142143The pipeline does NOT continue past an escalated sub-issue's work; it moves to the next scenario. It does NOT abort the whole run. Stage 4 then refuses to ready the final PR while any scenario is `unmerged`, and surfaces every `escalated` one in the blocking PR header — so an escalation can't ship silently into the trunk PR.144145## Run state146147`specs/<us-slug>/run-state.json` is the orchestrator's durable, per-scenario progress record. GitHub Issues remains the system of record (principle #5); this file is the local index that lets a crashed or interrupted run resume at the exact scenario+phase it stopped at, instead of replaying a whole stage. It is also what Stage 4 classifies on.148149Shape:150151```json152{153 "us_slug": "cart-checkout",154 "integration_branch": "atdd/cart-checkout/integration",155 "updated_at": "<iso8601>",156 "scenarios": {157 "<scenario-slug>": {158 "issue": 130,159 "branch": "atdd/cart-checkout/scenario-130",160 "phase": "red | green | auto-merge | merged | escalated",161 "pr": 142,162 "status": "pending | in_progress | merged | escalated",163 "attempts": { "red_fidelity": 0, "green_review": 0, "fix_iterations": 0 },164 "updated_at": "<iso8601>"165 }166 }167}168```169170Two rules:1711721. **Write after every transition.** The orchestrator rewrites the relevant scenario entry the moment a phase boundary is crossed (RED committed, draft PR opened, merged, escalated). Never batch the writes to the end — the value is entirely in surviving an interruption.1732. **Reconcile against GitHub on resume, never trust the file blindly.** A crash can land between "merged on GitHub" and "wrote run-state.json". On resume, for each scenario re-derive ground truth from `gh` (`gh pr view <pr> --json state,mergedAt`, `gh issue view <issue> --json state`, branch existence) and correct any drift before continuing. The file is a fast index; GitHub is the truth.174175`run-state.json` is seeded from `issues.json` at the start of Stage 3 (every scenario `pending`).176177## Outputs178179- `specs/<us-slug>/context.md`180- `specs/<us-slug>/*.feature`181- `specs/<us-slug>/review.md`182- `specs/<us-slug>/issues.json` (includes `integration_branch`)183- `specs/<us-slug>/run-state.json` (per-scenario phase/status; the crash-resume index — see *Run state*)184- `specs/<us-slug>/escalations.md` (only if any sub-issue / sub-PR escalated)185- `specs/<us-slug>/.cycles/<issue-number>/auto-merge.log` per scenario (pr-auto-merge timeline).186- One scenario branch + auto-merged sub-PR per successfully completed scenario.187- ONE final PR `atdd/<us-slug>/integration → main`, left OPEN for human review.188189## Resume semantics190191Two granularities, coarse and fine:192193- **Coarse (`--from-stage`)** jumps directly to a stage and reuses the existing artifacts on disk. The skill is idempotent: rerunning a completed stage is a no-op when its outputs already exist (unless `--force` is passed).194- **Fine (per-scenario, automatic).** When Stage 3 is re-entered, the orchestrator reads `run-state.json`, **reconciles each scenario against GitHub** (see *Run state*), and resumes each at its recorded phase: a scenario already `merged` is skipped, one stuck at `auto-merge` re-enters `pr-auto-merge`, one at `green` re-opens/repairs its PR, one `escalated` stays escalated. This is what makes an interrupted multi-hour run resumable at the scenario it died on rather than from the top of the stage.195196Background watches (CI / bot-idle) are NOT restored across a session restart, so the resume path re-derives watch state from `gh` rather than any in-memory timer.