AI 写的发布流程 CI 全绿,为什么仍没通过需求验收?

我让 AI 搭一个 Markdown 网站的自动发布流程。第一版 CI 全绿,15 项测试通过,MkDocs 也构建成功,但我仍没有让它上线。PR 审查发现:需求只允许发布专题目录的直接子文件 ,准备脚本却递归收集 Markdown,连产物审计也放行更深的路径。若将来出现 专题/草稿/未审核.md,它可能跟着构建产物进入公开网站。

这不是一个"测试没跑"的故事。代码运行了,测试也跑了;问题是它们共同验证了一个比需求更宽的范围。修正边界并补上反向用例后,17 项测试通过,但线上发布仍待单独验收。这个案例想回答的是:AI Coding 交付时,怎样判断它实现的是需求,而不只是实现了一套自洽的代码和测试?

任务很简单,边界不能含糊

这条流水线的路径是:

text 复制代码
GitHub Markdown → MkDocs → GitHub Actions → 网站

源仓库是私有的,网站却可以公开访问。需求允许四个指定的根目录页面,以及 记录/*.md、专题/*.md。这里的 * 只代表目录的第一层文件;专题/草稿/未审核.md 不属于白名单。仓库里"存在"一篇文章,与它"获准公开",是两回事。

AI 交付了内容准备脚本、产物审计、构建工作流和测试。第一轮 Actions 的构建审计任务成功,15 项测试全部通过,MkDocs 严格构建也成功。单看绿色状态,这份交付很像已经满足要求。

为什么全绿仍然错了?

把需求、实现和测试放在一起,偏差就很清楚:

text 复制代码
需求:专题/*.md
      只允许专题目录第一层 Markdown

初版实现:递归遍历专题目录
          专题/草稿/未审核.md 也会被收集

初版测试:覆盖允许文件、目录外文件和符号链接等情况
          没有"专题下的嵌套 Markdown 必须被排除"这一反例

第一版准备脚本用的是 os.walk(base, followlinks=False),会继续走进子目录。审计脚本则用 source.startswith("专题/") 加 .md 后缀判断来源。两处都没有表达"路径恰好只有两层"这个要求。于是 专题/草稿/未审核.md 在准备阶段能被收集,在审计阶段也能被接受。

问题有三层。第一,自然语言里的"专题目录下的 Markdown",若不明确写成 专题/*.md 且注明不递归,很容易丢掉目录深度这条边界。第二,递归遍历是常见写法,但在本任务中扩大了可发布范围;至于 AI 为什么选它,现有记录不能证明其内部原因。第三,初版交付的测试验证了"该进来的能进来",却没验证"看似属于专题、实际越界的不能进来"。代码和测试因此可以一起通过,而需求仍未满足。

这里的"草稿"文件是反向用例,不是已经被公开的真实文章。PR 自审在部署前发现了问题,没有证据表明未审核稿曾被发布。

修改代码,更要修改验收方式

修正后的准备脚本只看目录的直接子项:

python 复制代码
for source in base.iterdir():
    if source.is_symlink():
        relative = source.relative_to(root).as_posix()
        raise SourceBoundaryError(f"symlink input is not allowed: {relative}")
    if source.is_dir() or not source.name.lower().endswith(".md"):
        continue
    relative = source.relative_to(root).as_posix()
    found.append((_resolve_regular_file(root, relative), relative))

iterdir() 遍历第一层,子目录被跳过。这样 专题/草稿/未审核.md 在内容准备阶段就不会进入站点输入。

但只修准备脚本还不够。以后若代码回退或另一个入口写错,产物审计仍应独立拒绝越界路径。修正后的审计条件是:

python 复制代码
direct_child_markdown = (
    len(path.parts) == 2
    and path.parts[0] in {"记录", "专题"}
    and path.suffix.lower() == ".md"
)

专题/文章.md 是两段,可以通过;专题/草稿/未审核.md 是三段,必须拒绝。相比只检查 startswith("专题/"),这段代码把需求中的目录深度落实为可检查的条件。

随后补了两处反向测试:一处在临时仓库创建嵌套稿,确认准备脚本没有复制 它;另一处故意把同一路径写进产物清单,确认审计拒绝接受它。关键断言是:

python 复制代码
copied = stage_sources(self.root, output, manifest)
self.assertNotIn("专题/草稿/未审核.md", copied)

正向测试证明允许的内容能进去;反向测试证明不允许的内容进不去。两者缺一,白名单就没有被完整验收。修正后的 PR 构建运行了整套 17 项测试,并通过 MkDocs 严格构建、SHA 审计和静态产物上传。17 项是全部测试数,并非 17 项白名单测试。

我从这次交付提炼的四层验收顺序

这个顺序来自本次案例,用于检查类似的 AI Coding 交付;它不是一套已在所有项目验证过的标准。

  1. 需求边界 :把允许和禁止的输入都写成样例,例如 专题/文章.md 可以发布,专题/草稿/未审核.md 不可以。
  2. 反向测试:专门构造"差一点就合法"的输入,确认它被拒绝,而不只测试正常路径。
  3. 产物审计:检查最终清单和生成物是否仍满足边界。准备脚本正确,不等于后续环节永远正确。
  4. 真实环境验收:构建成功后,核对部署版本、提交 SHA 和网站实际内容,才能说线上完成。

本例目前通过的是前三层对应的 PR 阶段检查。部署步骤在 PR 运行中被跳过,PR 尚未合并,新版本也未完成线上验收。因此结论只能是:越界实现已修正,构建产物在 PR 阶段通过检查;自动发布到网站尚未验证完成。

AI Coding 最大的问题未必是代码写错,而是它可能完整地实现了一个"理解错的需求"。所以 AI 交付后,我现在最先补的不是更多正向测试,而是需求边界、反向用例,以及对最终产物的独立审计。

相关推荐
孟郎郎13 小时前
打造一切(Craft Anything)——克隆构造世间万物
人工智能·ai·github·软件构建·开源软件
海洋之恒14 小时前
GitHub Actions 自动化:5 个真实运维提效案例
运维·自动化·github
小Z先生15 小时前
我用 Go + 系统 WebView 写了个纯本地 Postman:不装 Electron、不连云端
后端·github
fthux21 小时前
待办清单写满了,别忘了给休息留个位置:试试 Tick Rest
开源·github·mac·提醒·open source·消息提醒·tick rest·tick rest for mac·消息提醒app
GitHub实测笔记1 天前
dust 本机实测:/usr 扫树中位 92ms、du -sh 80ms;-s 不是汇总,稀疏文件 0→100Mi
github
逛逛GitHub1 天前
有个刚开源的 GitHub 项目有说法,竟然能在终端里再跑一台 Mac。
github
用户2991422196801 天前
GitHub 热榜项目:日榜(2026-11-09)
人工智能·开源·github
徐小夕1 天前
JitArchives,一款基于JitWord协同AI文档打造的企业级电子档案系统
前端·vue.js·github
特创数字科技1 天前
写了个 Windows 下载器:一键拉 GitHub / Gitee 源码,带 SHA256 校验
python·github
miofly1 天前
GitHub 日榜趋势速报 | 2026-11-09
开源·github