OpenAI Codex · 代码模式

把架构决策写成 lint

同一份 AGENTS.md 里,有命令的规则会在三台操作系统上亮红。只有路径的那条,重命名之后没人发现。

课程目标读完能说清三件事。一条调用点规则怎样变成 rustc 插件,并在 Linux、macOS、Windows 上同时拦。散文写成的路径为什么会失效。漏登记的特性为什么能用穷尽表抓住。
先玩一遍 · 一次提交过架构检查
同一份规范,五张改动卡片:看它被哪一层拦住,以及那一层想守住什么
这次改动
点播放看门禁怎么走。也可以直接点右侧某一层,看它放行还是拦住。
提交与门禁待命
create_openai_url(None)调用点写了裸 None。编译能过,读者必须跳到定义才知道它管什么。
这一步的判定
手里的改动裸 None
撞上的门尚未触发
这条要守住什么先走一遍门禁
结局待命
等待开始。
逻辑轨迹 · 动画每一步对应源码里的哪一段
  1. 调用点是不是匿名字面量lib.rs L261
  2. 注释名字是否等于参数名lib.rs L222
  3. 被调方是不是 workspace cratelib.rs L177
  4. CI 是否三平台同时跑rust-ci.yml L174
  5. Markdown 路径是否存在AGENTS.md L35
  6. Feature 是否登记在穷尽表lib.rs L379
  7. 开发中特性默认必须关闭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。类型解析完成后,才能拿到被调方的参数名。入口只看函数调用和方法调用,宏展开出来的直接跳过。

检查按这个顺序走。

1. 只查本仓库 crate,stdtokio 直接放过。

2. 注释从参数前的空隙、前 64 字节、参数文本自身三处找。

3. 名字不对报 mismatch。错注释不会再落到没写注释那条。

4. 没写时,方法名等于唯一参数名就豁免,例如 .enabled(false)

5. 剩下的只拦匿名字面量。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 插件更便宜,也更先该做。