gsd-core 命令契约校验(ADR-0002):从命令文件到 CI 的双层验证体系
【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载本篇指南以 gsd-core 仓库中的 ADR-0002 决策记录为主线系统讲解commands/gsd/*.md命令文件契约的五条结构规则与第六条仓库级工作流可达性规则并结合 lint-command-contract.cjs、command-contract-helpers.cjs 与 command-contract.test.cjs 的源码实现说明这套校验如何被纳入lint:ci流水线以及遇到不可达工作流报错时应如何处置。读完本文你将掌握命令文件的正确定义方式、execution_context的规范写法以及 CI 门禁的底层判定逻辑与修复路径。背景为什么需要命令契约校验在 ADR-0002 之前gsd-core 对commands/gsd/*.md的契约校验是零散且不一致的tests/skill-frontmatter-contract.test.cjs源自enh-2790-skill-consolidation合并史诗 #1969只检查特定命令的存在性与 frontmattertests/docs-update.test.cjs源自bug-3135-capture-backlog-workflow只检查execution_context中的 -引用能否在磁盘上解析没有任何一条检查同时覆盖所有命令的allowed-tools合法性、name:命名约定与description:非空。这意味着任何触碰命令文件的 PR 都可能悄悄破坏契约而没有任何测试拦截。add-backlog.md的缺口#3135就是典型案例在针对性回归测试写出之前对应的工作流文件在整个合并周期内一直缺失。同时65 个命令文件中有 40 个存在冗余的 prose -引用——同一个路径既出现在execution_context真正加载文件的地方中又重复出现在process正文里。这种惰性副本每次调用命令都额外消耗约 900 tokens并且形成了漂移缝隙prose 引用可能在可执行的execution_context引用之外独立过期。另外debug.md与thread.md两个最大命令将完整实现内联在命令文件中而非委托给工作流文件导致约 4,400 tokens 的实现细节在每次会话中都随技能索引描述被急切加载。决策双层验证体系ADR-0002 的决策是将命令契约收敛为单一验证缝validation seam在两层执行快速 lint 脚本scripts/lint-command-contract.cjs——作为 CI 预测试步骤在毫秒级内跑完行为回归测试tests/command-contract.test.cjs——针对真实文件系统验证完整契约。契约本身定义了什么是一个合法的commands/gsd/*.md文件见 ADR-0002 决策记录。五条逐文件规则命令文件结构契约lint 脚本对每个命令文件执行五条逐文件检查源码见 lint-command-contract.cjs 的 check 函数name:字段必须存在、非空且匹配gsd:*或gsd-*前缀ns- 命令使用gsd-description:字段必须存在且非空allowed-tools:块必须存在、非空且所有条目来自规范工具集execution_context块内的每个 -引用都必须解析为磁盘上真实存在的文件execution_context块内的 -引用必须独占一行不得有行尾 prose。规范工具集CANONICAL_TOOLS第三条规则中的规范工具集定义在 command-contract-helpers.cjs 中作为单一事实来源供 lint 脚本与测试套件共享。新增一个规范工具只需改这里两个消费方会自动同步const CANONICAL_TOOLS new Set([ Read, Write, Edit, Bash, Glob, Grep, Task, Agent, Skill, SlashCommand, AskUserQuestion, WebFetch, WebSearch, TodoWrite, mcp__context7__resolve-library-id, mcp__context7__query-docs, mcp__context7__*, ]);校验时还有一条通配豁免任何以mcp__context7__开头的工具只要CANONICAL_TOOLS包含mcp__context7__*即视为合法见 check 函数第 3 条规则。一个符合契约的命令文件长什么样仓库中的 commands/gsd/add-tests.md 是符合契约的完整示例。frontmatter 部分--- name: gsd:add-tests description: Generate tests for a completed phase based on UAT criteria and implementation argument-hint: phase [additional instructions] allowed-tools: - Read - Write - Edit - Bash - Glob - Grep - Agent - AskUserQuestion argument-instructions: | Parse the argument as a phase number (integer, decimal, or letter-suffix), plus optional free-text instructions. Example: /gsd:add-tests 12 Example: /gsd:add-tests 12 focus on edge cases in the pricing module requires: [phase] ---execution_context块则只声明一个独占一行的 -引用execution_context ~/.claude/gsd-core/workflows/add-tests.md /execution_context注意这里的关键转变execution_context块现在是命令加载声明的唯一权威来源。ADR-0002 从 40 个命令文件中删除了process正文里重复的 prose -引用每次调用约回收 900 tokens这些惰性副本不再被允许存在。frontmatter 解析的 CRLF 容错command-contract-helpers.cjs 的 parseFrontmatter 特意按/\r?\n/切分行以兼容 Windows checkoutautocrlftrue留下的行尾\r——若不做容错lines.indexOf(---, 1)会因匹配到---\r而失败导致整个 frontmatter 被解析为空、所有字段都被误报为缺失。它还支持 YAML 列表块的累积解析续行以-开头的行追加到前一个键名下。-引用提取与规范化executionContextRefs 用正则匹配execution_context或execution_context_extended块逐行处理行以开头才进入候选取第一个空白分隔的 tokentrailingProse标志当行内 token 之后还有内容时置位对应第五条规则。token 会剥掉~/、$HOME/、.claude/、gsd-core/等前缀做规范化再拼接GSD_ROOT检查磁盘存在性对应第四条规则。第六条规则工作流可达性仓库级检查第六条与前五条性质不同它是一个仓库级可达性图每次运行计算一次而非逐文件检查源码见 checkWorkflowReachability。可达性语义种子loadercommands/**、agents/**、skills/**下的每个 markdown 文件。docs/与测试夹具故意不算 loader——文档或测试里提一句路径并不等于任何运行时真的会加载它遍历从种子出发沿引用边在gsd-core/**不止gsd-core/workflows/因为references/或templates/文件也可能点名某个工作流路径内做传递闭包判定任何gsd-core/workflows/*.md文件若遍历结束后仍未被标记即报告为 orphan孤儿。关键设计是只从 loader 播种绝不从工作流自身内容播种。一个只引用自己的工作流或两个互相引用的工作流都必须被判为不可达——因为没有任何命令、agent 或技能 loader 会真正打开它们。互引自洽的岛从内部看是连通的但对外不可达依然要被报告。三种引用形态workflowPathRefs 识别三种引用形状形态示例适用场景急切 -包含~/.claude/gsd-core/workflows/x.md每次调用都内联。保留给命令始终需要的工作流惰性路径~/.claude/gsd-core/workflows/x.md在使用点按需读取。flag 门控或条件工作流的默认选择父级相对子文件execute-phase/steps/x.md既有工作流目录下的子文件惰性形态是默认首选急切 -包含会在该命令的每次调用中都被内联进上下文包括那些根本用不到该工作流的路径。渐进式披露拆分#717存在的目的就是把这份成本移出公共路径。该解析器还有几处防御性设计遍历段..被丢弃而不是上报解析器永远只报告workflows/之下的路径.md扩展名用负向前瞻(?![A-Za-z0-9_])锚定杜绝.mdx、.md5被静默截断成看似合法的.md路径结果去重且保持首见顺序。可达性闭包算法unreachableWorkflows 实现 BFS 闭包把 loader 内容里解析出的所有工作流引用入队出队时若未被访问则标记并递归入队该文件自身的引用visited集合保证在有环含自环/互环情况下遍历必然终止。测试对以下场景逐一验证见 command-contract.test.cjs急切包含可达、惰性路径可达、父级相对可达、深度三层传递可达、自引用不可达、互引用岛不可达、环终止、docs-only 提及不可达、悬空引用到达不了任何东西、空工作流集、无 loader 则全部不可达、CRLF 容错、152 个文件中精确报告唯一孤儿等。lint 脚本如何接入 CIpackage.json 的 lint:ci 脚本 将node scripts/lint-command-contract.cjs串入 lint 流水线位于测试套件之前运行npm run lint:cilint 脚本退出码语义0 表示干净1 表示有违规并输出诊断。它同时支持--root dir参数指向任意仓库根测试套件正是用它驱动临时夹具目录做端到端验证。正常输出形如ok lint-command-contract: 65 command files checked, 0 violations ok lint-command-contract: 151 workflow files, 151 reachable, 0 unreachable违规时向 stderr 输出逐文件、逐条违规明细并提示查阅契约规范文档不可达工作流则逐个列出gsd-core/path并说明每个文件都会随所有运行时安装却没有任何命令/agent/技能 loader 引用直接或传递——要么把它接上 loader要么删除它。行为回归测试全表面契约守护tests/command-contract.test.cjs 是整条命令表面的权威行为契约测试取代了enh-2790与bug-3135中的分散覆盖。它针对真实文件系统逐文件断言五条逐文件规则name:、description:、allowed-tools:、-引用可解析、-引用独占一行并包含三组重点回归#3561 —— /gsd-map-codebase --fast 路由到可加载工作流断言 commands/gsd/map-codebase.md 的--fast路由行确实点名了一个可解析的workflows/scan.md同时完整 map 路径不得急切加载scan.md只有workflows/map-codebase.md一个 -引用#3560 —— 真实孤儿会 fail 构建用临时目录搭建最小夹具树含一个合法命令文件加一个被急切加载的 live.md分别验证干净夹具通过植入孤儿失败且诊断输出点名孤儿路径仅 docs/ 提及的孤儿仍然失败仅传递可达的孤儿通过四种情形#3560 —— 已删除的工作流不得残留断言discovery-phase.md、plan-milestone-gaps.md已从gsd-core/workflows/物理删除且所有 install-tree 夹具清单不再包含它们多语言 INVENTORY 文档也不再提及。该文件还折入了原bug-3168-task-to-agent-rename的检查命令、工作流、agent 的allowed-tools/toolsfrontmatter 中禁用Taskdispatcher 工具是Agent工作流正文中不允许出现Task(调度调用TaskCreate等任务跟踪器命名除外。接到不可达工作流报错怎么办当npm run lint:ci或直接node scripts/lint-command-contract.cjs报告不可达工作流时诊断形如ERROR lint-command-contract: 1 unreachable workflow file(s) gsd-core/workflows/scan.md ships to every runtime install tree, but no command, agent, or skill references it处理指引见 docs/how-to/resolve-unreachable-workflow-findings.md只有两种正确解法解法一接线Wire it——工作流是活的缺的是引用当某个命令、flag 或 agent 在文档上声明会使用该工作流时选择此方案。在派发该工作流的 loader 中补一条引用优先用惰性路径- If it is --fast: strip the flag, then read and execute ~/.claude/gsd-core/workflows/scan.md (passing remaining args).若 loader 是commands/gsd/*.md随后重新生成技能表面npm run gen:plugin-skills这正是scan.md的正确归宿——/gsd-map-codebase --fast是一个已发布、有文档的 flag其路由行却点名了一个不可解析的路径。删除文件等于删掉一个活功能的唯一实现#3561。解法二删除Delete it——工作流确实已死当没有东西应该引用它时典型场景命令已删除、工作流遗留选择此方案。删除前先核实声称的调用者真实存在discovery-phase工作流头部声称由 plan-phase.md 的 mandatory_discovery 步骤调用但该步骤并不存在docs/INVENTORY.md声称它是/gsd-new-project的替代入口new-project.md却从未引用过它。声称的调用者不是调用者。discovery-phase在 #3560 中被删除。删除是五步清扫任何一步缺失都会让树不一致移除docs/INVENTORY.md中的行——全部五个语言版本docs/INVENTORY.md及docs/ja-JP/、docs/ko-KR/、docs/zh-CN/、docs/pt-BR/并检查各文件底部的说明性注释是否也点名了该工作流重新生成 inventory 清单——先构建再生成顺序反了会静默丢模块npm run build:lib node scripts/gen-inventory-manifest.cjs --write重新生成 golden install-tree 夹具19 个运行时都会列出每个已发布的工作流npm run gen:install-tree清扫点名该文件的测试——allowlist 与内容断言两类都要。两个陷阱#3560 都踩过。按裸文件名键控的 allowlist 匹配不到全路径搜索tests/planner-language-regression.test.cjs中discovery-phase的陈旧条目就是路径式清扫漏掉的断言文件存在或内容的测试会钉死它tests/phase.test.cjs要求plan-milestone-gaps存在并检查其mkdir模式删除文件在远端 runner 上变成四个红测试。注意 lint-removed-but-needed.cjs 两类都抓不到——它扫描.github/workflows/、gsd-core/、docs/和package.json不含tests/需要自行搜索tests/添加一个Removed类型的 changeset 片段并记得Removed类型要求伴随docs/变更——第 1 步已经满足。最后确认树一致npm run lint:ci什么不算引用可达性检查刻意只扫描commands/、agents/、skills/与gsd-core/**位置算吗原因docs/**否文档是对系统的断言不是 loader。scan.md被docs/INVENTORY.md记录的同时完全不可达tests/fixtures/install-tree/*.json否发布清单证明文件会发布——这正是被报告的问题而非反驳changeset 片段否历史记录不是加载路径如果企图通过在某个方便的地方加一条提及来让检查通过那正是这套作用域要防的失败模式——文件仍然是死的门禁却变绿了。检查通过≠真的被用到结构性可达的边界第六条规则证明的是结构性可达某个 loader 点名了该文件。它无法证明文件在任一条已执行路径上被真正读取。对照表现象含义151 workflow files, 151 reachable, 0 unreachable每个已发布工作流都被至少一个 loader 点名。不代表每个都被使用仅从另一个不可达工作流可达的工作流正确报告——可达性只从 loader 播种不可达文件不能把可达性授予任何其他文件只互相引用的两个工作流两者都被报告。互引用岛不满足任何东西引用自己的工作流被报告。自引用不是 loader仅出现在围栏代码块内的路径计为引用。这是刻意的高估检查会 fail 构建正确树上的一次误报比漏掉孤儿更糟所以歧义引用朝可达倾斜被 loader 点名却从未实际执行的工作流不在本检查范围内——那是本结构性检查不回答的语义问题。关联能力契约漂移的相邻防线命令契约校验与仓库内其他漂移门禁互补。契约校验规则 4 负责 -引用存在性include miss而 scripts/check-contract-drift.cjs 负责另一方向的契约漂移检测lint-allowed-tools-parity.cjs 也在lint:ci中与命令契约校验相邻运行进一步约束工具清单的一致性。若想深入了解契约的完整规范可直接阅读 ADR-0002 决策记录若要理解 -引用解析的更广上下文含required_reading门禁标签与 agent 契约注册表可从 command-contract-helpers.cjs 的readTagViolations与contractViolations实现入手继续探索。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐get-shit-done 命令契约校验ADR-0002以双层校验与前端字段规范锁定 65 个 gsd 斜杠命令的质量基线get shit done 命令契约校验ADR 0002以双层校验与前端字段规范锁定 65 个 gsd 斜杠命令的质量基线 导读 本篇文章围绕 get s人工智能AI 应用提示工程开发工具工作流自动化AI Agentget-shit-done ADR-0002 深度解析用 lint 回归测试两层机制集中校验 commands/gsd 命令契约get shit done ADR 0002 深度解析用 lint 回归测试两层机制集中校验 commands/gsd 命令契约 本文以 get shit人工智能AI 应用提示工程开发工具工作流自动化AI Agentoh-my-pi 嵌入式 Shell 内建命令体系pi-builtins 双层架构、Host 契约与逐命令特性门控oh my pi 嵌入式 Shell 内建命令体系pi builtins 双层架构、Host 契约与逐命令特性门控 crates/pi builtins 是人工智能AI Agent代码智能体工具调用CLIMCP Clients上一篇DataHub SQL 解析器深度解析基于 sqlglot 的列级血缘提取原理、能力边界与配置下一篇BilibiliDown免费B站视频下载器教程3步装好单条到收藏夹批量保存创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考