Skip to content

fix(runtime-host): preserve durable RuntimeEvent order in branch and revision copies #4103

Description

@Colafornia

What happened

Editing and resending an earlier message can fail with persistence_failed even when the source Session is valid.

The failure requires two conditions:

  1. The copied history contains a history-compaction checkpoint.
  2. RuntimeEvents appear in a different order when sorted by timestamp than when appended to durable storage.

Parallel tool responses can create this condition. For example, storage can append A before B while their timestamps place B before A.

The checkpoint digest represents A, B. The copy path validates it against B, A and returns source_hash_mismatch. Runtime Host then rolls back the target Session and reports persistence_failed.

The source Session is not damaged, but edit-and-resend cannot complete. Branch copies use the same idle copy path and can fail for the same reason. Once a Session contains this ordering condition, the failure is deterministic.

Expected behavior: A valid Session should copy successfully regardless of timestamp ordering. Integrity checks should use the durable RuntimeEvent order.

How to reproduce

Use a deterministic storage fixture:

  1. Create a Session with two compactable RuntimeEvents, A and B.
  2. Append them in durable order A, B.
  3. Set A.ts = 101 and B.ts = 100.
  4. Create a history-compaction checkpoint whose covered prefix is A, B.
  5. Create a branch or revision that includes the checkpoint.
  6. Observe that the copy fails with persistence_failed.
Durable order:    A(ts=101) -> B(ts=100)
Read-model order: B(ts=100) -> A(ts=101)
Checkpoint input: digest(A, B)
Copy input:       digest(B, A)

Environment

  • Maka incident commit: 19dcb223e
  • Affected path rechecked at: 24a025e90
  • OS: macOS 26.3.1, arm64
  • Surface: Desktop / Runtime Host
  • Electron: 43.4.1
  • Node.js: v24.12.0

Logs, screenshots, or additional context

Error occurred in handler for 'sessions:reviseBeforeTurn':
RuntimeHostOperationError: Session conversation copy could not be committed
  operation: 'session.revision.create'
  code: 'persistence_failed'

Root cause

HostSessionRevisionCoordinator obtains the copy source from SessionManager.readConversationCopySnapshot().

That snapshot comes from RuntimeReadModel.getSessionView(). The read model sorts events by:

  1. event.ts
  2. run position
  3. event position
  4. event ID

This order is suitable for presentation, but it is not the durable ledger order.

The coordinator passes source.events to prepareConversationRuntimeLedgerCopy(). Checkpoint cloning later computes an order-sensitive digest from those events. It therefore treats presentation order as durable authority order.

The persistence layer already exposes the correct authority through readSessionRuntimeEventEntries(), which reads runtime_session_event_ordinals in ordinal order.

The defect is at the copy boundary: checkpoint validation consumes a presentation projection where it requires durable ledger order.

Proposed fix

For idle branch and revision copies:

  1. Read RuntimeEvents through readSessionRuntimeEventEntries().
  2. Filter the ordinal-ordered entries to the inline runs from the source view before preparing the copy plan.
  3. Pass the filtered events as sourceEvents.
  4. Continue to use RuntimeReadModel for messages, turns, and UI presentation.
  5. Keep checkpoint digest validation strict.

Behavior and scope

The intended behavior change is limited to RuntimeEvent ordering inside branch and revision copies. Their target ledgers will preserve source durable order instead of timestamp order.

The following behavior should not change:

  • Which messages, turns, and runs are copied.
  • RuntimeReadModel presentation ordering.
  • Checkpoint content validation.
  • Active side-conversation copies.

Active side conversations remain on the current projection path because they can copy while a Turn is running. Durable ordinal entries do not include mutable in-flight presentation state, so changing that path requires a separate review.

The durable-event filter must preserve the source view's inline-run boundary. It must not add non-inline child-agent runs. Top-level continuation runs can still be inline and must remain included.

Error diagnostics are outside this issue. #4006 tracks preserving and surfacing the underlying copy failure.

Acceptance invariants

  • Branch and revision copies validate checkpoints against durable RuntimeEvent order.
  • Timestamp ordering cannot cause a valid checkpoint to fail validation.
  • The target ledger preserves the copied durable order.
  • A regenerated checkpoint digest matches its target event prefix.
  • Changed event content still causes checkpoint validation to fail closed.
  • The copied message, Turn, and run sets remain unchanged.
  • RuntimeReadModel presentation ordering remains unchanged.
  • Active side-conversation behavior remains unchanged.

AI use

I used OpenAI Codex to diagnose the failure, inspect the affected call paths, and prepare this report. I reviewed and approved the issue text.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions