* test: require viewport-bounded Vault rows * fix: keep Vault rendering and scans off main thread * fix: let the Vault table fill the sidebar viewport * fix: close Vault CI and review gaps * fix: preserve bounded Antigravity history paging * fix: defer Vault table mutations past layout * fix: close final Vault review feedback * fix: preserve bounded Antigravity history access * test: cover Vault paging review regressions * fix: bound Vault history paging work * fix: keep Antigravity history single-root * test: cover Vault byte and viewport boundaries * fix: preserve Vault boundaries during paging * chore: leave legacy XCTest suite untouched * docs: clarify Vault JSONL paging offsets
36 lines
1.1 KiB
Swift
36 lines
1.1 KiB
Swift
import Foundation
|
|
|
|
/// Defers and coalesces Vault table mutations past the originating layout callback.
|
|
@MainActor
|
|
final class SessionIndexTableMutationScheduler {
|
|
private var pendingApply: SessionIndexTableApplyInput?
|
|
private var isFlushScheduled = false
|
|
private let applyFlush: @MainActor (SessionIndexTableApplyInput) -> Void
|
|
|
|
init(applyFlush: @escaping @MainActor (SessionIndexTableApplyInput) -> Void) {
|
|
self.applyFlush = applyFlush
|
|
}
|
|
|
|
func stageApply(_ input: SessionIndexTableApplyInput) {
|
|
pendingApply = input
|
|
guard !isFlushScheduled else { return }
|
|
isFlushScheduled = true
|
|
RunLoop.main.perform(inModes: [.common]) { [weak self] in
|
|
// RunLoop guarantees main-thread delivery, but Foundation does
|
|
// not annotate this callback with MainActor.
|
|
MainActor.assumeIsolated {
|
|
self?.flushPendingApply()
|
|
}
|
|
}
|
|
}
|
|
|
|
private func flushPendingApply() {
|
|
let input = pendingApply
|
|
pendingApply = nil
|
|
isFlushScheduled = false
|
|
if let input {
|
|
applyFlush(input)
|
|
}
|
|
}
|
|
}
|