Transcript Incremental Projection

Nucleic-Session: 0FFD007B-0696-4517-9429-129C7B0FD5AC
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-06 18:48:30 -07:00
co-authored by Nucleic
parent 1374476d20
commit f381c373e3
@@ -639,20 +639,23 @@ final class RemoteStore: ObservableObject {
guard let self, hostID == self.openSessionHostID, snap.summary.sessionID == self.openSessionID else { return } guard let self, hostID == self.openSessionHostID, snap.summary.sessionID == self.openSessionID else { return }
// Merge, don't replace: a fresh open merges into an empty transcript (the tail window), // Merge, don't replace: a fresh open merges into an empty transcript (the tail window),
// while a reconnect's warm-resubscribe delta appends to the history already on screen // while a reconnect's warm-resubscribe delta appends to the history already on screen
// instead of truncating it to the host's 200-event tail. // instead of truncating it to the host's 200-event tail. Drain the streaming buffer
// first so the seq-dedup merge sees the full stream (a buffered event the snapshot
// also carries would otherwise be re-appended as a duplicate after the merge).
self.drainPendingOpenEvents()
self.openEvents = Self.mergedEvents(self.openEvents, snap.recentEvents) self.openEvents = Self.mergedEvents(self.openEvents, snap.recentEvents)
self.openApprovals = snap.pendingApprovals self.openApprovals = snap.pendingApprovals
self.persistOpenTranscript() self.persistOpenTranscript()
} }
cb.openEvents = { [weak self] batch in cb.openEvents = { [weak self] batch in
guard let self, hostID == self.openSessionHostID, batch.sessionID == self.openSessionID else { return } guard let self, hostID == self.openSessionHostID, batch.sessionID == self.openSessionID else { return }
self.openEvents.append(contentsOf: batch.events) self.enqueueOpenEvents(batch.events)
self.persistOpenTranscript()
} }
cb.openBackfill = { [weak self] batch in cb.openBackfill = { [weak self] batch in
guard let self, hostID == self.openSessionHostID, batch.sessionID == self.openSessionID else { return } guard let self, hostID == self.openSessionHostID, batch.sessionID == self.openSessionID else { return }
// Full-history backfill precedes what's on screen — merge by seq so it slots in above the // Full-history backfill precedes what's on screen — merge by seq so it slots in above the
// tail rather than appending out of order. // tail rather than appending out of order. Drain first (same reason as openSnapshot).
self.drainPendingOpenEvents()
self.openEvents = Self.mergedEvents(self.openEvents, batch.events) self.openEvents = Self.mergedEvents(self.openEvents, batch.events)
self.persistOpenTranscript() self.persistOpenTranscript()
} }