From 2f084a7d1847f78172fc705149c8543cef7e9193 Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Mon, 6 Jul 2026 18:27:01 -0700 Subject: [PATCH] Transcript Incremental Projection Nucleic-Session: 0FFD007B-0696-4517-9429-129C7B0FD5AC Co-authored-by: Nucleic --- .../Transcript/TranscriptProjection.swift | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/NucleicRemote/NucleicRemote/Views/Transcript/TranscriptProjection.swift b/NucleicRemote/NucleicRemote/Views/Transcript/TranscriptProjection.swift index 2ca4205..bb22f9c 100644 --- a/NucleicRemote/NucleicRemote/Views/Transcript/TranscriptProjection.swift +++ b/NucleicRemote/NucleicRemote/Views/Transcript/TranscriptProjection.swift @@ -183,7 +183,15 @@ enum TranscriptProjection { /// `file_path` is stripped of `worktreeRoot` and normalized so it compares against the note's /// repo-relative paths. A note overlapping no preceding edit is left in place (renders /// standalone), matching the Mac's `foldLockNotes`. - private static func foldLockNotes(_ flat: [TranscriptItem], worktreeRoot: String?) -> [TranscriptItem] { + /// + /// The backward scan continues past the front of `flat` into `priorEdits` — the edits of + /// already-folded earlier segments, oldest first — so a note whose edit was sealed in a prior + /// segment (a lock released turns later) still folds exactly where a whole-stream fold would + /// put it. Those hits are reported via `priorLockPatches` for the caller to attach. + private static func foldLockNotes( + _ flat: [TranscriptItem], worktreeRoot: String?, priorEdits: [PriorEdit], + priorLockPatches: inout [(toolCallID: String, lock: NoteLock)] + ) -> [TranscriptItem] { // Each tool item's repo-relative edited paths (only edit-class tools have any), by index. var editsByIndex: [Int: (id: String, paths: [String])] = [:] for (i, item) in flat.enumerated() { @@ -193,7 +201,8 @@ enum TranscriptProjection { .filter { !$0.isEmpty } if !paths.isEmpty { editsByIndex[i] = (group.toolCallID, paths) } } - guard !editsByIndex.isEmpty else { return flat } + guard !editsByIndex.isEmpty || !priorEdits.isEmpty else { return flat } + let priorIDs = Set(priorEdits.map(\.toolCallID)) var locksByCall: [String: [NoteLock]] = [:] var folded = Set() @@ -212,13 +221,26 @@ enum TranscriptProjection { guard let edit = editsByIndex[j] else { continue } if edit.paths.contains(where: { pathsOverlap($0, path) }) { hitID = edit.id; break } } + if hitID == nil { + // Nothing in this segment — keep scanning backward across the seam, newest + // prior edit first, exactly where a whole-stream scan would look next. + for prior in priorEdits.reversed() + where prior.paths.contains(where: { pathsOverlap($0, path) }) { + hitID = prior.toolCallID + break + } + } guard let hitID else { matchedAll = false; break } if let k = indexByID[hitID] { perCard[k].paths.append(path) } else { indexByID[hitID] = perCard.count; perCard.append((hitID, [path])) } } guard matchedAll, !perCard.isEmpty else { continue } for card in perCard { - locksByCall[card.id, default: []].append(NoteLock(state: lock.state, paths: card.paths)) + if priorIDs.contains(card.id) { + priorLockPatches.append((card.id, NoteLock(state: lock.state, paths: card.paths))) + } else { + locksByCall[card.id, default: []].append(NoteLock(state: lock.state, paths: card.paths)) + } } folded.insert(i) }