컨텍스트 거버넌스를 code review에 쓰세요
지난 레슨은 컨텍스트에 넣는 글을 타입으로 묶었습니다. 타입이 통과해도 그 글은 여전히 합법적으로 길고, 자주 바뀌고, 끝이 없을 수 있어요. 그 비용을 막는 것은 저장소 루트의 열 줄 금령과, 같은 절을 다시 읽는 리뷰 skill입니다.
- 주입이 ContextualUserFragment로 등록됐는가AGENTS.md L100
- 이 항목에 하드 상한이 있는가AGENTS.md L97 · protocol.rs L3112
- 한 건이 10K token을 넘을 수 있는가AGENTS.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에서 hint 한 줄을 format해 테스트를 돌리라고 일깨웁니다. 병은 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에서 Message를 format!하면 컴파일은 되고 리뷰가 돌려보냅니다. 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 열거가 없고, 새 struct의 body()가 1K를 넘을지 짐작하는 lint도 없습니다.출처: codex-rs/context-fragments/src/additional_context.rs 5행
2조가 보는 것은 타이밍이에요. 추가할 수 있으면 추가합니다. 매 턴 환경 XML을 다시 쓰고 도구 목록을 바꾸면 접두사가 안 맞고, cache는 첫 층부터 폐기돼요. 세션 클라이언트는 턴을 넘는 안정과 턴 안의 점성을 나누고, sticky token은 턴을 넘어 재생하면 안 됩니다. 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는 포맷, lock 파일 드리프트, 일부 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의 정의 crate와 유일한 구현을 접을지 논한 메모는 Status를 rejected로 적고, Alternatives considered를 따로 남깁니다. 나중에 원격이나 recall 백엔드가 있을 수 있다는 것은 지금 패키지를 쪼갤 이유가 못 돼요. Codex 쪽에는 나중에 읽는 이에게 매 턴 git status 주입이 왜 철회됐는지 말해 주는 rejected/ 디렉터리가 없습니다. 나중 사람은 prompt_caching.rs와 Guardian 주석에서 거꾸로 짚어야 해요.
Claude Code: 제품 심사와 런타임 빨간선은 다른 층
복원 소스에서 Model visible context, ContextualUserFragment, unbounded context를 찾아도, 공개된 컨텍스트 주입 리뷰 규범은 없어요. REVIEW.md는 심사 모델이 보는 제품화된 PR 규칙으로, 어떤 문제를 심사에서 짚을지 표시합니다. 런타임에 모델 컨텍스트에 글을 넣는 공학 빨간선과는 층이 다릅니다.
이 칸은 비어 있어요. 나중에 새 복원 소스가 있으면 이 단어들로 다시 보면 됩니다.
검색함 · 대응 규범 없음 · 2026-08-22이 format을 남겨도 될까요
누군가 session/turn.rs에서 <workspace_map>를 format해 현재 디렉터리 나무를 넣고, 디버그일 때만 켠다고 말해요. 여섯 조를 하나씩 지나 보세요. 어떤 등이 빨개지고, 어떻게 고쳐야 남을 수 있는지요.
한 단계 더: 디렉터리 나무의 최악이 1K token을 넘으면 PR 제목에 P0을 달아야 할까요. 소스에 대신 달아 주는 속성 매크로가 있는지도요.