* enhancement(#558): add liveness hints to all GSD spawn announcements Append '(runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)' inline to every ◆ Spawning… banner and subagent dispatch instruction across 26 workflows. Silent subagents look identical to frozen sessions — this note sets the expectation so users wait instead of killing healthy in-progress work. Changes: - references/ui-brand.md: document liveness convention under Spawning Indicators - 10 banner workflows: append liveness note to ◆ Spawning… lines in-place - 18 subagent-only workflows: add print instruction with liveness phrase - tests/spawn-liveness-banner.test.cjs: new test; fails if any workflow with subagent_type omits 'runs in a subagent' - docs/USER-GUIDE.md: troubleshooting entry for frozen-looking spawns - .changeset/558-spawn-liveness-banner.md: changeset fragment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): add missing pr field to changeset fragment The changeset lint requires pr: <NNN> in frontmatter; the fragment was written without it, causing parse.cjs to reject it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): address codex review — missed spawns and tighten test - plan-phase.md: add liveness note to chunked outline planner and per-plan chunked planner banners (two missed ◆ Spawning… lines) - quick.md: add liveness note to research banner and add missing display line before planner spawn in Step 5 - plan-review-convergence.md: add liveness note to initial planning and review-agent spawn Display lines - docs-update.md: add Print instructions with liveness note before gsd-doc-verifier spawns in Phase 1 and Phase 2 - autonomous.md: add Print instruction with liveness note before background plan-phase agent dispatch in step 3b - tests/spawn-liveness-banner.test.cjs: replace single file-level check with two assertions: (1) every ◆ Spawning… banner line carries the phrase on that line (2) every file with subagent_type contains the phrase somewhere The tighter test would have caught all five missed spawns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): tighten spawn-liveness test regex to catch spawn-word-anywhere variants Previous SPAWN_BANNER_RE only matched ◆ immediately followed by Spawning|spawning. Replace with /◆[^\n]*\bspawning?\b/i which matches the spawn word anywhere on the ◆ line — catching "◆ Chunked mode: spawning outline planner..." and similar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): rename changeset to PR number 566 and correct pr field Changeset was filed as 558-spawn-liveness-banner.md (issue#) but the convention is the PR number. Renamed to 566-spawn-liveness-banner.md and updated pr: 558 → pr: 566 so release notes link to the right PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
9.5 KiB
After UAT finds gaps, spawn one debug agent per gap. Each agent investigates autonomously with symptoms pre-filled from UAT. Collect root causes, update UAT.md gaps with diagnosis, then hand off to plan-phase --gaps with actual diagnoses.
Orchestrator stays lean: parse gaps, spawn agents, collect results, update UAT.
<available_agent_types> Valid GSD subagent types (use exact names — do not fall back to 'general-purpose'):
- gsd-debugger — Diagnoses and fixes issues </available_agent_types>
Debug files use the .planning/debug/ path (hidden directory with leading dot).
<core_principle> Diagnose before planning fixes.
UAT tells us WHAT is broken (symptoms). Debug agents find WHY (root cause). plan-phase --gaps then creates targeted fixes based on actual causes, not guesses.
Without diagnosis: "Comment doesn't refresh" → guess at fix → maybe wrong With diagnosis: "Comment doesn't refresh" → "useEffect missing dependency" → precise fix </core_principle>
**Extract gaps from UAT.md:**Read the "Gaps" section (YAML format):
- truth: "Comment appears immediately after submission"
status: failed
reason: "User reported: works but doesn't show until I refresh the page"
severity: major
test: 2
artifacts: []
missing: []
For each gap, also read the corresponding test from "Tests" section to get full context.
Build gap list:
gaps = [
{truth: "Comment appears immediately...", severity: "major", test_num: 2, reason: "..."},
{truth: "Reply button positioned correctly...", severity: "minor", test_num: 5, reason: "..."},
...
]
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees 2>/dev/null || echo "true")
Report diagnosis plan to user:
## Diagnosing {N} Gaps
Spawning parallel debug agents to investigate root causes:
| Gap (Truth) | Severity |
|-------------|----------|
| Comment appears immediately after submission | major |
| Reply button positioned correctly | minor |
| Delete removes comment | blocker |
Each agent will:
1. Create DEBUG-{slug}.md with symptoms pre-filled
2. Investigate autonomously (read code, form hypotheses, test)
3. Return root cause
This runs in parallel - all gaps investigated simultaneously.
AGENT_SKILLS_DEBUGGER=$(gsd_run query agent-skills gsd-debugger)
EXPECTED_BASE=$(git rev-parse HEAD)
Spawn debug agents in parallel:
For each gap, fill the debug-subagent-prompt template and spawn:
Print: ◆ Spawning diagnostics agent... (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)
Agent(
prompt=filled_debug_subagent_prompt + "\n\n<worktree_branch_check>\nFIRST ACTION: assert this is a disposable worktree branch before any repair. Run:\n```bash\nHEAD_REF=$(git symbolic-ref --quiet HEAD || echo \"DETACHED\")\nACTUAL_BRANCH=$(git rev-parse --abbrev-ref HEAD)\nif [ \"$HEAD_REF\" = \"DETACHED\" ] || echo \"$ACTUAL_BRANCH\" | grep -Eq '^(main|master|develop|trunk|release/.*)$'; then\n echo \"FATAL: diagnose worktree HEAD on '$ACTUAL_BRANCH'; refusing reset --hard on a protected branch.\" >&2\n exit 1\nfi\nif ! echo \"$ACTUAL_BRANCH\" | grep -Eq '^worktree-agent-[A-Za-z0-9._/-]+$'; then\n echo \"FATAL: diagnose worktree HEAD '$ACTUAL_BRANCH' is not in the worktree-agent-* namespace; refusing reset --hard.\" >&2\n exit 1\nfi\nACTUAL_BASE=$(git merge-base HEAD {EXPECTED_BASE})\nif [ \"$ACTUAL_BASE\" != \"{EXPECTED_BASE}\" ]; then\n git reset --hard {EXPECTED_BASE}\n [ \"$(git rev-parse HEAD)\" != \"{EXPECTED_BASE}\" ] && { echo \"ERROR: Could not correct worktree base\"; exit 1; }\nfi\n```\nFixes EnterWorktree creating branches from main on all platforms while preventing protected-branch data loss.\n</worktree_branch_check>\n\n<files_to_read>\n- {phase_dir}/{phase_num}-UAT.md\n- .planning/STATE.md\n</files_to_read>\n${AGENT_SKILLS_DEBUGGER}",
subagent_type="gsd-debugger",
${USE_WORKTREES !== "false" ? 'isolation="worktree",' : ''}
description="Debug: {truth_short}"
)
ORCHESTRATOR RULE — CODEX RUNTIME: After calling Agent() above to spawn debug agent(s), stop working on this task immediately. Do not read more files, edit code, or run tests related to these gaps while the subagent(s) are active. Wait for all subagents to return before proceeding. This prevents duplicate work, conflicting edits, and wasted context.
All agents spawn in single message (parallel execution).
Template placeholders:
{truth}: The expected behavior that failed{expected}: From UAT test{actual}: Verbatim user description from reason field{errors}: Any error messages from UAT (or "None reported"){reproduction}: "Test {test_num} in UAT"{timeline}: "Discovered during UAT"{goal}:find_root_cause_only(UAT flow - plan-phase --gaps handles fixes){slug}: Generated from truth
Each agent returns with:
## ROOT CAUSE FOUND
**Debug Session:** ${DEBUG_DIR}/{slug}.md
**Root Cause:** {specific cause with evidence}
**Evidence Summary:**
- {key finding 1}
- {key finding 2}
- {key finding 3}
**Files Involved:**
- {file1}: {what's wrong}
- {file2}: {related issue}
**Suggested Fix Direction:** {brief hint for plan-phase --gaps}
Parse each return to extract:
- root_cause: The diagnosed cause
- files: Files involved
- debug_path: Path to debug session file
- suggested_fix: Hint for gap closure plan
If agent returns ## INVESTIGATION INCONCLUSIVE:
- root_cause: "Investigation inconclusive - manual review needed"
- Note which issue needs manual attention
- Include remaining possibilities from agent return
For each gap in the Gaps section, add artifacts and missing fields:
- truth: "Comment appears immediately after submission"
status: failed
reason: "User reported: works but doesn't show until I refresh the page"
severity: major
test: 2
root_cause: "useEffect in CommentList.tsx missing commentCount dependency"
artifacts:
- path: "src/components/CommentList.tsx"
issue: "useEffect missing dependency"
missing:
- "Add commentCount to useEffect dependency array"
- "Trigger re-render when new comment added"
debug_session: .planning/debug/comment-not-refreshing.md
Update status in frontmatter to "diagnosed".
Commit the updated UAT.md:
gsd_run query commit "docs({phase_num}): add root causes from diagnosis" --files ".planning/phases/XX-name/{phase_num}-UAT.md"
Display:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► DIAGNOSIS COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| Gap (Truth) | Root Cause | Files |
|-------------|------------|-------|
| Comment appears immediately | useEffect missing dependency | CommentList.tsx |
| Reply button positioned correctly | CSS flex order incorrect | ReplyButton.tsx |
| Delete removes comment | API missing auth header | api/comments.ts |
Debug sessions: ${DEBUG_DIR}/
Proceeding to plan fixes...
Return to verify-work orchestrator for automatic planning. Do NOT offer manual next steps - verify-work handles the rest.
<context_efficiency> Agents start with symptoms pre-filled from UAT (no symptom gathering). Agents only diagnose—plan-phase --gaps handles fixes (no fix application). </context_efficiency>
<failure_handling> Agent fails to find root cause:
- Mark gap as "needs manual review"
- Continue with other gaps
- Report incomplete diagnosis
Agent times out:
- Check DEBUG-{slug}.md for partial progress
- Can resume with /gsd:debug
All agents fail:
- Something systemic (permissions, git, etc.)
- Report for manual investigation
- Fall back to plan-phase --gaps without root causes (less precise) </failure_handling>
<success_criteria>
- Gaps parsed from UAT.md
- Debug agents spawned in parallel
- Root causes collected from all agents
- UAT.md gaps updated with artifacts and missing
- Debug sessions saved to ${DEBUG_DIR}/
- Hand off to verify-work for automatic planning </success_criteria>