From 9df7142f49856f0b99baf46b162824f8caeafffb Mon Sep 17 00:00:00 2001 From: Alan Wizemann Date: Mon, 4 May 2026 23:33:30 +0200 Subject: [PATCH] =?UTF-8?q?feat(scarfmon):=20A1=20=E2=80=94=20instrument?= =?UTF-8?q?=20iOS=20file-watcher=20polling=20cadence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds three measure points to CitadelServerTransport.watchPaths: - ios.fileWatcher.tick (interval) — full poll cycle latency including the SSH stat round-trips. > 1500ms here is what 'out of sync' feels like — the channel is congested or the host is slow. - ios.fileWatcher.delta (event) — fires only when the signature actually changed. Low delta/tick ratio means we can safely drop the 3-second cadence; high ratio means we'd just burn bandwidth. - ios.fileWatcher.paths (event, bytes=count) — number of paths watched per cycle. Explains slow ticks as the project list grows. Surgical addition; existing 3-second cadence + signature-diff logic unchanged. With Full mode on, a few minutes of usage on LAN will tell us empirically whether the cadence can drop to 1s — the original v2.6.0 user feedback complained 'chat is out of sync' between iOS and Mac on a fast LAN. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ScarfIOS/CitadelServerTransport.swift | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scarf/Packages/ScarfIOS/Sources/ScarfIOS/CitadelServerTransport.swift b/scarf/Packages/ScarfIOS/Sources/ScarfIOS/CitadelServerTransport.swift index 850303d..ea1576c 100644 --- a/scarf/Packages/ScarfIOS/Sources/ScarfIOS/CitadelServerTransport.swift +++ b/scarf/Packages/ScarfIOS/Sources/ScarfIOS/CitadelServerTransport.swift @@ -272,14 +272,32 @@ public final class CitadelServerTransport: ServerTransport, @unchecked Sendable // Polling-based, identical in shape to `SSHTransport`'s remote- // watch fallback: stat each path, yield `.anyChanged` when any // mtime shifts. 3s tick keeps bandwidth low. + // + // ScarfMon — A1 instrumentation: + // - `ios.fileWatcher.tick` (interval) — full poll cycle latency, + // includes the SSH stat round-trips. Pre-fix this is what an + // "out of sync" user is feeling: anything > 1500 ms means + // the channel is congested or the host is slow. + // - `ios.fileWatcher.delta` (event) — fires only when the + // signature actually changed. Low ratio (delta count / tick + // count) means we're polling more aggressively than the + // change rate warrants — opens the door to dropping the 3s + // cadence on LAN. + // - `ios.fileWatcher.paths` (event with bytes=count) — number + // of paths watched per cycle, helps explain a slow tick when + // the project list grows. AsyncStream { continuation in let task = Task.detached { [weak self] in var lastSignature = "" while !Task.isCancelled { guard let self else { break } - let current = await self.buildWatchSignature(for: paths) + ScarfMon.event(.transport, "ios.fileWatcher.paths", count: 1, bytes: paths.count) + let current = await ScarfMon.measureAsync(.transport, "ios.fileWatcher.tick") { + await self.buildWatchSignature(for: paths) + } if !current.isEmpty, current != lastSignature { if !lastSignature.isEmpty { + ScarfMon.event(.transport, "ios.fileWatcher.delta", count: 1) continuation.yield(.anyChanged) } lastSignature = current