本文结论
- 原则只有改变范围、备选方案、行为场景和验收依据,才真正进入 Spec;写一句"遵循原则"不产生质量保证。
- Spec 保存行为约定,Plan 组织执行,测试提供观察;先按问题读取相关约束和现状,再选择需要的工件。
- 模板的价值是保存后续真正会用到的决定;文件数量不代表质量,轻量化也不能绕过所选流程的真实依赖。
- Spec 阶段就应演进已有测试,执行与评审沿真实消费者核验;局部通过不能替代用户可取得的结果。
- 归档保留有效行为与选择理由,模板只吸收可复用的盲点;流程自身也要减少重复、常驻负担和无法退出的规则。
适用
- 使用 Coding Agent 维护已有系统,希望把设计哲学落实到需求、方案、实施和质量判断的工程师。
- 跨职责、跨会话变更,以及需要维护 Spec 模板、测试和工程知识的团队。
不适用
- 希望仅凭文档、结构检查或安装工具,就自动获得正确需求、真实模型质量或发布批准的场景。
预计阅读 44 分钟。
Spec 是 specification 的缩写,通常译为"规格说明"或"规范"。在软件开发中,它用明确、可讨论的文字约定系统应该做什么、在什么条件下这样做,以及哪些边界必须保持。它不是某款 AI 工具的名字,也不等于一份实现任务清单。
当我们让 Coding Agent"增加文件读取能力"时,代码很快就能开始生成,但需求并没有因此变清楚:模型给出的任意 URL 都能下载吗?文件只解析了一部分该怎样表示?读取失败是否应该中断整个任务?这些决定若留到实现时临时猜测,最终得到的可能是一个能运行、却不符合团队预期的系统。
本文先解释 Spec 为什么值得使用,再沿构思、模板、实现、验证、归档和维护介绍一套完整流程。ETF Agent 的文件接入是贯穿案例,其他经历只用来说明关键选择;读者不需要复制我们的目录或原则,重点是掌握怎样让团队的约束进入每次变更,而不只停在一份原则文档里。
一、Spec 是什么,为什么在 AI 开发中重新受到重视?
它不是 AI 时代才出现的概念
Spec 早于 AI 编程。Leslie Lamport 在2013 年的文章里已讨论先写规格再编码,并区分非形式化与形式化规格。这个年份不是起点,只是一个早期例子。
这个概念背后的问题一直存在:人的意图、程序的实际行为和下一位维护者的理解,并不会自动一致。 只保存实现,后来的人很难分清某个行为是有意选择、历史包袱,还是偶然写成这样;只有口头讨论,边界又容易在交接中丢失。规格说明为这些判断提供了一个可以共同检查和修改的位置。
例如,"支持文件读取"只是目标;"获准文件可以在本任务中读取,未经准入的文本不得触发下载,部分解析不能冒充全文"才开始形成行为约定。至于用哪个解析库、代码接在哪个模块,则属于设计和实现。Spec 约定结果与边界,Plan 安排执行,测试观察是否满足约定;三者互相连接,但不能互相替代。
Coding Agent 放大了哪些原有问题?
AI 可以把一句含糊要求迅速变成大量实现,但缺少的信息仍然需要有人补齐。若没有明确约定,补齐者就可能是当前模型、某段提示词,或既有代码里偶然存在的模式。换一次会话、换一个执行者,同一个词也可能被解释成另一套方案。
GitHub 在 2025 年 9 月介绍 Spec Kit时,针对的正是这一类偏差:生成代码看起来合理,却可能遗漏意图,或采用不合适的技术和架构。它把规格、计划、任务与实现组织成相互衔接的工作方式。
因此,今天讨论的规范驱动开发(Spec-driven development,SDD),不是"先多写一些文档再编码",而是把关键约定作为实现和评审的持续输入。它尤其适合需要跨会话接续、修改已有行为、协调多个模块,或处理权限和恢复边界的工作。对一次性小实验,清楚的需求、少量测试和 PR 描述也可能已经足够。
OpenSpec是其中一种工具实现:它区分现行规范与待实施的变更,用增量描述已有系统要如何改变,并强调迭代而非不可回头的瀑布。本文借用它组织工件,但不会把 OpenSpec、本项目的模板和 Spec 这个通用概念画上等号。
从一次性方案,变成贯穿变更的判断依据
一份施工方案回答"先改哪里、再做什么";一条完整 Spec 流还要回答"为什么值得改、哪些条件不能丢、如何知道改对了"。它可以理解为:
用户目标 → 相关约束与现状 → 方案及取舍 → 可观察行为 → 实现与验证 → 接受或修订 → 下一次设计的依据。
原则在设计时帮助排除不合适的方案,在测试和评审时提供判断依据;新事实则可以反过来修正方案。只要范围、依据和行为变化被同步更新,回到前面的决定并不是违反流程。

图 1:主线保存一项变更的承诺、实现与接受依据。证据贯穿全部阶段,反馈返回受影响的决定。
这里的质量既包括功能正确,也包括需求是否有用、职责是否清楚、必要保护是否保持,以及未来是否容易维护。Spec 不能自动保证这些问题都有正确答案,但能让它们在编码前被讨论,在执行中被检查,而不是等问题出现后才想起。
二、编写之前:把相关原则转成这次设计的问题
起草之前,不必先建立一套庞大的文档体系。对大多数已有项目,先找到三类材料就够了:团队长期遵守的约束,受影响模块的现行规范、代码和测试,以及本次需求已经明确的目标与未决选择。只有理解某个决定确实需要时,再查对应设计记录或历史。
这些材料承担不同职责。原则帮助判断什么方案值得选择;现行代码和测试说明系统实际怎样工作;历史解释当时为什么这样做。不要把它们压成一段无差别的"项目背景",也不要要求每次任务把所有资料重读一遍。前置阅读应该产生会改变方案的事实,例如"现有材料工作区已经能搜索和读取文件,这次缺的是接入,不是另建平台"。
我们的具体原则可查原则索引,五不及其取舍见架构演化专题。这里更重要的是它们如何被使用:选择与当前变化有关的原则,把它改写成一个具体问题,再让答案进入方案、场景和验证。
例如,原则说"局部失败不能否决独立合法的结果"。面对文件接入,就要问"一个附件解析失败,是否有理由让整次工具调用的其他结果消失?"如果没有,Design 应选择附件级失败处理,Spec 应明确其他结果仍可用,测试则同时观察失败附件和成功内容。只在提案中写"遵循原则",或者只测解析器抛出了异常,都没有走完这条链。
终结权改造提供了一个简短的真实反例:把各处错误统一成 terminate(failed),集中的是写入入口,调用者仍可能自行决定整轮失败。设计因此转向让局部模块报告事实,由既有运行控制职责决定继续、收尾或终结;验收也从"调用了哪个函数"转成"局部故障后哪些合法效果仍能继续"。完整机制另有专题,这里留下的判断是:原则必须改变方案与可观察行为,而不只是改变命名。
实践中,这些答案放入已有的方案说明或决策记录即可,不需要再建"原则合规表"。原则也不自动授权增加拦截:新增拒绝要说明保护什么、依据什么事实,以及影响哪个效果;必要保护继续保留,独立合法的路径也要得到验证。
三、模板不是文档套餐:每个文件为什么存在
原则需要一个可以持续使用的载体,但这个载体不一定是一份很长的总规范。我们使用 OpenSpec 管理现行行为与变更增量,用 Superpowers 相关方法帮助构思、执行、测试和复核,再由项目自己的工作流承接证据、关闭和历史。
这些方法并非只有我们才在连接原则与执行。GitHub Spec Kit 的计划模板包含对项目 Constitution 的检查;OpenSpec强调可迭代的工件组织;Superpowers把设计澄清、计划与测试实践串联起来。这里要解释的是本项目如何组织这些职责,不是宣称别的工具只会生成文档。
Schema、模板和一次变更,是三种东西
schema.yaml 描述工件类型、依赖、生成位置与操作指令;templates/ 提供每类工件的起草骨架;changes/<change>/ 保存某一次变更的真实决定与观察。修改模板,影响的是后续起草的默认提示,不会自动改写已有变更,更不会自动证明执行者已经遵守新规则。
我们核对的 superpowers-bridge 模板目录有十种 Markdown:
text
openspec/
schemas/superpowers-bridge/
schema.yaml
templates/
brainstorm.md
proposal.md
design.md
spec.md
evidence.md
tasks.md
plan.md
apply.md
verify.md
retrospective.md
specs/<capability>/spec.md # 已接受的行为契约
changes/<change>/ # 一次变更的工件实例
specs/<capability>/spec.md # 实例中的规范增量,而非模板本身
这不是要求每次都写十篇文章。Schema 声明了九类工件,apply 另有执行指令;模板目录里的 apply.md 只是必要时使用的交接导航,不是第二本执行账本。一个 spec.md 模板也可能生成多个领域的规范增量,文件数量不等于阶段数量。
| 工件 | 独有职责与消费者 | 为什么值得单独保存 | 怎样保持轻量 |
|---|---|---|---|
brainstorm.md |
保存问题理解、合理选项、未决条件,供提案使用。 | 防止一个尚未讨论的实现猜测直接变成承诺,也保留未选方案当时为何合理。 | 已明确的决定直接归纳,不抄全部聊天记录,不为简单需求重新表演探索。 |
proposal.md |
保存问题、本期范围、非目标、验收路线和实质决定。 | 它是后续范围判断的依据;否则执行者很难区分"讨论过"和"承诺本期实现"。 | 只保留影响范围、行为、权力和验收的事项,复用已有明确授权。 |
design.md |
保存实现选择、替代方案、边界、代价与测试接缝。 | 行为要求不能完整解释"为什么这样接,而不是另一种合理方式"。 | 重点是关键决定;不复制任务清单、命令和运行结果。 |
specs/**/*.md |
保存新增、修改或删除的可观察行为。 | 它让不同实现可以对同一要求负责,也是将来接续和演进的合同。 | 写有实质差异的场景,不把每个内部函数名升成长期要求。 |
evidence.md |
保存基线、采集口径、执行观察和限制,供验证与交接使用。 | 计划与事实不能合成一份"我们做到了"的自述;换会话后仍要能回到原观察。 | 同一结果只记录一次,原始产物按来源定位,不重复粘贴整份日志。 |
tasks.md |
保存有凝聚性的工作单元、依赖和完成状态。 | 规格说明行为,却不说明哪部分由谁推进、哪些还没完成。 | 多个场景可以共用一个工作单元,不机械复制四阶段 checkbox。 |
plan.md |
保存执行次序、接线位置、测试入口及必要前提。 | 复杂工作需要让下一位执行者知道从哪里接续,而不重新猜测。 | 只补有价值的执行细节,不再次维护需求、状态或证据副本。 |
apply.md |
必要时记录当前步骤、阻塞和下一步定位。 | 长任务交接偶尔需要一张路标,但它不拥有新的完成事实。 | 已由 Tasks 和 Evidence 说清时不新增,不把它变成第四份进度报告。 |
verify.md |
从观察判断承诺满足到哪里、还有哪些必要条件。 | 运行输出不等于验收结论;需要把观察放回承诺范围判断。 | 可生成视图,但不生成执行;手写总结也只引用已有事实。 |
retrospective.md |
提炼有价值的决定、失败根因与计划偏差。 | 下一次设计需要理由,不需要重新读完一串终端输出。 | 没有独有收获可以明确说无;归档不应强迫制造一篇故事。 |
"按需"不能用来隐瞒实际依赖
这里有一个必须说准确的地方。通用工作原则允许简单任务采用轻量方式,Plan 模板也鼓励只写必要内容;但选用本项目这个 Schema 时,apply 明确依赖 plan 和 evidence,Evidence 又依赖 Design 与 Specs。不能一边声称使用该模式,一边因为文章说了"可选",就跳过工具真实要求的输入。
正确的简化有两条路:小任务选择现有轻量入口;需要完整模式时,保留它要求的工件身份,把无新增信息的内容压缩到必要说明与引用。若依赖关系本身已经不合理,就作为工作流维护变更修正 Schema 与相应检查,而不是靠编写者临时绕开。
工件依赖还不等于执行事实。这个 Schema 的 Verify 在依赖图里跟随 Plan,但它的指令要求在实现已经产生可复核变更后再形成结论。图中一个节点"可生成",并不会自动证明前面的测试实际运行过。因此,依赖图负责准备哪些输入,执行约定负责怎样工作,证据与相应门禁负责说明实际做到了哪里,三者不能互相借用权威。
这也解释了为什么不能只看模板正文。模板中的一个字段、Schema 的生成指令、共享规则和校验器可能处于不同演进阶段。出现冲突要查当前约定和真实消费者,不能把某行旧提示解释成新的权限,或通过复制更多表格来掩盖不一致。
字段的价值,在于它会被后续使用
Proposal 中的 First deliverable 要影响任务顺序;Design 表中的 Test seam 要影响测试放在哪条生产路径;Spec 中的合法与拒绝场景要影响断言;Evidence 中的未采集要限制最终主张。字段如果只在起草时被填写,之后无人读取,就很难承担质量作用。
同样,Approval 是已有指令的记录,不会因为文本写了 approved 就产生授权;observed-run 是对观察来源的声明,不会因为解析成功就变成独立认证。模板把重要问题摆到合适位置,真正的质量仍取决于回答、执行和复核。
四、从请求到行为约定:以文件接入为例
本节采用项目在 2026 年 9 月底至 10 月初的文件接入设计与观察记录;精简场景是教学整理,不把历史局部验证当作当前部署的认证。
业务工具返回基金说明书、产品文档或文件引用,研究 Agent 却没有统一路径读取。最直接的想法是"加个解析器",但这只描述了中间步骤,没有定义能力的入口、权力、输出与生命周期。
当时的设计先确认现状:已有研究资产和任务内材料工作区,已有通用的搜索、读取和来源定位;缺口位于上游。于是提案没有承诺新建文档中心,而是把可信 MCP 返回文件接到这些既有能力上。

图 2:案例不是从零建设文件平台,而是补齐可信工具结果与现有材料工作区之间的连接。
第一次改变:问题从"能解析什么"变成"谁有权让它解析"
模型在回答里写出一个 URL,不应直接成为宿主下载文件的授权。业务工具返回的真实文件描述,也需要与对应工具调用、当前任务范围和已配置获取方式绑定。凭证由宿主内部使用,不能为了方便模型操作,就进入模型上下文或普通日志。
这对应的是"语义判断与执行权分开",但真正进入 Proposal 和 Design 的不是原则名字,而是明确决定:只有宿主验证过的规范工具结果可以形成文件描述;任意模型文本、文件路径或自报身份不能扩张获取范围。
这个决定会改变测试。一个"给定 URL,返回文件文本"的测试不足以支持它。需要在真实宿主接缝上比较:同样看起来像文件的输入,来自被准入工具结果时能够处理,来自模型文本或缺失授权的输入时不能触发获取。
第二次改变:能力放进既有职责,不扩散到每个消费者
设计比较过把解析交给业务 Skill、增加格式专用工具、在宿主结果路径统一接入等路线。对一次性、无鉴权的小脚本,前一种办法可能更便宜;但对已有通用材料工作区、多个来源共享获取和权限要求的系统,集中在宿主边界更有理由。
选择之后,获取适配器处理已允许的来源,解析器处理格式差异,资产与工作区继续保存来源、访问范围和读取状态。模型使用原有通用搜索与读取入口。原 MCP 工具身份和业务字段保持不变,文件接入提供单独的材料引用,不重新包一层业务工具。
这既落实了"不让复杂度外溢",也落实了"不向正常路径征税"。没有文件时,不必让模型理解一组新格式工具;新增格式时,也不要求每个业务 Skill 跟着改。代价是宿主侧必须认真维护格式适配、容量限制和接线测试,这份复杂度并没有消失,只是被放到了有理由承担它的位置。
第三次改变:部分解析是一种真实状态,而不是失败后的粉饰
首期范围是带文本层的 PDF、DOCX、XLSX 和静态 HTML,不包含 OCR、图表理解、旧 Office 格式或自动长期入库。解析需要保留格式原生位置,例如 PDF 页、DOCX 段落、XLSX 工作表和单元格、HTML 的节与锚点。
关键不只是提取文字,还包括准确描述没有提取到的部分。文件因上限只解析了一部分,不等于剩下的地方没有内容。工作区中一次读取的精确范围,也不等于整个文件的解析覆盖。若一个结论依赖未解析或未读取的区域,已有部分材料不能替它背书。
下面是从真实约束整理的教学场景,不是新增接口:
text
要求:文件获取来自真实准入,而不是文本猜测。
给定:工具调用经过准入,宿主取得与该调用绑定的文件描述。
当:对应获取适配器完成有界获取。
那么:材料进入当前任务工作区,保留原工具身份和业务事实。
对照:同样的 URL 仅出现在模型文本中,或当前调用缺少相应准入。
那么:不触发文件获取;其他独立合法的业务结果仍可保留。
要求:部分材料不冒充完整资料。
给定:文件只完成部分解析。
当:读取已经可用的片段。
那么:返回真实片段及覆盖范围,不能把未解析区域解释为内容不存在。
规范同时描述了有用能力和保护边界。只写"禁止未授权获取",可能漏掉合法文件能否真正被研究消费;只写"文件能读",又可能让入口不知不觉变成任意下载器。
这些行为先作为本次规范增量存在,而不是立刻变成已经接受的事实。新增要求使用 ADDED,尚未出现在现行规范中是正常状态;修改或删除使用 MODIFIED、REMOVED 时,必须先找到同一能力中被影响的原要求;RENAMED 则明确名称变化。无关的已有行为应继续保留,不能为了让新方案自洽而整篇覆盖旧合同。
以文件接入为例,"可信工具返回文件进入任务工作区"是新增能力;若需要改变已有材料读取语义,则应明确指出原要求和变化,而不是复制一套同名读取规则。规范增量使评审者能够看到这次究竟增加了什么承诺、改变了什么保护。结构合法仍不证明实现成立,接受和同步需要后续的验收依据。

图 3:待实施增量与现行契约分开维护;未满足声明范围的验收时,不把提议写成已接受事实。
第四次改变:相同内容不等于同一份权利
历史观察里出现过一个有辨别力的受控反例:两个任务范围中的同一来源、同一内容生成了相同的资产标识,造成存储身份冲突。后续修改把范围纳入相关身份,避免不同任务相互覆盖。
这个测试不只是补一个参数。它说明"内容去重"和"授权隔离"不是同一个问题。即使字节相同,新的调用仍要满足自己的准入和范围;缓存命中也不是当前权限或新鲜度的证明。
设计曾讨论内容寻址的解析缓存,但该阶段实际采用任务内临时存储,没有实现跨任务解析缓存。长期知识库的接纳、保留和索引继续属于独立生命周期。文件成功解析,不等于用户批准它以后一直可用。
把第一份可交付结果写进范围
完整讨论一个能力,不等于本期就要实现所有增强。文件接入先交付任务内可读取的材料,OCR、跨任务缓存和长期入库分别保留后续归属;但来源准入、范围隔离和真实覆盖是当前结果成立的条件,不能一起延期。
周报项目也曾让历史、比较和订阅遮住首份文件交付。后来将当前承诺收拢为用户能取得真实保存、可下载的 HTML,并同步改动范围、任务依赖和验收,而不是只补一句"MVP 优先"。具体经历见分期复盘。这里可以复用的方法是:围绕第一个有用结果组织必要工作,将增强移出当前完成条件,同时保留必要保护和旧失败记录。

图 4:完整结果包括必要保护,增强能力留在本期承诺之外。是否分期取决于交付,而不是目录大小。
贯穿关系到底落在哪里?
| 设计判断 | 在变更中形成的约束 | 实现或验证要观察的结果 |
|---|---|---|
| 不让模型自授执行权 | 获取只消费可信工具结果绑定与原任务准入。 | 伪造文本不触发获取,合法调用能够进入真实接线。 |
| 复用既有事实职责 | 继续使用研究资产与材料工作区,不另建引用系统。 | 原工具身份和业务字段不变,同任务能搜索、读取新材料。 |
| 局部失败局部处理 | 附件逐个接纳和失败,不抹去独立合法结果。 | 同批一个附件失败,其他成功附件与安全业务事实仍可用。 |
| 投影不能升级事实 | 保留解析覆盖与精确读取范围。 | 未解析内容不能被解释为没有内容,局部读取不被标成全文。 |
| 能力生命周期不能偷偷扩大 | 默认任务内使用,长期入库另行处理。 | 隔离与撤权按原职责生效,没有隐式长期知识写入。 |
这张表不是建议再建一个必须填写的文件,而是回看这个案例时的解释。实际记录应复用已有决策、场景、任务和观察。重要的是读者能够沿一项原则追到真实效果,而不是表格每一格都有字。
五、执行之前就处理测试,而不是做完后为实现补一套证明
原则进入了提案和规格,还不够。如果任务拆分、测试前提和实际执行都只围绕方便实现的局部展开,原则仍可能停留在纸上。
文件接入将工作组织为可信描述与获取、格式解析与覆盖、工作区与生命周期三个有凝聚性的单元。每个单元有自己的输入、保护边界和可观察结果,同时通过共享接缝组合成一条路径。它不是给每一个场景再生成 RED、GREEN、REFACTOR、VERIFY 四个 checkbox。

图 5:开发依赖示意,不是历史并发调度或运行时数据流。共享接口先稳定,再并行独立工作。
Task 管结果,Plan 管怎么接续
Task 应当说明一个完整结果何时成立。以可信文件接入为例,它不能仅写"新增 ingestor 类",而要让接手者知道:消费宿主已验证的工具结果,获准附件进入解析,失败附件留下局部状态,原业务字段和凭证边界保持,并通过同一入口验证合法与伪造输入。
Plan 再补复杂工作真正需要的细节:生产接在哪里,先稳定哪个输出合同,哪些测试入口可以直接使用,依赖什么环境,下一位执行者从哪个任务继续。命令结果仍只进入 Evidence,完成状态仍只更新 Tasks。
多 Agent 并行应服从这些依赖。接口和测试前提还没稳定时,把工作分给更多执行者,可能只是更快地产生几套不兼容的假设。只有共享接缝明确、修改范围独立、最终有人负责真实集成时,并行才有清楚的收益。图 5 展示开发依赖,不声称该历史案例按图中方式真实并发执行。
旧测试本身也可能携带旧哲学
一个常见盲点是,新设计已经改变了职责,旧测试却仍把原先的错误边界当成正确答案。例如,设计决定某种可选反馈不能否决完成,旧测试却要求它必须导致整轮失败。此时为了绿灯恢复旧行为,就等于让历史测试替当前产品作决定。
但这也不意味着测试一红就可以删除。编写或实质修改 Spec 时,需要同步判断受影响测试的命运:有效合同继续保留;绑定内部调用顺序、函数名或累计数量的断言可以重构到稳定行为;重复覆盖可以合并;只服务已撤销机制的用例先核对调用者和持久化读者,再退役或删除。
这些判断写在现有 Design 或 Plan 中即可,重点是路径、理由和保留下来的保护,不是为每个断言再造台账。权限、幂等、事务、恢复等有效的独有反例,必须有相应覆盖,不能以"新架构更优雅"为理由移除。
这会让测试成为设计的一部分。接口已经足够明确时,Spec 编写阶段就能演进相关测试、夹具和必要的执行入口;如果还缺关键接缝,记录缺口和最早可执行点,而不是生成一批空测试、todo 或 skip,等实现结束再让模型照着代码写预期。
RED 的价值是辨别力,不是仪式顺序
有意义的 RED 应该实际触及目标行为,并因为该行为缺失或错误而失败。数据库没有启动、模块无法导入、测试本身拼错,都是值得记录的真实问题,但不等于目标行为已被验证。
文件接入的历史账本也不是一份完美的流程故事。其中既有提前观察到的资产层失败,也有无法导入模块的记录,以及明确标为事后构造的集成基线。它们不能全部被重新包装为"严格先测后写"的证明。保留真实偏差,才能知道流程哪里还需要改;美化成模板要求的形状,反而破坏了质量依据。
默认的 TDD 仍应在生产实现前观察有意义的失败。已有明确授权的先实现后集中验证,应保留其不同身份和实际验证,而不是补造过去的 RED。文档与检查工作使用真实 CHECK,也没有必要假装经历了一次产品行为失败。
六、怎样核验原则真的进入了系统,而不只进入文字
"提案提到了五不,Design 写了 Owner,测试也全绿"仍不是充分的答案。核验要沿真实用户路径,观察原则想保护的效果有没有传到最终消费者。

图 6:行为测试、生产接线和独立复核各有问题要回答;环境报错不能替代业务失败观察。
先检查完成对象有没有被缩小
文件接入的早期资产层测试通过后,账本明确保留了一个未完成项:可信描述准入、获取适配、凭证投影和工作区暴露还没有被验证,因此不能把所属工作单元勾成完成。
这个记录阻止了一次常见的完成对象偷换:原承诺是"业务工具返回文件后,研究任务能读取",实际观察却只有"字节能注册成资产"。后续检查才把本地格式夹具送过真实宿主接线,从同一任务工作区读取,核对位置、部分覆盖、撤权和跨范围不可访问。
因此,验收不应只在模块输出处结束。需要检查下游是否真的拿到了该输出、是否仍保留原身份与限制,以及用户结果依赖的下一步是否实际发生。内部调用成功、材料已保存、模型读过和用户拿到结果,是相邻但不同的事实。
既要证明该拒绝,也要证明没有多拒绝
对一个受保护效果,非法路径应被拒绝;对同批独立合法的效果,应当继续保留。两边缺一,测试都可能支持错误的系统。
在文件接入中,这是"伪造描述不能获取,合法附件能够读取";在终结权中,这是"真正取消不发新请求,可恢复的局部错误不直接抹掉整轮";在 HTML 交付中,这是"主动危险内容不能作为静态文件提交,普通合法呈现不因偏好被否决"。
这些不是三套额外测试平台,而是选择有辨别力的反例与对照。它们让测试能区分"保护有效"和"拒绝一切",而不是把更高的拦截率误认为更高的质量。
独立复核不能只复述实现者的故事
复核者需要直接看原要求、相关设计决定、真实 diff、测试和原始观察,而不是只读实现者总结。换一个模型或新开会话,不会自动产生独立性;真正有用的是,预期行为的依据不能完全由被审查实现提供。
比如终结权改造,源码中只剩一个终结入口是有价值的线索,但还要追问调用者是否预先算好了 failed;文件接入复用了一类资产结构,也还要检查同内容跨范围是否共用错误身份;周报已经有下载接口,也还要检查返回链接指向实际保存的最终字节,而不是另一份临时预览。
这里不必强制再增加"哲学评审 Agent"。现有 code review 可以同时检查契约符合性与设计代价。重要的是给评审者正确问题、原始材料和修订空间,不是增加角色数量。
不同质量主张,使用不同的证据
本地合同、真实集成和用户效果需要不同材料。格式解析、来源隔离和局部拒绝可以通过定向合同测试与受控集成检查;真实文件服务可用性需要实际服务的证据;模型能否理解材料、是否给出更好的研究结论,不能从前两种通过推出。
测试层级与是否调用真实模型是两个维度。一个走过完整生产装配入口的端到端测试,也可能使用 fake gateway;它并不会因为叫 e2e 就自动获得真实模型质量的含义。
Spec 应当提前说明本次想支持哪种主张,再据此选择证据。涉及权限的改动即使很小,仍可能需要严格的边界验证;一个改动范围很大的文档或确定性重构,也不一定需要付费模型。风险高低和证据路线不能用同一个粗糙标签替代。
七、新事实出现时,修改被推翻的判断,而不是绕开它
Spec 驱动不是冻结需求后拒绝变化。它更像是给每项决定一个明确的落点,让新事实出现时知道该回到哪里。

图 7:按最早失效的判断选择返回位置;缺条件只阻塞相应路线,撤回也是一种有效结果。
用户把扫描件加入首期,改变的是承诺范围与验收;解析器把截断错误标成完整,首先是实现不满足现有合同;供应商凭证缺失,说明一条验证路线尚未具备条件;普通格式反复被静态文件检查拒绝,则可能说明设计中的拒绝依据本身不成立。
| 新事实 | 优先修订的对象 | 需要保留什么 |
|---|---|---|
| 用户目标或当前交付改变 | Proposal、受影响 Specs、Tasks 与验收范围 | 原决定的来路、延期工作的归属和历史失败。 |
| 设计前提被反例推翻 | Design 及相关行为约束 | 旧方案当时解决什么,为什么现在选择另一方案。 |
| 实现违反有效要求 | 代码、测试与对应观察 | 正确合同,不为绿灯降低必要保护。 |
| 测试绑定了退役机制 | 现有测试、夹具和活动执行引用 | 仍有效的独有保护,以及替代覆盖或退出依据。 |
| 环境、授权或依赖缺失 | 对应验证路线和重试条件 | 未执行、受阻与失败的真实区别。 |
变更理由要能被反驳
一条有价值的设计反思不只说明"为什么选",还应说明哪些事实出现时需要重新考虑。假如新增检查反复拒绝正常任务,却找不到独立保护效果,那么要讨论删除或收窄,而不是一味扩充允许列表。假如可选抽象未减少消费者复杂度,反而让所有普通调用都理解新的状态,它就不该仅凭已经写完而继续保留。
这种修订不应越过现有授权。技术细节在已批准范围内可以自主调整;用户可见行为、权限、范围或验收承诺发生实质变化,则要重新处理相关决定。不能让 approved 一次盖过未来所有变化,也不能每改一个函数都重新索要同样的批准。
退出也是一个合格结果
发现需求收益不足、既有能力已能解决、或维护成本超过实际价值时,Spec 可以收敛为不做、局部修复、仅采集现状,或者撤回。这不是流程失败。反而,明知没有必要还把整份计划做完,才是把执行完整性放在了系统质量之前。
退出时要明确哪些提议没有进入现行规范,哪些临时接线与测试应清理,哪些观察仍有历史价值。停止不等于删掉失败记录;也不能把实际仍有消费者的能力当作已经退役。
八、关闭与归档:把本次正确带入下一次,而不改写历史
实现完成后,Verify 根据证据判断承诺满足到哪里;正式关闭执行所声明的必要验收;已接受的规范增量随后同步到现行规范;归档保留这次变化的过程;有价值的历史帮助下一次设计理解原因。发布仍由独立发布流程决定。

图 8:验收成功后同步规范、归档与交接有价值的历史;缺口继续处理,发布始终是独立动作。
这几个动作为什么不能合成一个"done"?
任务勾完说明工作状态,不证明正式验收已经执行。Verify 生成成功说明视图可以从现有记录得到,不会制造一次新运行。正式本地关闭证明的是声明范围内的合同,不自动批准上线,也不证明真实模型表现。
同样,规范被接受是工程决定,不等于任意部署版本都已符合它。若后来修改了解析器或工作区行为,旧关闭记录仍然是原版本的历史,不能替新的行为背书。文件接入案例在首轮关闭后还有修复与定向复验,相关记录保留各自范围,没有理由把它们合并成一次永远有效的认证。
本项目的 spec:close 是自己的验收机制,不是 OpenSpec 或公开 Evidence Kit 自带的通用发布权。结构检查也有明确边界:它能检查所需任务和观察结构,不能自动证明 Proposal、Design、Delta 与实现语义完全一致。这个差距需要真实执行和评审处理,而不是在文档上再贴一个"完整"的标签。
现行规范保存行为,History 保存理由
为什么不把所有理由都塞进现行 Spec?因为下一个实现者首先需要清楚知道现在的合同,而不是一路穿过所有被放弃的设计。为什么又不能只留代码?因为代码能告诉你今天怎样工作,却未必能解释当初为何拒绝一个依然看起来合理的方案。
文件接入的现行规范需要保留可信来源、覆盖范围、范围隔离和局部失败行为;历史更适合解释为什么解析不放在 Skill、为什么不默认长期入库。终结权的现行规范需要说明谁能继续、收尾与终结;历史则解释为什么统一写库还不够。
这样,归档不是把文件移入冷藏目录,而是完成两种不同交接:把已接受的行为交给后续实现,把有解释力的原因交给后续判断。历史内容仍保留原时点,不自动升级为当前命令;当前任务应先读当前合同,需要理解取舍时再沿链接回看。
没有重要经验,不必制造一篇历史
材料交接采用 none、candidate、history 的区分。没有长期价值可以不晋升;有素材但还不足以形成稳定判断,可以保留候选;真正需要长期使用时才整理正式历史。日常摘要和主题索引是阅读入口,不应复制另一份事实。
已有成功关闭、行为和必要输入没有发生相关变化时,单纯整理归档不应重新发起一轮验收。反过来,有实质未验证变化或具体失败,就不能借"历史复用"掩盖缺口。停止条件与证据来源应当清楚,而不是每进入一个阶段就自动多跑一遍。
九、模板维护:让流程本身保持轻量
一套流程可以在早期解决真实问题,又在使用中产生新的负担。Evidence 就经历过这样的演变:最初是做前状态和执行观察容易丢失,于是增加持续账本;后来有了账本,命令与结果却又被复制到 Tasks、Plan 和 Verify,甚至为了归档被迫制造低价值 History。
2026 年 10 月初的收尾简化,正是用同样的原则审查开发流程本身:已经有事实来源,为什么还要维护第二份?归档是否真的需要一篇新故事?一个记录工具是否正在取得不属于它的验收权?
一个真实的减法:Verify 变成视图
改造复用既有解析能力,从 Tasks 与 Evidence 生成 Verify。它保留原观察日期、版本和结果,输入变了则识别视图陈旧;不覆盖手写文件,不允许越界路径或符号链接绕行。生成器不执行测试,也不判断正式关闭。
这样做并不是让验证更自动就必然更可信,而是减少同一事实的重复维护。它仍依赖作者提供真实记录,也仍需要判断那些观察是否适用于当前主张。视图新鲜与证据适用是两件事,026 的证据验收专题专门展开了这个区别。
与此同时,History 从"归档时总要有"变成依材料价值判断。已有明确验收承诺不会因模板更新被偷偷删除,历史变更也不会被自动回填成新版格式。这个改造有本地合同的验证记录,但没有可比较的开发时间测量,因此不需要宣称"效率提高了多少"才能解释它的价值。
一次踩坑应该改代码、领域规则,还是公共模板?
每次遇到问题都新增全局规则,等于让所有未来任务为一次局部事故付费。更合适的做法是先判断失效发生在哪一层:
| 发现的问题 | 优先落点 | 不应该做的扩张 |
|---|---|---|
| 某种格式的特殊解析限制 | 解析实现、测试和相应领域规范 | 要求所有提案填写这一格式的检查项。 |
| 一个 Owner 的消费者误读了状态 | 修复原生产者或消费者接线及行为回归 | 另造一套全局事实登记与二次裁决。 |
| 多类设计反复遗漏决定权或失败范围 | 在已有 Design Reflection 中改进问题与例子 | 为每个原则新增强制审批状态。 |
| 工件之间重复记录同一事实 | 收拢字段职责,调整生成与检查逻辑 | 再加一张"确保四份文档一致"的对账表。 |
| 新原则似乎与已有原则不同 | 先检验能否被现有判断解释 | 把一次修复、一个阈值或某个技巧立即晋升为核心哲学。 |
这张表是维护时的判断方式,不是增加一套新的工作流文件。原则需要少而稳定,方法可以按问题演进,格式与实现细节回到各自职责。
模板修改要经过自己的变更过程
真正修改模板时,不能只改一个提示段落。维护者需要先定位真实消费者:全局入口怎样路由,共享工作流怎样解释,Schema 怎样生成和判断前置条件,模板提供哪些默认字段,检查器和收尾工具实际读取哪些结构,现有示例是否还成立。
如果改变的是某个问题的表达,保留字段与行为不变,可能只需要定向内容检查;如果改变的是必需字段、生成视图或关闭语义,就需要相应的行为回归。比如生成 Verify 的安全写入,应该测试手写文件不被覆盖、输入变化能识别陈旧、错误路径被拒绝;这些可观察行为不能由一段"注意保护"的指令替代。
同样,若发现旧模板残留要求全量映射、而共享工作流已经强调按需链接,就要查执行指令和实际检查是否一致,再修正受影响的引用。不能假定规则更新后所有旧句子都会自动消失,也不能因为看见一行旧话就重新建立更重的流程。
维护既要测试复杂案例,也要拿一个简单任务试读:新规则是否让作者更容易发现实质遗漏,还是迫使他填写大量没有意义的"不适用"?合理的测试场景至少包括小型检查、跨职责改动和缺少外部前提的任务;这是维护建议,不表示存在一个已经自动认证所有写作行为的评测系统。
给规则保留缩减和撤销的可能
有效模板应该促成有价值的差异:某个问题让我们放弃不必要的机制,某个场景发现过度拒绝,某个执行约束避免把局部绿灯当整项完成。如果一个栏目长期只产生同样的套话,没人用它作判断,它可能需要合并或移除。
这种减法仍要保护真实不变量。删除重复说明,不等于删除权限验证;取消无价值的报告,不等于隐藏失败;减少格式门,不等于让缺少必要观察的任务通过。维护的目标是让重要问题更突出,而不是让所有检查都更容易变绿。
十、把它带回自己的项目:先建立判断链,再选择工具规模
这套方法不要求每个团队复制所有目录,也不要求每个改动经历全部工件。先看现有 PR、CI、规范和评审能否保存承诺、理由、行为与观察;能够承担的部分继续使用。只有跨会话、跨职责、权限与恢复等复杂度出现时,再增加必要载体。
对简单修改,需求和有效测试可能已足够;对有合理备选的行为改动,需要留下选择与反例;对多职责能力,需要真实接线、边界和交接;对模型质量或用户效果主张,则要另选相称的实际评估。文件数量与机制数量都不是成熟度指标。
可以从一个具体问题检验自己的流程:拿掉"遵循原则"这句话以后,读者还能从范围、方案、场景、测试和验收中看出这条原则改变了什么吗? 如果看不出,原则尚未进入工程;如果能看出,而且不需要复制五份说明,它才开始成为持续工作的方式。
可公开复现的是哪一部分?
本文讨论的项目工件和业务案例,不等于公开工具已经包含全部业务实现或内部关闭机制。Agent Engineering Suite 的 Spec Flow提供公开方法与工具材料,其中 Evidence Kit可以检查任务与观察的结构、生成 Verify、读取已有完成记录;它不执行你的产品测试,也不会取得正式关闭或发布权。
准备 Node 26.11.1--26.x 后,可以运行以下固定版本的离线格式示例,不需要模型密钥或数据库:
bash
git clone https://github.com/hpoenixf/agent-engineering-suite.git
cd agent-engineering-suite
git checkout 3b515de2f30e25b1e0757243f3ce4d1be19b00b0
cd skills/aes-spec-flow/toolkit
node bin/spec-evidence.mjs lint --root examples --changes-dir changes --change example --stage apply
node bin/spec-evidence.mjs verify --root examples --changes-dir changes --change example
node bin/spec-evidence.mjs verify --root examples --changes-dir changes --change example --check
产物是示例目录中的 verify.md,不是一次产品验收。示例记录是虚构格式材料;读到这些记录不等于执行了其中的测试。具体安装见固定版本说明,后续维护仍在同一模块的 main。
工具提供骨架,产品仍需要自己的原则、领域合同、合理验证与真正的负责人。尤其不能因为检查器能检查一个字段,就把它误认为那个字段背后的判断也已经被自动解决。
回到文件接入这项需求,Spec 的价值不是多出了多少文件,而是让范围、职责、行为和验收共同约束同一次变化。那些在构思时作出的判断,没有在实现、交接和维护中被悄悄替换;新观察也有明确的位置可以改变旧方案。
Spec 不只是告诉 Agent 怎样施工,还要让团队持续知道:为什么值得这样改,哪些原则必须保持,哪些假设可以被推翻,依据什么接受结果,以及下一次怎样少走同样的弯路。 它不能保证每个判断都正确,却可以让判断有落点、偏离有信号、修订有依据,最终让"坚持设计哲学"从一句口号变成可维护的工程实践。
继续深入验证机制,可读证据链与可信验收;从整体工程责任回看这些机制,可读AI Coding 质量全景。本文保留原阅读地址和完整英文版。源稿与讨论在 GitHub 技术文集,欢迎 Star 支持。
阅读站点原文与完整图解 · GitHub 技术文集,欢迎 Star 支持。