awesome-copilot Bug Receipt 凭证契约:为缺陷修复构建可机器校验的证据结构

awesome-copilot Bug Receipt 凭证契约:为缺陷修复构建可机器校验的证据结构

【免费下载链接】awesome-copilot Community-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot. 【免费下载链接】awesome-copilot 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot

导读

本文围绕 awesome-copilot 仓库中 bug-receipt 技能 的证据契约文档 receipt-contract.md 展开,讲解如何把一次缺陷诊断、修复与验证过程,固化为一份结构化的 JSON「修复凭证(Bug Receipt)」。读者将掌握凭证的全部必填字段与取值约束、三种状态(verified / partial / blocked)各自必须满足的不变量,以及如何通过 JSON Schema 与校验脚本在本地或 CI 中自动验证凭证的合法性,让 AI 助手产生的修复结论可被机器可靠消费。

为什么需要一份机器可读的修复凭证

GitHub Copilot 在修复缺陷或处置事故时,自然语言回复天然存在歧义:哪些结论是"当场执行验证过的",哪些只是"用户提供的既有证据";哪些检查真的通过了,哪些只是"没跑过但看起来应该没问题"。当人类阅读时这些差异尚可容忍,但当用户、CI 流水线或其他工具需要消费修复结果时,就必须有一份结构明确、字段固定、状态可自动判定的工件。

这就是 Bug Receipt 契约的定位。契约文档明确划定了它的适用边界:

Use JSON only when the user, CI, or another tool needs a structured artifact. Keep the normal final answer human-readable.

也就是说,日常对话场景仍然输出人类可读的文本收据(见 SKILL.md 中定义的 BUG RECEIPT · VERIFIED | PARTIAL | BLOCKED 文本模板),JSON 凭证只在需要结构化产物时才出场。契约的全部强制要求,最终都被落成了一份可执行的 JSON Schema(receipt.schema.json)和一个 Node 校验脚本(validate-receipt.mjs),从而把"证据规范"从散文变成了可编程的约束。

必填字段与取值约束

契约规定一份凭证必须包含以下字段,缺一不可:

字段类型与取值含义
version整数 122 用于新凭证;1 保留兼容
statusverified / partial / blocked修复状态判定
evidenceSourceexecuted-now / supplied / mixed证据来源(version: 2 必填)
problem非空字符串简洁描述缺陷与预期行为
baseline对象 { command, result, evidence }复现基线
rootCause对象 { summary, evidence[] }根因结论与证据
changes数组 { file, summary }[]变更清单
verification数组 { command, result, evidence }[]验证检查清单
gaps非空字符串数组缺失的证据陈述

其中两类结果枚举值是独立的,不可混用:

  • 基线结果(baseline.resultfailed(失败复现)、observed(观察到问题)、not-run(未运行);
  • 验证结果(verification[].resultpassedfailednot-run

receipt.schema.json 中,additionalProperties: false 被全局开启,且所有字符串字段均通过 nonEmptyString 定义(minLength: 1pattern: "\\S")——这意味着空字符串、纯空白、未知字段一律非法。校验脚本 validate-receipt.mjs 对每个字段逐项落地了这些检查:例如 baseline 必须是对象且仅允许 command / result / evidence 三个键(第 57 行),rootCause.evidence 数组中的每一项都必须是包含 locationobservation 的对象(第 71-77 行)。

字段详解:从证据边界到验证闭环

problem:先描述"观察到什么"与"应该是什么"

problem 要求一句话同时给出缺陷现象与预期行为,这是整个凭证的证据起点。SKILL.md 中的证据边界原则(Evidence Boundary)与本字段呼应:在动手编辑代码前,就必须先记录观察到的问题、预期行为、最强的直接检查手段以及证据来源。凭证只记录事实,不隐含推断。

baseline:复现基线的三重信息

"baseline": {
  "command": "npm test -- discount.test.ts",
  "result": "failed",
  "evidence": "Expected 90, received 100."
}
  • command:可精确复现缺陷的命令或交互;
  • result:只能是 failed / observed / not-run 三者之一;
  • evidence:决定性的观察结果,或说明为何无法取得。

not-run 是一个被明确允许但携带强烈信号的取值——它意味着"没有复现证据",凭证的状态因此不可能达到 verified

rootCause:根因必须带"位置 + 观察"

"rootCause": {
  "summary": "The subtotal was rounded before the percentage discount was applied.",
  "evidence": [
    { "location": "src/pricing.ts:42", "observation": "roundCurrency(subtotal) was passed into applyDiscount()." }
  ]
}

契约要求根因对象由 summary(机制结论)与 evidence(证据数组)组成,且每条证据必须同时包含 locationobservation。这正是 SKILL.md 中"在命名根因之前,必须有一个具体的位置或运行时转变"(Require a concrete location or runtime transition before naming root cause)的机器化表达——没有定位到文件与行号、没有可观察事实支撑的"根因",只是假设。

changesverification:最小变更 + 决定性检查

  • changes:每个条目记录被修改的文件(file)与变更摘要(summary),强调"最小负责变更",避免无关清理、静默回退等动作混入;
  • verification:每个条目是 { command, result, evidence } 三元组,其中 result 枚举为 passed / failed / not-run。契约特别规定"不要把未运行的检查伪装成通过"(Never convert an unrun check into passed),这正是 not-run 枚举存在的意义。

SKILL.md 给出了按受影响界面选择"决定性证明"的指引:逻辑层要求原始失败输入或聚焦测试转为通过,UI 层要求真实交互加控制台与网络观察,持久化层要求经过真实所有者路径的写/读或重载往返,并发或生命周期问题要求重复并发触发与事务证据。verification 数组应只包含受影响契约要求的检查,而不是一场漫无目的的测试狂欢。

gaps:诚实地声明缺失的证据层

gaps 是字符串数组,逐条列出"缺失的证明"。契约的立场非常鲜明:对于 partialblocked 状态,必须指明能弥合决定性缺口的那一个最小实验或证据包,绝不虚构命令、观察、计数、位置或结果。

状态不变量:三种状态的硬性判定规则

契约为每种状态定义了不可违反的不变量,这些规则同时被写进了 receipt.schema.jsonallOf 条件约束(第 74-98 行)与 validate-receipt.mjs 的运行时校验中。

verified:证据闭环的完整拼图

要达到 verified,以下条件全部必须满足:

  • 基线必须被观察到baseline.result 只能是 failedobserved,绝不能是 not-run
  • 至少一条具体根因证据rootCause.evidence 非空,且每条都有 locationobservation
  • 至少一处变更changes 数组至少包含一个文件或工件;
  • 至少一项验证verification 非空;
  • 所有验证结果均为 passed:存在任何 failednot-run 项即失败;
  • 无缺口gaps 必须为空数组(Schema 中体现为 maxItems: 0,校验脚本第 111 行对应报错 "Verified status cannot contain proof gaps.")。

partial:保留证据,标注缺口

partial 表示"有可用证据,但某个必需证明层缺失或不具决定性"。其不变量是:

  • 保留已获得的所有证据,不因状态降级而删除;
  • 把每一个缺失或不确定的证明层写入 gaps(因此 gaps 至少要有 1 项,见校验脚本第 114 行);
  • 绝不把未运行的检查改写为 passed

blocked:外部条件阻断,拒绝推测

blocked 表示"某个具体的外部条件阻止了复现、修复或证明"。其不变量是:

  • 至少一个 gaps 条目明确点名外部阻断条件(校验脚本第 115 行对应报错 "Blocked status must name the external blocking condition.");
  • 未执行的工作保持为空或标记 not-run,不推测其结果。

三种状态的分工与 SKILL.md 的状态判定口径完全一致:VERIFIED 要求"已观察基线 + 具体根因 + 负责变更 + 声明检查全部通过 + 无实质缺口";PARTIAL 承认证据存在但不闭环;BLOCKED 承认外部条件卡住了进程。对 partial / blocked,还必须给出弥合缺口的最小下一步实验。

版本兼容:evidenceSource 的引入

契约明确了两点版本规则:

  • 新凭证一律使用整数 version: 2
  • version: 1 仍被接受,用于兼容历史工件。

二者的关键差异在于 evidenceSource 字段:它在版本 2 中是必填的(取值 executed-now / supplied / mixed),用于回答一个尖锐的问题——"这些证据是本次运行当场执行出来的,还是用户/上游提供的,还是两者混合?"。SKILL.md 强调"绝不明示或暗示所提供的证据是在当前运行中执行的"。校验脚本第 50-51 行的检查顺序体现了这一点:evidenceSource 若存在则必须落在合法枚举内;而当 version === 2 时它必须存在。

这一点对 CI 场景意义重大:一个标注 supplied 的凭证与一个标注 executed-now 的凭证,在可信度上完全不同,而机器可以通过该字段直接区分,无需猜测。

三明治式的三层验证体系

契约给出了三条互相补充的验证路径,可从三个不同位置触发:

  1. Schema 静态校验:凭证必须通过 receipt.schema.json 的结构校验;
  2. 本地脚本校验:在技能目录下运行
    node scripts/validate-receipt.mjs <file>
    
  3. 标准输入管道 + JSON 输出(适合 CI):
    cat receipt.json | node scripts/validate-receipt.mjs - --json
    

    脚本从标准输入读取 JSON(- 参数),并以 JSON 形式输出 { valid, issues } 结果,便于流水线程序化消费;

  4. CLI 命令:当安装该技能配套的 npm 包 CLI 时,可直接使用 bug-receipt check <file>

这些命令的行为可以在 validate-receipt.mjsmain() 函数(第 120-144 行)中看到:校验通过时向标准输出打印 ✓ <file> is a valid <STATUS> bug receipt. 并以退出码 0 结束;校验失败时向标准错误逐条打印 字段路径: 错误信息 并以退出码 1 结束——这一退出码约定让校验可以直接挂在 CI 的门禁检查上。

一个完整的 verified 凭证示例

校验脚本中导出的 sampleReceiptvalidate-receipt.mjs)是一个可直接照抄的最小合法示例,完整展示了 verified 状态的每个必需元素:

{
  "version": 2,
  "status": "verified",
  "evidenceSource": "executed-now",
  "problem": "A 10% checkout discount returns 100 instead of 90 after currency rounding.",
  "baseline": {
    "command": "npm test -- discount.test.ts",
    "result": "failed",
    "evidence": "Expected 90, received 100."
  },
  "rootCause": {
    "summary": "The subtotal was rounded before the percentage discount was applied.",
    "evidence": [
      { "location": "src/pricing.ts:42", "observation": "roundCurrency(subtotal) was passed into applyDiscount()." }
    ]
  },
  "changes": [
    { "file": "src/pricing.ts", "summary": "Apply the discount to the subtotal before currency rounding." }
  ],
  "verification": [
    { "command": "npm test -- discount.test.ts", "result": "passed", "evidence": "1 test passed." },
    { "command": "npm test", "result": "passed", "evidence": "42 tests passed." }
  ],
  "gaps": []
}

对照前面的不变量逐项核验:baseline.resultfailed(已观察)、rootCause.evidencelocationobservationchangesverification 均非空、全部验证 passedgaps 为空——六条 verified 约束全部命中。

从模板开始:partial 凭证的起点

对于尚未闭环的场景,技能提供了官方起点模板 assets/receipt.template.json。它预设了一个诚实的最低信息骨架:

{
  "version": 2,
  "status": "partial",
  "evidenceSource": "supplied",
  "problem": "Describe the observed defect and intended behavior.",
  "baseline": {
    "command": "Record the exact reproduction command or interaction.",
    "result": "not-run",
    "evidence": "State the decisive observation, or why it could not be obtained."
  },
  "rootCause": { "summary": "State the evidence-backed mechanism, or mark it unresolved.", "evidence": [] },
  "changes": [],
  "verification": [],
  "gaps": ["Replace this with the exact missing proof layer."]
}

注意模板的默认设计本身就演示了契约精神:基线显式标记 not-run、根因证据为空、changesverification 为空、gaps 保留一条占位——这是一份合法但明确未闭环的凭证,与"留空假装完整"形成了鲜明对比。SKILL.md 建议:需要 JSON 工件时从该模板出发,写入任务专属路径,再用 node scripts/validate-receipt.mjs <receipt.json> 校验;除非用户明确要求,生成的凭证不提交到仓库。

实战建议

  • 只有结构化消费者才使用 JSON:向人类汇报仍以 SKILL.md 的文本收据为准,JSON 凭证是给用户、CI 和其他工具准备的;
  • 先定证据边界,再写字段evidenceSourcebaseline.result 应在动工前就确定,避免事后把"推测"升级为"事实";
  • not-run 是诚实的盟友:未执行的检查写 not-run 而非 passed,这既是契约义务,也是保护凭证可信度的底线;
  • 把校验挂进门禁:借助 node scripts/validate-receipt.mjs - --json 的标准输入/JSON 输出能力和非零退出码,可在 CI 中自动拦截"伪造完整"的凭证;
  • 追溯实现细节:字段约束与状态不变量的最终解释权在 receipt.schema.jsonvalidate-receipt.mjs 两份文件中,任何对契约的疑问都应回到这里核验。

【免费下载链接】awesome-copilot Community-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot. 【免费下载链接】awesome-copilot 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值