关于 find-gaps
Find Gaps 是一项用于实现前审查计划、验收标准和设计模拟稿的技能,帮助产品负责人和工程团队找出未说明的状态、边界条件与约束。它通过逐项提问,将确认后的决定写回原始文档,而不止提供问题清单。
主要功能
- 01按文档类型检查缺失项
- 02按严重程度分类问题
- 03一次提出一个聚焦问题
- 04将确认决定写回事实来源
- 05复核计划、验收标准和模拟稿
适用场景
- 01实现前检查计划中的风险与依赖
- 02补充验收标准的失败路径和可验证条件
- 03在交接前完善设计模拟稿的状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ citypaul/ .dotfiles --skill find-gaps安装后在 Claude Code 中输入/find-gaps确认已加载。
详细介绍
查找缺口
大多数已发布的 Bug 和上线后的紧急处理,都是因为有些事情从未被写下来,而不是因为写下来的内容有误。这项技能会在实施前系统地找出这些缺漏,因为此时修复成本低。
但找出缺口只完成了一半工作。一份无人作答的待解决问题清单,不过是多了几道步骤的待办清单。如果存在实质性缺口,真正的产出应是更新后的产物——一份计划、验收标准集或模拟稿规格,其中纳入了此前未包含的决策。这些决策由用户作出,原样记录,并写回唯一可信来源。如果评审结论明确指出已检查的章节和极端情况,那么评审未发现问题也完全有效;切勿为了让流程显得有成果而凭空捏造缺口。
何时使用此技能
当用户出现以下情况时,使用此技能:
- 询问“缺了什么?”“找找缺口”“挑挑毛病”“可能会出什么问题?”“帮我完善一下”
- 分享计划、规格说明、验收标准或设计模拟稿,并要求评审
- 即将开始实施,希望先进行合理性检查
- 要把工作交给另一个团队或工程师,希望检查内容是否完整
- 正在进行事前验尸
评审多份模拟稿时,可与 storyboard 配合使用——storyboard 提供单页视图,此技能则找出它们之间缺少了什么。
当故事、计划、规格说明或待办项过于庞大、横向跨度过大、按组件拆分,或尚未表达为各自具备独立价值的子故事时,可与 story-splitting 配合使用。
当“缺口”是指现有代码中无人记录的行为时,可与 characterisation-tests 配合使用。
与相邻技能的界限
find-gaps 需要检查已有产物。它不会从零开始梳理完整的决策树,也不会把宽泛的工作拆分成子故事。
| 需求 | 使用 | 原因 |
|---|---|---|
| 对尚未解决的产品或设计决策进行压力测试 | 如果已安装,则使用 grill-me;否则使用 specification,或每次提出一个聚焦问题 | 在评审书面产物前先厘清决策树 |
| 将宽泛的工作拆分成各自具备独立价值的子故事 | story-splitting | 它创建的是产品/待办列表中的故事,而非实施任务 |
| 完善已写好的故事、计划、验收标准集或模拟稿规格 | find-gaps | 它会找出缺少的状态、边缘情况、角色、约束和无法验证的表述,然后将已确认的决策写回 |
| 判断已完成的实施是否满足权威产物 | acceptance-review | 它只读地逐条评审代码,不改写需求 |
| 将选定的子故事拆分为适合 PR 的工作 | planning | 它负责实施切片和 TDD 执行计划 |
如果尚未把产物写下来,且已安装 grill-me 技能,请使用该技能;否则一次提出一个聚焦问题,或使用 specification 来建立产物;如果问题是工作规模过大,而不是意图尚未明确,则使用 story-splitting。如果评审发现产物实际上是多个纠缠在一起的故事,请停止并转回 story-splitting。如果产物已清晰到足以开始实施,则转交给 planning。
核心原则
1. 页面上没写的内容,比写下的内容更危险。 计划没有提及错误处理,就不是处理得不够妥当,而是完全没有处理。没有衡量方法的验收标准,并非含糊不清,而是无法验证。缺少空状态的模拟稿并非灵活,而是新用户首次打开时就会出问题。把沉默视为红旗,而非绿灯。
2. 每个缺口都是一次对话,而不是一条评论。 静态的缺口清单只是一份报告。这项技能产出的是决策,并将其作为对产物的更新记录下来,由负责这项工作的人作出。提问、记录、写回、确认——这个循环才是核心产出。
工作原理
这是一个对话式循环,而不是一次性报告。流程如下:
- 检查产物,并对照相应的检查清单(计划 / AC / 模型)
- 分诊候选缺口,将其归为阻塞项 / 应处理项 / 可选项
- 开启循环,告知用户有多少个缺口、分别在哪里;如果没有缺口,则报告已审查的证据并结束
- 一次只问一个问题(或一组紧密相关的问题),从阻塞项开始
- 记录每个回答,并将其落实为具体的产物更新——新增一条 AC、一段计划内容或一个命名的模型状态
- 展示拟议的更新,并向用户确认
- 写入经确认的更新,将其保存到事实来源(文件、画布、文档)
- 每解决 3–5 个缺口就回顾一次——让用户了解进展,并及时发现矛盾
- 结束条件:所有阻塞项和应处理项均已解决,或用户表示时间到(明确记录剩余事项,暂不处理)
不可妥协:一次只问一个问题。 一次性抛出二十个问题,这是报告。逐个提出二十个问题,并逐个获得回答、记录下来,才能让产物更加完善。两者的区别完全在于节奏。
缺口闭环
步骤 1 — 检查
按相关检查清单进行检查(见下文的“发现缺口”)。默默记下候选缺口,暂不展示。
如果产物由多个部分组成(例如嵌入了模型的计划,或引用了模型的 AC),请分别检查各部分,以免检查清单相互影响。
步骤 2 — 分诊
将每个候选缺口分类为:
- 阻塞项——没有明确决策就无法继续实施,或实施结果会出错(没有认证模式、没有错误约定、验收标准无法验证)
- 应处理项——如果不处理,可能导致返工或出现错误(没有空状态、成功指标含糊)
- 可选项——不会阻碍本轮迭代,但值得记录(试点阶段的深色模式、v2 的分析事件)
如果所有事项都属于“可选项”,则应从反面再检查一遍,确认是否遗漏了失败路径或未明确说明的假设。如果仍然没有实质性缺口,请结合检查清单中的证据说明这一点;不要把个人偏好升级为问题,也不要凭空捏造阻塞项。
步骤 3 — 开启循环
在提出第一个问题之前,告知用户:
- 已审查的产物类型和章节
- 各严重程度的数量(例如:“3 个阻塞项、7 个应处理项、4 个可选项”)
- 缺口最多的章节或屏幕
- 你会从阻塞项开始,一次逐个讨论,并将每个回答记录为一项更新
明确征求同意后再继续(例如:“我们从支付错误开始,好吗?”或“现在开始吗?”)。如果用户想先查看完整列表,就提供完整列表;但之后仍要继续逐个问答。
步骤 4 — 提问、完善并记录
对于每个缺口:
- 用一句话说明缺口。 不要铺垫,也不要解释理由。
- 提出具体问题。 绝不要把互不相关的问题捆绑在一起。如果答案选项可以枚举——例如失败处理策略、严重程度分类、状态差异范围、暂缓决策——则在可用时使用宿主的结构化输入功能,并遵循其当前架构。否则,用简洁的自由文本提出同一个问题。有关判断方法和示例,请参阅下文的结构化提问。
- 如果回答含糊,就追问,使其变得可测试。 “用户会看到错误” → “显示什么消息?用户能否重试?” 关于微文案的追问应使用自由文本;如果追问是在少量行为选项中缩小范围,则应使用结构化输入。
- 根据以下模式,将完善后的回答转化为产物更新。
- 原文展示拟议的更新,然后通过受支持的结构化输入或一次自由文本确认,让用户选择按原样写入 / 在线编辑 / 放弃并重做。只有在措辞确实可以并列比较时,才使用宿主支持的并排预览功能。
- 确认后,将更新写入事实来源。
- 继续下一项。 不要在此处停留过久。
步骤 5 — 每发现 3–5 个差距就回顾一次
总结哪些问题已解决、按严重程度还剩哪些问题,以及你注意到的答案之间有哪些不一致。这一步能发现“买家可以从错误页面重试,但两个问题之前我们说只有管理员才能重试”这类在单个问题中看不到的情况。
步骤 6 — 结束
遇到以下情况时停止:
- 所有 Blocker 和 Should-address 项都已解决(理想的结束状态)
- 用户表示要暂停(“暂时就这样”)——明确列出尚未解决的差距及其负责人,确保没有遗漏
- 遇到需要由用户无权做出的决策的差距——指出实际负责人,将该差距列入待办,然后继续处理其他问题
如果你发现这份产物需要进行比问答所能完成的范围更大的改写(例如,AC 集描述了三个纠缠在一起的不同功能),请明确说明,并建议用户重新开始编写该产物。
差距发现 — 检查清单
针对每种产物逐项检查到底。不要因为“这可能不适用”就跳过类别——检查只需一行,遗漏却可能导致服务中断。
计划
- 范围与意图: 是否说明了不在范围内的内容?是否有一句话的问题陈述?是否有成功指标和基线?不采取行动的代价是什么?
- 前置条件与依赖项: 必须预先具备或满足什么?哪些其他团队必须先交付?是否有跨领域迁移?
- 排序与增量价值: 能否分阶段交付?第一个最小但有价值的阶段是什么?每个阶段的回滚路径是什么?是否有暗发布、功能标志或金丝雀发布?是否有应通过
story-splitting重新拆分的纯数据库、纯 API 或纯 UI 组件阶段? - 故障与恢复: 生产环境中最可能发生的 3 种故障是什么?每种故障由哪些明确命名的仪表板或告警检测?如何恢复(操作手册、自动重试、回滚)?数据丢失的影响范围有多大?
- 状态与数据: 每个实体的有限状态模型是什么?如何处理并发修改?是否具备幂等性?回填或迁移计划是什么?保留、删除和 GDPR 方面如何处理?
- 可观测性与运维: 记录或发出什么信息来确认其在生产环境中正常工作?值班负责人是谁?操作手册链接在哪里?SLO 或错误预算是什么?
- 安全与合规: 认证和授权矩阵是什么?如何处理 PII 和机密信息?针对首要攻击向量的威胁模型是什么?
- 测试: 各层(单元、集成、E2E)的测试策略是什么?明确不测试哪些内容,为什么这样做是可以接受的?
- 未明说的团队经验: 如果新工程师只阅读这份计划,哪些内容会被误解?
验收标准
- 可衡量性: 能否通过机器或测试验证?模糊词汇清单:快速、直观、无缝、现代、整洁、响应迅速、运行良好、直接可用、健壮——每项都需要有数字或具体行为定义。
- 前置条件/触发/结果规范: 每条标准都包含前置条件、触发和可观察的结果。缺少任何一项 → 就只是一厢情愿。
- 负向路径: 每条顺利路径都要有对应的失败路径(超时、验证错误、并发编辑、权限拒绝、超出配额、离线、数据过期)。
- 输入边界情况: 空值/null/缺少可选项;最小值/最大值/边界值;超长字符串;非 ASCII 字符、表情符号、从右向左书写的文本、组合附加符号;重复项、大小写变体、空白字符;数值 0/负数/极大值/货币精度。
- 时间与区域设置: 时区(用户、服务器、存储)、夏令时切换、i18n 文本扩展、复数形式、日期格式歧义。
- 参与者与角色: 每条标准适用于哪种角色——匿名用户/已认证用户/管理员/服务/模拟用户?会话期间权限发生变化时会怎样?
- 非功能性要求: 性能目标(p50/p95 和工作负载)、无障碍性(WCAG 级别、键盘、屏幕阅读器)、安全性(认证、速率限制、审计日志)、隐私(PII 可见性)。
- 可观测性标准: 哪些事件或指标能证明该标准在生产环境中已满足,而不只是测试通过?
- 完成标准: “完成”意味着什么——已合并、已部署、已向 100% 用户推出,还是已观察到对 N 位用户正常运行?
设计稿
- **UI 状态:**加载中/骨架屏、空状态(首次使用)、部分加载、错误(网络、验证、404、403、500、超时)、成功/确认、禁用、只读(无权限)、离线、速率受限、数据过期/需要刷新。
- **内容变化:**最短(1 个字符、1 个项目)、最长(最大长度、10k 列表)、零/一个/多个;缺少头像、图片损坏;Unicode(表情符号、从右向左的文字、CJK 换行、组合附加符号);数字(0、负数、大数、货币、百分比);日期(今天、相对日期、久远的过去、遥远的未来)。
- **交互状态:**悬停、焦点(键盘!)、激活、选中、禁用、拖动、异步等待与乐观更新。
- 响应式与密度:≤360px 手机屏幕、平板竖屏/横屏、桌面、超宽/拥挤布局、浏览器缩放至 200%。
- **无障碍:**仅通过颜色传达信息、交互元素的对比度、焦点环与顺序、屏幕阅读器标签/aria/alt、触控区域 ≥44×44、减少动态效果的替代方案、表单标签与错误关联。
- **主题/平台:**浅色/深色/系统/高对比度、减少动态效果、后退/前进/刷新/深层链接、移动 Web 与原生应用。
- **权限与角色:**匿名查看、只读、编辑、管理员、会话期间角色变更。
- **数据生命周期:**创建/编辑/删除流程+撤销+确认;底层记录被其他人删除时的行为。
- **国际化:**文本扩展(德语 +40%)、文本收缩(CJK)、从右向左镜像(不仅是文本,还包括布局)、按区域设置格式化数字/日期/货币。
补齐缺口 — 将答案转化为工件更新
每个已解决的缺口都要在工件中以文字形式体现。以下是三种转换模式。
答案 → 验收标准
将每条标准写成 前置条件 → 触发条件 → 可观察结果,每条标准只包含一个可观察结果。包含参与者、状态、具体 UI/数据行为,以及用户实际确认会发出的任何事件。(这是验收标准的结构要求,不是编写 Gherkin 场景或给定/当/那么测试 DSL 的指令——测试仍按照 testing 技能,以行为为驱动。)
- 缺口:“没有关于重复工作区邀请的规格说明。”
- 问题:“当邀请 API 报告此邮箱已收到邀请时,所有者应该看到什么?”
- 含糊的回答:“我们会告知用户。”
- 追问:“具体显示什么消息?显示在哪里?”
- 细化后的回答:“在电子邮件字段的错误提示区域显示‘此人已有待处理的邀请。’”
- 要添加的 AC:
**AC-14:**已登录的工作区所有者位于邀请表单时,如果邀请 API 返回
already-invited,UI 会在电子邮件字段的错误提示区域显示 “此人已有待处理的邀请。”
**测试:**QA 工程师应该能够执行这条标准,而无需提出任何追问。如果他们还需要追问,这条标准就还没有完成——继续细化。
答案 → 更新计划
写出作者若事先想到,就会写进计划中的句子(或段落)。明确说明所属章节、权衡和故障模式。
- 缺口:“迁移没有回滚策略。”
- 问题:“如果迁移中途失败,我们如何恢复到可正常运行的状态?”
- 回答:“每个步骤都有对应的逆向操作;我们有一个按顺序执行逆向操作的
migrate down。” - 计划更新(新增章节):
回滚。
migrations/中的每个迁移步骤都提供up()和down()。发生故障时,运行pnpm migrate down,按相反顺序重放每个已完成步骤的down()。**数据丢失风险:**在up()完成到故障发生之间插入的任何行都会被down()留下孤儿记录——通过在 Redis 中持有migration-in-progress标志来降低此风险;应用层会读取该标志,并在迁移期间短路插入操作。
答案 → 模拟状态规范
对于每个遗漏的状态,都要记录 名称 / 触发条件 / 视觉呈现 / 行为 / 退出条件,确保无需再次询问即可实现该状态。
- 缺口:“联系人列表没有空状态。”
- 问题:“新用户首次打开‘联系人’屏幕时应该看到什么?”
- 答案:“一条友好的消息,以及用于导入 CSV 或手动添加的按钮。”
- 状态规范:
empty-first-use
- 触发条件: 已通过身份验证的用户,账户中有 0 个联系人
- 视觉呈现: 居中的内容列;插图(复用 impeccable tokens 中的
EmptyIllustration);H2“还没有联系人”;段落“将你的人脉关系带入应用。”;两个按钮——主按钮“导入 CSV”(打开导入表单),次按钮“手动添加”(打开添加联系人表单)- 行为: 页面加载时按钮已启用,没有其他可用操作
- 退出条件: 成功添加或导入任何联系人 →
populated列表状态
与用户协作
只问用户能回答的问题。“错误处理策略是什么?”属于设计探索。“付款被拒时,用户应该看到什么消息?”则是一个具体决策。
每轮只问一个问题——除非两个问题紧密相关(“错误是什么,用户能从那里重试吗?”)。结构化输入请求只能在宿主能力支持的限制范围内批量询问紧密相关的子问题;把无关的缺口打包到一个请求中,就会变回缺口倾倒。如果你发现自己要打“另外”,就停下来,挑最重要的问题问。
**沿用用户的词汇。**如果用户说“买家”,AC 中就写“买家”。不要悄悄改成“用户”或“客户”。领域用语本身就是一种功能。
**每次都要清晰记录决策。**每个已确认的答案都要在继续之前写入产物,并让用户看得见。绝不要私下列出清单,打算“最后再核对”——那样只会不了了之。
**明确说明权衡,不要隐藏。**如果答案会引发后续问题,就说:“这意味着匿名用户仍然可以提交表单,但会收到 401 错误——你希望采用这种体验,还是先重定向到登录页面?”让用户了解后果。
**知道何时升级处理。**如果某个缺口需要用户无法独自做出的决策,就明确指出实际负责人,连同问题和负责人一起明确搁置,然后继续。
**不要重复分流。**你已经为每个缺口决定了它属于阻塞项 / 应处理项 / 可选项。不要对每个缺口都问“你想处理这个吗?”——直接问具体问题即可。用户想跳过的话可以说“跳过”。
结构化提问
你向用户提出的每个问题,要么是自由文本,要么通过当前宿主实际提供的能力进行结构化提问。检查并遵循该能力的架构,不要想当然地假定特定提供方的工具名称、字段或限制。根据答案的价值所在来选择:
- 选项本身就是答案 → 使用受支持的结构化输入。选择比生成更快,用户也能直观看到选项范围,而且常见答案可以预先确定。
- 用户的具体措辞就是答案 → 使用自由文本。领域词汇、微文案、新颖决策,以及任何将原样复制到产物中的内容。
适用场景
当宿主支持结构化输入,且答案范围确实可以枚举、并会在不同项目中反复出现时,请使用结构化输入:
| 场景 | 结构化提问为何有帮助 |
|---|---|
| 故障处理策略 | 重试 / 快速失败 / 排队 / 故障转移——每种方式都有值得说明的权衡 |
| 严重程度重新分类 | 阻塞 / 应做 / 可选——当你的分类与用户的分类不一致时,这很有用 |
| 状态差异范围界定 | v1 中哪些状态重要——从多个已命名选项中选择,可以减少来回沟通 |
| 暂缓决策 | 暂缓并指定负责人 / 立即升级 / 继续处理——补上问题处理流程中的缺口 |
| 确认写回 | 照原样写入 / 行内编辑 / 丢弃——起草更新后,经典的 3 选 1 收尾方式 |
| 方案对比 | 两份 AC 草案或两份状态规范,以受支持的并排形式呈现——对比胜过逐段讲解 |
不适用场景
不要在不适合的地方强行使用结构化输入:
- 微文案——“应该显示什么错误消息?”需要用户提供确切措辞。
- 真正开放的问题——“你想在这里实现什么?”你会凭空编造选项。
- 领域专家问题——“在我们的定价流程中,‘已确认’是什么意思?”用户掌握你不知道的信息;结构化选项会让他们受你的猜测影响。
- 流于形式的提示词——如果正确答案已经显而易见,就不要提问,直接提出建议。
结构规则
- 仅将紧密相关的子问题合并提问,并遵守宿主支持的问题数量和选项数量上限。
- 遵循已发现的架构中对标签、描述、推荐标记、自定义答案行为和预览的规定;不要编造不受支持的字段。
- 标签要简短;当选项描述字段可用时,应在其中说明重要权衡。
- 仅当宿主支持并排预览,且相关产物确实可比较时,才使用并排预览。
示例——结构化处理重复邀请
缺口:“没有关于重复邀请行为的规范。”
如果宿主支持包含两个问题的结构化请求,就一并提出这两个紧密关联的决策。否则,分轮提问:
- 用户体验:“当邀请 API 返回
already-invited时,应该如何处理?”- **行内字段错误(推荐):**让负责人留在当前上下文中,并指出需要处理的邮箱。
- **页面横幅:**更加醒目,但与字段的关联不够明确。
- **打开待处理邀请:**仅当负责人可能需要查看该记录时才有用。
- 遥测:“是否应为重复尝试发送遥测事件?”
- **发送
invitation.duplicate_rejected(推荐):**支持滥用情况和转化漏斗分析,同时不包含受邀者邮箱。 - **不发送事件:**减少数据量;如果现有的聚合拒绝指标已能回答问题,则适合采用此选项。
- **发送
用户选择后,为面向用户的结果起草一条验收标准;如果用户选择了遥测,则另起草一条遥测验收标准。它们可以共享相同的前置条件和触发条件,但每条标准都应对应一个可独立判定的结果。自定义文本应逐字使用。然后,通过受支持的结构化输入,或一个简洁的自由文本问题,请求用户选择照原样写入 / 行内编辑 / 丢弃。仅当宿主支持该呈现形式且差异确实重要时,才提供并排草案。
输出
主要输出是更新后的制品,写入事实来源所在的位置:
- 验收标准 → AC 列表,在适当位置追加或插入新增/修订的标准
- 计划 → 计划文档,新增段落或章节
- Mock 规范 → 每个屏幕对应的
states.md或同等文件
次要输出是在会话结束时记录一份决议日志:
## Gaps closed — find-gaps session, YYYY-MM-DD
Resolved (12):
[Blocker → AC-14] Duplicate invitation handling
[Blocker → Plan §4.2] Rollback strategy for migration
[Should → AC-15] Empty contacts list state
[Should → states.md] Search results loading/empty/error states
[Nice → AC-19] Dark-mode contrast on error banner
...
Parked (2):
[Blocker] Analytics event schema — owner: @growth-lead (decision pending for v2)
[Should] i18n for German — owner: @i18n-team (no locale priority yet)
日志应记录在 PR 描述、发行说明或其他追踪工作进度的位置,这样决策(包括搁置的决策)才不会消失。
反模式
- 罗列 20 个缺口后就撒手不管。 这只是份报告,不是评审。用户不会据此采取行动。逐个跟进。
- 每发现一个缺口都问“要解决这个问题吗?”。 你已经完成了分类——说明缺口,提出具体问题,记录答案,然后继续。
- 接受含糊的回答。 “用户会看到错误”无法测试。继续 уточ уточ化,直到得到具体、可观察的结果。
- 把问题捆在一起。 “消息是什么、什么时候显示、用户能否重试、是否会记录?”→ 分四轮提问,而不是一次问完。
- 悄悄改写用户的用词。 如果他们说“检查点”,就写“检查点”,不要写“保存状态”。
- 跳过回写制品。 缺口只有写入文档后才算解决。口头约定会在不同会话之间消失。
- 让一个巨大的缺口吞噬整个会话。 如果某个缺口需要讨论 30 分钟,那就是一次设计探索。先搁置它,继续推进,之后再回来处理。
- 停在随意设定的配额上。 完成相关检查清单,并沿着关联制品追踪证据,但不要为了让评审显得全面而凭空捏造缺口;有证据支持的干净结果也是有效结果。
- 把品味问题当作缺口。 风格偏好不是缺口,缺少决策才是。
- 孤立地评审制品。 交叉核对计划 ↔ AC ↔ Mock——缺口往往表现为两者之间的矛盾,而不是某一项中的缺失。
- 为了使用结构化输入而编造选项。 如果你不清楚实际的选项范围,就改用自由文本提问——虚构的选项会让用户受你的猜测影响,也会掩盖他们真正的答案。
- 对微文案使用结构化选项。 “应显示什么错误消息?”必须使用自由文本。用户的原话就是要记录的内容;结构化选项会抹去这些原话。
- 把无关的缺口打包到一个结构化请求中。 如果宿主支持,与同一缺口紧密相关的问题可以放在一个请求中;不同问题的组合只是假装成结构化请求的缺口堆砌。
快速参考
| 制品 | 务必检查的 3 大缺口 |
|---|---|
| 计划 | 未说明范围外事项 · 无回滚路径 · 无可观测性 |
| 验收标准 | 不可衡量的措辞 · 缺少负向路径 · 无非功能性目标 |
| 设计 Mock | 缺少加载/空/错误状态 · 未考虑长文本差异 · 未处理键盘焦点 |