Write Context Governance into Code Review
The last lesson folded every injection into a type. Once the type passes, that text can still be legally long, frequent, and unbounded. What stops those costs is ten lines of bans at the repo root, plus a review skill that rereads the same section.
ContextualUserFragment can still compile a PR that blows the cache, fills the window, or breaks restore of an old session; and, of the six bans, which ones land in code and which ones only people and a skill can hold.
- Is the injection registered as ContextualUserFragmentAGENTS.md L100
- Does this item have a hard capAGENTS.md L97 · protocol.rs L3112
- Could a single item exceed 10K tokenAGENTS.md L98 · model_info.rs L167
- If a new kind can cross 1K, mark P0 for extra reviewAGENTS.md L99 · additional_context.rs L5
- Will it rewrite a prefix already sentAGENTS.md L96 · client.rs L272
- Is it appending a new row, or rewriting an old one in historyAGENTS.md L95 · session/mod.rs L3383
- Would rewriting an old row break restore of an existing rolloutAGENTS.md L110
Picture four PRs that look responsible. A adds a git_status field to environment context and writes the full workspace state every turn. B formats a hint in turn.rs to remind the model to run tests. C mints a fragment that stuffs a whole source file into model-visible text, with no truncation. D, when AGENTS.md changes, rewrites that one note in history in place.
All four can ship a clean struct and clean tests. The type system will clear them. The next inference round loses its cache prefix, the token bill doubles per turn, and restore from an old rollout reads rewritten history.
ContextualUserFragment is the registry slot for a marked stretch of text stuffed into model context. The last lesson used it to fold injections into types. From then on the compiler only accepts a struct that implements this trait. The shape can be right and the cost still illegal: long, frequent, unbounded.
Codex writes the cost as six bans in the repo-root AGENTS.md, under the heading Model visible context. The same text is copied into .codex/skills/code-review-context/SKILL.md. The review bot reads these six lines. There is no second explanation.
### 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, checked file AGENTS.md, commit 4f39251a01, checked 2026-08-22. The code block keeps the original source. The same six lines also appear in .codex/skills/code-review-context/SKILL.md lines 7–13.Rules 6, 3, and 4 ask about the door and the ceiling first. Skip the trait and format! a Message in the handler: it compiles, review sends it back. Implement the trait but skip a hard cap: same bounce. Tool output defaults to a 10_000-byte cut; overflow is sliced from the middle, with a warning line up front telling the model the original token count and total lines.Source: codex-rs/protocol/src/protocol.rs line 3112;codex-rs/models-manager/src/model_info.rs line 167;codex-rs/utils/output-truncation/src/lib.rs lines 12–24
Generic extra context is capped at 1_000 token. 1K is exactly rule 5's threshold: existing kinds are already cut to 1K in code; only a new kind that might cross 1K needs a human. There is no P0 enum in source, and no lint that estimates whether a new struct's body() will exceed 1K.Source: codex-rs/context-fragments/src/additional_context.rs line 5
Rule 2 watches timing. Append when you can. Rewrite the environment XML every turn, swap the tool list every turn, and the prefix no longer matches: cache dies from layer one. The session-level client splits cross-turn stability from in-turn stickiness; a sticky token must not replay across turns. Guardian review sessions reuse the same trunk on purpose, to keep prompt_cache_key. The integration test prompt_caching.rs watches that instructions and tools stay identical across two consecutive turns.Source: codex-rs/core/src/client.rs lines 262–274;codex-rs/core/src/guardian/review.rs lines 932–934
A type system proves shape. It cannot prove whether this text changes every turn, whether it has a ceiling, or whether it rewrites a prefix already sent. Those are process properties. Rewrite it in another language and you still need a second door.
Daily commands cannot fill this door either. just fmt and just test catch formatting, lockfile drift, and some API breakage. They cannot read whether you inject git status every turn. Zero of the six have a dedicated lint. Rules 1 and 2 have integration-test shadows; 3 and 4 lean on local caps; 5 is purely human. Rule 6 can stop a path that calls render_full without implementing the trait; it cannot stop you from stitching a Message in the handler. The skill exists because the executor is review.
When AGENTS.md changes, the cheapest move is to find that UserInstructions row in history and swap the body. This turn uses one fewer message; token count even looks lower. Restore from an old rollout reads the rewritten text. The session no longer matches.
Compaction looks like rewriting history too: the old window vanishes from live history. If someone implements it as opening the history file and editing a line, rule 1 and breaking-change item 5 both get stepped on. Item 5 names restore of a session from an existing rollout.
replace_compacted_history loads the new table wholesale into live history. Old content is appended to the rollout as a CompactedItem carrying replacement_history. Old rows are not rewritten. The comment says “Compaction starts a new history window”. Rule 1 and compaction can coexist because compaction is defined as opening a new window. The in-place table swap on the production path is replace_history, marked #[cfg(test)].Source: codex-rs/core/src/session/mod.rs lines 3373–3418;AGENTS.md line 95、line 110
Remote compaction has one more filter. A transcript from the server is untrusted: developer messages are dropped, then the local side re-renders marked fragments from the current world state. History keeps building incrementally. Compaction keeps swapping windows.Source: codex-rs/core/src/compact_remote.rs lines 354–372
Append-only writes and snapshot window swaps are the usual shape of a log. Event sourcing swaps a projection; an LSM tree swaps an SSTable. Neither rewrites a row already written. Ban in-place updates, and restore has something to match.
Who owns the total? The six bans write no number. Code fills that with two layers: full_context_window_limit is the hard top of the model window; the session tree's RolloutBudget bills weighted token and stops writes for the whole thread when spent. Forty legal items at 9K each still get stopped by a full window or the session budget.Source: codex-rs/core/src/session/context_window.rs lines 53–54、lines 74–79;codex-rs/core/src/rollout_budget.rs lines 45–65
DeepSeek Harness: a principle plus notes, few bans
Line 107 of the DSH repo-root AGENTS.md says “Model-visible ⟺ logged”: anything sent in a model request must be rebuildable from the session log; a new model-visible input must map to a session event. It governs visibility versus disk, not whether an item is unbounded, rewritten every turn, or over 10K.
Rejected paths get a file. A note on whether to fold compaction's definition crate and its only implementation together marks Status as rejected, and leaves Alternatives considered: a future remote or recall backend is not reason enough to split the crate now. Codex has no rejected/ directory telling a later reader why an every-turn git status inject was pulled. Later readers reverse-engineer it from prompt_caching.rs and Guardian comments.
Claude Code: product review and runtime red lines are not the same layer
Search the reconstructed source for Model visible context, ContextualUserFragment, unbounded context: no public review spec for context injection turns up. REVIEW.md is productized PR rules for a review model — which issues to flag in review — not the same layer as the engineering red line for stuffing text into model context at runtime.
This cell stays empty. If newer reconstructed source shows up, recheck these words.
Searched · no matching spec · 2026-08-22Can this format stay
Someone wants to format a <workspace_map> in session/turn.rs, stuff in the current directory tree, and claims it only turns on while debugging. Walk the six rules: which lamps go red, and what rewrite would let it stay.
A harder follow-up: if the directory tree's worst case exceeds 1K token, should the PR title mark P0, and is there an attribute macro in source that marks it for you.