OpenAI Codex · 代码模式 把架构决策写成 lint 同一份 AGENTS.md 里,有命令的规则会在三台操作系统上亮红。只有路径的那条,重命名之后没人发现。 一句话速览 同一份 AGENTS.md 里,有命令的规则会在三台操作系统上亮红。只有路径的那条,重命名之后没人发现。
课程目标 读完能说清三件事。一条调用点规则怎样变成 rustc 插件,并在 Linux、macOS、Windows 上同时拦。散文写成的路径为什么会失效。漏登记的特性为什么能用穷尽表抓住。
先玩一遍 · 一次提交过架构检查
同一份规范,五张改动卡片:看它被哪一层拦住,以及那一层想守住什么
播放 单步 重置
这次改动
裸 None 错名字 失效路径 再加行 漏登记
点播放看门禁怎么走。也可以直接点右侧某一层,看它放行还是拦住。
提交与门禁 待命
create_openai_url(None) 调用点写了裸 None。编译能过,读者必须跳到定义才知道它管什么。
1 编译器 2 自定义 lint 3 表与测试 4 三平台 CI 5 人工评审 6 挡不住
这一步的判定
手里的改动 裸 None 撞上的门 尚未触发 这条要守住什么 先走一遍门禁 结局 待命
等待开始。
逻辑轨迹 · 动画每一步对应源码里的哪一段
调用点是不是匿名字面量 lib.rs L261 注释名字是否等于参数名 lib.rs L222 被调方是不是 workspace crate lib.rs L177 CI 是否三平台同时跑 rust-ci.yml L174 Markdown 路径是否存在 AGENTS.md L35 Feature 是否登记在穷尽表 lib.rs L379 开发中特性默认必须关闭 tests.rs L18
点播放,看这张改动穿过六层门禁时停在哪。
谁拦住 守住什么 换一张卡片 有红灯的,重命名或漏写当天就会红。没红灯的,文字还在,对象已经搬家。
教学示意:门禁分层为课程化归纳,用于对照「有检查」和「只有散文」。逻辑轨迹右侧行号对应 openai/codex 仓库 commit 4f39251a01。
思路一 · 能局部检查的决策,写成机器能跑的红灯
它解决什么问题 新人接到任务:改 MCP 工具调用。它打开 AGENTS.md ,抄下第 35 行的路径。文件不存在。真实文件叫 connection_manager.rs ,就在同一个目录。文档里那个带 mcp_ 前缀的名字,是一次重命名之后没改干净的残留。 出处: AGENTS.md 第 32 至 36 行; codex-rs/codex-mcp/src/connection_manager.rs 第 1 至 15 行 同一份文件里,位置参数少了 /base_url/ ,本地命令会红。改了 Cargo.toml 忘刷 Bazel 锁,CI 会红。第 35 行那条路径没有检查器。Markdown 不会自己核对文件在不在。
思路是什么 先改 API,让调用点自己能读。 foo(false) 的读者必须跳到定义才能知道这个 false 管什么。改不了 API,才允许 /param_name/ 。lint 是退路。 出处: AGENTS.md 第 14 至 20 行 实现住在独立的 Dylint 库,当一次 rustc。类型解析完成后,才能拿到被调方的参数名。入口只看函数调用和方法调用,宏展开出来的直接跳过。 检查按这个顺序走。
- 只查本仓库 crate, std 和 tokio 直接放过。
- 注释从参数前的空隙、前 64 字节、参数文本自身三处找。
- 名字不对报 mismatch。错注释不会再落到没写注释那条。
- 没写时,方法名等于唯一参数名就豁免,例如 .enabled(false) 。
- 剩下的只拦匿名字面量。 None 、布尔、数字要写,字符串和字符放过。 出处: tools/argument-comment-lint/src/lib.rs 第 165 至 180 行; tools/argument-comment-lint/src/lib.rs 第 261 至 274 行
调用点 裸 None
workspace? 是才继续查
合法注释? 名字必须对上
deny,三台 CI 再跑一遍 Linux / macOS / Windows 输入是一处调用,输出是合并前的红灯,守住的是调用点自解释
教学化结构图:能解析到参数名的局部调用,才值得养一台 rustc 插件。
仓库入口把默认 Allow 的那条抬成 deny。CI 在 Linux、macOS、Windows 各跑一次,一台失败另外两台继续跑完。人在 macOS 上绿了,Windows 目标的宏展开若多出一处 None ,第三台仍会拦住。 出处: .github/workflows/rust-ci.yml 第 164 至 187 行
为什么长期成立 调用点局部、名字可解析、误报能用豁免收住。换个语言,形状一样:先改名字,改不了就要求行内名字。TypeScript 用 ESLint,Python 用 ruff,都用得上。
思路二 · 散文会腐坏,行数能数不等于有人在数
它解决什么问题 第 35 行和第 265 行是同一种腐坏。app-server 指南还写着 v2.rs ,当前是目录 v2/ ,下面拆成三十多个文件。文件靠近 800 行就要拆。拆了之后,指南里的单文件路径没人改。 出处: AGENTS.md 第 260 至 266 行 模块行数规则点名五个高频文件,四个已经越过 800,一个贴着 900。 chat_composer.rs 按行计有 12859 行。仓库里没有数行数的命令。行数能数,CI 不数。一次改动是不是机械,机器做不好,所以 800 行上限停在评审。 出处: AGENTS.md 第 49 至 61 行; AGENTS.md 第 125 至 131 行
思路是什么 把规则分成两套来读。一套有命令或编译器,合并前会亮红。一套只能被人和评审读,漏看就过。路径是否存在本来最容易检查:抽出反引号路径,对仓库根做存在性判断。仓库没做。预算花在调用点可读性上,没有花在路径存在性上。
规则写进 AGENTS.md
有没有命令或编译器 有,才进机器
lint、测试或 schema job
只有散文
三平台 CI,合并被拦
人或评审,也许抓住
路径改名,文字还在
教学化分流图:有检查的当天红,只有散文的静默断。
为什么长期成立 文档不会自己复查。能局部检查却只写在 Markdown 里,重命名和拆文件的那天,文字还在,对象已经搬家。最小形态是二十行脚本核对路径,不需要 rustc 插件。
写成 lint 的规则,文件改名当天就会红。
思路三 · 生命周期写成枚举加穷尽表
它解决什么问题 特性开关如果只靠布尔和一篇说明,漏登记、开发中默认打开、Deprecated 一直待着,都不会第一时间亮红。
思路是什么 Feature 枚举旁边有一张 FEATURES 表。 FeatureSpec 把标识、配置键、阶段、默认是否打开焊在同一行。表里找不到对应项就 unreachable! 。枚举多一个变体、表少一行,运行到 key() 会直接崩。 出处: codex-rs/features/src/lib.rs 第 41 至 58 行; codex-rs/features/src/lib.rs 第 819 至 826 行; codex-rs/features/src/lib.rs 第 379 至 384 行 旁边两道测试锁住默认值。开发中的特性默认必须关闭。默认打开的特性,阶段只能是 Stable 或 Removed。阶段有五态,多出来的 Experimental 带着菜单名和公告。Deprecated 没有过期日,三个 Deprecated 项仍能打开。阶段能表达不该再用,不能表达下个版本删。 出处: codex-rs/features/src/tests.rs 第 17 至 28 行; codex-rs/features/src/tests.rs 第 82 至 94 行
UnderDevelopment 默认必须关
Experimental 菜单加公告
Stable 才允许默认开
Deprecated
Removed 输入是枚举加一行表,输出是漏登记就崩;Deprecated 到 Removed 没有计时器
教学化状态图:穷尽表锁住登记和默认值,锁不住自动删除。
为什么长期成立 穷尽表加两条测试,换语言也成立。漏登记就崩,默认值被锁住。换不来自动删除,只换来这两条不变量。
横向对比 · 同一道题的另一种答法
DSH:每个包必须露面,空也要解释 DeepSeek Harness 把「每个包必须拥有 ./invariant 」同时写成散文和门禁。散文在 packages/AGENTS.md 。门禁是 21 行的 verify-package-invariants ,失败就 process.exit(1) 。空安装器必须带固定前缀 No runtime invariant: 。空是显式架构结论,以后引入可变状态,必须换成真正的检查。 笔记回答为什么允许空,检查器保证空必须解释。两者缺一,就会回到 Codex 第 35 行那种状态:文字还在,对象已经搬家。DSH 没有 rustc 插件去管 foo(false) 。Codex 没有穷尽式包门禁去管路径存在性。 出处: packages/AGENTS.md 第 18 行; scripts/verify-package-invariants.ts 第 1 至 21 行 两侧均已核对源码 · 2026-08-22
Grok:能局部化的决策直接丢进 clippy Grok Build 仓库根没有 AGENTS.md 。它仍把一条架构决策写成 lint: clippy.toml 禁止 canonicalize ,理由是 Windows 上会得到 verbatim 前缀,破坏 git、泄漏进模型上下文。执行边界写在同一份文件:这条禁令由各 crate 的 cargo clippy presubmit 执行,只走 Bazel 的 crate 要靠人看。 和 Codex 的参数注释是同一类判断:调用点局部、误报面可控。Grok 承认 Bazel 覆盖不全。Codex 承认本地只跑当前操作系统。小团队先抄路径存在性和 21 行 verify 脚本,比抄 Dylint 便宜。 出处: clippy.toml 第 9 至 28 行 两侧均已核对源码 · 2026-08-22
课堂练习
01
先做哪一道自动检查 AGENTS.md 第 35 行和第 265 行都是失效路径。若你只能先做一道自动检查,你检查带 codex-rs/ 前缀的路径,还是检查所有反引号里含 / 的字符串? 第一种会漏掉 app-server-protocol/src/protocol/v2.rs 这种相对写法。第二种会把命令名、crate 名和网址碎片误伤。写出你的过滤规则,并用这两条失效路径当正例。
Takeaway: 能局部检查的决策,不要只写在 Markdown。条款告诉人审什么,红灯在人没看的时候仍然亮。路径存在性和穷尽表,比养一台 rustc 插件更便宜,也更先该做。