Transcript Incremental Projection

Nucleic-Session: 0FFD007B-0696-4517-9429-129C7B0FD5AC
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-06 19:43:58 -07:00
co-authored by Nucleic
parent 2f8fa2d52f
commit 5cb7e6659f
@@ -692,6 +692,39 @@ final class HostConnection {
send(.fetchTranscript(TranscriptFetch(requestID: requestID, sessionID: sessionID, afterSeq: 0)))
}
/// Whether a background transcript prefetch can start now: live, the host can serve
/// transcript fetches, and no prefetch is already in flight (they run one at a time).
var canPrefetchTranscript: Bool {
connectivity.isLive && capabilities.canSyncTranscripts && client != nil && prefetchRequestID == nil
}
/// Fetch a session's transcript in the background — no subscribe, no open — so the offline
/// cache is warm before the user ever opens the session. `afterSeq` bounds the pull to what
/// the cache is missing. The result (all chunks, merged) arrives via
/// `callbacks.transcriptPrefetched`; returns false when it can't start (caller retries on a
/// later session-list update).
@discardableResult
func prefetchTranscript(_ sessionID: SessionID, afterSeq: UInt64) -> Bool {
guard canPrefetchTranscript else { return false }
let requestID = UUID().uuidString
prefetchRequestID = requestID
prefetchSessionID = sessionID
prefetchEvents = []
send(.fetchTranscript(TranscriptFetch(requestID: requestID, sessionID: sessionID, afterSeq: afterSeq)))
return true
}
/// Settle the in-flight prefetch: hand what arrived to RemoteStore (nothing on
/// unavailable/disconnect) and clear the slot so the next queued prefetch can start.
private func finishPrefetch(delivering: Bool) {
guard let sessionID = prefetchSessionID else { return }
let events = delivering ? prefetchEvents : []
prefetchRequestID = nil
prefetchSessionID = nil
prefetchEvents = []
callbacks.transcriptPrefetched(sessionID, events)
}
/// The device's network path changed (Wi-Fi ⇄ cellular, joined/left a network). React now rather
/// than waiting for a zombie LAN socket to time out or the reconnect backoff to elapse — this is
/// what makes the transport switch feel immediate. Only reconnect-managed hosts (a pinned host)