【免费下载链接】gsd-core
Git. Ship. Done - Core
导读
本文围绕 gsd-core 仓库中一次针对健康诊断规则 W019 的修复展开:RETROSPECTIVE.md被正式写入CANONICAL_EXACT注册表(位于 src/artifacts.cts),使得gsd-health(底层为validate health)不再将其标记为「未识别的.planning/根文件」并抛出 W019 告警。读完本文,你将理解 GSD 的 canonical artifact 注册机制、W019 规则的判定逻辑、RETROSPECTIVE.md作为/gsd-complete-milestone活文档的产生与消费链路,以及如何用测试固化这类注册变更。
1. 修复背景:W019 的误报问题
在.changeset/archived/3198-retrospective-canonical.md记录的变更中,一行描述点名了两个核心事实:
gsd-health曾对RETROSPECTIVE.md抛出 W019「未识别文件」告警;- 修复方式是把它注册进
CANONICAL_EXACT,与它作为/gsd-complete-milestone产出活文档(living artifact)的既有地位对齐。
W019 属于健康诊断规则组「Milestone archive + root hygiene」,与 W018 同组,定义在 src/health-diagnostic-rules/milestone-archive-hygiene.cts。该规则的职责是:遍历.planning/根目录下的所有.md文件,凡是不在 canonical 工件清单之内的,一律发出 W019 告警,并附带修复建议:
Unrecognized .planning/ file: {filename} — not a canonical GSD artifact建议:「Move to .planning/milestones/ archive subdir or delete if stale. See templates/README.md for the canonical artifact list.」
问题在于:RETROSPECTIVE.md是/gsd-complete-milestone在每次里程碑收尾时正式产出并持续维护的文档,但它此前并不在CANONICAL_EXACT集合里,于是每次运行健康检查都会收到一条「请归档或删除」的错误建议——明明该文件是工作流主动创建的,却被告知它不是规范工件,属于典型的自产文件误报。
2. 核心机制:Canonical Artifact 注册表
2.1CANONICAL_EXACT:精确匹配清单
修复落点位于 src/artifacts.cts 的CANONICAL_EXACT集合。该文件头部注释明确说明其定位:
Enumerates the file names that gsd workflows officially produce at the .planning/ root level. Used by gsd-health (W019) to flag unrecognized files so stale or misnamed artifacts don't silently mislead agents or reviewers. Add entries here whenever a new workflow produces a .planning/ root file.
注册表分为两套匹配规则:
精确匹配(CANONICAL_EXACT)——目前包含 16 个条目:
| 文件名 | 产出方 / 说明 |
|---|---|
PROJECT.md | /gsd:new-project,项目身份与目标 |
ROADMAP.md | /gsd:new-milestone、/gsd:new-project |
STATE.md | /gsd:new-project、gsd-health --repair |
REQUIREMENTS.md | /gsd:new-milestone |
MILESTONES.md | /gsd:complete-milestone |
BACKLOG.md | /gsd-add-backlog |
LEARNINGS.md | /gsd:extract-learnings等 |
THREADS.md | /gsd:thread |
config.json | /gsd:new-project |
CLAUDE.md | /gsd-profile自动组装 |
RETROSPECTIVE.md | /gsd:complete-milestone(本次修复新增语义) |
WINDOWS.md | broken-windows ledger(src/broken-windows.cts,#3224) |
STATE-ARCHIVE.md | state.cts的cmdStatePrune |
milestone.lock | src/milestone-lock.cts(#3311) |
state.json | src/state-contract.cts步骤边界发布(#3227) |
skill-manifest.json | init.cts的cmdSkillManifest --write(#3964) |
PATTERNS.md | 跨阶段模式沉淀(#4282),区别于阶段内NN-PATTERNS.md |
注意RETROSPECTIVE.md在源码中位于第 26 行,紧邻CLAUDE.md与WINDOWS.md之间,正是本次 changeset(PR 3200)所引入的登记。
模式匹配(CANONICAL_PATTERNS)——针对带版本戳的文件名:
/^v\d+\.\d+(?:\.\d+)?-MILESTONE-AUDIT\.md$/i, // gsd-complete-milestone (pre-archive) /^v\d+\.\d+(?:\.\d+)?-.*\.md$/i, // other version-stamped planning docs2.2 判定函数:isCanonicalPlanningFile
注册表的唯一消费入口是isCanonicalPlanningFile(filename)(src/artifacts.cts),它按「先精确、后正则」的顺序判定:
export function isCanonicalPlanningFile(filename: string): boolean { if (CANONICAL_EXACT.has(filename)) return true; for (const pattern of CANONICAL_PATTERNS) { if (pattern.test(filename)) return true; } return false; }三个关键约束值得注意:
- 只接受 basename:调用方传入的是不带路径的文件名,路径处理在上层完成;
- 大小写敏感:
RETROSPECTIVE.md合法,而retrospective.md或RETROSPECTIVE.MD均会被拒绝(测试中有state.md判false的用例佐证); - 空串与无关文件返回
false:保证 W019 对任何未登记文件照常触发。
3. W019 规则的实现链路
W019 的检查函数checkW019位于 src/health-diagnostic-rules/milestone-archive-hygiene.cts,实现逻辑清晰:
function checkW019(snapshot: PlanningSnapshot): Diagnostic[] { const diagnostics: Diagnostic[] = []; for (const filename of snapshot.planningRootFiles.value) { if (!filename.endsWith('.md')) continue; if (isCanonicalPlanningFile(filename)) continue; diagnostics.push({ code: 'W019', severity: SEVERITY.WARNING, message: `Unrecognized .planning/ file: ${filename} — not a canonical GSD artifact`, remedy: adviseRemedy( 'Move to .planning/milestones/ archive subdir or delete if stale. See templates/README.md for the canonical artifact list.', ), }); } return diagnostics; }从实现可以提炼出几条明确的规则语义:
- 只检查
.planning/根目录:文件清单来自 planning snapshot 的planningRootFiles,阶段子目录(.planning/phases/NN-name/)内的文件不在检查范围; - 每个未识别文件产生一条独立告警:与 W018 的聚合式报告不同,W019 是「一文件一告警」,测试中两个杂散文件会产生两条 W019 即为此意;
- 非自动修复(
repairable: false):规则表(同文件第 98-113 行)中 W019 明确标注repairable: false,健康检查的--repair不会自动移动或删除文件,需要人工依据建议处理。
该文件头部还注明了来源:规则从cmdValidateHealth(原src/verify.cts)行为保持地移植而来,并遵循 ADR-457「build-at-publish」策略——源码是src/health-diagnostic-rules/milestone-archive-hygiene.cts,编译产物为 gitignored 的bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs。
4. RETROSPECTIVE.md 的生产与消费:为什么它必须是 canonical
要理解本次修复的必要性,需要看清RETROSPECTIVE.md在完整里程碑收尾工作流中的角色。
4.1 模板:活文档的结构
模板位于 gsd-core/templates/retrospective.md,开篇即声明其定位:
A living document updated after each milestone. Lessons feed forward into future planning.
模板包含两大板块:
- 单里程碑板块:
## Milestone: v{version} — {name},内含 Shipped/Phases/Plans/Sessions 元信息,以及What Was Built、What Worked、What Was Inefficient、Patterns Established、Key Lessons、Cost Observations六个小节; - 跨里程碑趋势板块:
## Cross-Milestone Trends,用表格沉淀Process Evolution、Cumulative Quality与Top Lessons (Verified Across Milestones)。
4.2 工作流:每次收尾都会写入
在 gsd-core/workflows/complete-milestone.md 的write_retrospective步骤中,流程完整定义了该文件的维护方式:
- 探测:
ls .planning/RETROSPECTIVE.md 2>/dev/null || true检查文件是否存在; - 分支处理:已存在则读取并在
## Cross-Milestone Trends之前追加新里程碑板块;不存在则从模板retrospective.md创建; - 数据采集:从
SUMMARY.md提取交付物、从VERIFICATION.md提取验证分数与缺口、从UAT.md提取测试结果、从 git log 统计提交与时间线,再结合里程碑过程反思; - 提交:
gsd_run query commit "docs: update retrospective for v${VERSION}" --files .planning/RETROSPECTIVE.md,将更新固化到 git 历史。
同工作流的 checklist(第 727 行)也把RETROSPECTIVE.md updated with milestone section列为收尾必检项。这意味着:只要完整执行过/gsd-complete-milestone,.planning/RETROSPECTIVE.md就必然存在——它既不是临时草稿,也不是残留杂物,而是一个被工作流持续维护的规范产物。
4.3 消费:里程碑总结的输入源
在 gsd-core/workflows/milestone-summary.md 中,RETROSPECTIVE.md被列为「Always available」的三个路径之一(与PROJECT.md、STATE.md并列),其 lessons learned 是生成里程碑总结时「what to improve」部分的内容来源。此外 gsd-core/workflows/help/modes/full.md 在.planning/目录速览里也将其标注为 "Living retrospective (updated per milestone)"。
至此结论闭环:一个被工作流主动创建、每次收尾持续更新、被其他工作流当作权威输入读取的文档,理应属于 canonical artifact 清单。此前它不在CANONICAL_EXACT中,导致gsd-health给出「请归档或删除」的误导性建议——这正是本次 changeset 修复的实质。
5. 修复的验证:测试与文档联动
5.1 注册表单元测试
tests/artifacts.test.cjs 集中覆盖了注册表行为,其中对同类误报修复的回归用例提供了先例参照(如 #3227 的state.json、#3224 的WINDOWS.md、#4282 的PATTERNS.md),其模式完全适用于RETROSPECTIVE.md:
- 断言
CANONICAL_EXACT.has('RETROSPECTIVE.md')为真; - 断言
isCanonicalPlanningFile('RETROSPECTIVE.md')返回true; - 断言
isCanonicalPlanningFile('random-file.md')仍返回false(W019 的兜底能力不受影响)。
5.2 W019 集成测试
同一文件的gsd-health W019 — unrecognized .planning/ root files分组(第 187 行起)通过临时项目夹具验证了完整行为矩阵:
.planning/MY-NOTES.md→ 触发一条 W019,消息包含文件名,repairable === false;- 仅标准
BASE_FILES→ 无 W019; - 版本戳文件
v1.0-MILESTONE-AUDIT.md→ 无 W019(命中CANONICAL_PATTERNS); - 阶段子目录文件 → 无 W019(根目录外不检查);
- 两个杂散文件 → 产生两条 W019(一文件一告警)。
对应规则单测位于 tests/health-diagnostic-rules/milestone-archive-hygiene.test.cjs,明确标注其来源为 Phase 11、#3309、ADR-3180 §8.2/§8.3/§8.5。
5.3 权威清单文档同步
gsd-core/templates/README.md 是该机制的权威索引,开篇即声明:
if a
.planning/root file is not listed here,gsd-healthwill flag it as W019 (unrecognized artifact).
其根工件表格第 25 行已列出RETROSPECTIVE.md,来源列标注为/gsd:complete-milestone,用途为 "Living milestone retrospective updated at each milestone close"。由于 W019 的修复建议文本会指引用户「See templates/README.md for the canonical artifact list」,文档、注册表、规则三者必须保持一致——本次变更正是这种一致性的又一次落地。同时第 45、66 行分别说明:阶段子目录文件与归档到.planning/milestones/的文件永远不会被 W019 检查。
6. 实践指引
6.1 运行健康检查观察效果
在项目根目录执行:
gsd-health修复前:若.planning/根目录存在RETROSPECTIVE.md,会收到W019 — Unrecognized .planning/ file: RETROSPECTIVE.md告警及「归档或删除」的建议。修复后:该文件命中CANONICAL_EXACT,不再产生任何告警;而未登记的文件(如MY-NOTES.md、scratch.md)仍会被正常标记。
6.2 新增根工件时的正确姿势
参照src/artifacts.cts头部注释的指引,任何新工作流若要在.planning/根目录产出文件,应完成三件事:
- 注册:将文件名加入
CANONICAL_EXACT(或符合语义时加入CANONICAL_PATTERNS); - 文档化:在 gsd-core/templates/README.md 的根工件表格中登记产出方与用途;
- 测试固化:在 tests/artifacts.test.cjs 增加「注册表包含 + 判定为 canonical」的回归用例,并视需要在 W019 集成测试中补充「不误报」用例。
6.3 边界行为速查
| 场景 | W019 行为 |
|---|---|
.planning/RETROSPECTIVE.md(本次修复) | 不告警 |
.planning/PROJECT.md等精确匹配项 | 不告警 |
.planning/v1.2.0-MILESTONE-AUDIT.md | 不告警(正则匹配) |
.planning/phases/01-foundation/01-01-PLAN.md | 不告警(仅查根目录) |
.planning/milestones/归档文件 | 不告警(归档目录豁免) |
.planning/scratch.md等未登记文件 | 告警,且不可自动修复 |
大小写变体(如retrospective.md) | 告警(精确匹配区分大小写) |
7. 小结
本次 changeset(PR 3200)是一次典型而精准的「注册表遗漏」修复:RETROSPECTIVE.md作为/gsd-complete-milestone持续维护的活文档,其 canonical 地位此前只体现在工作流与文档层面,却未同步到 src/artifacts.cts 的CANONICAL_EXACT,导致gsd-health的 W019 规则对它误报。修复后,注册表、W019 判定、模板 README 权威清单三者达成一致,规则仍保留对真正杂散文件的告警能力。这一模式(注册 → 文档化 → 测试固化)为 gsd-core 中所有根级工件的管理提供了可复制的范本。
【免费下载链接】gsd-core
Git. Ship. Done - Core
相关推荐
gsd-core W002 误报修复详解:/gsd:health 为何不再为已归档 Phase 报错
gsd core W002 误报修复详解:/gsd:health 为何不再为已归档 Phase 报错 本文围绕 gsd core 仓库中的一个变更集记录(cha
gsd-core 里程碑归档目录解析修复:getActiveMilestoneArchiveDir 的 null 语义与 W007 误报消除
gsd core 里程碑归档目录解析修复:getActiveMilestoneArchiveDir 的 null 语义与 W007 误报消除 本文聚焦 gsd
Vitest `includeTaskLocation` 配置详解:为任务注入源码定位并启用按行号过滤测试
Vitest includeTaskLocation 配置详解:为任务注入源码定位并启用按行号过滤测试 includeTaskLocation 是 Vitest
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考