From c5b7846d7c8a8a681ee844d7f35d6623ecc3ddef Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Sun, 5 Jul 2026 04:30:11 -0700 Subject: [PATCH] Session Sync Repair Nucleic-Session: 0C7BC346-0002-4533-ADDD-3B4C92E58527 Co-authored-by: Nucleic --- NucleicRemote/NucleicRemote/Models/HostConnection.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/NucleicRemote/NucleicRemote/Models/HostConnection.swift b/NucleicRemote/NucleicRemote/Models/HostConnection.swift index 2d20037..0dba1bd 100644 --- a/NucleicRemote/NucleicRemote/Models/HostConnection.swift +++ b/NucleicRemote/NucleicRemote/Models/HostConnection.swift @@ -476,12 +476,17 @@ final class HostConnection { callbacks.didUpdate() case .snapshot(let snapshot): guard snapshot.summary.sessionID == openSessionID else { break } - seenSeq = Set(snapshot.recentEvents.map(\.seq)) + // A snapshot may be a fresh open (tail window) or a warm-resubscribe delta; either way + // union its seqs into the dedup set and advance the cursor. RemoteStore merges the events + // into the transcript rather than replacing, so an existing transcript isn't truncated. + seenSeq.formUnion(snapshot.recentEvents.map(\.seq)) + if let maxSeq = snapshot.recentEvents.map(\.seq).max() { openMaxSeq = max(openMaxSeq ?? 0, maxSeq) } callbacks.openSnapshot(snapshot) case .events(let batch): guard batch.sessionID == openSessionID else { break } let fresh = batch.events.filter { !seenSeq.contains($0.seq) } for e in fresh { seenSeq.insert(e.seq) } + if let maxSeq = batch.events.map(\.seq).max() { openMaxSeq = max(openMaxSeq ?? 0, maxSeq) } if !fresh.isEmpty { callbacks.openEvents(EventBatch(sessionID: batch.sessionID, events: fresh)) } case .approvalRequested(let req): let title = sessions.first { $0.sessionID == req.sessionID }?.title ?? "Approval"