把上下文治理写进 code review
上一章把往上下文里塞东西收成类型。类型过了,这段文字仍然可以合法地又长、又勤、又无界。挡这些后果的,是仓库根十行禁令,外加一份会把同一节再读一遍的评审 skill。
ContextualUserFragment 的改动,编译器仍会放行一份会打掉 cache、撑满窗口或让旧会话恢复失败的 PR;以及六条禁令里,哪几条落在代码里,哪几条只能靠人和 skill 守。
- 注入有没有登记成 ContextualUserFragmentAGENTS.md L100
- 这一条有没有硬上限AGENTS.md L97 · protocol.rs L3112
- 单条是否可能超过 10K tokenAGENTS.md L98 · model_info.rs L167
- 新种类若可能过 1K,标 P0 另审AGENTS.md L99 · additional_context.rs L5
- 会不会每轮改已经发出去的前缀AGENTS.md L96 · client.rs L272
- 是追加新行,还是改历史里的旧行AGENTS.md L95 · session/mod.rs L3383
- 改旧行会不会让已有 rollout 恢复失败AGENTS.md L110
想象四份看起来很负责的 PR。甲给 environment 上下文加一个 git_status 字段,每轮写入完整工作区状态。乙在 turn.rs 里 format 一句 hint,提醒模型跑测试。丙新建一个 fragment,把整个源文件塞进模型可见文本,不写截断。丁在 AGENTS.md 一改时,就地改写历史里那一条说明。
四份都能写出干净的 struct、干净的测试。类型系统会放行。下一轮推理的 cache 前缀会被打掉,token 账单会按轮翻倍,从旧 rollout 恢复时会读到被改过的历史。
ContextualUserFragment 是往模型上下文里塞一段带标记文字的登记口。上一章用它把注入收成类型。编译器从此只接受实现了这个 trait 的 struct。形状对了,成本还可以不合法:又长、又勤、又无界。
Codex 把成本写成六条禁令,放在仓库根 AGENTS.md,标题就叫 Model visible context。同一段原文被抄进 .codex/skills/code-review-context/SKILL.md。评审机器人读到的就是这六条,没有第二套解释。
### Model visible context
Codex maintains a context (history of messages) that is sent to the model in inference requests.
1. No history rewrite - the context must be built up incrementally.
2. Avoid frequent changes to context that cause cache misses.
3. No unbounded items - everything injected in the model context must have a bounded size and a hard cap.
4. No items larger than 10K tokens.
5. Highlight new individual items that can cross >1k tokens as P0. These need an additional manual review.
6. All injected fragments must be defined as structs in `core/context` and implement ContextualUserFragment trait
openai/codex,核对文件 AGENTS.md,commit 4f39251a01,核对日期 2026-08-22。代码块保留源码原文。同一段六条还出现在 .codex/skills/code-review-context/SKILL.md 第 7 到 13 行。第 6 条和第 3、4 条先问入口和上界。没走 trait,handler 里直接 format! 一段 Message,编译能过,评审打回。走了 trait 但没写硬 cap,同样打回。工具输出侧默认按字节 10_000 截断,超了从中间砍,前面加一行警告,告诉模型原 token 数和总行数。出处:codex-rs/protocol/src/protocol.rs 第 3112 行;codex-rs/models-manager/src/model_info.rs 第 167 行;codex-rs/utils/output-truncation/src/lib.rs 第 12 至 24 行
通用附加上下文另卡在 1_000 token。1K 正好是第 5 条的门槛:已有种类被代码截到 1K,新的可能超过 1K 的种类才需要人看。源码里没有 P0 枚举,也没有 lint 去估一个新 struct 的 body() 会不会超过 1K。出处:codex-rs/context-fragments/src/additional_context.rs 第 5 行
第 2 条盯的是时机。能追加就追加。每轮重写环境 XML、每轮换工具清单,前缀对不上,cache 从第一层作废。会话级客户端把跨 turn 稳定和 turn 内粘滞拆开,sticky token 不准跨 turn 重放。Guardian 审查会话故意复用同一条 trunk,好保住 prompt_cache_key。集成测试 prompt_caching.rs 盯的就是连续两轮 instructions 和 tools 必须一致。出处:codex-rs/core/src/client.rs 第 262 至 274 行;codex-rs/core/src/guardian/review.rs 第 932 至 934 行
类型系统证明的是形状。它证明不了这条文字会不会每轮变、有没有上界、会不会改已经发出去的前缀。这些是过程属性,换语言重写也得另开一扇门。
日常命令也补不上这扇门。just fmt 和 just test 挡住格式、锁文件漂移和一部分 API 破坏。它们读不懂你是不是每轮注入了 git status。六条里零条有专用 lint。第 1、2 条有集成测试影子,第 3、4 条靠局部 cap,第 5 条纯靠人。第 6 条拦得住没实现 trait 就走 render_full 的路,拦不住在 handler 里直接拼一段 Message。skill 存在,说明执行主体是评审。
AGENTS.md 改了,最省事的做法是找到历史里那一条 UserInstructions,把正文换掉。当前轮少占一条消息,token 看起来还降了。从旧 rollout 恢复时,读到的是被改过的文本,会话对不上。
压缩看起来也像在改历史:旧窗口从 live history 里消失。若有人把压缩做成打开历史文件改一行,第 1 条和 breaking changes 第五项会一起被踩中。第五项点名的就是从已有 rollout 恢复会话。
replace_compacted_history 把新表整表装进 live history,旧内容以带 replacement_history 的 CompactedItem 追加到 rollout,不回改旧行。注释写明 「Compaction starts a new history window」。第 1 条和压缩能共存,因为压缩被定义成开新窗口。生产路径里那条就地换表的函数叫 replace_history,上面标了 #[cfg(test)]。出处:codex-rs/core/src/session/mod.rs 第 3373 至 3418 行;AGENTS.md 第 95 行、第 110 行
远端压缩还有一层滤网。服务端送回来的 transcript 不可信,developer 消息直接丢掉,再由本地按当前 world state 把带 marker 的 fragment 重新渲染进去。历史继续增量构建,压缩继续换窗口。出处:codex-rs/core/src/compact_remote.rs 第 354 至 372 行
追加写、用快照换窗口,是日志系统的通用形状。事件溯源换的是投影,LSM 树换的是 SSTable,都不回改已经写下的旧行。禁止就地更新,恢复才有得对。
总量谁来管,六条没写数字。代码用两层补上:模型窗口的 full_context_window_limit 是硬顶,会话树的 RolloutBudget 按加权 token 记账,用尽对整棵 thread 停写。40 条都合法且每条 9K,总量仍会被满窗或会话预算拦住。出处:codex-rs/core/src/session/context_window.rs 第 53 至 54 行、第 74 至 79 行;codex-rs/core/src/rollout_budget.rs 第 45 至 65 行
DeepSeek Harness:原则加笔记,少写禁令
DSH 仓库根 AGENTS.md 第 107 行写的是 「Model-visible ⟺ logged」:送到模型请求里的东西,必须能从会话日志重建;新的模型可见输入,必须对应一条 session 事件。它管的是可见与落盘对齐,不管这一条是不是无界、是不是每轮改、单条是不是超过 10K。
否决过的路会立档。一篇讨论要不要把 compaction 的定义包和唯一实现折在一起的笔记,Status 写明 rejected,还单独留下 Alternatives considered:将来可能有远端或 recall 后端,不够成为现在就拆包的理由。Codex 这一侧没有 rejected/ 目录告诉后来者,某次每轮注入 git status 为何撤回。后来者只能从 prompt_caching.rs 和 Guardian 注释反推。
Claude Code:产品审查和运行时红线不是一回事
用 Model visible context、ContextualUserFragment、unbounded context 检索还原源码,找不到公开的上下文注入评审规范。REVIEW.md 是给审查模型看的产品化 PR 规则,用来标记该不该在审查里指出某类问题,和运行时往模型上下文塞东西的工程红线不是同一层。
这一格空着。后续如果有新的还原源码,可以按这几个词复查。
已检索 · 未找到对应规范 · 2026-08-22这句 format 能留吗
有人要在 session/turn.rs 里 format 一段 <workspace_map>,把当前目录树塞进去,声称只有调试时才开。按六条逐条过:哪几条亮红,改成什么样才能留。
进阶一问:若目录树最坏超过 1K token,PR 标题要不要标 P0,源码里有没有对应的属性宏替你标。