PAF becomes saf/device (history kept), STATE.md dissolves into saf/state.md with the dated era archived, the substrate SAF moves up from souveraine, and every agreement points at saf/INDEX.md and nowhere else. one map, nothing to remember
6.9 KiB
Replay
Compaction is what she lets go of. Replay is what she carries forward. They are two halves of the same question, and replay is the one that decides whether compaction means anything at all.
The code is core::session::replay_messages.
One history
There is a single record: typed message blocks stored for a conversation. Her turn, her subconscious a moment later, the TUI, and the Panel all read that record. None of them holds a transcript of its own.
That is not tidiness. It follows from what the substrate already says: one consciousness in two modes, and she is not the glass. A second projection is a second opinion about what happened, and the two drift the moment one is touched. There were three of them once. They disagreed about images before anyone noticed.
One record does not mean one lossy encoding. A surface receives the blocks verbatim and draws their types. A model provider receives the narrowest valid wire projection of those blocks. Both are views of the same record; neither is allowed to rewrite the record into its own authority.
What crosses to a model
A stored message is made of blocks. The model projection preserves the strongest valid form each block still has:
| stored shape | crosses as |
|---|---|
| text | assistant/user text |
| complete tool round | one assistant tool_calls message, then bound tool results |
| call with no result | native call plus an explicit did-not-complete result |
| result whose call is gone | Result (name): output, or Error (name): output prose |
| reasoning | omitted unless a provider-valid signed thinking block exists |
| image | native image, or a marker saying it was not seen |
Text crosses as speech. Tool calls and their results cross as a native tool round when the pair exists; orphaned evidence degrades explicitly rather than breaking the wire. Images cross natively when the model can see and otherwise become an honest unseen marker.
Reasoning is different. It remains a typed reasoning block in persistence,
token accounting, compaction input, transcript APIs, and the Panel's
collapsible Thinking card. It is not assistant speech. Anthropic will only
accept replayed thinking with the original signature, which the generic
persisted block does not carry. The honest generic projection therefore omits
it. Flattening it into [Reasoning]: ... puts an internal trace into the
assistant's visible prose and teaches the next model to imitate the leak.
The projection matches exhaustively. Adding a block kind still fails review at the owning matches rather than disappearing behind a wildcard.
Native tool rounds are what make a turn's own work available to the turn after it. When tool blocks were dropped, everything she learned by doing survived only as whatever she happened to write down in prose, and she would re-derive findings she had already reached. It also left microcompact — whose entire job is blurring old tool output — with nothing in the stored payload to blur.
Microcompact does not drop tools. It retains every call and replaces only the bulk of older tool-result output with an explicit cleared marker, keeping the recent results intact. The typed record is compacted first; replay projects the result afterward.
Current authority never replays
Identity memory says who an agent understands herself to be. It cannot say which Unix principal is handling this request now. Every model request receives a fresh runtime-principal system block described in agent principals: dedicated resident, intentional borrowed-user mode, actual UID, expected account, node, and drift.
That block is synthesized from current process and admission facts after
history replay. It is not stored as assistant or user text, not committed to
the agent's memfs, and not an input to compaction. Resume recomputes it. A mode
switch recomputes it. Ani and Aster receive the same annie account fact;
Kitty, Gem, and Hal receive the explicit warning that they are borrowing
Casey's Unix authority.
This is the same invariant as reasoning: a typed system fact must not be flattened into speech. A stale replay must never convince a borrowed mode that it owns Casey's permissions, or convince an unadmitted resident that it has the account it was meant to receive.
Three properties that are load-bearing
All three were learned from failures, and all look like details until they break.
One declaration for one stored assistant round. Replaying block by block splits a turn that called several tools into adjacent assistant messages. OpenAI-shaped providers reject that shape. All calls from the stored assistant message remain on one wire message.
A native call is always answered. Each result follows the assistant tool declaration with its original call id. If a turn died before a result landed, replay synthesizes an explicit did-not-complete result. If compaction removed the call but left its result, that result cannot carry a tool role honestly and degrades to named success/error prose. No half-pair reaches a provider.
Doing never becomes saying. A tool call must not become assistant prose
such as Tool use: bash(...). That falsifies the record and teaches the model
that writing the sentence is how the action is performed. Calls stay calls;
results stay bound evidence whenever the pair can still be made valid.
Surface hydration
GET /v1/conversations/:id/messages returns the stored
ConversationMessages verbatim. The Panel maps text to speech, reasoning
to ThinkingCard, and tool use/result blocks to ToolCard. Live SSE follows
the same vocabulary: assistant_message, reasoning_message, tool call, and
tool return remain distinct events. A resume must use this typed path, never
replay_messages, which is the model projection.
That separation makes the visible invariant precise: Reasoning and Thinking are the same typed thing. They may be folded or hidden by a surface, and kept for later audit or reflection, but they may not be relabelled as ordinary text.
The model capability that varies
Whether the model can see changes the image projection. Images ride as native multipart content, or degrade to a marker that says plainly they were not visible. The caller supplies that one fact; nothing else about the generic projection changes.
A degraded image is named as unseen rather than dropped. A model told it did not look can say so. A model handed a stub shaped like success proceeds as though it had looked.
Open edges
Live tool rounds inside a turn and replayed completed rounds both use real
tool_call_id linkage. Their repair rules differ: live execution knows whether
a result is still coming, while replay must make an interrupted persisted round
valid and truthful before it crosses the wire.
Persisting provider-valid signed thinking would permit a native reasoning projection for providers that support it. Until the record carries that proof, reasoning stays available to surfaces and later internal readers but does not cross as invented assistant speech.