You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Imagine recording the same conversation in two notebooks. While the conversation is happening, we read notebook A. As soon as it finishes, we switch to notebook B.
Even if both notebooks are meant to say the same thing, they are written separately. A crash, retry, or reconnect can catch them at different points.
That is the current transcript architecture:
flowchart LR
subgraph Today["Today: one conversation, two ledgers"]
direction TB
Run1["Runtime execution"] --> Events1["RuntimeEvent"]
Run1 --> Messages1["StoredMessage"]
Events1 --> Active["Active transcript"]
Messages1 --> Completed["Completed pages"]
end
subgraph Target["Target: one ledger, many views"]
direction TB
Run2["Runtime execution"] --> Events2["RuntimeEvent"]
Events2 --> Projection["Bounded transcript projection"]
Notes["UI notes"] --> Projection
WorkHub["WorkHub facts"] --> Projection
Projection --> View["StoredMessage view"]
end
Loading
RuntimeEvent records what happened. StoredMessage describes how transcript data is presented. They should not both be durable authorities for the same ordinary execution fact.
What happens today
Ordinary runtime conversation facts are persisted through two paths:
RuntimeEvent records the execution timeline.
AiSdkTurn, ToolRuntime, and AgentRun also persist equivalent StoredMessage conversation records.
Those writes do not share one commit order. The read path then switches authority at the turn boundary:
while a root turn is active, its transcript overlay is projected from RuntimeEvent;
after the turn becomes terminal, completed pages are read from persisted StoredMessage records.
The same conversation can therefore be reconstructed from different durable representations before and after completion. Recovery, reconnect, pagination, and migration all depend on those representations remaining equivalent even when their writes settle in different orders.
The architectural rule
RuntimeEvent is the single durable semantic authority for ordinary Session execution facts.
Everything else has one clear role:
Transcript pages are bounded read projections over the RuntimeEvent timeline. A page must not require loading the full Session.
SessionEvent remains live transport for active clients; it is not a second storage authority.
StoredMessage remains a presentation and protocol DTO. It is not being deleted; normal runtime execution simply stops persisting it as an equivalent second ledger.
UI-only notes and WorkHub coordination keep their own legitimate semantic authorities. They are composed with the runtime projection at the transcript read boundary instead of being forced into RuntimeEvent.
What changes
Normal execution writes each ordinary user, assistant, tool, usage, and turn-state fact to the RuntimeEvent authority.
Active overlays and completed transcript pages use the same bounded projection over that authority.
The projection supplies stable item identities and paging cursors across terminalization, reconnect, and restart.
UI-only and WorkHub facts join the transcript at the read boundary.
Direct normal-runtime persistence of equivalent StoredMessage records is removed from AiSdkTurn, ToolRuntime, and AgentRun.
What does not change
StoredMessage remains the client-facing presentation/protocol shape.
SessionEvent remains the live transport shape.
UI-only notes and WorkHub coordination keep their separate authorities.
This issue does not introduce byte-exact provider request replay.
Compatibility and cutover
Supported imported Sessions must follow one forward path: migrate or backfill once, or fail at an explicit compatibility boundary.
Unmarked 0.1.x data does not need to be supported.
Any wire or paging semantic change updates the Runtime Host compatibility epoch.
Transitional import, comparison, or repair code has one direction. Obsolete paths are removed after cutover rather than becoming permanent parallel authorities.
Acceptance criteria
Active overlays and completed transcript pages derive ordinary execution facts from the same RuntimeEvent authority.
Direct normal-runtime persistence of equivalent StoredMessage conversation records is removed.
Paging remains bounded and item identities and cursors remain stable across turn completion, reconnect, and process restart.
Recovery tests prove that supported transcript projections can be rebuilt from durable facts.
Imported Session handling has an explicit one-way migration/backfill or rejection boundary.
Transitional comparison and repair paths are removed after cutover.
Wire or paging semantic changes update the Runtime Host compatibility epoch.
#4779 establishes the provider-history boundary: what model history is replayed, compacted, and summarized for the next provider request.
This issue changes durable transcript storage and paging. It has different failure modes, compatibility concerns, and recovery tests. Folding it into #4779 would make two authority migrations share one review surface without making either safer.
The problem in one picture
Imagine recording the same conversation in two notebooks. While the conversation is happening, we read notebook A. As soon as it finishes, we switch to notebook B.
Even if both notebooks are meant to say the same thing, they are written separately. A crash, retry, or reconnect can catch them at different points.
That is the current transcript architecture:
flowchart LR subgraph Today["Today: one conversation, two ledgers"] direction TB Run1["Runtime execution"] --> Events1["RuntimeEvent"] Run1 --> Messages1["StoredMessage"] Events1 --> Active["Active transcript"] Messages1 --> Completed["Completed pages"] end subgraph Target["Target: one ledger, many views"] direction TB Run2["Runtime execution"] --> Events2["RuntimeEvent"] Events2 --> Projection["Bounded transcript projection"] Notes["UI notes"] --> Projection WorkHub["WorkHub facts"] --> Projection Projection --> View["StoredMessage view"] endWhat happens today
Ordinary runtime conversation facts are persisted through two paths:
RuntimeEventrecords the execution timeline.AiSdkTurn,ToolRuntime, andAgentRunalso persist equivalentStoredMessageconversation records.Those writes do not share one commit order. The read path then switches authority at the turn boundary:
RuntimeEvent;StoredMessagerecords.The same conversation can therefore be reconstructed from different durable representations before and after completion. Recovery, reconnect, pagination, and migration all depend on those representations remaining equivalent even when their writes settle in different orders.
The architectural rule
RuntimeEventis the single durable semantic authority for ordinary Session execution facts.Everything else has one clear role:
RuntimeEventtimeline. A page must not require loading the full Session.SessionEventremains live transport for active clients; it is not a second storage authority.StoredMessageremains a presentation and protocol DTO. It is not being deleted; normal runtime execution simply stops persisting it as an equivalent second ledger.RuntimeEvent.What changes
RuntimeEventauthority.StoredMessagerecords is removed fromAiSdkTurn,ToolRuntime, andAgentRun.What does not change
StoredMessageremains the client-facing presentation/protocol shape.SessionEventremains the live transport shape.Compatibility and cutover
Acceptance criteria
RuntimeEventauthority.StoredMessageconversation records is removed.Why this is separate from #4779
#4779 establishes the provider-history boundary: what model history is replayed, compacted, and summarized for the next provider request.
This issue changes durable transcript storage and paging. It has different failure modes, compatibility concerns, and recovery tests. Folding it into #4779 would make two authority migrations share one review surface without making either safer.
Out of scope
StoredMessageas a presentation/protocol type.RuntimeEvent.