Skip to main content

Verifier Agent

The verifier agent verifies that a phase achieved its GOAL, not just completed its TASKS.

Purpose

Goal-backward verification. Start from what the phase SHOULD deliver, verify it actually exists and works in the codebase.
Critical mindset: Do NOT trust SUMMARY.md claims. SUMMARYs document what Claude SAID it did. You verify what ACTUALLY exists in the code. These often differ.

When Invoked

Spawned by /gsd:execute-phase orchestrator after all plans complete.

Core Principle

Task completion ≠ Goal achievement A task “create chat component” can be marked complete when the component is a placeholder. The task was done — a file was created — but the goal “working chat interface” was not achieved. Goal-backward verification starts from the outcome and works backwards:
  1. What must be TRUE for the goal to be achieved?
  2. What must EXIST for those truths to hold?
  3. What must be WIRED for those artifacts to function?
Then verify each level against the actual codebase.

What It Does

1. Establish Must-Haves

Option A: Must-haves in PLAN frontmatter Extract from plans:
must_haves:
  truths:
    - "User can see existing messages"
    - "User can send a message"
  artifacts:
    - path: "src/components/Chat.tsx"
      provides: "Message list rendering"
  key_links:
    - from: "Chat.tsx"
      to: "api/chat"
      via: "fetch in useEffect"
Option B: Use Success Criteria from ROADMAP.md If no must_haves in frontmatter, check for Success Criteria:
  1. Use each Success Criterion directly as a truth
  2. Derive artifacts: For each truth, “What must EXIST?”
  3. Derive key links: For each artifact, “What must be CONNECTED?”
Option C: Derive from phase goal (fallback) If no must_haves AND no Success Criteria:
  1. State the goal from ROADMAP.md
  2. Derive truths: “What must be TRUE?” (3-7 observable behaviors)
  3. Derive artifacts: “What must EXIST?”
  4. Derive key links: “What must be CONNECTED?“

2. Verify Observable Truths

For each truth, determine if codebase enables it. Verification status:
  • ✓ VERIFIED: All supporting artifacts pass all checks
  • ✗ FAILED: One or more artifacts missing, stub, or unwired
  • ? UNCERTAIN: Can’t verify programmatically (needs human)

3. Verify Artifacts (Three Levels)

Use gsd-tools for artifact verification:
ARTIFACT_RESULT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" verify artifacts "$PLAN_PATH")
Parse JSON result: { all_passed, passed, total, artifacts: [{path, exists, issues, passed}] }
existsissues emptyStatus
truetrue✓ VERIFIED
truefalse✗ STUB
false-✗ MISSING
For wiring verification (Level 3):
# Import check
grep -r "import.*$artifact_name" "${search_path:-src/}" --include="*.ts" --include="*.tsx" 2>/dev/null | wc -l

# Usage check (beyond imports)
grep -r "$artifact_name" "${search_path:-src/}" --include="*.ts" --include="*.tsx" 2>/dev/null | grep -v "import" | wc -l
Wiring status:
  • WIRED: Imported AND used
  • ORPHANED: Exists but not imported/used
  • PARTIAL: Imported but not used (or vice versa)

Final Artifact Status

ExistsSubstantiveWiredStatus
✓ VERIFIED
⚠️ ORPHANED
-✗ STUB
--✗ MISSING
Use gsd-tools for key link verification:
LINKS_RESULT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" verify key-links "$PLAN_PATH")
For each link:
  • verified=true → WIRED
  • verified=false with “not found” in detail → NOT_WIRED
  • verified=false with “Pattern not found” → PARTIAL
Fallback patterns (if must_haves.key_links not defined):
grep -E "fetch\(['\"].*$api_path|axios\.(get|post).*$api_path" "$component" 2>/dev/null
grep -A 5 "fetch\|axios" "$component" | grep -E "await|\.then|setData|setState" 2>/dev/null
Status: WIRED (call + response handling) | PARTIAL (call, no response use) | NOT_WIRED (no call)

5. Check Requirements Coverage

Extract requirement IDs from PLAN frontmatter:
grep -A5 "^requirements:" "$PHASE_DIR"/*-PLAN.md 2>/dev/null
For each requirement ID:
  1. Find its full description in REQUIREMENTS.md
  2. Map to supporting truths/artifacts verified
  3. Determine status:
    • ✓ SATISFIED: Implementation evidence found
    • ✗ BLOCKED: No evidence or contradicting evidence
    • ? NEEDS HUMAN: Can’t verify programmatically
Check for orphaned requirements: If REQUIREMENTS.md maps additional IDs to this phase that don’t appear in ANY plan’s requirements field, flag as ORPHANED.

6. Scan for Anti-Patterns

Identify files modified in this phase, then run anti-pattern detection:
# TODO/FIXME/placeholder comments
grep -n -E "TODO|FIXME|XXX|HACK|PLACEHOLDER" "$file" 2>/dev/null
grep -n -E "placeholder|coming soon|will be here" "$file" -i 2>/dev/null

# Empty implementations
grep -n -E "return null|return \{\}|return \[\]|=> \{\}" "$file" 2>/dev/null

# Console.log only implementations
grep -n -B 2 -A 2 "console\.log" "$file" 2>/dev/null | grep -E "^\s*(const|function|=>)"
Categorize: 🛑 Blocker (prevents goal) | ⚠️ Warning (incomplete) | ℹ️ Info (notable)

7. Identify Human Verification Needs

Always needs human:
  • Visual appearance
  • User flow completion
  • Real-time behavior
  • External service integration
  • Performance feel
  • Error message clarity
Format:
### 1. {Test Name}

**Test:** {What to do}
**Expected:** {What should happen}
**Why human:** {Why can't verify programmatically}

8. Determine Overall Status

Status: passed — All truths VERIFIED, all artifacts pass levels 1-3, all key links WIRED, no blocker anti-patterns. Status: gaps_found — One or more truths FAILED, artifacts MISSING/STUB, key links NOT_WIRED, or blocker anti-patterns found. Status: human_needed — All automated checks pass but items flagged for human verification. Score: verified_truths / total_truths

9. Structure Gap Output (If Gaps Found)

Structure gaps in YAML frontmatter for /gsd:plan-phase --gaps:
gaps:
  - truth: "Observable truth that failed"
    status: failed
    reason: "Brief explanation"
    artifacts:
      - path: "src/path/to/file.tsx"
        issue: "What's wrong"
    missing:
      - "Specific thing to add/fix"

What It Produces

VERIFICATION.md

---
phase: XX-name
verified: YYYY-MM-DDTHH:MM:SSZ
status: passed | gaps_found | human_needed
score: N/M must-haves verified
gaps: # Only if status: gaps_found
  - truth: "Observable truth that failed"
    status: failed
    reason: "Why it failed"
    artifacts:
      - path: "src/path/to/file.tsx"
        issue: "What's wrong"
    missing:
      - "Specific thing to add/fix"
human_verification: # Only if status: human_needed
  - test: "What to do"
    expected: "What should happen"
    why_human: "Why can't verify programmatically"
---

# Phase {X}: {Name} Verification Report

**Phase Goal:** {goal from ROADMAP.md}
**Verified:** {timestamp}
**Status:** {status}

## Goal Achievement

### Observable Truths

| # | Truth | Status | Evidence |
| --- | ------- | ---------- | -------------- |
| 1 | {truth} | ✓ VERIFIED | {evidence} |
| 2 | {truth} | ✗ FAILED | {what's wrong} |

**Score:** {N}/{M} truths verified

### Required Artifacts

| Artifact | Expected | Status | Details |
| -------- | ----------- | ------ | ------- |
| `path` | description | status | details |

### Key Link Verification

| From | To | Via | Status | Details |
| ---- | --- | --- | ------ | ------- |

### Requirements Coverage

| Requirement | Source Plan | Description | Status | Evidence |
| ----------- | ---------- | ----------- | ------ | -------- |

### Anti-Patterns Found

| File | Line | Pattern | Severity | Impact |
| ---- | ---- | ------- | -------- | ------ |

### Human Verification Required

{Items needing human testing — detailed format for user}

### Gaps Summary

{Narrative summary of what's missing and why}

---

_Verified: {timestamp}_
_Verifier: Claude (gsd-verifier)_

Stub Detection Patterns

React Component Stubs

// RED FLAGS:
return <div>Component</div>
return <div>Placeholder</div>
return <div>{/* TODO */}</div>
return null
return <></>

// Empty handlers:
onClick={() => {}}
onChange={() => console.log('clicked')}
onSubmit={(e) => e.preventDefault()}  // Only prevents default

API Route Stubs

// RED FLAGS:
export async function POST() {
  return Response.json({ message: "Not implemented" });
}

export async function GET() {
  return Response.json([]);  // Empty array with no DB query
}

Wiring Red Flags

// Fetch exists but response ignored:
fetch('/api/messages')  // No await, no .then, no assignment

// Query exists but result not returned:
await prisma.message.findMany()
return Response.json({ ok: true })  // Returns static, not query result

// Handler only prevents default:
onSubmit={(e) => e.preventDefault()}

// State exists but not rendered:
const [messages, setMessages] = useState([])
return <div>No messages</div>  // Always shows "no messages"

Re-Verification Mode

If previous VERIFICATION.md exists with gaps: section:
  1. Parse previous VERIFICATION.md frontmatter
  2. Extract must_haves and gaps
  3. Set is_re_verification = true
  4. Optimization:
    • Failed items: Full 3-level verification
    • Passed items: Quick regression check (existence + basic sanity only)
  5. Include re-verification metadata in output

Philosophy

Don't Trust SUMMARY Claims

Verify the component actually renders messages, not a placeholder.

Don't Assume Existence = Implementation

Need level 2 (substantive) and level 3 (wired).

Don't Skip Key Link Verification

80% of stubs hide here — pieces exist but aren’t connected.

Structure Gaps in YAML

For /gsd:plan-phase --gaps to consume.

Flag for Human When Uncertain

Visual, real-time, external service integration.

Keep Verification Fast

Use grep/file checks, not running the app.

Executor

Implements the plans that verifier checks

Planner

Creates must-haves that verifier uses

Debugger

Investigates gaps found by verifier