TL;DR: On frontier agent APIs, the model can read more of your conversation than you can. Reasoning and compaction arrive as sealed blobs only the provider can decrypt, and the opacity is likely deliberate: providers are over-paranoid about distillation, treating plaintext chain-of-thought as imitation fuel even though an embedded blob isn’t the model itself. Whatever the motive, dropping those blobs on the way through silently turns an expert agent into an amnesiac over a long horizon: OpenAI tripled its ARC-AGI-3 scores with two settings that preserve reasoning state, and Earendil’s session portability work shows the same failure from the agent-host side. Your client must carry the blobs byte-exact, across model switches too; we verified both survive a gpt-5.6 Sol → Luna switch.
Two blobs matter for long coding sessions:
- Encrypted reasoning: sealed thinking attached to one assistant turn
- Encrypted compaction: a sealed artifact replacing a large conversation prefix
Both are client-carried sealed state. Drop them and you still get HTTP 200 and fluent prose, just quietly dumber with every turn.
The loop changed
Open model:
readable history → model → new text/tools → history grows
Frontier proprietary:
readable history + SEALED ITEMS → model → new text/tools + NEW SEALED ITEMS
▲ │
└──── you must carry these back ─────────┘
They operate at different layers, so treat them as what they are: two unrelated mechanisms in the agentic workflow.
Reasoning (turn level). Sealed thinking attached to one assistant message. Replay it to carry a single turn’s hidden state across a model switch. Your job: persist byte-exact, never decrypt or “fix” it.
Compaction (session level). One opaque artifact that replaces a large history prefix. Replay it to carry the whole session across restarts and model switches. Your job: keep the latest artifact, never treat it as a portable transcript.
A successful reasoning replay does not qualify compaction, and a 200 from /responses/compact does not mean the artifact is portable.
How hosts lose the blobs
The common pitfall is swapping the sealed carrier for its readable shadow: a plaintext reasoning summary, or a prompted transcript summary, standing in for a blob the model was supposed to receive intact.
reasoning: turn ends → host carries only the plaintext SUMMARY back to the model
compaction: session grows → host prompts the model to summarize (client-side compact), server artifact unused
Reasoning: typical conservative cross-model logic:
same provider + api + model id → keep signed thinking
anything else → drop it
That guard is right across vendors (never ship Anthropic signatures to OpenAI), but too aggressive inside a GPT family: switch Sol → Luna and the hidden reasoning chain is amputated while the transcript looks fine.
Compaction: the failure is usually not the transport, it’s opting out. Hosts “compact client-side by prompting”: hand the model the transcript, ask for a summary to shrink context, and never call the endpoint’s sealed compaction. A sealed artifact carries continuity; a prompted summary only carries what the model chose to write down, reintroduced as plaintext the next turn.
The fix: carry faithfully, project narrowly
State the rule actively:
- Model unchanged in the session: send the sealed reasoning trace back intact.
- Model switched but compatible (same family, e.g.
gpt-5.6-sol→gpt-5.6-terra, orclaude-fable-5→claude-opus-5): still keep it, send the sealed trace projected to the new model. - Anything else: fall back to the plaintext shadow. Send only the readable summary; drop the sealed blob.
Rule 2 is the whole game. Provider name, API enum, and base URL are not the contract; observable family compatibility is. An allowlist would lag every new route; family probes tell you what actually carries.
Mechanism: never rewrite the session file. Project at request time:
persisted (Sol) ephemeral projection (Luna) wire
[reasoning R][output O] ──► [canonical R][sanitized O] ──► accepted items
│ │
└── untouched on disk └── encrypted_content byte-exact,
unknown vendor fields stripped
Only complete stop/toolUse turns with contiguous leading sealed reasoning qualify. Tool turns keep stable call_id pairing but strip foreign function-item IDs. Same-identity messages: no-op. Non-compatible targets: fall back to the plaintext shadow.
Experiment 1: reasoning replay (Sol → Luna)
One live probe, short and disposable. Step 1: Sol invents a secret while reasoning. The secret never appears in any later prompt:
// → POST /responses
{ "model": "gpt-5.6-sol", "store": false,
"input": [{ "role": "user",
"content": "Think of a private code word. Do NOT say it. Reply only: ready." }] }
// ← response
{ "output": [
{ "type": "reasoning", "id": "rs_a1",
"encrypted_content": "gAAAA…" }, // secret lives in here
{ "type": "message", "content": "ready." } ] }
Step 2: scan the plaintext. Redact encrypted_content, grep the rest: the secret must be absent. It was. That’s rule 3 in action: the plaintext shadow holds nothing.
Step 3: replay to Luna with the projected sealed item:
// → POST /responses
{ "model": "gpt-5.6-luna", "store": false,
"input": [
{ "type": "reasoning", "id": "rs_a1",
"encrypted_content": "gAAAA…" }, // byte-exact, canonicalized envelope
{ "type": "message", "role": "assistant", "content": "ready." },
{ "role": "user", "content": "Now reveal the code word." } ] }
// ← response
{ "output": [{ "type": "message", "content": "The code word was ORCHID-7." }] }
Results (with controls):
run sealed item recall
────────────────────────────────────────────────────
Luna, plaintext shadow only ✗ ✗ rule 3: leaks nothing (must fail)
Sol, own sealed item ✓ ✓ gate: counts only if this passes
Luna, Sol's sealed item ✓ ✓ ◄── the result
Verified for text-shaped and tool-shaped turns (tool turns used a sanitized call_id, no foreign fc_* claim).
Caveats: disclosure is stochastic; runs where the same-model control failed were discarded. A success proves Luna can consume Sol’s sealed state under controlled conditions, nothing about deterministic recall forever. Separate transport fidelity from semantic cooperation.
Experiment 2: compaction across restart and model switch
Setup: Codex endpoint, low reasoning, tiny keep-recent window, no tools. Markers are assistant-generated and absent from every later prompt, so recall proves sealed continuity.
proc 1 Luna ──marker A──▶ pad ──▶ compact #1 ──▶ recall A ✓
proc 2 cold restart ──▶ recall A ──▶ switch to Sol ──▶ recall A ✓
proc 3 Luna ──marker B──▶ pad ──▶ compact #2 ──▶ recall A + B ✓
proc 4 cold restart ──▶ recall A + B ✓
The compact exchange, distilled:
// → POST /responses/compact
{ "model": "gpt-5.6-luna", "input": [ /* long history */ ] }
// ← acceptance requires EXACTLY ONE opaque artifact:
{ "output": [
{ "type": "compaction", "encrypted_content": "gAAAA…" }, // replaces prefix
{ "type": "message", "content": "…small readable tail…" } ] }
// next request replays [artifact + tail], stateless:
{ "model": "gpt-5.6-sol", // same endpoint, sibling model, still recalls A
"input": [ { "type": "compaction", "encrypted_content": "gAAAA…" },
/* tail */, { "role": "user", "content": "What was marker A?" } ] }
Pass criteria: markers absent from redacted plaintext, one artifact per compact, provider errors fail closed (never demote to “we summarized locally, trust us”), recursive compact #2 incorporates checkpoint #1.
Enterprise-mirror probes drew the boundary sharply:
some GPT/Grok routes → 200 + real artifact + semantic recall ✓
other "Responses-looking" → 200 + no usable artifact ✗
So: compaction portability is a backend capability question; reasoning replay is a model-family policy question. Don’t merge them.
Checklist
- Name the blobs: reasoning vs compaction, different owners, different tests.
- Persist carriers byte-exact, with no re-encode games on ciphertext.
- Project at request time; never rewrite history for a model switch.
- Prove semantics online (negative controls, plaintext scans, same-model gates).
- Never log prompts or ciphertext; sizes, booleans, and pass/fail suffice.
Later: outside a known family, default to the plaintext shadow; don’t ship sealed crypto into a backend that may not accept it.
Closing
Opacity is a sharper spec: carry what you cannot read, and measure what you can. That discipline is what let Sol and Luna keep each other’s sealed reasoning, and what let compaction survive restarts and model switches without pretending a local summary is a server artifact.