关于 old-coder
old-coder 是面向编码 Agent 的技能,要求先由人批准可执行规格,再开始实现。它以测试驱动流程、分层验证和可审计的证据报告组织开发。
主要功能
- 01由人批准可执行规格
- 02RED-GREEN-REFACTOR 工作流
- 03分层测试与质量验证
- 04可审计的证据报告
适用场景
- 01编码前明确行为与约束
- 02通过测试和静态检查验证改动
- 03记录代码验证的结果与限制
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ amazingang/ old-coder --skill old-coder安装后在 Claude Code 中输入/old-coder确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/gauntlet.mdtemplates.mdverifier-case-study.mdverifier.md详细介绍
Old Coder:在约束与测试下可靠编码
人类不会阅读你的实现。他们的信心完全来自你产出的两份材料:(1)他们在你编写代码前批准的可执行规范,以及(2)证明代码经受住整套考验的证据报告。你的任务是让这两份材料足够可信,从而在规范的边界内,逐行审查成为可选项。
这颠覆了常规审查模式:信任从检查转向约束。 要诚实说明这能带来什么:整套考验会把规范表达的约束转化为可执行证据——它无法证明规范涵盖了所有重要事项,而且证据也不能自行验证,因为检查器可能不可靠,映射声称的内容也可能超出其实际证明的范围。这正是人类要批准 SPEC 的原因(它是唯一能打破所有内容都由同一个 Agent 编写这一相关性的材料),也是 EVIDENCE 报告分层且可审计的信心,而非绝对证明的原因。你对整套考验采取的任何捷径,都会摧毁唯一的信任基础。
与 old-coder-api 配合: 当两项技能都适用时,本技能负责工作流顺序、SPEC 审批、整套考验和 EVIDENCE;old-coder-api 负责 HTTP/JSON 契约。起草 SPEC 时,运行其范围检查和 API 门禁;将保留下来的约束与风险转化为验收标准和检查项,再将这些检查项映射到 EVIDENCE。不要并行运行两套工作流。
循环
SPEC → (human approves spec, not code) → RED → GREEN → REFACTOR → GAUNTLET → EVIDENCE
↑_____________________|
repeat per behavior
1. SPEC — 编写代码前人类唯一阅读的内容
在动手修改实现文件之前,先把请求转化为可执行的验收标准:
- 使用 Gherkin 风格的场景或命名测试列表描述行为,明确具体输入、预期输出、边界情况和错误情况。“能处理错误输入”不是规范;
divide(1, 0) raises ZeroDivisionError with message X才是。 - 写明变更不得做什么(必须保留的不变量:现有测试、公共 API 签名、明确提出的性能预算等)。这些负向约束和任何场景一样,都是合同条款:每一项最终都必须在 EVIDENCE 中对应到一个测试、一层 gauntlet,或一条明确说明原因的跳过记录——绝不能悄然漏掉。
- 规范同时也是授权环节:其中应包含设置计划——要安装的工具、git 用法(是否 init?检查点提交的频率?)、gauntlet 将按路径新增的文件,以及每个新增依赖及其一句话理由(优先使用标准库和已有依赖;未说明理由的包属于规范缺陷)。这样,批准规范就能一次性授权环境变更,避免 N 次中断;同时人类可以在有风险的包安装前否决它。
- 用通俗语言向人类展示规范,并在编写实现之前取得批准。在自主模式下,在回复中说明规范并继续执行——但这意味着没有经过消除相关性偏差的审查,因此 EVIDENCE 必须记录
spec approval: not obtained (autonomous run),并相应降低置信度;规范将成为人类事后审查的产物。 - 对问题的回答不等于批准。 如果你请人类作出决定,他们只回答了问题,并未做其他事。这个回答是规范的输入,并且会改变规范——因此,你在提问前持有的任何批准,批准的都是一份已不存在的文档。提问和批准是先后两轮交流:先纳入答案并说明变更,再展示修订后的规范并再次征求批准。如果你无法引用批准这份规范的原话,就说明你没有获得批准——对问题的回答、针对其他步骤的“继续吧”、沉默,以及启动任务的请求,都不算批准。“推荐选项”的形式很容易让人犯错:当人类选择了你推荐的选项时,规范看起来没有变化,似乎也暗含了同意,但这两点都不成立。
- 任务期间,规范只能追加。如果实现过程揭示规范有误,就明确指出并公开修订——绝不能悄然偏离。
- 将规范写入文件,并注明绝对路径。 相对路径在终端里不可点击,因此人类无法打开这个要求他们批准的唯一产物。之后的 EVIDENCE 也一样。SPEC 和 Gherkin 模板见
references/templates.md。 - 在仓库的 git 约定允许的情况下,在批准时提交规范——设置计划中应已授权此操作。一旦获批的规范成为一次提交,之后的偏离就能通过
git diff直观看到。如果没有持久化的规范,压缩过程会让已批准的合同丢失,而它授权的代码仍然存在;届时无人能检查某个场景是否被悄悄从 EVIDENCE 映射中删掉。
2. RED——证明每项测试都能失败
针对一种行为编写测试。在编写实现之前,运行测试并观察它失败。从未亲眼见过失败的测试毫无证明力——它可能根本没有测试任何内容。实践中需要注意以下细节:
- 如果被测模块尚不存在,请创建一个会引发异常的存根(例如
NotImplementedError),这样测试会因行为而失败,而不是因导入而失败——收集错误不如断言失败能有力地证明 RED 阶段有效。 - 只要能分别观察到每项新测试失败,相关行为就可以在同一次 RED 运行中测试。
- 如果新测试一运行就通过,要么它没有实际作用(修正它),要么该行为已经存在。不要只断言是哪一种——要证明这一点:用一次性的临时变异破坏实现,观察测试失败,然后还原。接着将其记录为已有行为,并保留为回归防护。
3. GREEN——实现最小化
编写能让失败测试通过的最少代码。运行完整测试套件,而不只是新测试。
4. REFACTOR——在绿色状态下清理,冻结断言
最少代码往往不够优雅。测试套件通过时,可以改进命名、提取重复代码并简化结构。冻结的是行为断言,而不是整个测试文件:
- 实现重构不得触碰任何测试文件。
- 测试结构重构(提取辅助函数和 fixture、消除重复的设置代码)可以作为单独步骤进行:断言保持不变,重构前后测试套件都通过,然后重新运行变异测试,确认重构后的测试仍能杀死变异——削弱测试效果的重构,会在这场考验中留下无声漏洞。
- 任何需要编辑断言的操作都不属于重构,而是行为变更,应回到 SPEC 阶段。
每次重构后都运行测试套件。针对每种行为,重复 RED→GREEN→REFACTOR 流程。
5. GAUNTLET——约束关卡
所有规范行为都通过测试后,运行所有适用的层级。根据任务调整规模(参见“Calibration”),但绝不要默默跳过某个层级——如果某个层级不适用或工具不可用,请在证据报告中说明原因。
| 层级 | 检查内容 | 方法 |
|---|---|---|
| 完整测试套件 | 回归问题 | 使用项目的测试命令,确保没有新增失败(见下方基线说明) |
| 静态类型检查 | 整类错误 | 使用 tsc / mypy / 等工具,确保没有新增错误 |
| Lint + 格式检查 | 潜在错误、风格偏移 | 使用项目的 Linter,确保没有新增警告 |
| 变更行覆盖率 | 未测试的代码路径 | 确保每一行变更或新增代码都由测试执行;工具支持时检查分支覆盖率。全局百分比只是表面指标——约束应是变更行覆盖率。未达到阈值时,此层必须以非零状态退出(--cov-fail-under、diff-cover --fail-under 或等效选项):只打印百分比并以 0 状态退出的层是报告,而不是闯关层;覆盖率下降时它仍会显示绿色 |
| 变异测试 | 不验证任何内容的测试 | 优先使用项目的变异测试工具(mutmut、cosmic-ray、Stryker、PIT……),它会从语法树生成变异体,且不会悄悄跳过任何变异体。没有可用工具?按 references/gauntlet.md 手动变异——每次引入 3–5 个合理的错误;测试套件必须杀死每一个;之后恢复代码。手工编写的运行器必须证明每个变异体都已执行:如果运行器报告杀死了实际未运行的变异体,就会虚增分数,闯关也永远无法发现问题 |
| 基于属性的测试 | 未曾想到的边界情况 | 针对解析、数学、序列化,以及任何具有不变量(往返、一致性、顺序性)的内容——添加 hypothesis/fast-check 属性 |
| 复杂度预算 | 难以维护的输出 | 新函数应简短且用途单一;如果一个函数需要一整段文字来解释,就拆分它 |
| 实际运行 | “测试通过,但无法运行” | 使用真实输入实际运行一次应用/CLI/端点,而不仅仅运行测试框架 |
| 供应链与机密信息 | 易受攻击/不必要的依赖、泄露的凭据 | 依赖集合有变化时:对其进行审计(pip-audit / npm audit / govulncheck / cargo-audit)并检查许可证;扫描差异中的机密信息;每个新增依赖都必须能追溯到 SPEC 中的依据。另外,仔细检查能力差异:此次变更是否开始使用以前未使用的网络 / 子进程 / 文件系统 / 环境变量? |
| 测试套件健康状况 | 不稳定或依赖执行顺序的测试 | 以随机顺序运行测试套件(pytest-randomly 等);重复运行疑似不稳定的测试。每个 EVIDENCE 数字都以测试套件具有确定性为前提——不稳定的测试套件会悄无声息地使报告失效 |
基线说明——如果仓库中已有失败,先记录基线 (哪些测试已经失败,逐字记录),并确保没有新增 失败。修复无关的既有失败属于范围蔓延:应将其指出, 不要悄悄“改进”它们。
变异测试注意事项——失败会归因于最先失败的测试,因此
7/7 的杀死率验证的是整个测试套件,而非其中的每一层。在第 3 级,
声称属性验证了什么之前,应仅使用属性测试套件重新运行变异体;
如果仍有变异体存活,说明不变量存在盲点(一个常见问题是:
“永不超过上限”这类单向不变量无法发现故障时默认关闭的错误——
应搭配相反的边界)。
检查器说明——攻坚测试的可信度取决于检查器,而危险的检查器故障模式是放行失败:没有任何报错,层级却打印了通过。现成工具(pytest、mypy、tsc……)的失败行为值得信赖;自制检查——grep 门禁、自定义脚本、手动变异运行器——则不然,因此要遵守两条规则:(1)失败时拒绝放行——崩溃、输入不可读、退出代码意外,或门禁代码内部有项目被悄然跳过,都意味着该层级必须判定失败,绝不能判定通过;不得使用 || true、2>/dev/null 或无条件落空。(2)信任其通过前,先证明它能失败:用一个已知有问题的输入(负向对照)运行一次,并观察它失败——这是将 RED 原则应用于检查器,就像对一个一运行就通过的测试使用一次性变异体一样。在 EVIDENCE 中记录这个对照。请准确说明它能证明什么:**负向对照只能证明一个已知有问题的案例触发了检查器的失败路径。它不能证明检查器能够识别其声称要执行的约束所涉及的每一种违规。**grep 门禁可以完美地在失败时拒绝放行,却仍然可能只检查拼写,而非行为。若门禁的覆盖范围比它所服务的规则更窄,就应在规则的描述处说明,而不是让规则造成更广泛的暗示。
要证明负向对照本身并非空转,方法与证明测试有效相同:临时移除或破坏它所验证的防护措施,并观察对照是否变红。如果移除防护措施后对照仍然通过,那它就毫无测量价值——这只是一次性证明,不是永久增加的一层。
等价变异体说明——使用变异工具时,存活的变异体不一定意味着失败:有些变异体在语义上与原始版本等价,无法被杀死。在 EVIDENCE 中将此类存活变异体归类为“等价,因为 ”,而不要添加毫无意义的测试来杀死它们——那样会违反反作弊规则 4。手写变异体(手动流程)没有这种借口:既然是你选的,就要选择真正的 bug。
6. EVIDENCE——代码之后人类唯一会看的内容
最后提供一份人类无需打开任何源文件就能信任的报告(模板见 references/templates.md):
- 经批准的规范,并将每项行为对应到验证它的测试。
- 攻坚测试的每一层:运行的命令及其实际结果(粘贴具体数字,而非形容词)。“47 项测试全部通过,变更行覆盖率 100%(31/31 行),手动变异体杀死 5/5”——绝不能写“测试看起来不错”。
- 所有数字都必须来自最后一次代码编辑后执行的全新最终运行——任务中途运行的结果已经过时,不得报告。
- 报告必须能仅凭仓库内容复现:其中引用的每条命令(包括变异脚本)都必须作为持久化文件存在于仓库中,而不能放在临时目录或只出现在对话中。可复现意味着:开发工具版本已固定或记录;有一个入口命令可重新运行所有层级;并且已标明源码状态(提交 SHA;若无 git,则提供源码树哈希)。
- 跳过了哪些层级,以及原因。
- 任何失败及其解决方式,务必如实说明。第一次就通过的攻坚测试和经过修复后通过的攻坚测试都完全可以;唯一不可接受的是悄悄削弱攻坚测试。
反作弊规则(绝对)
只有无法作弊,这场考验才能建立信任。以下是硬性规则:
- 绝不要为了通过测试而削弱测试。 不要放宽断言、添加跳过项、提高容差或删除失败的测试。如果测试似乎有问题,那应该作为规格讨论提出,而不是掩盖起来。
- 绝不要在同一步中同时修改测试和实现以让测试通过。 先修改一方并运行测试,再修改另一方。同时修改会让你无意中重新定义正确性,使其与自己的缺陷相符。
- 绝不要模拟被测单元,也不要过度模拟,以至于测试只是在测试模拟对象。模拟边界(网络、时钟、文件系统),不要模拟逻辑。
- 绝不要追逐覆盖率数字。 覆盖率是用于检测未测试代码的指标,不是目标。只为触及代码行而添加、没有有意义断言的测试,就是作弊——变异测试的存在正是为了发现这种情况,包括你自己的情况。
- 绝不要报告你没有运行过的层。 诚实地说明“已跳过:此环境没有变异测试工具,已改为手动变异”,可以维持信任;捏造结果则会摧毁整个方案。
- 考验未通过,就不能算完成。 只要有任何一层失败,你就还没有完成。如果确实受阻,请逐字报告失败结果。
校准
根据影响范围调整工作量,并说明你选择的层级:
- 第 1 层——琐碎(拼写错误、注释、配置值):运行完整测试套件并执行 lint。无需新增测试,但要说明为何该变更无法测试或已有测试覆盖。
- 第 2 层——常规(缺陷修复、小型功能):完成完整流程。缺陷修复必须先编写能复现缺陷的 RED 测试——只有把昨天的缺陷变成明天的回归测试,修复才算完成。
- 第 3 层——高风险(资金、身份验证、数据丢失、并发、公共 API):先简要编写故障模型:列出此项具体变更可能造成损害的方式(竞态条件、部分写入、恶意输入、溢出、无界增长、回滚失败……),并为每种模式添加能够实际捕获它的测试层——并发问题用竞态/压力测试,解析器用模糊测试,迁移用回滚演练,延迟预算用基准测试,公共库用 API 兼容性检查,服务边界用契约测试,可能出现静默生产故障时加入日志/指标断言(完整选项见
references/gauntlet.md)。变异测试和覆盖率不能替代这些;通用考验是底线,不是上限。然后:完成完整流程 + 基于属性的测试 + 变异测试(如果可用,使用工具)+ 对抗性检查——在宣布完成前,明确进行一步操作,用恶意输入尝试攻破自己的实现。对于有意不覆盖的故障模式,应在 EVIDENCE 中列为已知限制。对抗性检查是你对自己的工作发起攻击,存在同样的盲点;如果规格缺口代价高昂,可考虑下文的独立验证——这是一种不同类型的保障,而不是另一层测试。
独立验证(Tier 3 选项,实验性)
压力测试套件是证据,而非自证:其检查器可能不可靠,其映射可能夸大其词,规范也可能不完整。人工批准规范只能通过打破作者关联来缓解最后一项问题,而且必须在代码出现之前进行——这并不能让规范变得完整。
在风险值得投入的情况下,独立验证可以处理其余问题:由一个拥有全新上下文的 Agent 在 EVIDENCE 签署之前,对完成的工作进行攻击性审查。它减少的是任务上下文关联,而非模型关联。它不是压力测试套件的一层——层是可执行且结果可由机器评估的检查;而这只是 Agent 返回的一段文字,必须由人判断,并且会耗用这项技能原本要保护的唯一资源。实验性:证据只有一个案例研究(references/verifier-case-study.md——用于决定是否运行验证,不供验证器阅读),并非基准测试。
验证协议见 references/verifier.md。只有完整阅读并执行该文件后,才算完成验证;文件缺失或无法读取时,状态为 blocked,绝不能是 passed。 不可妥协的要求如下:
- 使用全新上下文,先盲审,且只提供四项输入——任务约定、已批准的 SPEC、精确的源代码状态、入口点。绝不能提供你的对话记录。草稿 EVIDENCE 必须在验证结果生成之后才提供。
- 验证器不修复任何问题。 SPEC 缺口应提交给人,而不是交给构建者自行修改。
- 由人对发现的问题分级。 行为问题必须修复,并在新的上下文中重新验证;描述和映射问题只需修复并披露,不必因此增加一轮验证。你可以提出分级建议,但任何有争议或重大的问题都由人裁定,并由人批准是否在轮数上限处停止。自行分级是让这条规则失效的显而易见方式。
- 最多两轮,除非得到明确批准,否则不得增加。上限并不限制投入,而是让投入由人决定。
- 验证针对特定源代码状态。 验证器未见过的状态一律为
not performed,无论此前各轮得出了什么结论。因此,如果在最后一轮获准验证之后修复了行为问题,发布的就是未经验证的状态:应将其记录为已声明的降级,并保留此前各轮作为历史记录。 - 四种状态:
passed表示完成;failed和blocked不表示完成;not performed只有作为已声明的降级,才表示完成,与未经批准的规范类似。在 Tier 3 中,无需为此道歉——如实说明,并降低声明的程度。
设置
隔离 — 不要为执行任务而修改用户的工作树。 在 SPEC 中说明所用机制,并用一句话说明原因:工作树、分支,或不隔离——仅限 Tier 1,此时影响范围只是一个拼写错误。应由人工在审批时否决该机制,而不是事后才发现。
注意:新建的工作树不包含任何被 git 忽略的内容,因此在重新构建依赖项之前,通常无法在那里运行全套测试。两种做法都可以接受——在工作树中重建并运行,或改用分支并记录原因。切勿报告一个实际上从未运行过测试套件的工作树为通过。
如果隔离树与最终接收变更的树在被忽略或未跟踪的内容上有所不同,请在 EVIDENCE 中说明:在缺少最终接收树的 .env 或构建产物的树中运行并通过,不能作为最终接收树的证据。
如果项目没有测试运行器、代码检查器或类型检查工具,先为该语言搭建最精简的标准工具链(参见 references/gauntlet.md)。没有基础环境,就无法运行全套测试。搭建工具链会改变用户的环境——包括软件包、配置文件和锁文件——因此应纳入 SPEC 的设置计划,由 SPEC 审批一步授权;并在证据报告中记录实际进行的每项环境变更。如果用户不允许添加工具,则改用手动测试层(手动变异、手动执行),并如实记录降低后的置信度。
如果该目录不是 git 仓库,应在 SPEC 的设置计划中提出执行 git init。版本控制本身也是测试层之一:在 SPEC 以及每个 GREEN/REFACTOR 检查点提交,这样就可以通过 git diff(而不是肉眼检查)验证变异恢复、回滚糟糕的重构而非对其进行调试,并让最终差异准确显示所有变更。检查点提交只能在 SPEC 批准的授权范围内进行(或根据用户的明确要求进行)——绝不能强迫尚未同意的仓库所有者遵循提交节奏。如果用户拒绝或 git 不可用,请在 EVIDENCE 中记录这一点——此时变异恢复只能依靠重新运行测试套件来验证,保证较弱——并使用树哈希而非 SHA 标识源状态。