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 插件更便宜,也更先該做。