mcpField
O
openspec-verify-change

openspec-verify-change

github.com/fission-ai测试与质量73.3k3.5k 次安装4 天前更新
代码仓库

关于 openspec-verify-change

用于核对实现是否符合 OpenSpec 变更中的需求、任务、场景和设计,并生成建议性验证报告;不会代为实现或归档变更。

主要功能

  1. 01检查任务完成情况
  2. 02映射需求与实现
  3. 03审查场景覆盖
  4. 04检查设计与模式一致性
  5. 05报告严重程度及验证限制

适用场景

  1. 01归档前审查已完成的变更
  2. 02查找未完成任务或未覆盖需求
  3. 03核对实现与设计决策

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/fission-ai/openspec --skill openspec-verify-change

安装后在 Claude Code 中输入/openspec-verify-change确认已加载。

详细介绍

验证实现是否符合变更产物(规范、任务、设计)。

存储库选择: 如果用户指定了存储库(存储库是指在此计算机上注册的独立 OpenSpec 仓库),或当前工作位于某个存储库中,请运行 openspec store list --json 以查找已注册的存储库 ID,然后在读取或写入规范和变更的命令(new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)中传入 --store <id>。选定后,在工作流的其余部分始终使用 --store <id>。下文中这些命令未指定存储库的示例均为简写:运行前请加上该标志。例如,运行 openspec status --change "<name>" --json --store "<id>",而不是下文所示的未指定存储库形式。其他命令不接受此标志。命令打印的提示已包含该标志;后续命令也要保留它。未指定存储库时,命令会作用于最近的本地 openspec/ 根目录。

项目检查: 以下步骤要求项目已在使用 OpenSpec。在第一个会写入内容的步骤(new change、archive、sync specs 或编写产物文件)之前,请确认项目已有根目录:运行 openspec list --json(如果已选择存储库,则加上 --store <id>,因为此时该存储库就是根目录),并读取 root。root 对象表示项目已完成设置。"root": null 表示尚未设置——此处没有 openspec/ 目录,而 openspec new change 之类的写入操作会将其作为副作用创建。该命令还会以非零状态码退出;这就是预期结果,并非 CLI 出错,因此请读取 JSON,不要重试或绕过检查。

有一种情况中,"root": null 并不表示项目尚未设置:如果 status 错误消息以 Declared in 或 Invalid store declaration in 开头,并且指出了本项目的 openspec/config.yaml(或 config.yml),说明项目通过其声明的存储库使用 OpenSpec,但此计算机无法解析该存储库(存储库未注册,或 store: 行格式错误)。不要将其视为尚未初始化,也不要继续执行下方分支:请在写入前停止,并向用户显示该错误的 message 和 fix。

否则,如果没有根目录,接下来要做什么取决于工作流的触发方式:

  • 自动选择: 你自行选择了此工作流,用户没有提及 OpenSpec、此技能,也没有运行其斜杠命令。停止使用 OpenSpec,并像未安装 OpenSpec 一样正常回答用户请求。不要要求用户进行任何设置,也不要提及 OpenSpec 设置。
  • 明确请求 OpenSpec: 用户提及了 OpenSpec、此技能,或运行了其斜杠命令。在写入前停止,并询问用户如何继续:设置此项目(openspec init)、指定已有存储库(--store <id>),或在本次请求中不使用 OpenSpec 继续。等待用户答复。

在这两种分支中,都不得通过副作用创建根目录:用户未要求时不要运行 openspec init,不要手动创建 openspec/ 文件,也不要让命令创建该目录。

输入: 可选指定一个变更名称。如果省略,请检查能否根据对话上下文推断。如果名称含糊或存在歧义,必须询问用户可选的变更。

步骤

  1. 选择变更

    如果已提供名称,则使用该名称。否则:

    • 如果用户在对话中提到过某项变更,则根据上下文推断
    • 如果只有一个进行中的变更,则自动选择
    • 如果存在歧义,则运行 openspec list --json 获取可用变更,并请用户选择一项

    提示用户时,显示列表返回的所有进行中的变更,包括 status: "no-tasks" 的变更。 如果有可用的 schema,请同时注明每项变更所使用的 schema。 对任务尚未完成的变更标记“(进行中)”。

    始终告知用户:“正在使用变更:”,并说明如何更改,例如 /openspec-verify-change <other>。

  2. 检查状态以了解架构

    openspec status --change "<name>" --json
    

    解析 JSON 以了解:

    • schemaName:正在使用的工作流(例如,“spec-driven”)
    • planningHome、changeRoot、artifactPaths 和 actionContext:路径和范围上下文
    • 此变更有哪些产物
  3. 获取规划上下文并加载产物

    openspec instructions apply --change "<name>" --json
    

    这会返回变更目录、contextFiles(产物 ID -> 具体文件路径数组)、taskTrackingConfigured,以及从架构的 apply.tracks 配置匹配到且可读取的所有具体文件中汇总的顶层 tasks 和 progress。读取 contextFiles 中所有可用的产物。

    将 apply 的 state 和 instruction 视为上下文,而非验证结论。验证期间不要实施任务,也不要归档变更。

  4. 初始化验证报告结构

    创建一个包含三个维度的报告结构:

    • 完整性:跟踪任务和规格覆盖情况
    • 正确性:跟踪需求实现情况和场景覆盖情况
    • 一致性:跟踪设计遵循情况和模式一致性

    每个维度都可以包含 CRITICAL、WARNING 或 SUGGESTION 问题。

    验证仅提供参考。尊重有意省略的内容,例如 skip_specs: true、可选设计文档,以及不跟踪任务的架构。不要为了获得清洁报告而要求或臆造可选或有意省略的产物。Not verified 表示本报告的限制,不是新的归档前置条件。归档仍执行自身的检查并遵循用户确认流程。

    将架构未定义的检查,或状态报告中标记为有意跳过的产物,标记为 Not applicable。对于可读取的变更增量规格中包含 REMOVED 或 RENAMED 需求、但不包含 ADDED 或 MODIFIED 需求的变更,其正确性检查也标记为 Not applicable(见步骤 6)。将这些检查排除在跳过检查计数和归档就绪度评估之外。仅当适用检查缺少或无法使用证据时,才标记为 Not verified。

    如果适用检查只有任务证据,则仅验证任务完成情况,并将其余适用检查(包括 Code Pattern Consistency)标记为未验证,原因填写“Only task evidence available”。

    如果产物无法读取,或不包含可用的需求、场景或设计决策,则将受影响的检查标记为未验证,并说明具体原因。继续执行剩余证据支持的检查,但部分检查的输入集不代表该检查已完成验证。缺少需求会影响 Spec Coverage 和 Requirement Implementation Mapping;缺少场景会影响 Scenario Coverage;缺少设计决策会影响 Design Adherence。

  5. 验证完整性 任务完成情况:

    • 如果 taskTrackingConfigured 为 false,则将 任务完成情况 报告为不适用。不要将空的 tasks 视为缺少证据。
    • 否则,使用顶层的 tasks 和 progress 字段。它们已经汇总了所有与 apply.tracks 匹配且可读取的具体文件,无论被跟踪产物的 ID 是什么;不要根据 contextFiles 键推断跟踪情况。
    • 如果 unavailableTrackingFiles 非空,则将 任务完成情况 标记为未验证,并列出每个不可用路径及其原因。继续使用任何可读取的任务证据,但不要根据部分 tasks 和 progress 字段推断任务已完成。
    • 如果 taskTrackingConfigured 为 true 且 tasks 为空,则将 任务完成情况 标记为未验证,并记录 apply state 和 instruction 中的原因。仅凭非零总数无法确认任务描述可供评估。
    • 根据 progress 报告已完成任务数和任务总数。
    • 如果 progress.remaining 大于 0:
      • 为列出的每项未完成任务添加 CRITICAL 问题。如果未完成数量超过列出的未完成任务数,还要报告没有描述的未完成复选框,并建议添加描述并完成任务。不要仅根据列出的任务推断任务已完成。
      • 建议:“完成任务:”或“如果已实现,则标记为完成” 规范覆盖度:
    • 如果状态通过 skip_specs: true 将规范工件标记为跳过,或者架构未定义规范工件(没有任何 artifactPaths.<id>.outputPath 位于 specs/ 下的工件),则将依赖规范的检查报告为不适用。
    • 否则,contextFiles 以工件 ID 为键,而工件 ID 来自当前生效的架构,因此不要假定 ID 是 specs 之类的值。规范工件是指 artifactPaths.<id>.outputPath 位于 specs/ 下的工件;从 contextFiles.<id> 读取其文件。如果这些规范文件缺失或为空,则将规范覆盖度、需求实现映射和场景覆盖度标记为未验证;不要将其中任何一项视为无问题。
    • 如果这些规范文件中存在增量规范:
      • 提取所有需求(以 "### Requirement:" 标记的需求,或在 ## RENAMED Requirements 下列为 FROM:/TO: 对的需求),并记录每项所属的增量章节:## ADDED、## MODIFIED、## REMOVED 或 ## RENAMED Requirements。章节决定检查的内容。
      • 对于每项 ADDED 或 MODIFIED 需求(对于 MODIFIED,检查增量中的文本,而不是旧表述):
        • 在代码库中搜索与该需求相关的关键词
        • 评估实现是否可能已存在
      • 如果 ADDED 或 MODIFIED 需求看起来尚未实现:
        • 添加 CRITICAL 问题:"未找到需求:"
        • 建议:"实现需求 X:"
      • 对于每项 REMOVED 需求,变更要求移除相应行为,因此应反向检查:
        • REMOVED 块仅包含需求名称以及可能存在的 **Reason**/**Migration** 说明,因此增量本身并未描述该行为。搜索之前,应先在主规范 <planningHome.root>/openspec/specs/<capability-path>/spec.md 中读取基线需求,使用与增量规范相同的 capability path。根据应用 REMOVED 块时 OpenSpec 使用的规则,按精确规范化名称匹配:Requirement: 后的标题文本,去除首尾空白;只有在末尾 # 前有空格或制表符时才移除该串 #(因此 C# 会保留 #);比较时区分大小写。措辞相似的标题不算匹配;重命名应归入 RENAMED。其正文和场景是必须移除的行为证据;绝不能仅根据需求名称进行搜索。
        • 如果该文件中没有名称完全匹配的需求——例如先前的同步已应用移除,或措辞相似的 ADDED 需求已替代它——则从同一文件的历史记录中恢复基线;在规划仓库中而非当前目录中执行:git -C "<planningHome.root>" log -p -- openspec/specs/<capability-path>/spec.md,或者在确定应用移除的提交后执行 git -C "<planningHome.root>" show <commit>^:./openspec/specs/<capability-path>/spec.md。输出为空表示路径规范未匹配任何内容,并不表示不存在基线:git log 在路径不匹配时仍会报告成功,因此不要根据无输出就下结论,务必重新检查路径。
        • 如果基线除了标题本身没有提供任何内容——没有超出标题复述的正文,也没有场景——则证据不可用,与缺失基线相同。如果在当前位置和历史记录中都找不到可用基线,则将该条目的规范覆盖度标记为未验证,并说明原因,然后停止:不要搜索,也绝不能将未搜索的移除项计为通过。
        • 在代码库中搜索该行为。openspec/ 工件或文档中的匹配项,或仅用于支持 Migration 说明或 ADDED 需求的代码,都不能单独作为证据。报告所有仍提供已移除行为的代码路径,包括与 ADDED 需求共用的代码路径。
        • 未发现实现是预期结果,但前提是搜索对象确实是基线行为。绝不要将 REMOVED 需求报告为“未找到需求”,也不要建议实现它。
        • 如果该行为仍然存在:
          • 添加 CRITICAL 问题:"已移除的需求仍在实现:"
          • 建议:"按照该需求的 Migration 说明(如果有),移除 : 中剩余的实现"
      • 对于每项 RENAMED 条目(FROM:/TO:),名称会改变,但行为保持不变,因此应检查 TO 需求是否保留了该行为:
        • 不要报告 FROM 名称缺失,也不要要求重命名代码符号、标识符或文件名。
        • 如果 TO 名称也出现在 MODIFIED 下,则应根据 MODIFIED 文本检查其行为;在此处跳过。
        • 否则,在主规范 <planningHome.root>/openspec/specs/<capability-path>/spec.md 中读取基线需求,使用与增量规范相同的 capability path:读取 FROM 名称对应的需求;仅当 FROM 名称不存在(因为主规范已同步)时,才读取 TO 名称对应的需求。其正文和场景是 TO 需求所保留行为的证据。
        • 在代码库中搜索该行为,并评估其是否仍已实现。
        • 如果该行为看起来尚未实现:
          • 添加 CRITICAL 问题:"未找到重命名后的需求:"
          • 建议:"恢复 的行为(从 重命名而来);重命名不得改变行为"
        • 如果找不到或无法读取基线需求,则将该条目的规范覆盖度标记为未验证,并说明原因。绝不要将未经检查的重命名项计为通过。
  6. 验证正确性

    如果增量规范可读,且至少包含一项已移除或已重命名的需求,但不包含任何已新增或已修改的需求(变更仅移除或重命名需求),则将 需求实现映射 和 场景覆盖 报告为 不适用。规范覆盖中的已移除和已重命名检查是此类变更的证据(其中每项具有可用基线的已移除和已重命名条目都会在该处根据其基线行为进行检查,而已在该处标记为未验证的条目仍保持未验证),因此不要将这两项检查标记为未验证。完全没有可解析需求的增量规范属于不可用证据,而非仅移除需求的变更:将这些检查标记为未验证。

    需求实现映射:

    • 对增量规范中的每项已新增或已修改需求(已移除条目,以及没有已修改区块的已重命名条目,已在规范覆盖中处理):
      • 在代码库中搜索实现证据
      • 如果找到,注明文件路径和行范围
      • 评估实现是否符合需求意图
      • 如果发现偏差:
        • 添加警告:“实现可能与规范存在偏差:
          ”
        • 建议:“对照需求 X 检查 :”

    场景覆盖:

    • 对增量规范中每项已新增或已修改需求下的场景(以“#### Scenario:”标记):
      • 检查代码是否处理了相关条件
      • 检查是否存在覆盖该场景的测试
      • 如果场景似乎未覆盖:
        • 添加警告:“场景未覆盖:”
        • 建议:“为场景添加测试或实现:”
    • 跳过已移除需求下的场景;相应行为应当已被移除。
  7. 验证一致性

    设计遵循情况:

    • 如果架构中未定义设计制品(没有 id 为 design 的制品,且没有制品的 artifactPaths.<id>.outputPath 为 design.md 或以 design.md 结尾),则将 设计遵循情况 报告为不适用。
    • 如果设计制品的 contextFiles.<id> 文件存在:
      • 提取关键决策(查找“Decision:”“Approach:”“Architecture:”等章节)
      • 验证实现是否遵循这些决策
      • 如果发现矛盾:
        • 添加警告:“未遵循设计决策:”
        • 建议:“更新实现,或修改 design.md 以符合实际情况”
    • 否则,如果设计制品的 contextFiles.<id> 文件不存在或为空:将 设计遵循情况 标记为未验证。若存在其他支持性制品,仍应执行 代码模式一致性;仅有任务的情况仍仅限于任务完成情况。

    代码模式一致性:

    • 如果无法识别实现变更,将 代码模式一致性 标记为未验证,并说明缺少的证据。
    • 否则,检查新代码是否符合项目模式
    • 检查文件命名、目录结构和编码风格
    • 如果发现明显偏差:
      • 添加建议:“代码模式偏差:
        ”
      • 建议:“考虑遵循项目模式:”
  8. 生成验证报告

    摘要评分卡:

    ## Verification Report: <change-name>
    
    ### Summary
    | Dimension    | Status           |
    |--------------|------------------|
    | Completeness | X/Y tasks, N reqs|
    | Correctness  | M/N reqs covered |
    | Coherence    | Followed/Issues  |
    

    在每个状态单元格中,报告已执行检查的结果,并为每项跳过的检查注明 Not verified (<reason>)。如果某个维度的所有检查都被跳过,则在单元格开头写上 Not verified。绝不要将跳过的检查评为通过。在最终评估中,将所有未验证或部分验证的检查视为已跳过。N 仅统计已新增和已修改需求,并单独报告已移除和已重命名需求(例如,“确认移除 1 项,验证重命名 1 项”,或“1 项移除未验证(基线不可用)”)。对于仅移除或重命名需求的变更,“正确性”单元格填写 Not applicable (no ADDED or MODIFIED requirements)。

    按优先级分类的问题:

    1. 严重问题(归档前必须修复):

      • 未完成的任务
      • 缺少需求实现
      • 已移除的需求仍在实现中
      • 已重命名的需求,其行为已不再实现
      • 每项都应给出具体、可执行的建议
    2. 警告(应修复):

      • 与规范/设计不一致
      • 缺少场景覆盖
      • 每项都应给出具体建议
    3. 建议(可以修复):

      • 模式不一致
      • 小幅改进
      • 每项都应给出具体建议

    最终评估:

    • 如果存在严重问题:"发现 X 个严重问题。归档前请修复。" 如果有任何检查被跳过,还需逐一列出所有跳过的检查及原因。
    • 如果没有严重问题,但存在一个或多个警告,且没有跳过任何检查:"没有严重问题。另有 Y 个警告需要考虑。可以归档(但需留意上述改进)。"
    • 如果只有建议,且没有跳过任何检查:"没有严重问题或警告。另有 Z 条建议需要考虑。可以归档(但需留意上述改进)。"
    • 如果没有问题,且没有跳过任何检查:"所有检查均已通过。可以归档。"
    • 如果有任何检查被跳过,且没有严重问题:不得声称可以归档。请说明:"已运行的检查未发现严重问题。未验证 <检查项>:<原因>。" 如果警告数量非零,还应注明警告数量。
    • 如果建议数量非零,所有最终评估中都应注明建议数量。

验证启发式

  • 完整性:重点检查客观清单项(复选框、需求列表)
  • 正确性:使用关键词搜索、文件路径分析和合理推断——不要求完全确定
  • 一致性:查找明显的不一致,不要吹毛求疵地挑剔风格
  • 误报:如有不确定之处,优先归为建议,其次为警告,最后才是严重问题
  • 可执行性:每个问题都必须给出具体建议,并在适用时注明文件/行号

输出格式

使用清晰的 Markdown,包含:

  • 用表格呈现摘要评分卡
  • 按严重问题/警告/建议分组列出问题
  • 代码引用格式:file.ts:123
  • 具体且可执行的建议
  • 不要给出“考虑检查一下”这类含糊建议

评论

支持 Markdown