基于 UAT 的并行缺陷诊断工作流:get-shit-done 的 diagnose-issues 全解析
【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done
导读
本文深入解析 get-shit-done 项目中diagnose-issues工作流的完整设计:当用户验收测试(UAT)发现功能缺口(gap)时,它如何编排多个gsd-debugger子代理并行调查根因,再将诊断结果回写进 UAT.md,交给plan-phase --gaps生成精准修复计划。读完本文,你将掌握"先诊断、后规划"的缺陷闭环方法论,以及其中的并行子代理编排、工作树安全守卫、UAT 缺口 YAML 数据结构等可复用的工程细节。文中所有命令、模板与流程均来自当前仓库的实际源码与文档。
一、为什么需要"诊断前置":从症状到根因的鸿沟
diagnose-issues工作流位于 get-shit-done/workflows/diagnose-issues.md,它的核心原则只有一句话:
Diagnose before planning fixes.
UAT 告诉系统"什么坏了"(症状),调试代理负责找出"为什么坏"(根因),plan-phase --gaps随后基于真实原因而非猜测创建针对性修复。文档用一组对比例子说明差异:
| 方式 | 症状 | 结论 | 后果 |
|---|---|---|---|
| 不做诊断 | "评论不刷新" | 猜一个修复 | 可能修错 |
| 做诊断 | "评论不刷新" | "useEffect 缺少依赖" | 精确修复 |
从架构视角看,这是典型的"WHAT 与 WHY 分离"设计:verify-work工作流负责生产"WHAT"(见 get-shit-done/workflows/verify-work.md 中的diagnose_issues步骤),diagnose-issues负责生产"WHY",plan-phase --gaps负责生产"HOW"。每一层只做一件事,上下文因此保持精简。
二、工作流定位:它如何融入 GSD 缺陷闭环
diagnose-issues不是独立命令,而是由verify-work在用户验收发现缺口后自动触发的编排层。在 get-shit-done/workflows/verify-work.md 的diagnose_issues步骤中:
{N} issues found. Diagnosing root causes... Spawning parallel debug agents to investigate each issue.其流程为:加载 diagnose-issues 工作流 → 为每个缺口并行派生调试代理 → 收集根因 → 更新 UAT.md → 交给plan_gap_closure。诊断运行是全自动的,无需用户提示;并行调查让额外开销最小化,同时让修复更准确。
闭环的后续环节由 get-shit-done/references/planner-gap-closure.md 定义:plan-phase --gaps读取status: diagnosed的 UAT.md,将每个缺口(truth、reason、artifacts、missing)分组为 gap closure 计划,最终由 commands/gsd/execute-phase.md 的--gaps-only标志执行。
三、编排者的五项职责:并行诊断全流程
编排者(orchestrator)保持精简:解析缺口、派生代理、收集结果、更新 UAT。完整流程分为五步。
3.1 parse_gaps:从 UAT.md 提取缺口
首先读取 UAT.md 的 "Gaps" 小节(YAML 格式):
- 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: []对每个缺口,还要读取 "Tests" 小节中对应的测试以获取完整上下文,然后构建缺口列表:
gaps = [ {truth: "Comment appears immediately...", severity: "major", test_num: 2, reason: "..."}, {truth: "Reply button positioned correctly...", severity: "minor", test_num: 5, reason: "..."}, ... ]这一结构的字段含义(与 get-shit-done/templates/UAT.md 的模板一致):truth是失败测试的预期行为,reason是用户原话描述,severity由verify-work从用户自然语言推断(blocker/major/minor/cosmetic),test是测试编号,artifacts与missing留待诊断阶段填充。
3.2 report_plan:向用户报告诊断计划
先读取工作树配置:
USE_WORKTREES=$(gsd-sdk query config-get workflow.use_worktrees 2>/dev/null || echo "true")然后输出诊断计划表:
## 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.3.3 spawn_agents:并行派生调试代理
这是整个工作流的技术核心。首先加载子代理技能与基线提交:
AGENT_SKILLS_DEBUGGER=$(gsd-sdk query agent-skills gsd-debugger) EXPECTED_BASE=$(git rev-parse HEAD)然后为每个缺口填充debug-subagent-prompt模板并并行派生(单条消息内派生全部代理):
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}" )这段派生代码包含三个值得注意的工程细节:
- 子代理类型:必须使用精确名称
gsd-debugger(定义见 agents/gsd-debugger.md),不能回退到general-purpose。 - 工作树隔离:当
workflow.use_worktrees未设为false时,每个代理在独立 worktree 中运行(isolation="worktree"),并行互不干扰。 - worktree 分支安全检查:代理的第一个动作必须是断言自己处于可丢弃的 worktree 分支上,才允许
reset --hard。检查逻辑包括:拒绝在 DETACHED 状态或main|master|develop|trunk|release/*等受保护分支上执行;分支名必须匹配^worktree-agent-[A-Za-z0-9._/-]+$命名空间;基线必须与EXPECTED_BASE一致,否则回滚重置。这一守卫同时解决了"EnterWorktree 在所有平台上从 main 创建分支"和"防止受保护分支数据丢失"两个问题。
此外,工作流明确要求:在调用 Agent() 派生调试代理后,编排者必须立即停止工作,不得读取更多文件、编辑代码或运行与这些缺口相关的测试,直到所有子代理返回。这一规则防止重复工作、冲突编辑和上下文浪费。
模板占位符如下:
| 占位符 | 含义 |
|---|---|
{truth} | 失败了的预期行为 |
{expected} | 来自 UAT 测试 |
{actual} | reason 字段中的用户原话 |
{errors} | UAT 中的错误信息(或 "None reported") |
{reproduction} | "Test {test_num} in UAT" |
{timeline} | "Discovered during UAT" |
{goal} | find_root_cause_only(UAT 流程,修复交给 plan-phase --gaps) |
{slug} | 由 truth 生成 |
3.4 collect_results:收集根因
每个代理返回结构化诊断结果:
## 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}编排者解析出四个字段:root_cause、files、debug_path(调试会话文件路径)、suggested_fix(供缺口闭合计划参考)。如果代理返回## INVESTIGATION INCONCLUSIVE,则根因记为"Investigation inconclusive - manual review needed",并保留代理返回的剩余可能性。
3.5 update_uat:将诊断回写 UAT.md
对 Gaps 小节中的每个缺口,补充root_cause、artifacts、missing和debug_session字段:
- 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随后将 frontmatter 中的 status 更新为diagnosed,并提交:
gsd-sdk query commit "docs({phase_num}): add root causes from diagnosis" --files ".planning/phases/XX-name/{phase_num}-UAT.md"注意:UAT.md 模板中 Gaps 小节的 YAML 本身预置了
root_cause: ""、artifacts: []、missing: []、debug_session: ""四个待填充字段(见 get-shit-done/templates/UAT.md),diagnose-issues 正是这些字段的唯一写入方。完整的"测试完成 → 诊断 → 状态推进"生命周期同样在该模板的diagnosis_lifecycle小节中有说明。
3.6 report_results:汇报并移交
最后输出诊断完成报告:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 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...随后返回verify-work编排者进行自动规划。工作流强调:不要提供手动下一步选项——后续由 verify-work 处理。
四、上下文效率设计:症状预填与单一职责
diagnose-issues的两条上下文效率原则:
- 症状预填:代理启动时直接从 UAT 拿到
symptoms(expected / actual / errors / reproduction / timeline),跳过症状收集阶段。对应地,gsd-debugger在symptoms_prefilled: true模式下会跳过symptom_gathering,直接进入investigation_loop,并以status: "investigating"(而非 `gathering")创建调试文件。 - 只诊断不修复:
goal: find_root_cause_only模式下,调试代理在确认根因后即停止,跳过fix_and_verify,将根因交还给调用方。这保证了诊断阶段不产生代码变更,修复计划的唯一来源是plan-phase --gaps。
模板 get-shit-done/templates/debug-subagent-prompt.md 就是两者的载体:<mode>块中同时声明symptoms_prefilled和goal两个字段,<symptoms>块则直接携带 UAT 中的全部症状数据。
五、调试代理内部:诊断结果为何可信
虽然 diagnose-issues 只负责编排,但结果的可靠性来自 agents/gsd-debugger.md 的严格方法论,理解它有助于评估诊断质量:
- 可证伪性要求:好的假设必须能被实验推翻。"useEffect 缺少依赖" 优于"状态有问题"。
- 单一假设测试:一次只改一个变量,否则无法归因。
- 结构化推理检查点:在任何修复提议之前,必须填写五字段
reasoning_checkpoint(hypothesis、confirming_evidence、falsification_test、fix_rationale、blind_spots);五个字段填不出具体答案,就说明根因尚未确认。 - 调试文件协议:
.planning/debug/{slug}.md是调试代理的"大脑",包含 frontmatter 状态、Current Focus、Symptoms(不可变)、Eliminated(只追加)、Evidence(只追加)、Resolution。代理在每次动作之前更新文件,保证/clear后可从next_action精确续跑。文件结构详见 get-shit-done/templates/DEBUG.md。 - 知识库协议:已解决的会话会追加到
.planning/debug/knowledge-base.md,新会话在调查起点按关键词重叠(2+ 词)匹配既往根因,作为假设候选(而非确定结论)。
调试代理的返回值中还有一个Specialist Hint字段(根据涉及文件的扩展名和错误模式推断 typescript/react/swift/python/rust/go/ios/android/general),它在gsd-debug-session-manager(agents/gsd-debug-session-manager.md)中会被映射到对应的专家技能做修复评审——这是诊断链路上游机制的一部分,在 UAT 诊断(find_root_cause_only)场景中通常不触发。
六、故障处理与成功标准
6.1 失败处理策略
工作流为三种故障场景预定义了降级路径:
| 故障 | 处理方式 |
|---|---|
| 代理找不到根因 | 将该缺口标记为 "needs manual review",继续处理其他缺口,报告不完整诊断 |
| 代理超时 | 检查 DEBUG-{slug}.md 的部分进展,可用/gsd:debug恢复 |
| 所有代理均失败 | 通常是系统性问题(权限、git 等),上报人工调查;降级为不带根因的plan-phase --gaps(精度较低) |
6.2 成功标准
- [ ] 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其中${DEBUG_DIR}为.planning/debug(带前导点的隐藏目录),所有调试会话文件均保存在此。
七、从诊断到修复:下游消费链路
诊断数据在移交后继续驱动闭环:
- plan-phase --gaps:读取 UAT.md 的 Gaps 小节(此时含根因)。按 get-shit-done/references/planner-gap-closure.md,规划器按"同一 artifact、同一关注点、依赖顺序"将缺口分组为计划,每个
gap.missing条目转为一个<task>动作,生成带gap_closure: true标记的 PLAN.md。 - plan-checker 验证:
verify-work继续派生gsd-plan-checker验证修复计划,若发现问题则进入最多 3 轮的 planner ↔ checker 修订循环。 - execute-phase --gaps-only:修复计划就绪后,执行 commands/gsd/execute-phase.md 的
--gaps-only模式,只执行 gap closure 计划。
至此,"UAT 发现问题 → 并行诊断根因 → 基于根因规划修复 → 验证计划 → 定向执行"的完整链路闭合,每一条修复都建立在实际证据之上,而非猜测。
八、小结:可复用的编排模式
diagnose-issues工作流浓缩了一套值得借鉴的 Agent 编排模式:
- WHAT / WHY / HOW 分层:验收负责采集症状,诊断负责定位根因,规划负责生成修复,三层职责清晰、上下文各自精简;
- 并行与隔离:每个缺口一个子代理、一条消息内并行派生、worktree 隔离运行,配合分支命名空间守卫保证安全;
- 持久化状态:调试会话文件让任意代理可在
/clear后无缝续跑,知识库让既往根因成为新调查的起点; - 结构化契约:UAT.md 的 YAML 缺口、子代理的结构化返回、失败降级路径,共同构成了机器可解析的协作协议。
对任何采用"验收驱动开发 + 多代理协作"的工程团队而言,这套"先诊断、后规划"的闭环都是一份高价值的参考实现。
【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考