<purpose>
Execute all plans in a phase using wave-based parallel execution. Orchestrator stays lean — delegates plan execution to subagents.
</purpose>

<core_principle>
Orchestrator coordinates, not executes. Each subagent loads the full execute-plan context. Orchestrator: discover plans → analyze deps → group waves → spawn agents → handle checkpoints → collect results.
</core_principle>

<required_reading>
Read STATE.md before any operation to load project context.
</required_reading>

<process>

<step name="mode_aware_path_resolution" priority="first">
## 0. Mode-Aware Path Resolution (v1.5.9 Parallel Milestone Organization)

Resolve organizational mode + active milestone slug ONCE; all subsequent path lookups route through `resolveMilestonePaths(mode, slug, artifact)`. Workflow consumes `active_milestone_slug` from init JSON — it does NOT parse `--milestone` itself (P3 thin-wrapper; flag parsed once at gmd-tools.cjs init dispatch entry per Plan 66-01).

```bash
INIT=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" init execute-phase "${PHASE_ARG}" --raw)
MODE=$(echo "$INIT" | jq -r '.organizational_mode')
SLUG=$(echo "$INIT" | jq -r '.active_milestone_slug // empty')
NEEDS_PROMPT=$(echo "$INIT" | jq -r '.active_milestone_needs_prompt')
```

**Tier 4 prompt (parallel mode, no flag, no pointer, multiple/zero In Progress milestones):**

If `$NEEDS_PROMPT == "true"`:
- Read `.active_milestone_candidates` array from init JSON
- Invoke AskUserQuestion with the candidate list
- Persist selection: `node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" state set-current-milestone "<chosen-slug>"`
- Re-run init to pick up the now-set slug (re-execute the INIT=$(...) block above)

**Path lookups (used throughout this workflow):**

```bash
REQS_PATH=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'REQUIREMENTS'))")
ROADMAP_PATH=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'ROADMAP'))")
STATE_PATH=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'STATE'))")
PHASES_DIR=$(node -e "const {resolveMilestonePaths}=require('$HOME/.claude/get-magic-done/bin/lib/path-resolve.js'); console.log(resolveMilestonePaths('$MODE', '$SLUG' || null, 'phases-dir'))")
```

**Sequential mode:** `MODE=sequential, SLUG=null` → paths resolve to root `.planning/` (byte-identical to pre-v1.5.9 behavior per P1). No Tier 4 prompt fires.

**Parallel mode:** `MODE=parallel, SLUG=<active>` → paths route to `.planning/milestones/<slug>/`. If `--milestone <slug>` flag was passed at `/gmd:execute-phase` invocation, it overrides the pointer (Tier 1; init.cjs handled this at flag-parse entry).

**Project-level paths stay literal** (root in BOTH modes per Phase 65 Decision O6-lean PROJECT_LEVEL_PATHS table): `.planning/PROJECT.md`, `.planning/MILESTONES.md`, `.planning/config.json`.
</step>

<step name="initialize" priority="first">
Load all context in one call:

```bash
INIT=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" init execute-phase "${PHASE_ARG}")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
```

Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`, `phase_req_ids`, `organizational_mode`, `active_milestone_slug`, `active_milestone_needs_prompt`, `active_milestone_candidates`.

**If `phase_found` is false:** Error — phase directory not found.
**If `plan_count` is 0:** Error — no plans found in phase.
**If `state_exists` is false but `.planning/` exists:** Offer reconstruct or continue.

When `parallelization` is false, plans within a wave execute sequentially.

**Sync chain flag with intent** — if user invoked manually (no `--auto`), clear the ephemeral chain flag from any previous interrupted `--auto` chain. This does NOT touch `workflow.auto_advance` (the user's persistent settings preference). Must happen before any config reads (checkpoint handling also reads auto-advance flags):
```bash
if [[ ! "$ARGUMENTS" =~ --auto ]]; then
  node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" config-set workflow._auto_chain_active false 2>/dev/null
fi
```
</step>

<step name="vault_preflight" priority="early">
Run `vault-orient` to pre-warm the 5-min query cache and build a compressed `<vault_context>` block for injection into every downstream Task() prompt. This is the D9b orchestrator-side default: vault-use as the default code path, not an opt-in. Component-gate-aware: skips silently when `components.obsidian.enabled: false`.

```bash
VAULT_ORIENT_RAW=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" vault-orient \
  --agent orchestrator-execute-phase 2>/dev/null || echo '{"skipped":"vault unavailable"}')
```

**Compress orient JSON to a ~300-tok `<vault_context>` block:**

1. Parse the orient JSON. If `.skipped` is set OR the JSON contains an error field, set `VAULT_CONTEXT_BLOCK=""` (empty) and skip to step 3.
2. Otherwise, extract:
   - `index_summary` — cap at 1200 chars (append `…[truncated]` if longer)
   - `in_scope_notes[0..4]` — top 5 notes, emit `path + summary` only (no bodies)
   - `directives[*].summary` (or first-line fallback) — directive summaries only, no bodies
3. Build the block in this exact shape (omit entirely if compression produced nothing):

   ```
   <vault_context>
   ## Index Summary
   {index_summary}

   ## In-Scope Notes (top 5)
   - {path}: {summary}
   - ...

   ## Directives (summary only; re-read via vault-read if needed)
   - {path}: {summary}
   - ...

   vault_status: {ok | empty | error}
   </vault_context>
   ```

**Injection contract:** The `VAULT_CONTEXT_BLOCK` must be injected into every downstream Task() prompt (executor agents, debugger, verifier) immediately before the existing `<files_to_read>` block. When empty (skipped/error/empty orient), omit the block entirely — never inject an empty `<vault_context></vault_context>`. Cached orient means subsequent subagent `vault-query` calls hit the warm 5-min cache (~116ms cached vs ~1700ms uncached on Windows).

**Code-map slice (Tier-1 push — WIRE-01):** execute-phase builds the block PER EXECUTOR SPAWN (not once here) — the per-site source is that plan's `files_modified` frontmatter (via `phase-plan-index` or the plan file itself); never fabricate scope. Mechanics, run at each executor spawn in `execute_waves`:

```bash
CODE_MAP_CONTEXT_BLOCK=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" code-slice --files "<csv of that plan's files_modified>" --format block 2>/dev/null || true)
```

**Injection contract for `<code_map_context>`:** inject the per-plan block immediately AFTER `<vault_context>`, BEFORE `<files_to_read>`, in the executor Task() prompt. The debugger spawn reuses the FAILED plan's block (same per-plan source). When empty, omit entirely — never inject an empty `<code_map_context></code_map_context>`. The block already embeds the Tier-2 pull commands + the freshness verdict (launch point, not payload — D-V184-05); the orchestrator never widens it. **EXCLUSION: the verifier spawn (verify_phase_goal Step 2) is NOT a `<code_map_context>` push site — it receives the verify-time `<regression_xref>` block instead (WIRE-02).**
</step>

<step name="handle_branching">
Check `branching_strategy` from init:

**"none":** Skip, continue on current branch.

**"phase" or "milestone":** Use pre-computed `branch_name` from init:
```bash
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
```

All subsequent commits go to this branch. User handles merging.
</step>

<step name="validate_phase">
From init JSON: `phase_dir`, `plan_count`, `incomplete_count`.

Report: "Found {plan_count} plans in {phase_dir} ({incomplete_count} incomplete)"
</step>

<step name="discover_and_group_plans">
Load plan inventory with wave grouping in one call:

```bash
PLAN_INDEX=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" phase-plan-index "${PHASE_NUMBER}")
```

Parse JSON for: `phase`, `plans[]` (each with `id`, `wave`, `autonomous`, `objective`, `files_modified`, `task_count`, `has_summary`), `waves` (map of wave number → plan IDs), `incomplete`, `has_checkpoints`.

**Filtering:** Skip plans where `has_summary: true`. If `--gaps-only`: also skip non-gap_closure plans. If all filtered: "No matching incomplete plans" → exit.

Report:
```
## Execution Plan

**Phase {X}: {Name}** — {total_plans} plans across {wave_count} waves

| Wave | Plans | What it builds |
|------|-------|----------------|
| 1 | 01-01, 01-02 | {from plan objectives, 3-8 words} |
| 2 | 01-03 | ... |
```
</step>

<step name="execute_waves">
Execute each wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`, sequential if `false`.

**For each wave:**

1. **Describe what's being built (BEFORE spawning):**

   Read each plan's `<objective>`. Extract what's being built and why.

   ```
   ---
   ## Wave {N}

   **{Plan ID}: {Plan Name}**
   {2-3 sentences: what this builds, technical approach, why it matters}

   Spawning {count} agent(s)...
   ---
   ```

   - Bad: "Executing terrain generation plan"
   - Good: "Procedural terrain generator using Perlin noise — creates height maps, biome zones, and collision meshes. Required before vehicle physics can interact with ground."

2. **Spawn executor agents:**

   Pass paths only — executors read files themselves with their fresh 200k context.
   This keeps orchestrator context lean (~10-15%).

   Build the per-plan `<code_map_context>` block first (WIRE-01 — vault_preflight mechanics): `code-slice --files "<csv of THIS plan's files_modified>" --format block`; empty → omit.

   ```
   Task(
     subagent_type="gmd-executor",
     model="{executor_model}",
     prompt="
       <objective>
       Execute plan {plan_number} of phase {phase_number}-{phase_name}.
       Commit each task atomically. Create SUMMARY.md. Update STATE.md and ROADMAP.md.
       </objective>

       <execution_context>
       @C:/Users/Christopher/.claude/get-magic-done/workflows/execute-plan.md
       @C:/Users/Christopher/.claude/get-magic-done/templates/summary.md
       @C:/Users/Christopher/.claude/get-magic-done/references/checkpoints.md
       @C:/Users/Christopher/.claude/get-magic-done/references/tdd.md
       </execution_context>

       {VAULT_CONTEXT_BLOCK}

       {CODE_MAP_CONTEXT_BLOCK}

       <files_to_read>
       Read these files at execution start using the Read tool:
       - {phase_dir}/{plan_file} (Plan)
       - {STATE_PATH} (State — mode-aware; resolved at Step 0)
       - .planning/config.json (Config, if exists)
       - ./CLAUDE.md (Project instructions, if exists — follow project-specific guidelines and coding conventions)
       - .claude/skills/ or .agents/skills/ (Project skills, if either exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
       </files_to_read>

       <success_criteria>
       - [ ] All tasks executed
       - [ ] Each task committed individually
       - [ ] SUMMARY.md created in plan directory
       - [ ] STATE.md updated with position and decisions
       - [ ] ROADMAP.md updated with plan progress (via `roadmap update-plan-progress`)
       </success_criteria>
     "
   )
   ```

3. **Wait for all agents in wave to complete.**

4. **Report completion — spot-check claims first:**

   For each SUMMARY.md:
   - Verify first 2 files from `key-files.created` exist on disk
   - Check `git log --oneline --all --grep="{phase}-{plan}"` returns ≥1 commit
   - Check for `## Self-Check: FAILED` marker

   If ANY spot-check fails: report which plan failed, route to failure handler — ask "Retry plan?" or "Continue with remaining waves?"

   If pass:
   ```
   ---
   ## Wave {N} Complete

   **{Plan ID}: {Plan Name}**
   {What was built — from SUMMARY.md}
   {Notable deviations, if any}

   {If more waves: what this enables for next wave}
   ---
   ```

   - Bad: "Wave 2 complete. Proceeding to Wave 3."
   - Good: "Terrain system complete — 3 biome types, height-based texturing, physics collision meshes. Vehicle physics (Wave 3) can now reference ground surfaces."

5. **Handle failures:**

   **Known Claude Code bug (classifyHandoffIfNeeded):** If an agent reports "failed" with error containing `classifyHandoffIfNeeded is not defined`, this is a Claude Code runtime bug — not a GMD or agent issue. The error fires in the completion handler AFTER all tool calls finish. In this case: run the same spot-checks as step 4 (SUMMARY.md exists, git commits present, no Self-Check: FAILED). If spot-checks PASS → treat as **successful**. If spot-checks FAIL → treat as real failure below.

   For real failures: report which plan failed → ask "Continue?" or "Stop?" → if continue, dependent plans may also fail. If stop, partial completion report.

   **VERIFY-03 auto-debug on plan failure:**

   After the classifyHandoffIfNeeded guard filters false-failures, any remaining real failure automatically spawns `gmd-debugger` to find the root cause. This hook MUST execute AFTER the classifyHandoffIfNeeded guard — never before — so Claude Code runtime bugs do not fire the debugger.

   Failure detection taxonomy (fires auto-debug on any of):
   - (a) No SUMMARY.md created for the plan
   - (b) SUMMARY.md contains `## Self-Check: FAILED`
   - (c) Executor Task returns error AND error does NOT match /classifyHandoffIfNeeded/

   ```bash
   # Runs AFTER classifyHandoffIfNeeded guard (ordering enforced by audit-auto-debug-on-failure.sh)
   PLAN_FAILED=false
   SUMMARY_FILE="${PHASE_DIR}/${PLAN_ID}-SUMMARY.md"

   if [ ! -f "$SUMMARY_FILE" ]; then
     PLAN_FAILED=true
     FAILURE_REASON="No SUMMARY.md created"
   elif grep -q "## Self-Check: FAILED" "$SUMMARY_FILE"; then
     PLAN_FAILED=true
     FAILURE_REASON="SUMMARY.md contains Self-Check: FAILED"
   elif [ -n "$EXECUTOR_ERROR" ] && ! echo "$EXECUTOR_ERROR" | grep -q "classifyHandoffIfNeeded"; then
     PLAN_FAILED=true
     FAILURE_REASON="Executor returned error: $EXECUTOR_ERROR"
   fi

   if [ "$PLAN_FAILED" = "true" ]; then
     debugger_model=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" resolve-model gmd-debugger --complexity standard --raw)
     echo "[auto-debug] Spawning gmd-debugger for plan ${PLAN_ID} failure: ${FAILURE_REASON}"
   fi
   ```

   Dispatch gmd-debugger with symptoms pre-filled and goal locked to root-cause-only (no fix attempt — user decides after diagnosis):

   ```
   Task(
     subagent_type="gmd-debugger",
     model="{debugger_model}",
     prompt="
       <objective>
       Investigate issue: plan-${PLAN_ID}-failure
       Plan ${PLAN_ID} of phase ${PHASE_NUMBER} failed during execute-phase.
       </objective>

       <symptoms>
       expected: Plan ${PLAN_ID} completes all tasks, creates SUMMARY.md, commits per task
       actual: ${FAILURE_REASON}
       errors: ${EXECUTOR_ERROR}
       reproduction: /gmd:execute-phase ${PHASE_NUMBER}
       </symptoms>

       <mode>
       symptoms_prefilled: true
       goal: find_root_cause_only
       </mode>

       {VAULT_CONTEXT_BLOCK}

       {CODE_MAP_CONTEXT_BLOCK}

       <files_to_read>
       - ${PHASE_DIR}/${PLAN_ID}-PLAN.md
       - ${STATE_PATH} (mode-aware; resolved at Step 0)
       - .planning/config.json
       </files_to_read>
     ",
     description="Diagnose plan ${PLAN_ID} failure"
   )
   ```

   After gmd-debugger returns with root cause: present to user, then fall through to the existing Continue/Stop prompt. The debugger does NOT attempt fixes (goal: find_root_cause_only) — user decides whether to retry, plan a fix, or stop.

6. **Execute checkpoint plans between waves** — see `<checkpoint_handling>`.

7. **Proceed to next wave.**
</step>

<step name="checkpoint_handling">
Plans with `autonomous: false` require user interaction.

**Auto-mode checkpoint handling:**

Read auto-advance config (chain flag + user preference):
```bash
AUTO_CHAIN=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" config-get workflow._auto_chain_active 2>/dev/null || echo "false")
AUTO_CFG=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" config-get workflow.auto_advance 2>/dev/null || echo "false")
```

When executor returns a checkpoint AND (`AUTO_CHAIN` is `"true"` OR `AUTO_CFG` is `"true"`):
- **human-verify** → Auto-spawn continuation agent with `{user_response}` = `"approved"`. Log `⚡ Auto-approved checkpoint`.
- **decision** → Auto-spawn continuation agent with `{user_response}` = first option from checkpoint details. Log `⚡ Auto-selected: [option]`.
- **human-action** → Present to user (existing behavior below). Auth gates cannot be automated.

**Standard flow (not auto-mode, or human-action type):**

1. Spawn agent for checkpoint plan
2. Agent runs until checkpoint task or auth gate → returns structured state
3. Agent return includes: completed tasks table, current task + blocker, checkpoint type/details, what's awaited
4. **Present to user:**
   ```
   ## Checkpoint: [Type]

   **Plan:** 03-03 Dashboard Layout
   **Progress:** 2/3 tasks complete

   [Checkpoint Details from agent return]
   [Awaiting section from agent return]
   ```
5. User responds: "approved"/"done" | issue description | decision selection
6. **Spawn continuation agent (NOT resume)** using continuation-prompt.md template:
   - `{completed_tasks_table}`: From checkpoint return
   - `{resume_task_number}` + `{resume_task_name}`: Current task
   - `{user_response}`: What user provided
   - `{resume_instructions}`: Based on checkpoint type
7. Continuation agent verifies previous commits, continues from resume point
8. Repeat until plan completes or user stops

**Why fresh agent, not resume:** Resume relies on internal serialization that breaks with parallel tool calls. Fresh agents with explicit state are more reliable.

**Checkpoints in parallel waves:** Agent pauses and returns while other parallel agents may complete. Present checkpoint, spawn continuation, wait for all before next wave.
</step>

<step name="aggregate_results">
After all waves:

```markdown
## Phase {X}: {Name} Execution Complete

**Waves:** {N} | **Plans:** {M}/{total} complete

| Wave | Plans | Status |
|------|-------|--------|
| 1 | plan-01, plan-02 | ✓ Complete |
| CP | plan-03 | ✓ Verified |
| 2 | plan-04 | ✓ Complete |

### Plan Details
1. **03-01**: [one-liner from SUMMARY.md]
2. **03-02**: [one-liner from SUMMARY.md]

### Issues Encountered
[Aggregate from SUMMARYs, or "None"]
```
</step>

<step name="close_parent_artifacts">
**For decimal/polish phases only (X.Y pattern):** Close the feedback loop by resolving parent UAT and debug artifacts.

**Skip if** phase number has no decimal (e.g., `3`, `04`) — only applies to gap-closure phases like `4.1`, `03.1`.

**1. Detect decimal phase and derive parent:**
```bash
# Check if phase_number contains a decimal
if [[ "$PHASE_NUMBER" == *.* ]]; then
  PARENT_PHASE="${PHASE_NUMBER%%.*}"
fi
```

**2. Find parent UAT file:**
```bash
PARENT_INFO=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" find-phase "${PARENT_PHASE}" --raw)
# Extract directory from PARENT_INFO JSON, then find UAT file in that directory
```

**If no parent UAT found:** Skip this step (gap-closure may have been triggered by VERIFICATION.md instead).

**3. Update UAT gap statuses:**

Read the parent UAT file's `## Gaps` section. For each gap entry with `status: failed`:
- Update to `status: resolved`

**4. Update UAT frontmatter:**

If all gaps now have `status: resolved`:
- Update frontmatter `status: diagnosed` → `status: resolved`
- Update frontmatter `updated:` timestamp

**5. Resolve referenced debug sessions:**

For each gap that has a `debug_session:` field:
- Read the debug session file
- Update frontmatter `status:` → `resolved`
- Update frontmatter `updated:` timestamp
- Move to resolved directory:
```bash
mkdir -p .planning/debug/resolved
mv .planning/debug/{slug}.md .planning/debug/resolved/
```

**6. Commit updated artifacts:**
```bash
node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" commit "docs(phase-${PARENT_PHASE}): resolve UAT gaps and debug sessions after ${PHASE_NUMBER} gap closure" --files "${PHASES_DIR}"/*${PARENT_PHASE}*/*-UAT.md .planning/debug/resolved/*.md
```
</step>

<step name="profile_gated_auto_verify">

## Profile-driven auto-verify + auto-nyquist (VERIFY-01, VERIFY-04)

After a phase completes all waves successfully, decide whether to auto-dispatch `/gmd:verify-phase` and `/gmd:validate-phase` based on the user's `model_profile` config.

**VERIFY-01 locks (CONTEXT.md):**
- `quality` profile → always auto-verify
- `balanced` profile → auto-verify only if code changed in src/|agents/|skills/|workflows/|bin/|commands/
- `budget` profile → skip (milestone-only; user runs `/gmd:verify-phase` on demand)

**VERIFY-04 locks (CONTEXT.md):**
- `quality` profile → auto-run validate-phase for Nyquist coverage
- `balanced` / `budget` → skip; user runs `/gmd:validate-phase` manually

```bash
# Read user's persistent profile config
PROFILE=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" config-get model_profile 2>/dev/null || echo "balanced")

# Derive first phase commit for balanced profile's code-changed detection
FIRST_PHASE_COMMIT=$(git log --format="%H" --reverse --grep="${PHASE_NUMBER}-" | head -1)
[ -z "$FIRST_PHASE_COMMIT" ] && FIRST_PHASE_COMMIT="HEAD~1"

# VERIFY-01 profile gate for auto-verify
case "$PROFILE" in
  quality)
    AUTO_VERIFY=true
    ;;
  balanced)
    # Balanced profile: only run verify-phase if code (not just markdown) changed
    FILES_CHANGED=$(git diff --stat "${FIRST_PHASE_COMMIT}"..HEAD -- \
      'src/*' 'agents/*' 'skills/*' 'workflows/*' 'bin/*' 'commands/*' \
      2>/dev/null | grep -v '^ 0 files' | wc -l)
    if [ "$FILES_CHANGED" -gt 0 ]; then
      AUTO_VERIFY=true
    else
      AUTO_VERIFY=false  # markdown-only phase, skip auto-verify
    fi
    ;;
  budget)
    AUTO_VERIFY=false  # milestone-only; phases verified on-demand via /gmd:verify-phase
    ;;
  *)
    AUTO_VERIFY=false
    ;;
esac

# VERIFY-04 profile gate for auto-nyquist (validate-phase)
case "$PROFILE" in
  quality)
    AUTO_NYQUIST=true
    ;;
  *)
    AUTO_NYQUIST=false  # balanced/budget skip auto-validate-phase
    ;;
esac

echo "[profile-gate] profile=$PROFILE auto_verify=$AUTO_VERIFY auto_nyquist=$AUTO_NYQUIST"
```

**Routing:**

| AUTO_VERIFY | AUTO_NYQUIST | Action |
|-------------|--------------|--------|
| `true`      | any          | Proceed to `verify_phase_goal` (runs verify-phase + gmd-verifier two-stage) |
| `false`     | any          | Skip `verify_phase_goal`. Record `verification: skipped_by_profile` in STATE.md. Jump to `update_roadmap`. |

If `AUTO_VERIFY=false`, the user can still run `/gmd:verify-phase ${PHASE_NUMBER}` manually — the per-phase verification workflow exists and is invocable on demand.

If `AUTO_NYQUIST=true`, dispatch `/gmd:validate-phase ${PHASE_NUMBER}` AFTER `verify_phase_goal` completes successfully (so code quality and goal-achievement are confirmed before Nyquist coverage gets audited). The dispatch sets `CALL_MODE=auto` so validate-phase's profile gate recognizes the auto-invocation path:

```bash
if [ "$AUTO_NYQUIST" = "true" ]; then
  echo "[auto-nyquist] profile=quality — dispatching /gmd:validate-phase ${PHASE_NUMBER}"
  CALL_MODE=auto node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" dispatch-workflow validate-phase "${PHASE_NUMBER}" 2>/dev/null
  # (equivalent: inline-read workflows/validate-phase.md with PHASE_NUMBER and CALL_MODE=auto env)
fi
```

**Constraints (CONTEXT.md locks):**
- Do NOT add per-phase auto-fire of `gmd-integration-checker` here (explicitly rejected — too token-heavy per phase; milestone auto-fire in `audit-milestone.md` is authoritative). On-demand per-phase integration checks are available via `/gmd:check-integration`.
- Do NOT add inline Nyquist coverage check during plan-phase (deferred — validation happens post-execution only).
- Profile gate MUST be inline in this workflow markdown (Pitfall 3 — do not extract to helper files).
</step>

<step name="verify_phase_goal">
Verify phase achieved its GOAL **and** passes a code quality review on the phase diff (two-stage verification per workflows/verify-phase.md §dispatch).

**Skip if** the `profile_gated_auto_verify` step set `AUTO_VERIFY=false` — jump directly to `update_roadmap`.

**Step 1: Derive phase diff range for stage-2 code-quality review.**

```bash
BASE_SHA=$(git log --format="%H" --reverse --grep="${PHASE_NUMBER}-" | head -1)
if [ -n "$BASE_SHA" ]; then
  BASE_SHA="${BASE_SHA}~1"
else
  BASE_SHA=$(git log --format="%H" --reverse --diff-filter=A -- "${PHASES_DIR}/${PHASE_DIR_NAME}/*-SUMMARY.md" | head -1)
  [ -n "$BASE_SHA" ] && BASE_SHA="${BASE_SHA}~1"
fi
HEAD_SHA=$(git rev-parse HEAD)
```

**Step 1.5: Compute the regression cross-reference (WIRE-02) — fail-open: empty/unavailable never blocks verify.**

REUSE the Step-1 `BASE_SHA`/`HEAD_SHA` (the diff range is free):

```bash
# Regression cross-reference (WIRE-02) — fail-open: empty/unavailable never blocks verify
REGRESSION_XREF_BLOCK=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" code-slice --diff "${BASE_SHA}..${HEAD_SHA}" --format block 2>/dev/null || true)
```

The block carries the changed entities with callers partitioned test/non-test, callees + `type:external` stubs (the Phase-111 column), the freshness verdict, and the Tier-2 pull commands. A failed derivation yields an absent or `xref_status: unavailable` block — never a blocked verify. Inject `{REGRESSION_XREF_BLOCK}` into the Step-2 gmd-verifier prompt immediately after `{VAULT_CONTEXT_BLOCK}` (omit when empty). This stays in LOCKSTEP with verify-phase.md §dispatch Step 1.5 — same CLI invocation, same injection rule.

**Step 2: Dispatch gmd-verifier with explicit `<stages>` block (stage_1 + stage_2).**

```
Task(
  prompt="Verify phase {phase_number} goal achievement with two-stage flow.

<objective>
Stage 1: goal-backward verification (must_haves -> truths -> artifacts -> wiring -> requirements)
Stage 2: code quality review on git diff ${BASE_SHA}..${HEAD_SHA}
Create VERIFICATION.md with both stages as distinct sections (## Goal Achievement / ## Code Quality Review).
</objective>

<stages>
stage_1: goal_backward
stage_2: code_quality
require_both: true
</stages>

<diff_range>
base: ${BASE_SHA}
head: ${HEAD_SHA}
</diff_range>

{VAULT_CONTEXT_BLOCK}

{REGRESSION_XREF_BLOCK}

Phase directory: {phase_dir}
Phase goal: {goal from ROADMAP.md}
Phase requirement IDs: {phase_req_ids}
Check must_haves against actual codebase.
Cross-reference requirement IDs from PLAN frontmatter against REQUIREMENTS.md — every ID MUST be accounted for.",
  subagent_type="gmd-verifier",
  model="{verifier_model}"
)
```

**Step 3: Read combined status (stage_1 x stage_2 per verifier mapping):**
```bash
grep "^status:" "$PHASE_DIR"/*-VERIFICATION.md | cut -d: -f2 | tr -d ' '
```

| Status                 | Action                                                        |
| ---------------------- | ------------------------------------------------------------- |
| `passed`               | → update_roadmap                                              |
| `passed_with_warnings` | Present stage-2 Important findings; ask user to acknowledge   |
| `code_quality_gaps`    | Present stage-2 Critical findings; block; offer fix plan      |
| `human_needed`         | Present items for human testing, get approval or feedback    |
| `gaps_found`           | Present gap summary, offer `/gmd:plan-phase {phase} --gaps`   |

**If human_needed:**
```
## ✓ Phase {X}: {Name} — Human Verification Required

All automated checks passed. {N} items need human testing:

{From VERIFICATION.md human_verification section}

"approved" → continue | Report issues → gap closure
```

**If gaps_found:**
```
## ⚠ Phase {X}: {Name} — Gaps Found

**Score:** {N}/{M} must-haves verified
**Report:** {phase_dir}/{phase_num}-VERIFICATION.md

### What's Missing
{Gap summaries from VERIFICATION.md}

---
## ▶ Next Up

`/gmd:plan-phase {X} --gaps`

<sub>`/clear` first → fresh context window</sub>

Also: `cat {phase_dir}/{phase_num}-VERIFICATION.md` — full report
Also: `/gmd:verify-work {X}` — manual testing first
```

Gap closure cycle: `/gmd:plan-phase {X} --gaps` reads VERIFICATION.md → creates gap plans with `gap_closure: true` → user runs `/gmd:execute-phase {X} --gaps-only` → verifier re-runs.
</step>

<step name="update_roadmap">
**Mark phase complete and update all tracking files:**

```bash
COMPLETION=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" phase complete "${PHASE_NUMBER}")
```

The CLI handles:
- Marking phase checkbox `[x]` with completion date
- Updating Progress table (Status → Complete, date)
- Updating plan count to final
- Advancing STATE.md to next phase
- Updating REQUIREMENTS.md traceability

Extract from result: `next_phase`, `next_phase_name`, `is_last_phase`.

```bash
# NOTE-01 bundling: judgment notes are self-staged by `code-notes add` but live under the
# gitignored .planning/codebase/ — name them here so they land in THIS phase-docs commit
# (never leak into a later unrelated one). Guarded: a note-less phase is a no-op.
git add -f .planning/codebase/_notes/ 2>/dev/null || true

node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" commit "docs(phase-{X}): complete phase execution" --files "${ROADMAP_PATH}" "${STATE_PATH}" "${REQS_PATH}" {phase_dir}/*-VERIFICATION.md
```
</step>

## G1 Workflow-Boundary Maintenance Sweep (SYNC-03)

With the phase summary committed, run `vault-maintain --core` to sweep the vault: regenerate `Maps/Cross-Scope-Dependencies.md` and `Maps/_Test-Coverage-Map.md`, run schema-validate, refresh status. This is the G1 layer of the K-mixed sync cadence (per SPEC §11.4 + Phase 21 Decision 1). Failures are recoverable — the SessionStart 24h hook is the safety net, and the next workflow boundary sweeps again.

```bash
node bin/gmd-tools.cjs vault-maintain --core || {
  echo "vault-maintain --core failed at workflow boundary (recoverable; SessionStart 24h hook will retry)" >&2
}
```

Why here: the phase-summary write changed vault state. Sweeping before the workflow ends keeps the next phase's planner working from a fresh `_Cross-Scope-Map`. Why fail-open: a transient failure in maintain should never block phase completion — freshness is best-effort at workflow boundaries.

## Post-Workflow Vault Extraction (J1)

After the phase SUMMARY.md rollup is committed, extract knowledge candidates to `.vault/Knowledge/_inbox/`.

```bash
# Locate config (Phase 17 idiom)
HAS_CFG=""
if [[ -f get-magic-done/config.json ]]; then HAS_CFG="get-magic-done/config.json"
elif [[ -f config.json ]]; then HAS_CFG="config.json"
fi

# Gate on components.obsidian.enabled
if [[ -z "$HAS_CFG" ]] || [[ "$(jq -r '.components.obsidian.enabled // false' "$HAS_CFG" 2>/dev/null)" != "true" ]]; then
  echo "[J1] vault-extract-knowledge skipped: obsidian component disabled" >&2
else
  node bin/gmd-tools.cjs vault-extract-knowledge \
    --trigger J1 \
    --source-files "${PHASES_DIR}/${PHASE}/${PHASE}-SUMMARY.md" \
    --caller execute-phase \
    --phase "${PHASE}" \
  || echo "[J1] extraction returned non-zero — continuing; check .vault/_logs/" >&2
fi
```

**Flag-form rule (load-bearing):** every flag uses space separator. `--trigger J1`, NOT `--trigger=J1`. `--source-files "<path>"`, NOT `--source=<path>`. The parseAllFlags tokenizer at bin/gmd-tools.cjs:182 silently drops equals-form tokens — hooks would appear to run but extract nothing.

**Failure is non-fatal.** Extraction is additive enrichment; if it fails, the host workflow (phase complete) still succeeds.

<step name="offer_next">

**Exception:** If `gaps_found`, the `verify_phase_goal` step already presents the gap-closure path (`/gmd:plan-phase {X} --gaps`). No additional routing needed — skip auto-advance.

**No-transition check (spawned by auto-advance chain):**

Parse `--no-transition` flag from $ARGUMENTS.

**If `--no-transition` flag present:**

Execute-phase was spawned by plan-phase's auto-advance. Do NOT run transition.md.
After verification passes and roadmap is updated, return completion status to parent:

```
## PHASE COMPLETE

Phase: ${PHASE_NUMBER} - ${PHASE_NAME}
Plans: ${completed_count}/${total_count}
Verification: {Passed | Gaps Found}

[Include aggregate_results output]
```

STOP. Do not proceed to auto-advance or transition.

**If `--no-transition` flag is NOT present:**

**Auto-advance detection:**

1. Parse `--auto` flag from $ARGUMENTS
2. Read both the chain flag and user preference (chain flag already synced in init step):
   ```bash
   AUTO_CHAIN=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" config-get workflow._auto_chain_active 2>/dev/null || echo "false")
   AUTO_CFG=$(node "$HOME/.claude/get-magic-done/bin/gmd-tools.cjs" config-get workflow.auto_advance 2>/dev/null || echo "false")
   ```

**If `--auto` flag present OR `AUTO_CHAIN` is true OR `AUTO_CFG` is true (AND verification passed with no gaps):**

```
╔══════════════════════════════════════════╗
║  AUTO-ADVANCING → TRANSITION             ║
║  Phase {X} verified, continuing chain    ║
╚══════════════════════════════════════════╝
```

Execute the transition workflow inline (do NOT use Task — orchestrator context is ~10-15%, transition needs phase completion data already in context):

Read and follow `C:/Users/Christopher/.claude/get-magic-done/workflows/transition.md`, passing through the `--auto` flag so it propagates to the next phase invocation.

**If neither `--auto` nor `AUTO_CFG` is true:**

The workflow ends. The user runs `/gmd:progress` or invokes the transition workflow manually.
</step>

</process>

<context_efficiency>
Orchestrator: ~10-15% context. Subagents: fresh 200k each. No polling (Task blocks). No context bleed.
</context_efficiency>

<failure_handling>
- **classifyHandoffIfNeeded false failure:** Agent reports "failed" but error is `classifyHandoffIfNeeded is not defined` → Claude Code bug, not GMD. Spot-check (SUMMARY exists, commits present) → if pass, treat as success
- **Agent fails mid-plan:** Missing SUMMARY.md → report, ask user how to proceed
- **Dependency chain breaks:** Wave 1 fails → Wave 2 dependents likely fail → user chooses attempt or skip
- **All agents in wave fail:** Systemic issue → stop, report for investigation
- **Checkpoint unresolvable:** "Skip this plan?" or "Abort phase execution?" → record partial progress in STATE.md
</failure_handling>

<resumption>
Re-run `/gmd:execute-phase {phase}` → discover_plans finds completed SUMMARYs → skips them → resumes from first incomplete plan → continues wave execution.

STATE.md tracks: last completed plan, current wave, pending checkpoints.
</resumption>

<!-- PLAN-07 Audit: PASS — 2026-04-10
--auto flag: present (offer_next step, checkpoint_handling).
Chain flag (_auto_chain_active): present (initialize step sync, checkpoint_handling).
Auto-checkpoint handling:
  - Auto-approve human-verify: present (checkpoint_handling).
  - Auto-select first option for decisions: present (checkpoint_handling).
Also verified in plan-phase.md: --auto flag and auto-advance chain present.
-->

<!-- PLAN-08 Audit: PASS — 2026-04-10
Wave grouping from plan frontmatter: present (discover_and_group_plans via phase-plan-index).
Sequential waves: present (execute_waves: "Execute each wave in sequence").
Parallel plans within waves: present (parallelization config).
phase-plan-index CLI command: present (discover_and_group_plans step).
Dependency resolution for wave ordering: present (depends_on in plan frontmatter).
-->
