feat: add /gsd-spec-phase — Socratic spec refinement with ambiguity scoring (#2213) (#2322)

Introduces `/gsd-spec-phase <phase>` as an optional pre-step before discuss-phase.
Clarifies WHAT a phase delivers (requirements, boundaries, acceptance criteria) with
quantitative ambiguity scoring before discuss-phase handles HOW to implement.

- `commands/gsd/spec-phase.md` — slash command routing to workflow
- `get-shit-done/workflows/spec-phase.md` — full Socratic interview loop (up to 6
  rounds, 5 rotating perspectives: Researcher, Simplifier, Boundary Keeper, Failure
  Analyst, Seed Closer) with weighted 4-dimension ambiguity gate (≤ 0.20 to write SPEC.md)
- `get-shit-done/templates/spec.md` — SPEC.md template with falsifiable requirements
  (Current/Target/Acceptance per requirement), Boundaries, Acceptance Criteria,
  Ambiguity Report, and Interview Log; includes two full worked examples
- `get-shit-done/workflows/discuss-phase.md` — new `check_spec` step detects
  `{padded_phase}-SPEC.md` at startup; displays "Found SPEC.md — N requirements
  locked. Focusing on implementation decisions."; `analyze_phase` respects `spec_loaded`
  flag to skip "what/why" gray areas; `write_context` emits `<spec_lock>` section
  with boundary summary and canonical ref to SPEC.md
- `docs/ARCHITECTURE.md` — update command/workflow counts (74→75, 71→72)

Closes #2213

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-16 17:08:30 -04:00
committed by GitHub
parent f101a5025e
commit 2df700eb81
5 changed files with 684 additions and 5 deletions

View File

@@ -212,7 +212,30 @@ This step cannot be skipped. Before proceeding to `check_existing` or any other
Write these answers inline before continuing. If a blocking anti-pattern cannot be answered from the context in `.continue-here.md`, stop and ask the user for clarification.
**If no `.continue-here.md` exists, or no `blocking` rows are found:** Proceed directly to `check_existing`.
**If no `.continue-here.md` exists, or no `blocking` rows are found:** Proceed directly to `check_spec`.
</step>
<step name="check_spec">
Check if a SPEC.md (from `/gsd-spec-phase`) exists for this phase. SPEC.md locks requirements before implementation decisions — if present, this discussion focuses on HOW to implement, not WHAT to build.
```bash
ls ${phase_dir}/*-SPEC.md 2>/dev/null | grep -v AI-SPEC | head -1 || true
```
**If SPEC.md is found:**
1. Read the SPEC.md file.
2. Count the number of requirements (numbered items in the `## Requirements` section).
3. Display:
```
Found SPEC.md — {N} requirements locked. Focusing on implementation decisions.
```
4. Set internal flag `spec_loaded = true`.
5. Store the requirements, boundaries, and acceptance criteria from SPEC.md as `<locked_requirements>` — these flow directly into CONTEXT.md without re-asking.
6. Continue to `check_existing`.
**If no SPEC.md is found:** Continue to `check_existing` with `spec_loaded = false` (default behavior unchanged).
**Note:** SPEC.md files named `AI-SPEC.md` (from `/gsd-ai-integration-phase`) are excluded — those serve a different purpose.
</step>
<step name="check_existing">
@@ -437,6 +460,12 @@ Analyze the phase to identify gray areas worth discussing. **Use both `prior_dec
- These are **pre-answered** — don't re-ask unless this phase has conflicting needs
- Note applicable prior decisions for use in presentation
2b. **SPEC.md awareness** — If `spec_loaded = true` (SPEC.md was found in `check_spec`):
- The `<locked_requirements>` from SPEC.md are pre-answered: Goal, Boundaries, Constraints, Acceptance Criteria.
- Do NOT generate gray areas about WHAT to build or WHY — those are locked.
- Only generate gray areas about HOW to implement: technical approach, library choices, UX/UI patterns, interaction details, error handling style.
- When presenting gray areas, include a note: "Requirements are locked by SPEC.md — discussing implementation decisions only."
3. **Gray areas by category** — For each relevant category (UI, UX, Behavior, Empty States, Content), identify 1-2 specific ambiguities that would change implementation. **Annotate with code context where relevant** (e.g., "You already have a Card component" or "No existing pattern for this").
4. **Skip assessment** — If no meaningful gray areas exist (pure infrastructure, clear-cut implementation, or all already decided in prior phases), the phase may not need discussion.
@@ -915,6 +944,12 @@ mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
**File location:** `${phase_dir}/${padded_phase}-CONTEXT.md`
**SPEC.md integration** — If `spec_loaded = true`:
- Add a `<spec_lock>` section immediately after `<domain>` (see template below).
- Add the SPEC.md file to `<canonical_refs>` with note "Locked requirements — MUST read before planning".
- Do NOT duplicate requirements text from SPEC.md into `<decisions>` — agents read SPEC.md directly.
- The `<decisions>` section contains only implementation decisions from this discussion.
**Structure the content by what was discussed:**
```markdown
@@ -930,6 +965,19 @@ mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
</domain>
[If spec_loaded = true, insert this section:]
<spec_lock>
## Requirements (locked via SPEC.md)
**{N} requirements are locked.** See `{padded_phase}-SPEC.md` for full requirements, boundaries, and acceptance criteria.
Downstream agents MUST read `{padded_phase}-SPEC.md` before planning or implementing. Requirements are not duplicated here.
**In scope (from SPEC.md):** [copy the "In scope" bullet list from SPEC.md Boundaries]
**Out of scope (from SPEC.md):** [copy the "Out of scope" bullet list from SPEC.md Boundaries]
</spec_lock>
<decisions>
## Implementation Decisions

View File

@@ -0,0 +1,262 @@
<purpose>
Clarify WHAT a phase delivers through a Socratic interview loop with quantitative ambiguity scoring.
Produces a SPEC.md with falsifiable requirements that discuss-phase treats as locked decisions.
This workflow handles "what" and "why" — discuss-phase handles "how".
</purpose>
<ambiguity_model>
Score each dimension 0.0 (completely unclear) to 1.0 (crystal clear):
| Dimension | Weight | Minimum | What it measures |
|-------------------|--------|---------|---------------------------------------------------|
| Goal Clarity | 35% | 0.75 | Is the outcome specific and measurable? |
| Boundary Clarity | 25% | 0.70 | What's in scope vs out of scope? |
| Constraint Clarity| 20% | 0.65 | Performance, compatibility, data requirements? |
| Acceptance Criteria| 20% | 0.70 | How do we know it's done? |
**Ambiguity score** = 1.0 − (0.35×goal + 0.25×boundary + 0.20×constraint + 0.20×acceptance)
**Gate:** ambiguity ≤ 0.20 AND all dimensions ≥ their minimums → ready to write SPEC.md.
A score of 0.20 means 80% weighted clarity — enough precision that the planner won't silently make wrong assumptions.
</ambiguity_model>
<interview_perspectives>
Rotate through these perspectives — each naturally surfaces different blindspots:
**Researcher (rounds 1–2):** Ground the discussion in current reality.
- "What exists in the codebase today related to this phase?"
- "What's the delta between today and the target state?"
- "What triggers this work — what's broken or missing?"
**Simplifier (round 2):** Surface minimum viable scope.
- "What's the simplest version that solves the core problem?"
- "If you had to cut 50%, what's the irreducible core?"
- "What would make this phase a success even without the nice-to-haves?"
**Boundary Keeper (round 3):** Lock the perimeter.
- "What explicitly will NOT be done in this phase?"
- "What adjacent problems is it tempting to solve but shouldn't?"
- "What does 'done' look like — what's the final deliverable?"
**Failure Analyst (round 4):** Find the edge cases that invalidate requirements.
- "What's the worst thing that could go wrong if we get the requirements wrong?"
- "What does a broken version of this look like?"
- "What would cause a verifier to reject the output?"
**Seed Closer (rounds 5–6):** Lock remaining undecided territory.
- "We have [dimension] at [score] — what would make it completely clear?"
- "The remaining ambiguity is in [area] — can we make a decision now?"
- "Is there anything you'd regret not specifying before planning starts?"
</interview_perspectives>
<process>
## Step 1: Initialize
```bash
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE}")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
```
Parse JSON for: `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `state_path`, `requirements_path`, `roadmap_path`, `planning_path`, `response_language`, `commit_docs`.
**If `response_language` is set:** All user-facing text in this workflow MUST be in `{response_language}`. Technical terms, code, and file paths stay in English.
**If `phase_found` is false:**
```
Phase [X] not found in roadmap.
Use /gsd-progress to see available phases.
```
Exit.
**Check for existing SPEC.md:**
```bash
ls ${phase_dir}/*-SPEC.md 2>/dev/null | grep -v AI-SPEC | head -1 || true
```
If SPEC.md already exists:
**If `--auto`:** Auto-select "Update it". Log: `[auto] SPEC.md exists — updating.`
**Otherwise:** Use AskUserQuestion:
- header: "Spec"
- question: "Phase [X] already has a SPEC.md. What do you want to do?"
- options:
- "Update it" — Revise and re-score
- "View it" — Show current spec
- "Skip" — Exit (use existing spec as-is)
If "View": Display SPEC.md, then offer Update/Skip.
If "Skip": Exit with message: "Existing SPEC.md unchanged. Run /gsd-discuss-phase [X] to continue."
If "Update": Load existing SPEC.md, continue to Step 3.
## Step 2: Scout Codebase
**Read these files before any questions:**
- `{requirements_path}` — Project requirements
- `{state_path}` — Decisions already made, current phase, blockers
- ROADMAP.md phase entry — Phase description, goals, canonical refs
**Grep the codebase** for code/files relevant to this phase goal. Look for:
- Existing implementations of similar functionality
- Integration points where new code will connect
- Test coverage gaps relevant to the phase
- Prior phase artifacts (SUMMARY.md, VERIFICATION.md) that inform current state
**Synthesize current state** — the grounded baseline for the interview:
- What exists today related to this phase
- The gap between current state and the phase goal
- The primary deliverable: what file/behavior/capability does NOT exist yet?
Confirm your current state synthesis internally. Do not present it to the user yet — you'll use it to ask precise, grounded questions.
## Step 3: First Ambiguity Assessment
Before questioning begins, score the phase's current ambiguity based only on what ROADMAP.md and REQUIREMENTS.md say:
```
Goal Clarity: [score 0.0–1.0]
Boundary Clarity: [score 0.0–1.0]
Constraint Clarity: [score 0.0–1.0]
Acceptance Criteria:[score 0.0–1.0]
Ambiguity: [score] ([calculate])
```
**If `--auto` and initial ambiguity already ≤ 0.20 with all minimums met:** Skip interview — derive SPEC.md directly from roadmap + requirements. Log: `[auto] Phase requirements are already sufficiently clear — generating SPEC.md from existing context.` Jump to Step 6.
**Otherwise:** Continue to Step 4.
## Step 4: Socratic Interview Loop
**Max 6 rounds.** Each round: 2–3 questions max. End round after user responds.
**Round selection by perspective:**
- Round 1: Researcher
- Round 2: Researcher + Simplifier
- Round 3: Boundary Keeper
- Round 4: Failure Analyst
- Rounds 5–6: Seed Closer (focus on lowest-scoring dimensions)
**After each round:**
1. Update all 4 dimension scores from the user's answers
2. Calculate new ambiguity score
3. Display the updated scoring:
```
After round [N]:
Goal Clarity: [score] (min 0.75) [✓ or ↑ needed]
Boundary Clarity: [score] (min 0.70) [✓ or ↑ needed]
Constraint Clarity: [score] (min 0.65) [✓ or ↑ needed]
Acceptance Criteria:[score] (min 0.70) [✓ or ↑ needed]
Ambiguity: [score] (gate: ≤ 0.20)
```
**Gate check after each round:**
If gate passes (ambiguity ≤ 0.20 AND all minimums met):
**If `--auto`:** Jump to Step 6.
**Otherwise:** AskUserQuestion:
- header: "Spec Gate Passed"
- question: "Ambiguity is [score] — requirements are clear enough to write SPEC.md. Proceed?"
- options:
- "Yes — write SPEC.md" → Jump to Step 6
- "One more round" → Continue interview
- "Done talking — write it" → Jump to Step 6
**If max rounds reached (6) and gate not passed:**
**If `--auto`:** Write SPEC.md anyway — flag unresolved dimensions. Log: `[auto] Max rounds reached. Writing SPEC.md with [N] dimensions below minimum. Planner will need to treat these as assumptions.`
**Otherwise:** AskUserQuestion:
- header: "Max Rounds"
- question: "After 6 rounds, ambiguity is [score]. [List dimensions still below minimum.] What would you like to do?"
- options:
- "Write SPEC.md anyway — flag gaps" → Write SPEC.md, mark unresolved dimensions in Ambiguity Report
- "Keep talking" → Continue (no round limit from here)
- "Abandon" → Exit without writing
**If `--auto` mode throughout:** Replace all AskUserQuestion calls above with Claude's recommended choice. Log decisions inline. Apply the same logic as `--auto` in discuss-phase.
**Text mode (`workflow.text_mode: true` or `--text` flag):** Use plain-text numbered lists instead of AskUserQuestion TUI menus.
## Step 5: (covered inline — ambiguity scoring is per-round)
## Step 6: Generate SPEC.md
Use the SPEC.md template from @~/.claude/get-shit-done/templates/spec.md.
**Requirements for every requirement entry:**
- One specific, testable statement
- Current state (what exists now)
- Target state (what it should become)
- Acceptance criterion (how to verify it was met)
**Vague requirements are rejected:**
- ✗ "The system should be fast"
- ✗ "Improve user experience"
- ✓ "API endpoint responds in < 200ms at p95 under 100 concurrent requests"
- ✓ "CLI command exits with code 1 and prints to stderr on invalid input"
**Count requirements.** The display in discuss-phase reads: "Found SPEC.md — {N} requirements locked."
**Boundaries must be explicit lists:**
- "In scope" — what this phase produces
- "Out of scope" — what it explicitly does NOT do (with brief reasoning)
**Acceptance criteria must be pass/fail checkboxes** — no "should feel good" or "looks reasonable."
**If any dimensions are below minimum**, mark them in the Ambiguity Report with: `⚠ Below minimum — planner must treat as assumption`.
Write to: `{phase_dir}/{padded_phase}-SPEC.md`
## Step 7: Commit
```bash
git add "${phase_dir}/${padded_phase}-SPEC.md"
git commit -m "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)"
```
If `commit_docs` is false: Skip commit. Note that SPEC.md was written but not committed.
## Step 8: Wrap Up
Display:
```
SPEC.md written — {N} requirements locked.
Phase {X}: {name}
Ambiguity: {final_score} (gate: ≤ 0.20)
Next: /gsd-discuss-phase {X}
discuss-phase will detect SPEC.md and focus on implementation decisions only.
```
</process>
<critical_rules>
- Every requirement MUST have current state, target state, and acceptance criterion
- Boundaries section is MANDATORY — cannot be empty
- "In scope" and "Out of scope" must be explicit lists, not narrative prose
- Acceptance criteria must be pass/fail — no subjective criteria
- SPEC.md is NEVER written if the user selects "Abandon"
- Do NOT ask about HOW to implement — that is discuss-phase territory
- Scout the codebase BEFORE the first question — grounded questions only
- Max 2–3 questions per round — do not frontload all questions at once
</critical_rules>
<success_criteria>
- Codebase scouted and current state understood before questioning
- All 4 dimensions scored after every round
- Gate passed OR user explicitly chose to write despite gaps
- SPEC.md contains only falsifiable requirements
- Boundaries are explicit (in scope / out of scope with reasoning)
- Acceptance criteria are pass/fail checkboxes
- SPEC.md committed atomically (when commit_docs is true)
- User directed to /gsd-discuss-phase as next step
</success_criteria>