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 交付后,我现在最先补的不是更多正向测试,而是需求边界、反向用例,以及对最终产物的独立审计。

相关推荐
高频因子挖掘机6 小时前
A股量化从日线升级到5分钟线:数据量增加后最先暴露哪些工程问题?
后端·github·api
高频因子挖掘机7 小时前
历史行情返回顺序变了,为什么按行号计算指标很危险?
后端·github·api
码间留白7 小时前
手把手把 GitHub 推上阿里云 ECS:Actions CI/CD 全链路避坑实录(折腾好几天,到 2 分钟见绿)
运维·阿里云·ci/cd·docker·devops·github actions
用户7273744138848 小时前
两个日期中间隔了多少天:闰年和跨年最容易算错
github
阿良别做梦8 小时前
开源一个桌面项目工作台:把服务启动、文件编辑和 Git 合并放到一起
github
钱栈up9 小时前
GitHub 热榜实测|REA:用 Agent 逆向一切
typescript·开源·github
YJfox11 小时前
Qt Creator工具git使用完整教程
github
怕浪猫14 小时前
3 小时搭一个能用的聊天机器人后端,我用了这套技术栈
后端·面试·github
miofly15 小时前
NVIDIA 将 Run:ai 平台全面开源,纳入 DSX AI Factory 体系
开源·github
miofly16 小时前
GitHub 今日推荐|MOSS-Image:靠坐标框精确控制文字排版的图像生成模型
python·开源·github