首页
/ 深入解析 `gsd-sdk query validate.health`:get-shit-done 规划目录完整性体检如何消除三类误报

深入解析 `gsd-sdk query validate.health`:get-shit-done 规划目录完整性体检如何消除三类误报

2026-09-07 16:46:32作者:劳婵绚Shirley

本文围绕 get-shit-done(GSD)SDK 查询处理器 validate.health 的最新修复展开:它针对真实工作流中高发的三类“健康体检误报”——999.X 待办清单(backlog)阶段目录、里程碑归档(milestone-archive)布局下的阶段目录,以及带描述符的 PLAN/SUMMARY 文件名配对——逐一修正判定逻辑。读完本文,你将理解 GSD 规划体系(.planning/)的目录布局约束、validate.health 的十余项检查清单与输出契约,并能直接通过 gsd-sdk query validate.health 对项目做准确、无噪声的完整性诊断。

该修复记录于 changeset 片段 .changeset/graceful-geese-tumble.md(PR 3479,类型 Fixed),其对应的全部实现与回归测试均可在此仓库内直接核对。


一、背景:为什么需要一个“会体检”的查询处理器

get-shit-done 是一个面向 Claude Code 的元提示(meta-prompting)与上下文工程系统,它以“规格驱动开发”为核心:每个项目在 .planning/ 目录下维护一套高度结构化的规划产物,包括 PROJECT.mdROADMAP.mdSTATE.mdconfig.json,以及 phases/(活动阶段目录)、milestones/(归档阶段目录)等。

由于这套规划文件既是 Agent 决定“下一步做什么”的依据,也是各 slash 命令(/gsd-plan-phase/gsd-execute-phase 等)的输入,规划目录一旦出现缺文件、错命名、编号断档,就会向下游放大为执行错误。因此仓库提供了验证类查询处理器(validate 家族)做“体检”,其中:

  • validate.consistency——跨文件一致性扫描(编号断档、PLAN/SUMMARY 配对、frontmatter 完整性等);
  • validate.health——最综合的 10+ 项完整性检查,支持 --repair 自动修复,是本文主角;
  • validate.agentsvalidate.context——分别校验 Agent 文件安装与上下文窗口利用率。

它们被统一注册在 validate.* 命令清单中(见 sdk/src/query/command-manifest.validate.ts),并由 sdk/src/query/command-family-handlers.ts 映射到实际执行函数。validate.health 的实现位于 sdk/src/query/validate.ts(TypeScript 原生实现,由旧版 verify.cjs 移植而来),其注册名 canonical: 'validate.health'、别名 validate healthmutation: falseoutputMode: 'json',即它是一个只读的 JSON 查询命令。

调用方式:SDK 查询、CLI 与 slash 命令

validate.health 有三种等价入口,均输出结构化 JSON:

# 1. SDK 查询(推荐,注册表中的规范化点号名或空格别名皆可)
gsd-sdk query validate.health
gsd-sdk query validate health

# 2. 旧版 CJS 入口(gsd-tools.cjs)
node gsd-tools.cjs validate health

# 3. Claude Code 内的 slash 命令
/gsd-health                 # 仅体检
/gsd-health --repair        # 体检并自动修复可恢复问题

其中 --repairvalidateHealth 处理器的核心参数(args.includes('--repair')),用于自动修复可恢复缺陷(见下文的修复清单)。若在本仓库源码目录内直接调用 SDK,可先构建 SDK 后执行 node ./sdk/dist/cli.js query validate.health(SDK 用法详见 sdk/README.md)。


二、validate.health 的检查清单与输出契约

2.1 输入前置:.planning/ 与 CWD 守卫

处理器首先执行“家目录守卫”(E010):若解析后的 projectDir 等于用户主目录,说明当前工作目录错误,此时体检会读到错误的 .planning/,处理器直接返回 status: 'error' 并给出修复建议 cd into your project directory and retry(见 sdk/src/query/validate.ts)。

随后建立两类路径基线:

  • planBase = .planning/
  • roadmapPath = .planning/ROADMAP.md

2.2 逐项检查(Check 1–10)

处理器按固定顺序执行以下检查(源码中的代码即各 Check 的注释锚点,全部位于 sdk/src/query/validate.ts):

检查 判定项 输出 issue
Check 1 .planning/ 目录是否存在 缺失报 E001
Check 2 PROJECT.md 是否存在,是否含 ## What This Is / ## Core Value / ## Requirements 三个必需小节 缺失报 E002,缺小节报 W001
Check 3 ROADMAP.md 是否存在 缺失报 E003
Check 4 STATE.md 是否存在及其引用的阶段是否合法 缺失报 E004(可修复);引用未声明阶段报 W002
Check 5 / 5b config.json 是否为合法 JSON、schema 校验、workflow.nyquist_validation 键是否存在 解析错误报 E005(可修复),model_profile 非法报 W004,缺文件报 W003,缺键报 W008
Check 6 阶段目录命名是否符合 NN-name 格式 不符报 W005
Check 7 孤立 PLAN(有 PLAN 无 SUMMARY) I001(仅信息)
Check 7b RESEARCH 中含 ## Validation Architecture 但缺 VALIDATION.md W009
Check 8 ROADMAP 与磁盘阶段目录双向同步 ROADMAP 有、磁盘无报 W006;磁盘有、ROADMAP 无报 W007
Check 9 STATE.md 当前阶段与 ROADMAP 完成状态交叉校验 状态不同步报 W011
Check 10 config.json 字段取值合法性(branching_strategycontext_window、分支模板占位符) 分别报 W012W015

其中 Check 4、Check 8 正是本文修复的三类误报中“里程碑归档目录”与“999.X 目录”所涉及的核心逻辑所在。

2.3 输出契约与状态推导

处理器把所有 issue 收集为 errors / warnings / info 三个数组,并按以下规则推导整体 statussdk/src/query/validate.ts):

  • 存在任何 errorbroken
  • 无 error 但有 warningdegraded
  • 全部干净 → healthy

输出 data 中还包含 repairable_count(可修复错误 + 可修复警告之和)以及 repairs_performed(执行过 --repair 时列出实际修复动作)。同时每个 issue 项带 codemessagefix 字段,便于 Agent 直接消费后给出处理建议。

2.4 --repair 的三种自动修复动作

当传入 --repair 且检测到可修复问题时,处理器会执行:

  • createConfig / resetConfig:写入一组“只含安全默认值”的 config.json(默认 model_profile: 'balanced'branching_strategy: 'none'workflow.nyquist_validation: true 等,见 sdk/src/query/validate.ts);
  • regenerateState:根据 ROADMAP 结构重新生成最小化 STATE.mdsdk/src/query/validate.ts);
  • addNyquistKey:为已有 config.jsonworkflow 补写 nyquist_validation: truesdk/src/query/validate.ts)。

值得注意的是:修复程序只写“已知安全”的默认值,绝不臆造项目语义,因此设计上避免把体检工具变成数据破坏者。


三、三类误报的本质与修复原理

Changeset 片段明确指出,本次修复让 validate.health 规避了三类误报(false-positive):

  1. 接受 999.X 待办清单阶段目录;
  2. 在做“ROADMAP 是否存在”类检查时识别里程碑归档阶段目录;
  3. 规范化带描述符的 PLAN/SUMMARY 文件名配对。

下面结合源码逐一展开。

3.1 第一类:接受 999.X backlog 阶段目录(消除错误 W005)

为什么会产生误报。 get-shit-done 的“待办清单停车区”(Backlog Parking Lot)设计规定:backlog 项使用 999.x 编号,使其天然落在活动阶段序列(0102…)之外(需求文档见 docs/FEATURES.md)。当一个 backlog 项被捕获时,会立刻创建对应的阶段目录,例如 .planning/phases/999.1-backlog-sweep/(目录布局在 docs/FEATURES.md,命令用法见 docs/COMMANDS.md)。

在早期版本的 Check 6 阶段目录命名检查中,目录名若不以“两位数字 + - + 描述”的形态出现,就会触发 W005(“doesn't follow NN-name format”)。但 999.1-backlog-sweep 这类目录由 /gsd-capture --backlog 合法产生,命名单本身满足仓库约定,却被误判为“格式异常”,导致健康项目始终处于 degraded 状态。

修复方式。 Check 6 的命名正则被放宽为兼容多位整数 + 可选小数段的形态:

// Check 6 阶段目录命名校验(W005),现接受 999.X backlog 目录
if (e.isDirectory() && !e.name.match(/^\d{2,}(?:\.\d+)*-[\w-]+$/)) {
  addIssue('warning', 'W005', `Phase directory "${e.name}" doesn't follow NN-name format`, ...);
}

即:段首要求“两位及以上数字”,随后允许 (?:\.\d+)* 的任意小数扩展(.1.2…),再跟 -[\w-]+999.1-backlog-sweep 完全匹配,而真正不规范的 bad_name 依旧会被正确拦截。

回归测试锚点。 sdk/src/query/validate.test.ts 的用例 does not emit W005 for 999.X backlog phase directory naming (#3473) 创建了 .planning/phases/999.1-backlog-sweep 后断言不出现指向该目录的 W005;同文件上方还保留了对 bad_name 触发 W005 的对照组用例,确保修复没有把命名检查“一刀切放掉”。

3.2 第二类:ROADMAP 存在性检查识别里程碑归档目录(消除错误 W006/W007)

背景:里程碑归档布局。 当一个里程碑 vX.Y 完成时,milestone.complete(或 SDK 专属的 phases.archive)会把活动阶段目录整体搬移到归档布局 .planning/milestones/<milestone>-phases/ 下(归档行为可见 tests/milestone-archive.test.cjsv1.0-phases 目录即归档产物)。也就是说,历史里程碑的阶段(例如 .planning/milestones/v1.7-phases/64-secondary-grader-fix/)不再位于扁平的 .planning/phases/ 下。

为什么会产生误报。 Check 8 做“ROADMAP ↔ 磁盘阶段目录”双向同步检查时,若只扫描扁平的 .planning/phases/,那么 ROADMAP 中已发货(SHIPPED)里程碑声明的阶段会找不到对应磁盘目录,从而误报 W006(“Phase in ROADMAP.md but no directory on disk”)。反向同理,只有归档目录、没有扁平目录的阶段可能误报 W007

修复方式(源码级三层配合):

  1. 枚举归档目录listMilestoneArchiveDirs 扫描 .planning/milestones/ 下所有匹配 /^v\d+.*-phases$/i 的目录,并按版本号数值排序(v1.10 排在 v1.2 之后),见 sdk/src/query/validate.ts
  2. 收集归档阶段 tokenforEachArchivedPhaseToken 遍历每个归档目录下的阶段子目录,用 PHASE_TOKEN_FROM_DIR_RE(兼容 CK-64-... 这类项目代码前缀命名)提取规范阶段号并回调,见 sdk/src/query/validate.ts
  3. 并入“磁盘有效阶段”集合:Check 8 在统计 diskPhases 后,把归档 token 一并并入(await forEachArchivedPhaseToken(planBase, (token) => diskPhases.add(token))),于是 ROADMAP 声明的历史阶段被认为“存在”,不再触发 W006;而 W007 仍只针对扁平活动目录中的“真孤儿”,不会把归档目录里的历史阶段当作当前多余阶段,见 sdk/src/query/validate.ts

同样的归档识别思路也用于 Check 4(W002,STATE.md 阶段引用合法性):forEachArchivedPhaseToken 把归档阶段的 token 视为合法引用,避免跨里程碑引用历史阶段被误报(sdk/src/query/validate.ts)。

回归测试锚点。 单元测试层:sdk/src/query/validate.test.ts 构造 ROADMAP 中“Phase 7”仅存在于 .planning/milestones/v1.0-phases/07-old-shipped-phase/ 的场景,断言不出现指向 Phase 7 的 W006sdk/src/query/validate.test.ts 反向验证纯归档阶段目录不触发 W007。集成测试层:tests/milestone-archive.test.cjs 直接通过 gsd-tools validate health 在归档布局项目上断言 Phase 64 无“no directory”类 W006。这些测试覆盖了 #3164(validate 家族识别归档布局)与 #3473 两个历史 issue 的回归诉求。

3.3 第三类:规范化 PLAN/SUMMARY 文件名配对(消除错误 I001)

为什么会产生误报。 GSD 的规划产物允许阶段文件带“描述符”(descriptor)。例如某阶段目录同时存在:

  • 68-01-scaffolding-PLAN.md(带描述符 scaffolding 的计划文件)
  • 68-01-SUMMARY.md(不带描述符的总结文件)

两者本质属于同一对 68-01。但 Check 7 的“孤儿计划”检查在早期版本按字面文件名比对,会认为 68-01-scaffolding-PLAN.md 没有对应的 68-01-scaffolding-SUMMARY.md,从而产生信息级误报 I001(“has no SUMMARY.md, may be in progress”)。虽然只是 info,但噪声化的 info 会污染状态推导与 Agent 决策。

修复方式。 引入规范化配对函数 canonicalPlanStem:把文件名主干中“阶段号-计划号”之后的描述符剥离,得到规范主干:

/**
 * Canonical plan stem used for PLAN/SUMMARY matching.
 * Example: `68-01-scaffolding` -> `68-01`.
 */
function canonicalPlanStem(stem: string): string {
  const m = stem.match(/^(\d+[A-Z]?(?:\.\d+)*-\d+)/i);
  return m ? m[1] : stem;
}

Check 7 先为每个 SUMMARY 记录其主干与规范主干,再判断每个 PLAN 是否存在与自身字面主干或规范主干匹配的 SUMMARY:

summaryBases.add(summaryBase);                      // e.g. "68-01"
summaryBases.add(canonicalPlanStem(summaryBase));   // 归一化后仍为 "68-01"

// 对每个 plan,只要 PLAN 主干或其规范化主干命中 SUMMARY 集合即视为成对
const canonicalBase = canonicalPlanStem(planBase2);
if (!summaryBases.has(planBase2) && !summaryBases.has(canonicalBase)) {
  addIssue('info', 'I001', `${e.name}/${plan} has no SUMMARY.md`, 'May be in progress');
}

这样 68-01-scaffolding-PLAN.md(规范主干 68-01)能与 68-01-SUMMARY.md 正确配对,I001 不再误报。这一规范化逻辑同时服务于 validate 家族另一处理器的一致性检查(sdk/src/query/validate.ts 定义了该函数,Check 7 使用之)。

回归测试锚点。 sdk/src/query/validate.test.ts 构造 .planning/phases/68-bug-surface/ 下仅含 68-01-scaffolding-PLAN.md68-01-SUMMARY.md 的场景,断言不产生指向该 PLAN 文件的 I001


四、从实现看设计:validate 家族为何值得信赖

把上述三处修复放在一起看,能提炼出 get-shit-done 验证体系的几个设计原则,这些都直接体现在代码与测试中:

  1. “目录布局变体”是被显式建模的一等公民。 归档布局、backlog 的 999.X 编号、项目代码前缀(如 CK-64-...)都不是异常,而是合法状态。验证器通过 listMilestoneArchiveDirsforEachArchivedPhaseTokencollectPhaseRoots 等辅助函数把布局变体显式纳入集合计算,而不是靠“忽略警告”来掩盖问题。
  2. 阶段号比较一律“规范化”后做。 无论是 STATE.md 引用(Check 4)、ROADMAP 同步(Check 8),还是文件名配对(Check 7),比较时都会把 64 / 64A / 06.1 / 0064 等变体归一到规范 token 或补零变体再比较(phaseVariants 与补零逻辑可见 sdk/src/query/validate.tssdk/src/query/validate.ts),既消除格式误报,也保证 22A 不会被误折叠成 22(有专门测试守护:does not alias 22A to 22 when suppressing W006)。
  3. issue 带 code + fix 建议,Agent 可直接执行。 每条 issue 都携带稳定的错误码(E001E015W001W015I001I010 等)与修复指引字符串,配合 repairable_count / --repair,形成了“体检 → 归因 → 自动修复 → 再验证”的闭环。

4.1 相关文档与进一步阅读


五、实战:如何验证你的项目已“健康”

以源码仓库或任意 GSD 项目为例,确认修复生效与整体体检无噪声:

# 在项目根目录执行体检(必须包含 .planning/)
gsd-sdk query validate.health

# 期望输出中 status 为 healthy / degraded,并给出结构化 issue 列表
# 若 ROADMAP 存在已发货里程碑,而其阶段已归档到 .planning/milestones/vX.Y-phases/,
# 则不应再出现指向这些历史阶段的 W006

对三类误报场景做针对性自检:

场景构造 修复前 修复后
存在 .planning/phases/999.1-backlog-sweep/ 错误 W005 W005
ROADMAP 声明 Phase 7,磁盘上仅有 .planning/milestones/v1.0-phases/07-old-shipped-phase/ 错误 W006 W006
同目录下仅 68-01-scaffolding-PLAN.md + 68-01-SUMMARY.md 错误 I001 I001

如需自动修复可恢复缺陷(重建缺失的 config.json / STATE.md、补 nyquist_validation 键),在确认这些文件确属丢失后执行:

gsd-sdk query validate.health --repair

若想对运行环境做上下文窗口利用率体检,可使用 /gsd-health --context(阈值规则:小于 60% 为 healthy,60%–70% 为 warning,达到 70% 及以上为 critical,见 sdk/src/query/validate.ts)。

需要提醒的适用前提:validate.health 的判定模型面向 GSD 自身生成的 .planning/ 结构,检查是否命中 .planning 目录、ROADMAP 阶段编号与目录命名约定等均以本仓库 sdk/src/query/validate.ts 中实现为准;若项目启用了 phase_naming: custom 或其它非默认规划布局,检查口径会相应走自定义分支(例如编号断档检查会整体跳过,见 sdk/src/query/validate.ts)。


结语

validate.health 的三类误报修复,是 get-shit-done “用工程化手段治理 AI 工作流”思路的缩影:验证器必须深刻理解自身的目录布局语义,把“归档”“backlog”“描述符命名”这些真实状态都当作合法输入,才能真正成为值得 Agent 信赖的体检仪。从 changeset 一行描述出发,本次修复在 sdk/src/query/validate.ts 中落实为命名正则放宽、归档 token 并入磁盘阶段集合、以及 PLAN/SUMMARY 规范化配对三处逻辑变更,并由 sdk/src/query/validate.test.tstests/milestone-archive.test.cjs 中的多组回归用例钉死,确保此后任何改动都不会让这三类误报“复活”。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.16 K
2.78 K
docsdocs
暂无描述
Markdown
904
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
934
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
606
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.02 K
1.03 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
399
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.07 K
537