implemented(除 4 篇超长文档随后补)、proposed、rejected 全树配对; 同一流水线 + 二遍校验(paraphrase-back + 仓库上下文一致性)产出。 docs/rfc/implemented/AGENTS.md 与其 CLAUDE.md 符号链接列入排除 (agent 指令文件,与根 AGENTS.md 同策略)。
3.0 KiB
RFC:将 acp-agent 回放配置收归单一来源
Status: implemented
English | 中文
问题
examples/acp-agent 曾维护两份手写配置:cordis.yml(线上树)和一份 cordis.snapshot.yml,后者逐条镜像前者、仅替换 LLM 后端。去掉注释后,全部差异只是八行 llm-deepseek 段落换成两行 llm-replay 段落。每次应用形态变更都要改两遍,且没有门禁保证对称性:如果两份副本漂移,快照层会静默地测试一个与实际交付不同的应用——正是快照层本身要消除的「单元全绿、产品却坏」类缺口,在更高一层被重新引入,唯一的防线是评审者的警觉。
决策
cordis.snapshot.yml include 线上配置,按 id 和 name 禁用指定的 DeepSeek 适配器,并插入回放适配器。因此除此之外的所有条目均来自交付树。回放时选择 overlay;录制仍然启动 cordis.yml,加载守卫允许被有意禁用的条目。
overlay 依赖的一个 vendor 插件事实(有意为之):include 在加载文件时应用 patches——其 refresh()/internal/update 路径重读时不重新打补丁——这恰好满足一次性回放启动的需要(回放应用不加载 hmr,也没有东西在运行中改写配置)。快照套件即为证明:所有场景在 overlay 上原样通过,包括逐字节一致的 golden 文件。
曾考虑的替代方案
为什么不选这些方案?
保留完整的双份配置并加一道对称性校验门禁是记录在案的兜底方案——它能消除静默漂移这一类问题,但仍保留一份 125 行的近似副本,其全部内容只是一个条目的差异,且随应用每增加一个插件而增长。在 bin 侧做替换(解析配置、替换条目、删除文件)会把 YAML 手术放进发布产物,并将回放差异移出视野;overlay 方案让差异保持声明式、可读、且紧邻基础配置——这正是双份配置的支持者真正想要的教学价值。
后果
- 向
cordis.yml添加的插件无需第二次编辑即进入回放树;漂移类问题从结构上消除,而非仅靠门禁拦截。 - overlay 依赖条目携带稳定的
id:。禁用补丁上的name断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。id 重命名会使补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观察的结果是一条无用的无密钥llm-deepseek条目与llm-replay并存,回放输出仍然正确(llm-replay拥有流的短路权);这属于留给评审发现的配置腐烂,而非错误的快照。顶层插入的条目若 id 与已有条目冲突,通过 loader 的 id map 以 last-wins 解析——当前配置无冲突,新增补丁行才是引入冲突的位置。 - 如果未来回放树需要第二处分歧(另一个后端被替换),只需多加一行补丁,而非再 fork 一份文件。