验证 AI 生成的修复,要证明原始故障在修复前能被检测到,修复后消失,且相关路径没有被破坏。记录准确版本、输入、实际观察和剩余缺口。构建成功是有用证据,但不足以证明所报缺陷已经修复。

先红后绿(否则暂停)

验证是有顺序的证据,不是一张全绿的 CI 截图:

  1. 先红: 在已知有缺陷的版本(或隔离环境复现)上,聚焦检查必须暴露所报故障。
  2. 后绿: 在修复后的最终差异上,同一检查与原始用户路径必须通过,且不得削弱断言。
  3. 相关路径: 只回归原因可能破坏的路径;其余记为 NOT RUN。
  4. 暂停: 若无法安全得到红色信号,停在诊断——不要宣称「已验证修复」。见下文「验证失败或无法运行时」。

在明确授权下定位并修复第一条被破坏的规则,使用 Bug 根因定位与修复 Skill。若要验收的是功能(不只是缺陷声明),使用 AI 生成代码审查与验收清单。

先写一个可验证的结论

评估补丁前,写清预期行为,例如:“获授权的用户保存字段并重新打开记录后,应读到已保存的值。”同时记录角色、正常入口、输入、环境和版本。若正确规则仍有争议,先解决产品决策。

明确本次范围:诊断、验证、修改代码、修改测试、修复历史数据和部署是不同操作。要求验证,不等于授权所有操作。运行前阅读仓库规则,并检查测试命令的副作用。

1. 保留修复前的失败

保存原始步骤及实际结果。检查必须断言所报症状,不能只判断是否收到响应。浏览器故障应从用户的正常页面和角色出发,内部 API 调用不能替代完整用户路径;纯 API 或后台任务故障则在对应执行边界验证,无需硬加浏览器步骤。

条件允许且安全时,在隔离环境对已知有缺陷的版本运行同一回归检查,保留命令、版本、输入、预期和输出。缩小案例可以帮助诊断,但最终必须保留原始完整路径。不要为了得到一个失败测试,在生产重放破坏性行为。

2. 将修复与原因连起来

沿真实路径检查:入口、校验或转换、存储或外部操作、读回及用户结果。找出第一个违反已确认规则的边界。合理解释或一行代码变更,在观察支持之前仍只是推测。

审查最终差异,确认修复落在负责该规则的层,同时查同一原因的其他影响及同类错误位置。避免无关重构。代码修复不会自动纠正已有坏数据,历史数据修复须单独明确范围及授权。

3. 修复后重走原始路径

在修复版本上使用相同的相关输入、角色和条件,记录必要差异。重跑原始完整场景和回归检查。保存类问题要刷新或重新打开,并核对权威读回结果;成功提示不够。拒绝类操作还要确认没有发生禁止的写入或外部副作用。

不要把本地结果写成已部署。分别记录已实现、本地验证、已部署及线上路径验收。审查后若补丁再次修改,应在最终版本重跑受影响检查。

4. 按原因选择回归路径

根据故障机制选检查,不凑固定用例数量:

  • 共享校验:合法输入、相关边界及拒绝行为
  • 权限:允许的角色及适用的被拒角色或资源,包括副作用
  • 持久化:保存、读回、重新打开及适用的旧状态问题
  • 异步行为:相关重试、取消、重复或乱序路径
  • 共享调用:使用被修改规则的其他入口

只有实现、数据绑定及失败条件确实等价时才复用证据。页面长得相似,不代表等价;未检查的独立分支仍是缺口。按仓库要求和变更影响运行 lint、构建、集成或端到端检查。审查最新差异,缺少独立审查时如实说明。

合成演示:保存成功,刷新后旧值回来

这是虚构教学场景,不是 Boloop 事故,也未实际执行。

假定已确认的需求是:授权的个人资料编辑必须持久化。修复前计划按正常入口打开资料、修改字段、保存、刷新,再比较返回字段。对同一记录及时间线保存请求和权威读回。不要因为刷新暴露症状就认定缓存是根因。

提出修复后重走上述路径,补充相关拒绝保存检查;若有其他入口使用被修改规则,也应检查。观察前所有结果均保持 NOT RUN。本例提供验证计划,不提供已证实的根因、补丁或成功结论。

可执行教学演练(游标时间并列)

仅供教学——不是 Boloop 生产事故,也不会在你的仓库上跑测。把下面的 Python 复制到本地文件并执行 python3。它覆盖排序游标在同一时间并列的情况:已知有缺陷的实现会让断言失败;修复后的实现在同一断言上通过。

本次教学运行的预期标准输出(2026-11-06 捕获):

known-bad: RED [(101, 43)]
repaired: GREEN
TEACHING_DRILL_OK
"""Teaching drill: red-then-green on a sorted-cursor tie.

Not a production test and not a run against any live application.
Copy into a local file and run: python3 <that-file>
"""
from __future__ import annotations


def next_page_buggy(rows, after, limit):
    # Broken cursor: compares only the first field, drops ties incorrectly.
    ordered = sorted(rows)
    if after is not None:
        t, _ = after
        ordered = [row for row in ordered if row[0] > t]
    return ordered[:limit]


def next_page_fixed(rows, after, limit):
    ordered = sorted(rows)
    if after is not None:
        ordered = [row for row in ordered if row > after]
    return ordered[:limit]


def test_tie_keeps_next_id(fn) -> None:
    rows = [(100, 41), (100, 42), (101, 43)]
    result = fn(rows, after=(100, 41), limit=1)
    assert result == [(100, 42)], result


def main() -> None:
    try:
        test_tie_keeps_next_id(next_page_buggy)
        raise SystemExit("expected red on buggy")
    except AssertionError as e:
        print("known-bad: RED", e)

    test_tie_keeps_next_id(next_page_fixed)
    print("repaired: GREEN")
    print("TEACHING_DRILL_OK")


if __name__ == "__main__":
    main()

预期结果应来自排序规则,而不是来自错误实现的输出。若无法安全展示红色步骤,应暂停,不要声称修复已验证。

Boloop 真实案例:六秒超时被误判为 Google 查询失败

2026 年 10 月 20 日,Boloop 的统计邮件能读取站点地图,却无法返回六个页面的索引检查。页面如实显示检查暂不可用。这说明查询失败,不能解释为 Google 收录了零个页面。

第一步是找出请求在哪里停止。对照使用同一个只读账号和同样六个 URL:

  • 原截止时间下,六个请求均在约 6,002–6,011ms 被取消,异常为 AbortError。
  • 临时延长诊断截止时间后,同样六个请求在约 7,042–7,907ms 返回 HTTP 200。

这组观察支持“本地超时过短”是本轮故障的直接原因,不能证明过去每一次供应商失败都来自同一原因。本次对照也没有提供需要扩大 Google 权限的证据。

修复范围很小:只给 URL Inspection 设置独立的十五秒截止时间。令牌、GA4、搜索表现和站点地图仍保持六秒;六个检查继续并行,响应大小限制、部分结果、缓存及只读权限保持。没有增加自动重试,也没有提交页面索引。

关闭修复前,分别检查三种结果:

  • 八秒后正常返回的检查,能取回全部六页结果。
  • 始终不返回的检查,十五秒后仍会取消,并保留已经成功的站点地图结果。
  • 其他报表仍在六秒截止。

这些自动回归使用模拟供应商响应和测试时钟,用于验证超时行为,不是对 Google 当前速度的测量。八秒响应的回归在旧实现中失败,修后通过;本次整理案例又重跑了该检查和不返回时的截止检查。

真实供应商读回单独验证:修后的调用耗时 8,188ms,返回六页结果。经授权部署后,正常生产后台也显示全部六行。英文首页当时已收录,其余固定页面被 Google 报告为未知。修好查询本身并没有让这些页面自动收录。

这个案例支持一个有边界的结论:本轮观察中,过短的本地截止时间拒绝了有效响应,独立截止时间恢复了检查。它不证明普遍性能提升,不保证供应商以后一直可用,也不证明部署后的定时邮件已经正常运行;这些结果需要另行观察。

复用这个方法时,先写清原始症状、首个失败边界、修复前后证据和相邻失败路径,再用下面的结果模板分别记录本地回归、真实供应商读回与生产验收。

验证失败或无法运行时

暂停规则: 得不到安全的红色信号 ⇒ 不得声称「已验证修复」。请写清诊断、证据缺口和下一步授权动作。

  • 原始症状仍存在:记为 FAIL,回到诊断;不要降低预期以换取通过
  • 缺少权限、数据或环境:记为 BLOCKED,写清前置条件及下一步
  • 计划检查尚未尝试:记为 NOT RUN,不是 PASS 或 N/A
  • 间歇故障:记录尝试次数、失败次数、时序条件和不确定性;一批未失败样本不能证明问题消失
  • 无法复现原始故障:保留日志、输入及暂定根因,寻找独立支持证据;没有对缺陷敏感的回归信号时,停在诊断,不声称修复已验证

Mock 可隔离机制,不能证明未观察的真实系统结果。未经许可不要用合成数据替代实际验收数据。分享证据前移除密钥和个人信息。

何时可以停止

只有最终版本的原始场景及适用受影响路径都有对应证据、必需检查和审查完成,且没有使结论失效的未解决缺陷,才可关闭该范围的验证。保留剩余限制和最短回滚方式。只通过一部分,就只能对那部分作结论。

重要前置条件缺失时,停止依赖它的工作并说明如何解除阻塞。证据充分后,也不要重复增加无法改变结论的检查。目标是有边界、可解释的结果,不是无限增加绿色测试数量。

记录结果并开始下一步

配套 Markdown 结果模板可记录前后证据、回归、审查、状态边界及回滚。

已有故障从 $bug-fixing 开始;最终差异的独立只读审查用 $code-review-multiagent;按确认需求执行获授权验证时,明确选择 $test-case 模式。这些是流程说明,不提供权限或执行工具。

现在先填写预期行为、已知有缺陷的版本和原始复现步骤,再请 Agent 判断修复是否成立。

相关指南:缺陷声明已验证(或已暂停)之后,若仍需功能级验收、持久化读回或超出本缺陷的合并决策,请使用 AI 生成代码审查与验收清单。

对应 Skill 页面:bug-fixing · code-review-multiagent · test-case

下载 Markdown 模板

511 文章浏览

记录符合条件的页面浏览并过滤短期重复,不代表独立读者人数。