feat(recording): throttle screenshot capture while idle (fixes #286)#311
Open
praxstack wants to merge 2 commits into
Open
feat(recording): throttle screenshot capture while idle (fixes #286)#311praxstack wants to merge 2 commits into
praxstack wants to merge 2 commits into
Conversation
…Liu#286) After 2 minutes without keyboard/mouse input, reduce screenshot capture from the default 10s cadence to 30s — cutting idle-period disk writes and JPEG encode/analysis cost by 3x, per issue JerryZLiu#286's request to reduce capture frequency (esp. during inactivity). This throttles rather than pauses: ScreenRecorder's state machine is unchanged (still .capturing throughout), only the capture timer's interval adapts. A hard pause was considered and rejected — it would starve IdleBatchClassifier of the screenshots it needs to produce an "Idle" timeline card, turning idle periods into silent gaps instead. The 30s throttled interval is not an arbitrary choice: idleSecondsAtCapture measures time-since-last-INPUT, not time-since-last-screenshot, so a brief activity blip mid-idle-stretch resets that clock for the next screenshot. Exhaustively verified (IdleCaptureIntervalTests.swift) that 30s is the largest interval where a worst-case blip still can't leave more than IdleBatchClassifier's 30s uncovered-gap limit exposed — a 60s interval, tried first, fails this by nearly 2x and would silently kick affected batches out of idle classification into full LLM processing, defeating the whole point of the throttle. Adds a "Slow down capture when idle" toggle in Settings > Recording privacy (default on). Tests: 19/19 pass (11 pre-existing + 8 new), including a regression test that reproduces IdleBatchClassifier's real coverage-gap math and fails against the original (incorrect) 60s value.
Follow-up hardening pass. The original PR's tests covered the pure interval math (IdleCaptureInterval) but not the persistence/UI surfaces. Adds 5 tests: - defaults-to-enabled when unset (feature ships on; a fresh install must throttle) - persist-disabled + re-read, and re-enable round-trip - disabled-preference contract the recorder's effectiveScreenshotInterval gate relies on - RecordingPrivacySettingsViewModel reflects the persisted value at init and writes through on toggle change All pass; full DayflowTests suite green; no production code changed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fixes #286
what
after 2 minutes without keyboard/mouse input, screenshot capture slows from the default 10s cadence to 30s — cutting idle-period disk writes and analysis cost by ~3x. adds a "Slow down capture when idle" toggle in Settings > Recording privacy (default on).
why throttle, not pause
a hard pause was my first instinct but it's wrong:
IdleBatchClassifierneeds screenshots with idle readings actually present to produce an "Idle" timeline card (95% coverage, no gap >30s). stop capturing entirely and idle periods become a silent gap instead of an Idle card — worse than today.why 30s, not something bigger
idleSecondsAtCaptureis seconds-since-last-input, not seconds-since-last-screenshot. a brief activity blip mid-idle-stretch (checking your phone, a stray mouse jiggle) resets that clock for the next screenshot, so the worst case leaves(throttle_interval - 1)seconds of the previous gap uncovered. at 60s (what I tried first) that's up to 59s — nearly doubleIdleBatchClassifier's 30s limit, silently kicking the whole batch out of idle classification into full LLM processing. 30s is the largest value where the worst case (29s) still stays under the limit — verified exhaustively across every blip timing, not just spot-checked.IdleCaptureIntervalTests.testWorstCaseBlipDuringIdleStaysWithinClassifierGapLimitreproducesIdleBatchClassifier's actual coverage math and fails against the original 60s value (confirmed by testing it before fixing it).tests
19/19 pass (11 pre-existing, 8 new).
verification gap (being upfront)
I did not launch the built app to visually confirm the new Settings toggle renders — the real
/Applications/Dayflow.appwas already running on this machine and I didn't want a second instance conflicting on the shared database/UserDefaults. The#Previewblock for the modified view builds and links cleanly (__preview.dylibcompiles with no errors), which confirms the code is well-formed, but I haven't rendered it interactively. Happy to follow up with a screenshot if useful.Follow-up hardening pass (2026-07-08)
Added 5 tests (no production code change) covering surfaces the original tests left out: IdleCapturePreferences default-on + persist/re-read round-trip, the disabled-preference gate the recorder relies on, and RecordingPrivacySettingsViewModel reflecting the persisted value at init + writing through on toggle. Full DayflowTests suite green.