From 4b4e6af2eaef4108a9694181c311fac2acd0ed40 Mon Sep 17 00:00:00 2001 From: Ramnique Singh <30795890+ramnique@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:26:22 +0530 Subject: [PATCH] docs(core): surface the config-relative recomposition caveat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elision reads config/context.json at compose time, so the composed payload is no longer a pure function of the durable log — inspecting an old turn after a config edit can show different prefix bytes than were transmitted. Document the exception against §8.3 and make the inspect CLI print the policy in effect so divergence is visible instead of silent. The gold fix (recording the applied policy on the turn) is noted for when exact-bytes replay becomes a hard requirement. Co-Authored-By: Claude Fable 5 --- .../x/packages/core/docs/turn-runtime-design.md | 9 +++++++++ apps/x/packages/core/src/turns/inspect-cli.ts | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/x/packages/core/docs/turn-runtime-design.md b/apps/x/packages/core/docs/turn-runtime-design.md index 620a0ad8..5f462bd1 100644 --- a/apps/x/packages/core/docs/turn-runtime-design.md +++ b/apps/x/packages/core/docs/turn-runtime-design.md @@ -409,6 +409,15 @@ in `config/context.json` (`elideHistoricToolResults`, default true; `elideHistoricImages`, default true; `elideHistoricMiddlePaneContent`, default true). The inspect CLI composes through the same decorated resolver. +Caveat: elision makes the composed payload a function of the durable log +PLUS the config in effect at compose time — the one deliberate exception to +"recomposition from durable state alone" (§8.3). Within a turn this is +harmless (policy is loaded once per execution, at resolve time), but +inspecting an old turn after a config change may show different prefix +bytes than were transmitted; the inspect CLI prints the active policy so +the divergence is visible. If exact-bytes replay ever becomes a hard +requirement, record the applied policy on the turn and compose from that. + ### 6.7 Agent snapshot inheritance Session turns whose resolved system prompt and tool set are byte-identical diff --git a/apps/x/packages/core/src/turns/inspect-cli.ts b/apps/x/packages/core/src/turns/inspect-cli.ts index 3140148f..9326a73c 100644 --- a/apps/x/packages/core/src/turns/inspect-cli.ts +++ b/apps/x/packages/core/src/turns/inspect-cli.ts @@ -8,6 +8,10 @@ // messages (user-message context, attachments, tool-result envelopes) are // visible; the file itself stores only structural facts and references. // +// Caveat: historic-context elision reads config/context.json at compose +// time, so recomposition is exact only while that config matches what was +// live when the call ran. The header prints the policy in effect NOW. +// // Session mode prints the session overview (title, turns, statuses, sizes); // pass --turns to cascade full turn inspection for every turn. // @@ -27,7 +31,7 @@ import { convertFromMessages } from "../agents/runtime.js"; import { WorkDir } from "../config/config.js"; import { FSSessionRepo } from "../sessions/fs-repo.js"; import { composeModelRequest } from "./compose-model-request.js"; -import { createContextResolver } from "./context-elision.js"; +import { createContextResolver, loadElisionPolicy } from "./context-elision.js"; import { FSTurnRepo } from "./fs-repo.js"; const turnRepo = new FSTurnRepo({ @@ -81,6 +85,17 @@ async function inspectTurn( console.log( `agent ${agent.agentId} model ${agent.model.provider}/${agent.model.model} calls ${state.modelCalls.length}${inherited}`, ); + const policy = loadElisionPolicy(); + console.log( + `context elision (per config/context.json NOW; transmitted bytes reflect the config live at call time): ` + + [ + policy.toolResults + ? `toolResults>${policy.toolResultThresholdChars}` + : "toolResults off", + policy.images ? "images" : "images off", + policy.middlePaneContent ? "notes" : "notes off", + ].join(", "), + ); for (const call of state.modelCalls) { if (onlyIndex !== undefined && call.index !== onlyIndex) continue;