# SKILL.md — coder / org-coder 执行质量操作手册 v1 > 训练对象:`coder`(及 org 版 `org-coder`)四段式生命周期(RESEARCH/PLAN/EXECUTE/VERIFY) > 判据来源:`../digest/benchmark_v1.md`(6 维度,D1/D5 封顶) > 定位:这不是 benchmark 的复述,是"照做就能拿高分"的操作清单。每条都配一个可以直接执行的 > 机械动作,不是一句原则性的话。看不懂"怎么做"就说明这条没写到位,回来改。 > 不改变 `coder/agent.md` 的硬约束 1-7 和四段式产出物形态——本手册是在硬约束之上补"做得 > 够不够格"这一层,硬约束仍以 `agent.md` 原文为准。 --- ## 开工前必读:两张清单,RESEARCH 阶段建好,全程带着走 在 RESEARCH 阶段读完 prd/sdd/acceptance 之后,**在 `_research.md` 里追加两张表**(不是额外文件, 就是现有 RESEARCH 产出物里的一节),后面 PLAN/EXECUTE/VERIFY 全程对着这两张表走,不要凭记忆判断。 ### 清单 A:SDD 接口契约锚点表(服务 D4) 逐条过 SDD,把每一处"技术落点"分到两栏: | 类型 | 判据 | 处理方式 | |---|---|---| | **锚点**(必须逐字/逐值对齐) | 数值型规格(px/颜色值/断点/字号/间距/比例)、无障碍属性(`aria-*`/`role`)、被测试脚本/下游节点引用的 selector/id/事件名/API 字段名 | 实现时逐值照抄;如果因为客观原因做不到(比如平台限制),必须停下写 `blocked`,不许悄悄改数值 | | **内部命名**(允许自由发挥) | 没被声明为下游消费对象的纯内部 class 名/变量名 | 允许换名字,但换了之后 `coder.log` 要有一句"此项非接口契约,采用等效实现:SDD 写的是 X,我用了 Y,理由是……" | 机械动作:**扫描 SDD 全文里出现的每一个具体标识符/数值,逐条填进这张表,扫完为止**——用"扫完了" 而不是"我觉得重要的都记了"作为完成判据(借用 prd-planning 训练"描述性语言扫描"的思路,见 `../hunt/knowhow_v1.md` 2.3 节)。 ### 清单 B:SDD 明确禁止/明确不需要清单(服务 D5,全场最高权重锚点之一) 逐条过 SDD,凡是出现"不需要""不写""不做""明确选择不……""下游不应该补上"这类字样的句子, 原文摘录进这张表。这张表在样本 A/B/独立样本里都存在真实反例(见下方 D5 一节),**只要 SDD 里有一句话说"不需要防抖状态标志",这句话就必须被摘进清单 B,后面 EXECUTE 每写一行代码都要 回头看看有没有踩中这张表**。 如果 SDD 通篇没有这类句子,清单 B 记"本次 SDD 未出现明确禁止项",不是不用做这步,是做完之后 发现是空的。 --- ## RESEARCH 阶段(产出:`_research.md` + 清单 A/B + 规格空缺初判) 1. 读齐 prd/sdd/acceptance,缺一份不动手(硬约束2,不重复)。 2. 建清单 A、清单 B(见上)。 3. **规格空缺初判**(服务 D6):读的过程中标出所有"没写清楚/有歧义"的点,对每一点立刻问自己 一个可回答的问题——**"如果我按理解 X 实现,和按理解 Y 实现,acceptance 判定结果会不会不一样? 写入范围会不会不一样?"** - 会不一样 → 标记为"高风险空缺",带到 PLAN 阶段,PLAN 阶段直接 `blocked`,不进 EXECUTE。 - 不会不一样(只影响实现细节的具体形态)→ 标记为"低风险空缺",带到 PLAN 阶段,PLAN 里 写清楚打算采用哪种保守读法。 - 判断不了 → 按"高风险"处理,不要因为偷懒省事就往"低风险"那边靠。 4. **vacuous case 也要显式写一行**:如果这次规格完整、全程没遇到空缺,`_research.md` 里也要 写一句"本次规格未发现需要标记的空缺点"——不写这句话,VERIFY 阶段没法判断你是真没遇到, 还是遇到了但没记。 --- ## PLAN 阶段(产出:`_plan.md`) 1. 高风险空缺 → 本阶段直接 `report_task(blocked)`,不进 EXECUTE(D6 判据)。 2. 低风险空缺 → 写清楚采用的保守假设,一句话即可,但必须写(D6 判据"未显式记录假设"扣分点)。 3. **给每一条 acceptance 预先写好验证方式**:不是到了 VERIFY 阶段才想"这条怎么测",而是 PLAN 阶段就把"用什么命令/工具/参数测第几条 acceptance"写进表格。提前想清楚"怎么测"能倒逼你在 EXECUTE 阶段写出"测得出来"的实现(而不是写完发现没法验证)。 4. **内容/数值类功能,此时就定下最小标准**(服务 D3):涉及文案的功能点写最小字数/字符数区间, 或"必须包含至少一个具体名词/数据/场景化描述";涉及数值的功能点直接抄清单 A 里对应的数值, 不要留"大概"。 5. 最小步骤拆分(沿用现有硬约束,一段段推进,见 knowhow §一(c))。 --- ## EXECUTE 阶段(产出:代码 + `coder.log`) 这是 D5(核心锚点,权重25,≤2 分总分封顶50)真正决胜的阶段。**样本 B 的教训是:`currentScrollTarget` 这段代码在 EXECUTE 阶段写下去的那一刻就该被拦住,而不是等 VERIFY 阶段回头审查——回头审查 "看起来是合理的工程实践",会觉得没问题,正是这种"合理性掩盖了违规性"的错觉导致了漏记。** **机械动作(D5,必须当场做,不许挪到 VERIFY 阶段补记)**: 每写完一段实现(哪怕只有几行),在落笔进 `coder.log`"实现过程"之前,先做这一步自问 (三支判断,不是两支——"SDD 没禁止"不等于"可以不记"): 1. 这段代码对应清单 B 里的哪一条明确禁止项? - **对应**——**停下**。三选一,且必须显式写进 `coder.log`(不写视为违规,即使代码本身 工程上合理):删掉严格照 SDD 不写;或保留但写一句"SDD §X 建议不写 XX,但发现 YY 场景下 会有 ZZ 问题,权衡后仍加入,理由是……";或按 D6 判断线不确定就 `blocked`。 - **不对应任何一条清单B禁止项,往下走第2步,不要就此跳过。** 2. 这段代码实现的行为,SDD 全文(模块划分/接口契约/数据形态等章节)有没有明确要求过? - **没有要求过**(SDD 通篇没提这个行为,但也没禁止)——**必须留痕**:在 `coder.log` 补一句"SDD 未提及,新增理由:……",哪怕只有一句话也要写,不许因为"清单B没命中"就 当没发生过。这一支比第1支宽松(不需要三选一权衡),但"要不要留痕"没有商量余地。 - SDD 已经要求了这个行为,只是具体写法你换了个方式实现——走清单 A 内部命名判断(下一步)。 3. 这段代码有没有引入清单 A 里"锚点类"要求之外的新标识符/新数值?如果有,检查是不是应该 对齐某个锚点值,还是纯内部实现——按清单 A 的两种处理方式走。 **反模式对照(真实样本,直接照抄进 coder.log 会踩雷)**: - ❌ 样本B原型(命中第1支):SDD 写"不需要维护'是否正在滚动'的状态标志",实现里加了 `currentScrollTarget` 变量做条件判断,`coder.log` 只字未提。这是"明确禁止"级别的违规, 三选一都没做,直接命中 D5 最低档。 - ⚠️ 独立验证样本原型(`p-v82tpc`,命中第2支):SDD I-2 契约只要求"监听 click→ scrollIntoView→preventDefault",实现额外加了 `hashchange` 全局监听 + `history.replaceState` 清 hash 的防御性代码——SDD 没有禁止这么做,但也完全没提过,`coder.log`(重跑版)完全没提 这段代码的存在。这不是"明确禁止却写了"那么严重,但落进第2支"未提及"的范畴,同样需要留痕, 漏记只是程度较轻的失分(不像样本B那样触发封顶),但依然是失分。 - ✅ 正确做法:这两类偏离都只需要在写下去的当下补一句话,成本极低。样本B级别的漏记会让 D5 从 2 分被封顶到总分上限50(见 `industry_avg_score.md` 基线二反事实分析,一句话能把总分从 50 冲到 92.6);`p-v82tpc` 级别的漏记则是从满分掉到 3 分档左右,不触发封顶但仍然是可避免 的失分。 --- ## VERIFY 阶段(产出:逐条命令+真实输出写进 `coder.log`) 这是 D1(核心锚点,权重25,≤2 分总分封顶45)真正决胜的阶段。 **机械动作(D1,逐条 acceptance 过一遍,缺一不可)**: 1. 对每一条 acceptance 判定,问:"这条 PASS 的依据里,有没有出现以下任意一个信号词—— '代码走查'、'规则推导'、'逻辑上应该'、'理论上'、'看代码可以确认'、'不需要实际运行'?" 命中任意一个 → 这条判定**不算数**,必须回去用真实命令重跑,不许直接改措辞掩盖。 2. 每条判定必须能看到"具体执行的命令"(如 `npx playwright test ...`、`node xxx.js`、 `curl ...`、截图/DOM 快照路径)+ "真实输出"(终端返回值/具体数值/exit code)二者同时出现, 缺一不算过。 3. **反模式对照**:样本A `coder.log`(`rn_09845e11f11b`)attempt-1 原文——"本地未装浏览器 自动化工具,采用代码走查 + CSS 规则推导确认……判定:PASS"——这句话本身就是 1 分档反例, 即使最后代码是对的,判定过程本身不算数。 4. **正面标准(黄金参照,够格的样子长这样)**:样本B `coder.log`(`rn_9385bad9a4e7`)—— 真实 Playwright 测试 6 档视口高度、误差全部 ≤7px,定位根因(footer 太矮)→ 修复 (`min-height:60vh`)→ 复测确认,全过程写进日志。独立验证样本 `p-v82tpc` 的重跑记录同样 给出了具体命令(`node tests/unit-tester.check.js`、`curl -o /dev/null -w "%{http_code}"`) 和真实返回值(exit=0、200),这是可以直接复用的记录范式。 **机械动作(D2,可重放性,逐条判定检查三要素)**: 每条判定必须同时具备:**环境**(工具+版本/服务地址端口)、**输入**(具体参数:视口宽高/URL/ 点击序列/命令行参数)、**可比对的预期输出**(具体数值/DOM状态/误差范围)。三缺一,第三方就 没法照抄复现——检查方式是问自己"如果我现在把这条记录原样交给另一个人,他不问我任何问题, 能不能重跑出同一个结论",答不了"能"就是不合格。 **独立发现的 D2 缺口(供后续版本参考,本轮先记录不展开处理)**:`p-v82tpc` 的 `tests/unit-tester.check.js` 对 `responsive_layout` 只断言"两个断点是否存在",没有像 `hero_first_impression` 那样对每个断点下的实际计算值(如 480px 断点下标题:正文字号比例) 做数值校验——这意味着即使某个断点下比例真的跌破了 PRD 要求的下限,这份"可重放"的测试也 测不出来。D2 判据本身没错(这条记录确实可重放,重放出来的结论就是"断点存在"),但提醒我们: **"可重放"不等于"测的是对的东西"**,D3/D1 的深度要求要一起看,不能只满足 D2 就停手。 **机械动作(D3,内容深度)**: 1. 全文搜索交付代码里的 `TODO`/`待补充`/占位符文案。 2. 对照清单 A 里的数值型要求,逐项核对代码里的实际取值,不是"差不多"就算过。 3. 描述性要求("简洁大气"类),检查代码里能不能指出具体的实现痕迹(配色数量、留白数值), 不能只是套用默认样式敷衍。 **机械动作(D4,接口契约裁决)**: 逐条过清单 A,对"锚点类"要求检查代码是否逐字逐值对齐;对"内部命名类"检查如果换了名字, `coder.log` 是否留了那一句说明。**独立发现的真实反例**:`p-v82tpc` 的 SDD I-1 契约原文写 `
` + ``,实际交付用的是 `