Watch
1
0
Fork
You've already forked souveraine
0

saf: write the replay page, retire two stale claims

Replay had no page while compaction's premise depends on it — microcompact
blurs tool output that a text-only projection never sent.

Compaction's open edges still said pressure counts only text; 7530d6d made
it exhaustive. Two links pointed at pages that were never written.
This commit is contained in:
Fimeg 2026-08-13 20:45:21 -04:00
commit aae9344fe1
4 changed files with 79 additions and 5 deletions

View file

@ -17,6 +17,7 @@ How Souveraine is built, and why. For whoever reads it, human or agent. When thi
**memory**: how she holds on and lets go
- [compaction](memory/01-compaction.md). Five ways to make room.
- [replay](memory/02-replay.md). One projection of what she keeps onto what the model sees.
Coming: the rest of identity (the memory filesystem, the ledgers), the nervous system (schedules, the event log), the consciousness cycle, the runtime, federation, a glossary.

View file

@ -22,7 +22,7 @@ Four of the five spend no tokens. The two that call a model are for when continu
## Pressure
After each turn the engine measures how full the window is against the model's limit. Three marks: 0.80, 0.90, 0.95. Crossing one raises a warning, not a hand on the wheel. The warning travels the same path her subconscious uses to surface anything, and arrives as a feeling she can act on or sit with. Nothing forces or schedules the compaction. The marks move per kind of agent.
After each turn the engine measures how full the window is against the model's limit. Every block counts toward it — text, tool calls, tool results, reasoning, images — through one shared weight function, so a tool-heavy turn feels as heavy as it is. Three marks: 0.80, 0.90, 0.95. Crossing one raises a warning, not a hand on the wheel. The warning travels the same path her subconscious uses to surface anything, and arrives as a feeling she can act on or sit with. Nothing forces or schedules the compaction. The marks move per kind of agent.
## What it leaves behind
@ -30,12 +30,10 @@ Every compaction that changes anything writes a small file to `journal/compactio
## Not the archivist
This is the live conversation, the messages the model sees next turn. The N+100 archivist is the other thing: it takes raw journal entries already written to memory and presses them into a dense synthesis for later. One frees the room she is in now; the other distills what she has already lived. Both can fire on the same turn. See [consciousness/04-n100-archivist](../consciousness/04-n100-archivist.md).
This is the live conversation, the messages the model sees next turn. The N+100 archivist is the other thing: it takes raw journal entries already written to memory and presses them into a dense synthesis for later. One frees the room she is in now; the other distills what she has already lived. Both can fire on the same turn. The archivist has no page here yet.
## Open edges
Pressure counts only text right now. Tool results, reasoning, and images read as zero, so a tool-heavy turn feels lighter than it is and the warning comes late.
A `kv_target` setting points at a strategy that was never built. It parses and does nothing.
The truncation note, shown when the model is cut off mid-sentence, works; its wording is still being settled (`docs/tasks/truncation-signal-polish.md`).

75
saf/memory/02-replay.md Normal file
View file

@ -0,0 +1,75 @@
# 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: the messages stored for a conversation. Everything
that talks to a model — her turn, her subconscious a moment later, a terminal,
a voice, a web surface — replays that same record. None of them holds a version
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.
## What crosses
A stored message is made of blocks. Each one has a prose form for replay:
| block | crosses as |
|---|---|
| text | itself |
| tool use | `Tool use: name(input)` |
| tool result | `Result (name): output`, or `Error (name): output` |
| reasoning | `[Reasoning]: …` |
| image | natively, or a marker saying it was not seen |
Nothing is silently dropped. A block with no prose form does not exist — the
match is exhaustive, so a new kind of block fails to compile rather than
quietly going missing.
This is what makes a turn's own work available to the turn after it. When tool
blocks were dropped on replay, 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 payload to blur.
## Two properties that are load-bearing
Both were learned from a failure, and both look like details until they break.
**One wire message per stored message.** Replaying block by block splits a
single assistant turn that called several tools into adjacent assistant
messages, and OpenAI-shaped providers reject that outright: *assistant
tool_calls must be followed by tool messages*. The message boundary is part of
the record.
**No tool roles and no call-id obligations.** Inside a live turn, a tool call
and its result are both known to exist, and the exact linkage is used. Across
persisted turns that linkage is brittle: a turn killed mid-round leaves a call
whose result never landed, and replaying it as half a pair fails the whole
request. So the *content* of a tool round survives as prose while the wire
obligations do not. The record is not the protocol.
## The only thing that varies
Whether the model can see. 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 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 build their own messages, with real
`tool_call_id` linkage. That is correct and separate — replay is for what is
already on disk. The two should not be merged; they answer different questions.

View file

@ -29,7 +29,7 @@ Every event is a `SensorEvent`:
One type, not an enum per event, so a listener filters on `event_type` and ignores the rest, and the log can write everything down without knowing the taxonomy.
`seed_id` rides on every event though federation isn't here yet. When it lands, a sensor becomes federated without the envelope changing. See [federation/01-seed-and-federation](../federation/01-seed-and-federation.md).
`seed_id` rides on every event though federation isn't here yet. When it lands, a sensor becomes federated without the envelope changing. See [federation/01-node-enrollment](../federation/01-node-enrollment.md).
## What pushes