正在刊行长文 · Essay
2026-08-30所有内容
随机比特 · Random Bits

基于 2025—2026 年新上架的 AI 编程与软件工程书,解释验收证据何时必须重跑、何时能够安全复用。

2026-08-30AI Engineering / Systemsrbits.uk

AI 改完代码,哪些验收可以安全复用?

一次 cherry-pick 之后,旧测试应该全部重跑吗?直觉会给出两个相反答案。提交哈希变了,所以全都重跑;文件内容没变,所以全部复用。两者都把判断条件压缩得过头。

我做了一个可重复的 Git 对照实验。commit A 修改 policy/retry.conf,随后把同一补丁搬到另一条基线,得到 commit B。A、B 的 commit 与 tree 不同,目标文件的路径、Git mode、blob 和 SHA-256 相同。实验为同一项“文件内容精确匹配已接受摘要”的验证建立了两种真实缓存。

结果并不是二选一。commit 级缓存 miss,B 必须重验;artifact 级缓存 hit,B 没有再次运行验证器。

同一目标文件为什么有两种缓存结果

缓存范围 A、B 的键 B 的结果 验证器总运行次数
commit-scoped 39d413… / fefd070… miss,重新验证 2
artifact-scoped 58d205… / 58d205… hit,不再执行 1

这里把一次验证产生的结果记录称为 receipt,缓存键决定去哪里查这条记录。只有 statement 还带有可验证的签发身份与完整性保护时,它才构成可由消费者信任的 attestation。

第一种键包含 commit OID。A 是 faec87c8…,B 是 2e2d2af9…,所以 receipt A 面对 B 是 subject mismatch。它仍然记录“A 当时通过”,却不适用于 B。B 的通过来自第二次真实验证,而不是对 A 的信誉继承。

第二种键不把整个提交当成主张对象。B 先从自己的 tree 独立解析 policy/retry.conf,确认 path、mode 100644、blob 与文件 SHA-256,再连同 predicate(被证明的具体主张)、policy digest、verifier version、verifier-definition digest 和 inputs 计算键。全部相同时,它才命中 A 写入的缓存。

这里不能只比较 blob。Git blob 保存内容,不保存文件名、路径和 mode;这些关系由 tree entry 提供。如果主张是“这个路径上的配置与已接受版本相同”,消费方必须先证明 B 的这个路径确实解析到同一 mode 与 digest。

**验证是否重跑,不由 Git 操作决定,而由完整证据键是否相同决定。**这也是对“新提交一律继承不了旧验收”的修正。commit 级主张不能继承,不等于所有窄证据都必须重算。

实验仍有明确边界。它使用未签名、自声明的临时 JSON,只证明对象绑定与缓存语义,不构成可信供应链 attestation;验证器也只证明文件内容匹配,不能证明真实运行中的重试行为。这里的 verifier-definition digest 只是显式定义字符串的摘要,依靠人工保证定义与实现同步,并非实际可执行物、容器镜像或可信执行身份的摘要。生产系统必须绑定真实执行物、运行策略和签发身份。这个实验也不证明性能收益,因为生成 key 已经计算了文件摘要;只有后续 hermetic 验证远比摘要计算昂贵时,复用才会节省显著成本。

新书提供验证生命周期,标准提供证据封装

这次书目地图共列出十九本近期新书。在这批按生产工程价值筛选的样本中,值得关注的共同方向不是怎样让模型再多写一点代码,而是怎样装配上下文、限定执行、评估轨迹,并把生产反馈带回开发过程。

截至 2026 年 8 月 30 日,《Vibe Engineering》仍是 MEAP,《Evals for AI Engineers》仍是 Early Release,《Context Engineering》虽已开放全部章节,仍未成为正式版。它们适合捕捉验证阶梯、生产 trace、漂移监控和上下文生命周期这些新方向,不能冒充已经定稿的完整结论。

正式出版的《Observability Engineering, 2nd Edition》把验证延伸到生产中的真实行为;《Designing Data-Intensive Applications, 2nd Edition》提供部分失败、事务边界、durable execution 与不可变事件历史的系统基础;《Infrastructure as Code, 3rd Edition》区分 preview、资源验证和结果验证,并强调同一构建物的逐级晋升。三者共同提醒我们,构建物相同,不代表环境级结论也能继承。

这些书没有共同提出“Evidence Contract”。要把方向变成机器可判定的协议,还需要一手标准。in-toto Statement 用 subject 的名称与 digest 指明被证明对象,用 predicateType 区分主张类型;SLSA VSA 补充 verifier、验证时间、资源 URI、policy digest、输入 attestations 与结果,并要求消费方校验签名、信任根和 subject;SLSA Provenance 则记录参数、依赖、builder 与构建过程信息。

书籍解释“在哪些生命周期继续验证”,标准解释“怎样封装一项可携带的证明”。可复用性最终要由 subject、predicate 与消费策略共同判定。

不要把可接受性与验证结果混在一起

在真实系统中,消费端对一份历史凭证至少有五种适用性或信任状态。它们与 receipt 内的 PASS、FAIL 等验证结果正交。

当前状态 含义 正确处置
仍适用 完整键、请求与已签名 payload 匹配,信任、撤销与时效检查均通过 复用其中的 PASS 或 FAIL,由当前策略解释结果
对新对象不适用 subject 不匹配,例如 A 的 commit receipt 面对 B 保留 A 的历史记录,对 B 查找别的证据或重验
陈旧 新策略、规则库、时效要求已变化,或当前策略要求更新结果 保留旧结论,按当前策略补验
已撤销 验证器缺陷、密钥泄露或信任关系触发了显式撤销 追加撤销记录,停止接受受影响凭证
无效 签名、完整性或格式无法验证 直接拒绝,不能当成历史事实使用

这一区分很重要。一份签名可靠、subject 匹配的 FAIL receipt 可以是“仍适用”,只是当前门禁会据此拒绝交付。策略从 v3 升到 v4,也不会抹掉“对象 A 曾按 v3 通过”;它只说明这份结果不能满足当前消费者。新版结果取代旧版,通常只是让旧结果对当前策略陈旧,只有显式撤销才要求停止接受。正确模型是追加新验证或撤销事件,而不是删除旧 receipt,也不是把所有非当前证据统称为失败。

完整证据键决定何时不重跑

确定性验收的缓存键由六类输入组成。

request_key = H(canonical_encode(request.key_fields))
receipt = cache.lookup(request_key)
hit = receipt != null
payload_key = hit
  ? H(canonical_encode(key_fields(receipt.signed_payload)))
  : null

applicable = hit
          && payload_key == request_key
          && payload_matches_request
          && signature_valid
          && issuer_trusted
          && issuer_authorized_for(predicate.type, subject)
          && !revoked
          && freshness_policy_pass

accept = applicable
      && result_allowed(receipt.signed_payload.result)

key_fields 包含 schema version、subject、predicate、policy、verifier、inputs 和 parameters。

消费方不能因为“按 key 查到一份签名有效的 receipt”就放行。它必须先验证签名,再从已签名 payload 重算 payload_key,并核对 subject、资源 URI 与当前请求;还要确认签发者获准为该对象声明这种 predicate.type。否则,放错索引或缓存投毒的凭证即使签名真实,也可能证明另一件事。

canonical_encode 必须固定字段边界、字符编码与列表顺序,不能直接拼接字符串。生产化的 evidence-key/v1 只服务缓存查找,并非 in-toto 或 SLSA 的 attestation 格式。

schema: evidence-key/v1
subject:
  path: policy/retry.conf
  mode: "100644"
  git_blob: c90022f2…
  sha256: 58d7b6b5…
predicate: {type: "urn:example:predicate:exact-content:v1", digest: 6d7f125b…}
policy: {uri: "urn:example:policy:retry:v1", digest: 4634960b…}
verifier: {version: exact-content-sha256/v1, implementation_digest: "<executable-or-image-digest>"}
inputs: [{uri: "git:path:policy/retry.conf", sha256: 58d7b6b5…}]
parameters: {}

subject 应尽量绑定不可变 digest,并补齐名称、路径或资源 URI 等语义。predicate 同时携带类型或 schema 标识及内容摘要,用来区分内容一致、测试通过或策略合规等主张。policyverifier 不能只写人类可读版本号,应使用可稳定比较的 digest。所有会改变结果的评测集、模型、规则库、依赖、参数和豁免配置,都必须进入 inputsparameters 或被其引用。

因此,同一构建物的 checksum 校验可能直接复用;漏洞扫描若依赖更新过的漏洞库,就必须产生新键;集成测试要纳入服务版本、种子数据和环境配置。运行时证据更不能只绑 artifact。它至少需要部署版本、配置摘要、资源 generation 或 ETag、feature flag、观测时间窗与流量范围。无法绑定不可变对象时,就绑定可唯一识别的资源版本和观测窗口。

落地时,先为每项验证写清 predicate 与真实依赖,再生成规范化证据键;把签名校验、信任根与时效作为消费门槛;最后把 receipt、补验和撤销都保留为不可变事件。这样既不会让一项单文件检查冒充整次部署的证明,也不会因为 commit 哈希变化就浪费性地重跑所有确定性检查。

AI 提高了代码变更吞吐量,交付系统就必须回答得更精确。每项验收都要说明它证明哪个 subject,依赖哪版 predicate 与 policy,以及当前消费者为什么仍然可以接受它。

随机比特公众号二维码
公众号 · 随机比特
从 AI 工具热闹里拆工程真相

写边界、控制面、上下文、成本与安全。