AI 改完代码后,是否能上线要看改动范围、关键失败场景和恢复路径的证据。构建成功、页面能打开、AI 自己说“已完成”,都不能单独作出这个判断。 先按影响选检查,再把未验证项明确留在发布记录里。
本文面向已有项目的发布前审查,原审查资料复核日期为 2026-10-10;下方本站定位缺陷案例记录于 2026-11-06。权限和数据库示例是本站编写的教学场景,不是发现于读者项目的漏洞,也不是工具实测报告。如何给 AI 写首次任务,见 第一次让 AI 改代码;这里从交付后的改动开始。
先确认审查的是哪个版本
先读仓库的发布说明,记录目标环境、当前线上版本、拟发布代码与配置。工作区有别人尚未完成的修改时,不要为了得到“干净状态”而重置或提交它们;先明确哪些属于本次交付。
下面几条命令只查看本地状态,适合普通 Git 工作区:
git status --short
git diff --stat
git diff
git diff --cached --stat
git diff --cached
按 Git 官方 diff 文档,普通 git diff 比较工作区与暂存区,--cached 查看暂存区相对提交的变化。因此只看其中一份会漏改动。未跟踪文件需要按 status 列表另读;分支上已经提交的修改,还要与确认过的基准提交比较。测试记录应对应最终准备发布的版本,测试后又修改关键路径就要重新验证受影响部分。
读 diff 时,把每个文件归到需求、测试、依赖、配置或迁移。额外依赖、锁文件大改、关闭检查、删除测试、改权限或新增环境变量,都要有与本次目标对应的解释。不要因为文件由 AI 生成,就跳过它。
按影响选择检查深度
下表是工作分配建议,不是全项目安全认证。Google 的代码审查指南 强调设计、用户行为、边界和并发问题;这里把这些原则转成发布前可记录的对象。
| 改动范围 | 至少检查什么 | 需要升级审查的信号 |
|---|---|---|
| 文案、间距、静态导航 | 目标页面、手机显示、链接和键盘操作 | 实际改到了提交逻辑或权限 |
| 表单、接口、后台任务 | 正常、无效输入、失败、超时和重复处理 | 数据落库或外部动作无法撤回 |
| 身份、权限、缓存隔离 | 服务端授权、不同账号与资源的访问边界 | 只隐藏按钮,或只测管理员 |
| 数据库与部署配置 | 新旧版本兼容、数据核对、恢复步骤 | 删列、默认值覆盖旧数据、缺少恢复证据 |
低影响改动用针对性的检查即可,不必为改一行文案堆出一套镜像测试。涉及权限或数据时,则不能用截图替代行为证据。同一改动跨多行时,按影响更大的那行决定审查深度。
示例一:按钮隐藏了,接口仍能删别人的记录
假设需求是“成员只能删除自己创建的草稿”。AI 在前端根据创建者隐藏删除按钮;管理员的正常操作也通过了。这两项都不足以证明服务端落实了规则。
在自有测试环境准备账号 A、账号 B、各自的草稿,以及一个按产品规则不允许删除的已发布对象。使用测试数据和项目测试客户端,不在真实用户数据上试删。
| 请求者与对象 | 期望结果 | 应保留的证据 |
|---|---|---|
| A 删除 A 的草稿 | 允许且只影响该对象 | 响应、对象状态、审计记录 |
| A 直接请求删除 B 的草稿 | 拒绝且对象不变 | 服务端拒绝及前后状态 |
| B 访问或修改 A 的对象 | 按权限规则拒绝 | 对象、账号和动作的对应记录 |
| 未登录请求删除 | 拒绝且无副作用 | 身份检查结果与数据状态 |
| A 删除不允许删除的已发布对象 | 按业务规则拒绝 | 状态规则与记录未变 |
允许请求返回的具体状态码由接口约定决定;拒绝可能采用 403 或隐藏对象存在性的 404。验收重点是权限与副作用,不是背某一个状态码。
OWASP 授权指南 要求默认拒绝,并对每次请求检查具体对象或功能的权限。随机 ID、客户端校验和按钮可见性不能代替这个检查。还要检查同一数据的列表、导出、后台任务和缓存路径,避免一个入口正确、另一个入口泄露。
如果这里只能访问前端仓库,应记录“服务端权限未验证”,保留发布阻碍,不能把前端测试标成整个功能通过。
示例二:改字段后,回退代码不等于恢复数据
假设把文章的 published 布尔字段改成 status。直接新增默认 draft 的字段再删除旧字段,可能让历史已发布文章变成草稿;即使新代码能启动,也不代表迁移正确。旧代码还可能依赖已被删除的列。
Prisma 的扩展与收缩说明 展示了分阶段引入新结构、迁移数据和客户端、最后移除旧结构的思路。这里采用这一审查思路,不提供可直接用于生产库的 SQL;锁表、事务和回填方式需按实际数据库决定。
| 阶段 | 发布前需要回答的问题 | 阻断信号 |
|---|---|---|
| 扩展 | 加新字段后,旧应用还能读写吗? | 新约束使旧写入失败 |
| 回填 | 旧值如何映射?空值如何处理? | 把所有历史行直接设为同一默认值 |
| 并行运行 | 回填期间的新写入由谁同步? | 只复制一次,之后两列持续分歧 |
| 切换读取 | 新路径与旧路径的业务结果一致吗? | 行数相同但发布状态不同 |
| 收缩 | 旧客户端和任务是否全部退出? | 回退版本仍读取将删除的字段 |
用脱敏的代表性数据在隔离环境演练,比较状态分布、关键对象、空值和新旧路径,而不只比较总行数。遇到部分失败,记录哪些阶段已完成以及如何继续,不能盲目把整个迁移重复执行。
恢复方案也要分开写:代码可以回到哪个版本;数据可以恢复到什么时点;备份之后的新写入如何保留或补偿;恢复由谁执行。备份文件存在不等于恢复成功,应该有可用性验证和恢复演练证据。已经丢失且没有备份的数据,不会因为 Git 回退而回来。
测试通过后,还要读测试到底断言了什么
先运行项目要求的检查,再针对改动补关键场景。类型检查说明类型约束是否满足,构建说明产物能否生成,行为测试说明特定条件下的结果;它们不能互相代替。
| 看似绿色的结果 | 需要追加的审查 |
|---|---|
| 权限测试通过 | 是否只测了自己的对象或管理员? |
| 迁移测试通过 | 是否只有空库,没有历史行和并行写入? |
| 新增测试全部通过 | 是否把真实接口替换成总返回成功的模拟对象? |
| 原来的失败消失 | 是否删除断言、跳过测试或放宽了预期? |
| UI 截图正常 | 键盘、手机、加载失败和禁用状态是否正确? |
能安全复现的缺陷,应证明关键检查在旧行为下会失败、修复后通过。必要时用单独的测试副本,不要为复现去破坏工作区或生产状态。已有基线故障与本次新增故障分开记录;“环境不具备”仍然是未运行,不是通过。
让另一位审查者或 AI 帮忙读 diff 可以增加发现问题的机会,但其结论应指出具体路径、触发条件和证据。多份“看起来没问题”不能替代一个确实执行过的负例。
本站真实案例:筛选正确,旧分类链接仍被导航遮挡
2026-11-06,我们在本站提示词库的发布前检查中发现 PL-QA-01:旧分类链接选中了正确分类,但分类按钮和结果起点被固定导航遮挡。这属于上表的低影响界面改动,需要针对定位的浏览器检查;它不降低权限、数据迁移等高风险改动的审查要求。此处记录真实项目缺陷与修复,没有比较模型或提示词,不能用来证明某个提示词提升了效果。
先自己复现遮挡,再看修复
打开离线定位对照页,也可保存 HTML后用浏览器打开。它只有 HTML/CSS,无脚本、无外部资源、无表单,不需要 Key 或剪贴板。它重现的是滚动遮挡机制,不包含本站筛选逻辑,也不是原始测试页面。
- 点击顶部“失败 / Before”。分类按钮会滚到页面顶部,被固定导航盖住;向上滚动一点,能找到刚才被盖住的按钮。
- 点击“修复 / After”。目标按钮留出 100px 滚动间距,应完整位于导航下方。两种状态的差别是分类按钮有没有对应的
scroll-margin-top。 - 把视口缩窄到 390×844,再分别点击两个入口。以按钮和首张卡片是否可见判断,不以 URL 的 hash 是否变化判断。示例没有运行自动判定;如果观察不同,请记录浏览器、视口和实际现象。
若在自己的项目复测完整路径,先准备独立测试副本:直接打开带分类 hash 的新页面;再输入一个无匹配结果的查询,通过页内链接或地址栏只改变 hash,确认没有刷新成新文档。等待滚动稳定,检查查询是否清空、分类与数量是否正确,以及分类按钮和首卡是否都在导航下方。已修复的本站线上页面不用于展示旧失败,不需要回退生产。
原因与最小修复
旧实现只给模板卡片 .prompt 设置滚动留白,分类 hash 的实际目标却是带 data-library-filter 的按钮。筛选断言因此仍可通过,但定位可见性失败。修复只将已有 100px 留白应用到分类按钮,没有修改筛选逻辑、模板正文或复制控制器。
修复前:
#prompt-library .prompt {
scroll-margin-top: 100px;
}
修复后:
#prompt-library .prompt,
#prompt-library [data-library-filter] {
scroll-margin-top: 100px;
}
这是项目真实差异的格式化摘录。CSS 滚动规范说明 scroll-margin 可用于调整滚动定位区域。100px 是本站当前布局沿用的数值,不是所有网站通用的导航高度;换字体、缩放或导航布局后应重新检查。
旧候选的桌面直接加载 #writing 时,结果为正确的 3 条,但按钮顶部约 −0.02px、底部 43.98px,导航底部 73px,整个按钮被盖住;首卡顶部 65.98px,也有约 7px 被挡。旧候选还记录了残留搜索切换 #image、#agent 的同类失败;没有旧版完整16场景逐项失败表,不能写成“修复前16项全失败”。
16个场景实际复测了什么
历史复测:16 个场景全部通过,桌面与模拟手机各 8 个。 2026-11-06,独立测试在 macOS 的 Chromium 中,对四个分类分别检查了两种入口:直接打开分类链接,以及无匹配搜索后切换分类链接。每个场景的查询都已清空,活动分类和结果条数符合预期。
- 桌面 1200×800:8/8。 导航底部为 73px,分类按钮范围为 99.98–143.98px,首卡从 165.98px 开始。
- 模拟手机 390×844:8/8。 导航底部为 65px,分类按钮范围为 100.20–144.20px,首卡从 217.20px 开始。
两个视口里,按钮完整位于导航下方,首卡起点可见,页面没有横向溢出。这些是滚动位置稳定超过 350ms 后记录的 CSS 像素,保留两位小数。可查看完整 16 场景脱敏记录(JSON),逐项核对入口、分类、条数和坐标。这些历史数据来自本站候选版本,不是上方简化对照页的输出。
修复后的源码与前一候选比较,仅这一条 CSS 选择器改变,其余353个源文件逐字节相同。独立复测重新构建,并检查上述16项及代表性首屏、模板定位;前一候选的类型检查、28项测试和站点审计沿用已有结果,没有把它们说成在本次重新执行。当天发布后的同组16项定位检查也通过;发布检查与候选复测是不同证据。
结果和未覆盖项分开写
本案例说明:筛选结果正确,不等于读者到达了可见的阅读位置。 对此类改动,把“目标和内容都出现在固定导航下方”写成独立验收条件即可,不需要引入新测试平台。
本轮手机是视口模拟,未测实体手机、Safari、屏幕阅读器或全部缩放组合。16项定位检查不证明整个站点无缺陷,也不证明提示词质量、用户增长或商业效果。
用发布记录作出通过或阻断决定
下载 中英文发布验收记录模板。它是待填写的工作表,不含预先勾选的通过项。每项写检查对象、命令或操作、环境、实际结果、证据位置和未验证边界,不把密钥或真实用户数据放进去。
上线前至少能回答:
- 本次交付解决哪个行为,哪些文件与配置属于发布范围?
- 最重要的禁止行为是否被阻止,失败是否会留下错误数据或重复动作?
- 必需检查是否在最终版本运行?未运行项的原因是否影响发布?
- 线上配置和权限是否具备,回退代码与恢复数据分别怎么做?
- 发布后检查哪些 URL、关键路径和异常指标,由谁负责发现问题并停止扩大影响?
可阻断条件包括跨账号访问未验证、迁移会覆盖未知历史值、关键失败路径没有证据、恢复方案与当前数据结构不兼容。不要把这些项改名为“后续优化”来换取通过。小范围发布也需要明确暴露范围和停止条件,不意味着风险自动消失。
如果改动包含 AI 输出入库,继续使用 结构化输出验收;包含超时重发和外部动作时,核对 重试与业务幂等。本文的表格是建议执行的审查,不代表已替你的项目执行这些检查。