implement-task:一个任务,从失败的测试开始,到一个真提交结束
这是 skill 深挖系列的一篇。前面拆过澄清链的六份 skill(把一句话需求变成契约的那一组),这一篇开始拆实现组——契约签完之后,真正写代码的环节。母篇是《从能跑到可交付:一套前端 AI 协作系统的设计笔记
》,实现阶段的全貌在《实现阶段:一次只做一个任务,每个任务留一个真提交
》里讲过;这一篇只钻一份 skill:implement-task,开发者角色的核心技能。我用的系统是开源的 frontend-harness-cli
,文中所有规则都能在仓库里找到对应实现。
派它修一个 bug,它顺手重构了半个项目
先看一个具体的场景。
任务写得很清楚:订单列表用了优惠券之后,总额算错,修它。AI 接了任务开始干活。它打开订单组件,觉得日期工具函数写得太乱,顺手重写了;路过列表页,觉得加一个“最近浏览”小部件会更完整,加了;共享表格组件的接口它看着别扭,改了。两个小时后交活:六个文件、四百多行 diff,优惠券那个 bug 在主流程里确实好了——但有一种券的组合还是算错。
它没有偷懒,甚至可以说过于勤快。每处改动单看都说得过去。问题是:任务的边界被它当成了建议。 那四百行里,哪几行是修 bug 的?没人分得清。评测说“券的边界情况没过”,修复的人要在重构、加功能、修 bug 三摊改动里捞针。而日期工具的重写没有任何需求背书、没有测试契约、没有人验收过——它就这样混进了一个本该只有几十行的提交里。
implement-task 存在的理由,就是把“边界”从一句提醒变成一套有机器兜底的动作:一个任务,从失败的测试开始,到一个只含这个任务的真提交结束,中间不许漂移。
这份 skill 是什么:一次只执行一个任务
澄清阶段结束时,计划已经拆好了:tasks.json 里一条条任务,每条写明了要动的文件、契约(做完应该是什么样)和检查项。harness next 返回 implement-task 时,这份 skill 就被触发——由开发者角色执行,一次只执行其中一条。
它对自己的定义,原文第一句就是全流程的浓缩:“一个任务从头到尾:失败的测试、代码、通过的测试、提交、记录。内核只在检查通过且提交 SHA 真实存在时接受任务。”
注意“只执行一条”。这不是效率洁癖。任务是这套系统里最小的对账单位:一条任务对应一组需求编号、一次提交、一次检查。粒度一旦放大——一口气做三条、一个提交装五件事——后面所有环节(评测定位、回滚、修复)都失去坐标。所以这份 skill 的第一性原理是:任务的边界就是工作的边界,越界不算勤奋,算事故。
开工之前:先读契约,不读考题
动手之前,它规定先读五样东西,不得跳过:
harness packet <feature>给出的任务包:任务 id、标题、对应的需求;plan.md/tasks.json里这条任务本身:要动的文件、契约、检查项;tech-design.md:技术栈与边界——后面会讲,这份文件同时是一张白名单;.harness/standards.md:项目规范;vision.md:本任务涉及页面的目标状态,以及每一条红线(RL-n)。原文的要求是“有意识地防御红线”——写代码时主动想着别踩,而不是等评测来抓。
有一份文件它明确不读:rubric.json,评分表。理由在阶段篇里讲透了:干活的人按计划和愿景构建,不按考题构建;提前看过量具,目标就会从“把需求做对”滑向“让检查通过”。
这个读序本身就是设计:先知道任务要求什么(契约),再知道边界在哪(设计与规范),最后知道页面应该长什么样、什么绝对不能发生(愿景与红线)。唯独不知道“最后怎么打分”。
它怎么干:红、绿、重构、提交、记录
流程八步,每一步都有可查验的产出:
第一步,先写一个会失败的测试。 不是随便写一个测试,而是写“任务契约所要求”的那个测试,然后运行它,看它因为正确的原因失败。这一步的产出就是那段失败输出。为什么顺序不能反?反模式清单里写得很直白:先写代码、再补一个只是复述代码的测试——那种测试是一面镜子,代码写什么它照什么,永远不会红。先让测试红一次,你才证明了它真的在测东西:功能不存在时它会失败。
第二步,最小实现。 让这个测试通过,“别的不做”。最小不是将就,是纪律:多写的每一行都不在契约里,没有测试护着,也没有需求等着。
第三步,变绿。 运行这个测试,加上任务自带的 checks,全部通过,而且要是新鲜的输出——反模式里专门列了一条:不许拿“最后一次修改之前”的测试结果宣称完成。证据必须比代码年轻,否则你证明的是上一版代码没问题。
第四步,重构。 不改变行为地整理,然后重跑。重构夹在“已变绿”和“提交”之间,是因为这时你有测试兜底,改坏了立刻知道。
第五步,状态补全。 如果任务要渲染数据,加载中、空、错误、无权限四种状态必须都存在、且都有测试。这和语言层那篇的判断同源:AI 默认只写主线畅通的路径,而真实世界的 bug 一大半出在“不存在”上——这一步就是把四种“不存在”钉成任务的完成条件,而不是上线后的补丁。
第六步,精确提交。 命令原文给得很细:
git status --short
git add <本任务的确切路径>
git commit -m "feat(<TASK-ID>): <标题>"
git rev-parse --short HEAD
逐条点名要提交的路径,绝不 git add -A、绝不 git add .,绝不提交无关文件。提交信息带上任务编号,提交完立刻用 git rev-parse 取真实的 SHA——下一步要用它对账,不许凭记忆报。
第七步,写报告。 报告写到 .harness/tasks/<feature>/developer/<TASK-ID>-report.md:改了什么(文件清单)、提交 SHA、测试命令和结果计数、契约范围内自己做的决定、没能完成的部分。有个细节值得一提:评估者永远看不到这份报告。 它是给下一个开发者和后续修复用的。这是有意的——评测的独立性靠的就是不看执行者的自述;自述的用途是交接,不是证据。
第八步,记录。 执行 harness task-done <feature> <TASK-ID> --sha <sha>,由内核验收:检查是否通过、这个 SHA 是否真实存在。被拒,就修正原因、从失败的那一步重来——原文最后一句是硬话:“不伪造 SHA。”(这条规则为什么存在,阶段篇里那个不存在的提交讲过。)
设计一:范围是许可,不是建议
这份 skill 里最硬的一条边界,藏在“先读”的第三项里:tech-design.md 没写到的东西——框架、状态库、运行时、任何包——一律不碰。原文的处置不是“尽量别加”,而是:停下,报告 blocked。
为什么这么绝?因为加一个依赖不是实现细节,是设计决策。技术设计是规划者定的,依赖一旦被执行者即兴引进,后面评测打分的对象就悄悄换成了另一套系统:设计里没有的东西,评分表里自然也没有对应的检查,它会无声地通过所有验收。反模式清单的最后一条正是这一条:“因为方便加一个新依赖。”
换个角度看:任务里列出的文件清单和技术设计里的白名单,合起来定义了这次工作的许可范围。许可的意思是,没列出的默认禁止,而不是默认可以、回头再说。人的协作里这条靠默契,对 AI 必须写成规则——因为它的默认倾向恰好相反:遇到障碍时,它更愿意扩展工具箱,而不是停下来问。
设计二:为什么禁止“顺手”
反模式第二条:“『顺手』改别的任务的文件。”
顺手重构在人类工程师那里是美德,在这套系统里是违纪,原因有三层。
第一层,对账失效。每个任务一次提交、提交对得上需求编号,这是全系统的坐标系。顺手改动没有需求编号、没有测试契约,它混进哪个提交,哪个提交的账就花了。
第二层,验收失效。评测是按功能和任务组织的:这条需求对应这些检查。顺手改的文件不在任何任务的契约里,没有人为它写过检查——它等于绕过了整套验收直接入库。开头那场戏里被重写的日期工具就是这样:它可能是对的,但“可能对”没有经过任何一道门。
第三层,回滚失效。出了问题要退,退的单位是提交。一个提交里揉着修 bug 和重构,你要么全退(把修好的也退了),要么手工摘——摘的过程又是新的无验收改动。
所以规则不是“不许改进代码”,而是“改进要走流程”:发现别处有问题,记下来,它会成为另一条任务,有自己的契约和验收。顺手的反义词不是冷漠,是排队。
设计三:做不了就停下报告,不许即兴发挥
任务可能根本做不了:契约要求的组件在技术设计里不存在,依赖的接口和文档对不上,或者做下去就必须引入白名单之外的东西。普通做法是让 AI “灵活处理”——这正是漂移的起点。
这份 skill 的处置是停:报告 blocked,把做不了的原因写清楚,交回内核和规划者。任务契约写错了,修契约的人是规划者;执行者即兴改道,短期看任务“完成”了,实际是把一个计划错误,兑换成了一个没人知道的实现偏差——等到评测或上线时爆出来,排查成本翻几倍,还查不到源头(源头在某次没人记录的即兴发挥里)。
同理,如果测试或检查失败、原因又不明显,它也不许在这里硬猜乱试:切换到另一份 skill——systematic-debugging——按根因流程来。下一篇就拆它。
它管不了什么
边界说清。
这份 skill 保证的是:一条任务在它的契约范围内被执行,并且留下可验的证据——先红后绿的测试、范围内的改动、一个真实的提交。它保证不了计划本身是对的:任务拆错了、契约写歪了,它会忠实地把错的计划执行得很规范,那是澄清链要管的事。它也保证不了“任务的检查全过”等于“功能做对了”:任务级检查只是门禁,功能对不对要等评测阶段拿评分表逐条验。
它更像一个严格的施工队:按图施工、每道工序留记录、图外的活一概不接、图纸有问题停工上报。图纸对不对、房子最后合不合格,不归它——但没有它这一层,图纸再对,盖出来的也未必是图纸上的房子。