Codex 没法跑或读懂 build 结果:6 个误读触发 + 让验证步骤短到能 parse

Codex 跳过 build、误读输出、相信被截断的 tail——用机器可读的 verifier + exit code,不要看 prose 总结。

Codex 说「build succeeded ✓」——你拉分支跑 pnpm build 直接炸。或者它跑了测试、总结「全部通过」,但 vitest 实际上报了 3 个 fail,藏在输出 400 行之前。从此你对它的报告信任度归零,每个声明都得手动复核。

这不是模型不行,是工具层的输出解析问题。Codex 的工具层一般把输出截到几 KB;长 compiler dump 被截掉中间,agent 看到的是 tail(“Done in 12s”),然后判定通过。修法:用机器可读的 verifier、exit code 检查、把命令拆短让每条输出都装得进窗口。

常见原因

按命中率从高到低:

1. 工具输出超过 harness 上限被截

多数 Codex harness 命令输出上限 8KB–64KB。monorepo 里一个失败的 pnpm build 能 dump 200KB。中间部分(真错误所在)丢了,tail(“Done building in 12s”)留下,Codex 读 tail 就判通过。

如何判断:本地不截断重跑同命令。本地有的明显错误 Codex 没看见——就是输出截断。

2. Codex 自己又把输出总结了一遍、丢了细节

哪怕输出全到了,Codex 也可能撞自己的上下文上限再做一次摘要。摘要里只写”user-service 编译失败”——file:line 和具体错信息丢了。下一轮工作就是基于摘要而不是真错误。

如何判断:让 Codex 原样贴出失败那一行——贴不出来就是摘要里丢了。

3. ANSI 彩色码把 parser 干扰了

vitesttsceslint 默认都输出 ANSI 颜色码。agent 的 tokenizer 把 \x1b[31m 当垃圾,附近文本可能一起丢。

如何判断:加 --no-colorFORCE_COLOR=0 重跑——之前没识别的错误现在能识别,就是颜色搞的。

4. Codex 只抓了第一个 error,后面的连锁错全忽略

tsc 报 47 个错,第 1 个是「cannot find module foo」,根因是漏装。Codex 修了 install,跳过后 46 个(其实都是同一个根因的下游)。下一轮看到 47 - 1 = 46 个错,像是退步,开始来回跳。

如何判断:错误数量回来时是 Codex「修过」之后的倍数——根因分组缺失。

5. 子进程失败没传上来

npm run buildwebpack,webpack 调 worker,worker 失败。外层命令 exit 0 因为失败在子进程里、stderr 被吞了。Codex 看到绿灯。

如何判断:外层 exit 0 但 artifact 缺失或过期。脚本链里看有没有 shell pipe 但没 set -o pipefail

6. Codex 根本没跑那个命令

它生成了代码,说”已经用 pnpm typecheck 验证”,但 chat 里根本没有对应 tool call——是脑补出来的。

如何判断:搜 chat 看真实 tool 调用。没有就是 Codex 跳过了验证。

最短修复路径

按收益从高到低,Step 1 一步覆盖 60% 的”误读输出”。

Step 1:用产出短而结构化的命令

pnpm build 换成输出更少的 verifier:

# 差:500 行噪音,真错误藏中间
pnpm build

# 好:只看 error、排序去重
pnpm typecheck --pretty false 2>&1 | grep "error TS" | sort -u
echo "Exit: $?"

测试:

# JSON reporter——机器可读,Codex 能解析 exit code + 计数
pnpm vitest run --reporter=json --silent 2>&1 | jq '{passed, failed, errors: [.testResults[] | select(.status=="failed") | .name]}'

Lint:

pnpm eslint . --format=compact --max-warnings 0 2>&1 | tail -30

每条命令在干净 repo 下不到 100 行,broken 时不到 300 行——都能装进 harness 窗口。

Step 2:验证绑 exit code,不要绑 prose

prompt 里写:

跑 verifier 后报告:
1. exit code(命令后紧跟 `echo "Exit: $?"`)
2. error / failing test 数量
3. 前 3 个错误原样(file:line + message)

exit code 不是 0 就不要说「build 通过了」。
不要写「看着没问题」之类的总结——把原文贴出来。

exit code 是真相,prose 总结是有损压缩。

Step 3:去色、关交互

verifier 命令始终加:

FORCE_COLOR=0 CI=true NO_COLOR=1 pnpm test -- --no-color

CI=true 顺便禁掉 watch mode、进度条这些非 TTY parser 处理不了的东西。

Step 4:按关切拆命令,一条一意

别跑 pnpm build 这种一锅端(typecheck + lint + bundle + minify)。每步失败模式不同,混在一起遮掉根因。改成:

pnpm typecheck   # exit 0 / 1
pnpm lint        # exit 0 / 1
pnpm test        # exit 0 / 1
pnpm build       # 上面三个都过才跑

Codex 一条一条读得清,失败能归因。

Step 5:输出实在长就落盘 + grep

verifier 必须长输出时,落盘后只给 Codex 看关键片段:

pnpm build 2>&1 > /tmp/build.log
echo "Exit: $?"
# 只显示 error 行和上下 2 行上下文
grep -B1 -A2 -E "error|Error|ERROR|✗|FAIL" /tmp/build.log | head -50

Codex 看的是聚焦视图,全 log 还在文件里可继续 grep。

Step 6:强制 Codex 真的跑

严格模式:

每次改完代码必须按顺序跑:
1. `pnpm typecheck && echo "TYPECHECK OK" || echo "TYPECHECK FAIL"`
2. `pnpm test -- --run && echo "TEST OK" || echo "TEST FAIL"`
3. `pnpm lint --max-warnings 0 && echo "LINT OK" || echo "LINT FAIL"`

每条都要贴出 OK/FAIL。一项都不能跳。
任意 FAIL 修了重跑。三个 OK 之前不要说完成。

OK/FAIL 这种确定 token Codex 没法糊弄。

预防建议

  • test / lint 标准化用 JSON / compact reporter,不要 raw human 模式
  • Codex 跑的命令始终 strip ANSI 颜色:FORCE_COLOR=0 CI=true
  • 验证拆成 typecheck / lint / test / build,每条 < 100 行
  • 每个 prompt 强制 exit-code 验证,prose 总结不可信
  • Codex 跑的 shell 脚本加 set -o pipefail,子进程失败要传上来
  • CI 始终是最终闸——Codex 本地 verifier 是快速反馈,CI 是 gate

相关阅读

标签: #Codex #Coding Agent #排查 #排查 #Build 结果