返回文章

write-quality-vision:把「感觉不错」写成能打分的锚点

这是 Harness 技能深挖系列的一篇:21 个技能逐个拆,每篇只讲一个——为什么要有它,具体怎么干。这一篇在澄清链上排第三,前面是 澄清阶段 的访谈和 write-prd 写下的需求清单,后面是技术设计。系列母篇是《从能跑到可交付:一套前端 AI 协作系统的设计笔记 》,我用的系统是开源的 frontend-harness-cli ,文中所有规则都能在仓库里找到对应实现。

功能全对,还是觉得不对

先看一个具体的场景。

你让 AI 做一个通知列表页。验收时逐条对需求:列表能拉到数据,对;点一条标记已读,对;未读数实时更新,对;翻页、筛选、排序,全对。每条功能检查都打了勾。

然后你打开页面,皱眉:加载时整页闪一下白屏;列表是空的时候,中间一大片空白,什么都不显示;报错提示只有一句 “Error”;行与行挤在一起,标题和时间的字号分不出主次。你的评价是四个字:感觉不对。

问题来了:这四个字没法返工。你说感觉不对,AI 说功能都实现了——你们吵的不是同一件事。它手里有需求清单,每条都做到了;你手里有一种没写下来的期待:页面应该"像样"。这个"像样"从来没有被写进任何文件,于是它不存在于流程里,只存在于你验收时的心情里。

write-quality-vision 要解决的就是这一件事:在写代码之前,把"像样"拆成一条条能被检查的句子,钉进一份文件。

vision.md 是什么:给「感觉」留的合同

这个技能是规划者的著述链第二步(write-prd 之后、技术设计之前),产出一个文件:.harness/tasks/<feature>/vision.md。

技能文件里对它的定位只有一句话,但很准:vision.md 是"用户期望它给人什么感觉"与"评估者打什么分"之间的桥。 后面评测阶段的评分表(rubric)里有一类条目叫 judge 条目——靠评判者看证据打分的条目。规则是:每个 judge 条目都必须引用 vision.md 里的一个锚点;不引用的,内核直接拒绝。也就是说,评判者不能凭自己的审美打分,它打的每一分都要能追溯到这份文件里写好的一句话。

这份文件的原料也有明文规定。动手前必须先有两样东西:prd.md 已存在、澄清小结已确认;然后读两处材料——澄清阶段记下的 quality-expectations.md(访谈时问到的品质期待)和 PRD 里的"成功画像"一节。技能文件里这句写得最硬:愿景里的一切都来自用户的回答——你不发明品味。 规划者在这里是转述者,不是设计师。

锚点:REF、ANTI、RL 三种句子

vision.md 的核心是三种锚点,语法固定,一行一个,内核会解析:

REF-1: <正面参照——好在哪、在哪能看到>
ANTI-1: <反面参照——要避免什么、为什么>
RL-1: <红线——绝不可接受> (check: screenshot|dom|command)

三种锚点管三件不同的事:

REF 是正面参照:一个具体的来源(某个产品、某个页面、某张设计稿),加上它好在哪。规则二规定:只有链接、没有"好在哪"的,不算锚点。因为评判者拿着一个光秃秃的链接没法打分;拿着"这个列表的行高和留白比例,一行一条、扫读不累"才能比。

ANTI 是反面参照:要避免什么、为什么。正面参照说"往哪去",反面参照说"别掉进哪个坑"——比如某种花哨的动效、某种信息堆砌的密度。没有 ANTI,生成时模型很容易滑向它训练数据里最常见的那种"看起来很努力"的样子。

RL 是红线:绝不可接受的情况,而且每条必须声明怎么查——screenshot(截图)、dom(查 DOM)还是 command(跑命令)。以截图检查的红线,后面对应的 judge 条目必须引用一张真实的 PNG 截图当证据。

数量上有硬下限,澄清收尾(clarify-done)时内核强制检查:REF 至少 1 条、ANTI 至少 1 条、RL 至少 2 条,且每条 RL 都带 (check: …)。

文件其余部分是给锚点提供上下文的:一句定位(层级是 MVP、精打磨还是生产级;优先级排序,如"正确性 > 交互 > 视觉 > 性能";一句基调,如"密集而安静的工作工具,信息优先");设计意图(视觉方向、密度取向、交互范式,外加一张关键页面表:每行是一个页面,列是用户目标、目标状态、挂哪个锚点);最后是与 rubric 的映射——设计意图转成 L3 条目、交互范式转成 L4 条目、每条 RL 转成 pitfall 条目(或引用它的必查 judge 条目)、每个 REF 进入每次全量评估的对比项。映射写在这里,评分表就不是另起炉灶,是这份文件的下游。

一条品质条目,凭什么能打分

锚点语法只是格式,真正的门槛在规则一和规则三。

规则一:具象胜过形容词。 技能文件给的正例是"卡片间距 12–16 px,次要文字用 neutral-600 token",反例是"要好看"。为什么形容词不行?因为打分的人不是你,是一个上下文全新的评判者。它没参加过澄清,不知道你说的"高级"长什么样。两个评判者对"高级"的理解可以完全相反,于是同一份代码这次过、下次不过——分数变成掷硬币。“12–16 px"不一样:拿尺子量,要么在区间里,要么不在。

规则三管红线:每条红线都必须可检测,能在截图里看见、在 DOM 里查到、或能用命令验。技能文件的原例很直白——“要快"不是红线;“任何点击 100 ms 内有可见反馈"才是。前者是一种愿望,后者是一个可以拿秒表和截图去验的事实。

所以"流畅"“高级"“精致"这类词不是被审美否决的,是被可判定性否决的:它们写进 vision.md,评判者引用不了,引用了也判不出真假,最后只会变成评测阶段的噪声。品质条目的入场券不是写得美,是一个陌生人拿着它和一份证据,能说出"做到了"或"没做到”。

开篇那个通知列表页,换成锚点写法大概是这样:空状态挂一条 REF——“空列表显示一句话说明加一个主按钮,参照某产品的空状态处理”;白屏闪烁是一条 RL——“加载中显示骨架屏,不出现整页空白(check: screenshot)";“Error"是一条 RL——“错误提示包含可执行的下一步,不出现无上下文的英文报错(check: dom)"。写成这样,验收时就不再是"感觉不对"四个字,而是三条编号、一一对账。

为什么写在代码之前、由规划者写

顺序和作者,都是设计的一部分。

为什么必须在代码之前。 品质标准如果等代码写完再定,它就不再是标准,而是对既成事实的追认——页面已经长成这样了,写标准的人会不自觉地照着它写。先写锚点,锚点才有资格在评测时说"不”。这和澄清阶段"考卷出在考试之前"是同一条逻辑,只不过 PRD 管的是功能对不对,vision 管的是品质够不够。

为什么由规划者写。 因为只有规划者手里有用户的原话。它刚做完访谈,quality-expectations.md 就是它记的笔记。换成实现者写,它只能写自己的品味;换成评判者写,它就既当运动员又当裁判。而规划者也有越界的口子,规则四专门堵:如果用户没有给参照、是规划者提议了几个方向,只有被用户在澄清中选中的那个方向才能写进来——提议可以,替用户做主不行。

没有品质面的需求:豁免也要写明理由

不是每条需求都有品质面。比如"把日志按天切分"这类纯内部需求,你让规划者硬给它配一条视觉锚点,它只能编。

系统的处理方式不是放行不管,而是要求书面豁免:在评分表里给这条需求写一个 qualityWaivers 条目,注明它为什么没有品质面(“没有品质面"的原因要写出来)。覆盖门禁会强制检查这一条:每条需求要么有挂着锚点的品质条目,要么有一份带理由的豁免。

区别在哪?没有条目是疏漏,疏漏是无声的,日后没人知道这条需求是被评估过、确认不需要品质条目,还是压根被忘了。豁免是决定,决定有理由、有记录、可复查。系统不怕你说"这条不用管”,怕的是你什么都不说。

这一份文件管不了什么

边界照例说清。

第一,它放大不了用户没表达过的品味。 完成标准里有一条:文件里没有任何一条找不到用户回答作为来源。用户在访谈里没提过的事,vision.md 里不会有;访谈问得浅,这份文件就浅。它的上限是澄清的质量,不是规划者的想象力。

第二,它只覆盖说得清的品质。 能写成参照、反参照、红线的,才进得了这份文件。有些品质真实存在但难以落成可检测的句子——比如整体气质的微妙偏差——锚点体系承接不了,那部分仍然要靠人眼在验收时判断。vision.md 是把"可打分的品质"从"感觉"里尽量捞出来,不是宣布感觉从此不存在。

第三,没有 UI 的功能要换锚点种类。 规则五:纯接口功能保留定位、红线和映射三节,改写 API 品质锚点(错误格式一致、提示可操作),并明写 ui-vision: N/A — <理由>。还是那条原则:不适用可以,但要写明,不许留空。

到这里,澄清链已经回答了两个问题:做什么(PRD)、做到什么样算好(vision)。下一篇是 write-tech-design:在动手之前,把"打算怎么实现"也写成一份要过审的文件。

[END OF FILE]