PendingChangeStore.refresh() is @MainActor and does Data(contentsOf:), JSONDecoder.decode, and ActionValidator.validate inline for every file it examines. With maxPendingFilesScanned = 200 and maxPendingFileBytes = 1 MB, a single pass can read and parse up to 200 MB on the main thread, and the watcher's 0.25s debounce can re-arm it continuously while a writer keeps touching the directory.
Proposal: move read, decode, and validate to a background queue and hop back to the main actor with the results. The design call is which knownActions snapshot the background validation runs against; approve-time re-validation already guards correctness, so the scan-time verdict is advisory.
Also: the comment on refresh() still says "cheap enough to run on every filesystem event: the cap is 50 small files", which no longer matches the caps in the code.
PendingChangeStore.refresh()is@MainActorand doesData(contentsOf:),JSONDecoder.decode, andActionValidator.validateinline for every file it examines. WithmaxPendingFilesScanned = 200andmaxPendingFileBytes = 1 MB, a single pass can read and parse up to 200 MB on the main thread, and the watcher's 0.25s debounce can re-arm it continuously while a writer keeps touching the directory.Proposal: move read, decode, and validate to a background queue and hop back to the main actor with the results. The design call is which
knownActionssnapshot the background validation runs against; approve-time re-validation already guards correctness, so the scan-time verdict is advisory.Also: the comment on
refresh()still says "cheap enough to run on every filesystem event: the cap is 50 small files", which no longer matches the caps in the code.