Files
AGENTS/.pi/gsd/workflows/execute-milestone.md
2026-04-24 20:00:33 +02:00

12 KiB

Execution Context (pre-injected)

Roadmap:

State:

Progress:

execute-milestone workflow

Execute all planned phases in the current milestone with scope guardian, UAT gates, and configurable recovery.


Worktree Check (always first)

git worktree list

If not in an isolated worktree:

"Large-scale milestone execution should run in an isolated worktree to protect your main branch. Create one now? (y/n, default: y)"

If yes: Skill(skill="gsd-new-workspace", args="milestone-exec"), then continue in the new worktree. If no: warn once, proceed on current branch.


Mode Selection (step 1 - always second)

Ask the user ONE binary question:

"How should I behave when I hit a doubt, error, or scope deviation?"

  • Interactive - Stop and ask me; I'll guide you through it
  • Silent - Try to self-correct; only surface unrecoverable blockers

Store as MODE (interactive | silent). Do not ask again.


Phase Discovery

pi-gsd-tools roadmap analyze --raw
pi-gsd-tools progress json --raw

Build execution queue: phases with ≥1 PLAN.md and status ≠ Complete, in roadmap order.

If queue is empty: "All phases are already complete. Run /gsd-audit-milestone." Stop.


Per-Phase Execution Loop

For each pending phase N:

A. Scope Pre-check (lightweight, one LLM call)

Read:

  • .planning/REQUIREMENTS.md
  • Phase goal + success criteria from ROADMAP.md

Prompt (internal): "Does executing this phase risk implementing anything not covered by active requirements, or conflict with what previous phases delivered? Rate: low / medium / high. One sentence reason."

  • low - continue silently
  • medium - log in scope-log, continue
  • high + interactive - surface to user, ask: proceed / adjust phase goal / stop
  • high + silent - log prominently, continue, include in final report

B. Execute Phase

Skill(skill="gsd-execute-phase", args="${N}")

C. Scope Post-audit (full, one LLM call)

Read new SUMMARY.md files from the phase directory.

Check:

  1. Undelivered must-haves - PLAN.md must_haves entries absent from SUMMARY
  2. Scope creep - files modified that are outside this phase's stated scope
  3. Requirement drift - work done that has no matching REQUIREMENTS entry

Classify result as SCOPE_STATUS:

  • clean - continue
  • drift - log + warn, continue
  • violation - trigger recovery (see §F)

D. Verify

Skill(skill="gsd-verify-work", args="${N}")

Compute UAT pass rate = passing items / total items. Default threshold: 80%. Override with --uat-threshold N.

E. Gate Check

Condition Interactive Silent
UAT pass rate < threshold Ask: fix gaps now or continue? → Recovery loop
Context remaining < 20% Warn, ask: stop or continue? → Write HANDOFF, stop
SCOPE_STATUS = violation Surface details, ask → Recovery loop
All gates pass Continue to checkpoint Continue to checkpoint

F. Recovery Loop

When triggered:

1. pi-gsd-tools validate health --repair
2. Self-correct: identify root cause, patch, re-run verification
3. Re-check gates
4. Gates pass → continue to checkpoint
5. Still failing:
   - Interactive: explain issue, ask user how to resolve, loop from step 2
   - Silent: write HANDOFF files (see §G), stop

G. Hard Stop - HANDOFF Files

On unrecoverable stop, write two files matching original GSD pause-work convention:

.planning/HANDOFF.json (machine-readable, consumed by /gsd-resume-work):

{
  "stopped_at": "ISO-timestamp",
  "phase": "N",
  "phase_name": "phase name",
  "stop_reason": "uat_failure | scope_violation | context_exhausted | unrecoverable_error | audit_exhausted | audit_no_result",
  "outer_cycles": 0,
  "gaps_store": [],
  "debt_store": [],
  "gaps_phases_tried": [],
  "debt_phases_tried": [],
  "uat_pass_rate": 75,
  "scope_status": "violation",
  "phases_completed": ["1", "2", "3"],
  "phases_remaining": ["N", "N+1"],
  "scope_log": ["note 1", "note 2"],
  "next_action": "Run /gsd-execute-milestone --from N to resume"
}

.planning/phases/NN-name/.continue-here.md (human-readable):

---
phase: N
status: stopped
stop_reason: [reason]
last_updated: [timestamp]
---

## What happened
[Clear explanation of why execution stopped]

## State at stop
- UAT pass rate: X%
- Scope status: [clean/drift/violation]
- Scope notes: [any flags]

## How to resume
Run: /gsd-execute-milestone --from N
Or fix the specific issue first: [specific suggestion]

H. Checkpoint (on success)

pi-gsd-tools state update current_phase ${N}
pi-gsd-tools state update last_activity $(date -u +%Y-%m-%d)
pi-gsd-tools commit "chore: complete phase ${N}" --files .planning/

Announce: ✓ Phase ${N} complete - UAT: ${pass_rate}% Scope: ${scope_status}


After All Phases - Mode Split

Interactive mode

Do NOT auto-invoke the lifecycle. Surface the execution summary and hand back:

━━ execute-milestone: all phases done ━━━━━━━━━━━━
✓ Phases:   ${done}/${total} complete
📊 Avg UAT: ${avg_uat}%
⚠ Scope:   ${scope_flag_count} flag(s) (details above)

Next: /gsd-audit-milestone when you are ready to review
      and close the milestone.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Stop. The user owns the audit decision.


Silent mode - Auto Lifecycle

Only in silent mode. Display transition banner:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 All phases complete → lifecycle: audit → complete → cleanup
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Read config once:

  • config.workflow.auto_retry_audit (default: true)
  • config.workflow.auto_retry_audit_budget (default: 1)
  • config.workflow.auto_retry_tech_debt (default: true)
  • config.workflow.auto_retry_tech_debt_budget (default: 1)

Initialise accumulators (persist across the outer loop):

  • gaps_store = [] - unsatisfied requirements not yet resolved
  • debt_store = [] - tech debt items not yet resolved
  • gaps_phases_tried = [] - inserted phases attempted for gap closure
  • debt_phases_tried = [] - inserted phases attempted for debt resolution
  • outer_cycles = 0

OUTER LOOP - Full audit cycle

LABEL: outer_loop

Step A - Full audit

Skill(skill="gsd-audit-milestone")

If no result / malformed → Write HANDOFF (§G), stop.

Extract from audit result:

  • current_gaps[] - unsatisfied requirement IDs + affected phase numbers
  • current_debt[] - tech debt items + affected phase numbers

If both empty → AUDIT PASSED. Proceed to Step D (complete).


Step B - Gap closure loop (only if current_gaps non-empty)

If auto_retry_audit = false: add current_gaps to gaps_store, skip to Step C.

While current_gaps non-empty and auto_retry_audit_budget > 0:

1. Decrement auto_retry_audit_budget
2. Insert a gap-closure phase (decimal after last phase):
   Skill(skill="gsd-insert-phase", args="${last_phase}.${gap_cycle} 'Gap closure: ${gap_summary}'")
3. Plan it with gap context:
   Skill(skill="gsd-plan-phase", args="${new_phase} --auto")
   (Pass unsatisfied requirement details as planning context)
4. Execute it:
   Skill(skill="gsd-execute-phase", args="${new_phase}")
5. Track: append new_phase to gaps_phases_tried
6. Targeted re-audit - affected phases only:
   Skill(skill="gsd-audit-milestone", args="--phases ${gap_affected_phases}")
7. Re-read current_gaps from result
   - Resolved? current_gaps = [], break loop
   - Reduced? loop again if budget > 0
   - Same/worse? loop again if budget > 0

After loop:

  • If current_gaps empty → gaps resolved , gaps_store = []
  • If still non-empty → gaps_store = current_gaps (budget exhausted or disabled)

Step C - Tech debt loop (only if current_debt non-empty)

If auto_retry_tech_debt = false: add current_debt to debt_store, skip to final gate.

While current_debt non-empty and auto_retry_tech_debt_budget > 0:

1. Decrement auto_retry_tech_debt_budget
2. Insert a debt-resolution phase (decimal after last phase):
   Skill(skill="gsd-insert-phase", args="${last_phase}.${debt_cycle} 'Tech debt: ${debt_summary}'")
3. Plan it with debt context:
   Skill(skill="gsd-plan-phase", args="${new_phase} --auto")
   (Pass tech debt item details as planning context)
4. Execute it:
   Skill(skill="gsd-execute-phase", args="${new_phase}")
5. Track: append new_phase to debt_phases_tried
6. Targeted re-audit - affected phases only:
   Skill(skill="gsd-audit-milestone", args="--phases ${debt_affected_phases}")
7. Re-read current_debt from result
   - Resolved? current_debt = [], break loop
   - Reduced? loop again if budget > 0
   - gaps_found in re-audit? add to gaps_store, break (handled in next outer cycle)

After loop:

  • If current_debt empty → debt resolved , debt_store = []
  • If still non-empty → debt_store = current_debt

Final gate (end of outer loop body)

If gaps_store empty AND debt_store empty: → AUDIT CLEAN. Proceed to Step D.

If anything remains in stores:

  • Increment outer_cycles
  • If outer budget remaining (derived from max of both budgets > 0): → GOTO outer_loop (re-run full audit from top, fresh eyes)
  • If exhausted: → Write enriched HANDOFF (§G), stop.

Step D - Complete Milestone

Skill(skill="gsd-complete-milestone", args="${milestone_version}")

Verify archive produced:

ls .planning/milestones/v${milestone_version}-ROADMAP.md 2>/dev/null || true

If absent → Write HANDOFF, stop. Message: "complete-milestone did not produce archive files."

Step E - Cleanup

Skill(skill="gsd-cleanup")

Cleanup handles its own dry-run and confirmation internally.


Worktree Merge (both modes, after lifecycle or summary)

If running in an isolated worktree, ask:

"Merge this worktree back to your main branch? (y/n, default: y)"

If yes:

git checkout main
git merge --no-ff milestone-exec -m "feat: complete milestone ${milestone_version}"
git worktree remove milestone-exec

If no: leave the worktree open. Tell the user how to merge manually.


Final Banner (silent mode only, after full lifecycle)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 GSD ► EXECUTE-MILESTONE ▸ COMPLETE 🎉
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Milestone: ${milestone_version} - ${milestone_name}
 Phases:    ${done}/${total} complete
 Avg UAT:   ${avg_uat}%
 Lifecycle: audit ✅ → complete ✅ → cleanup ✅

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━