fix(recording): recover capture after dark wake#329
Open
serg-shcherbak wants to merge 2 commits into
Open
Conversation
pagarsky
reviewed
Jul 22, 2026
- reject stale setup completions with a startup generation guard - keep display intent changes inside the guarded recorder queue commit - cover an old pre-sleep setup completing after a post-wake restart
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.
Summary
Dayflow could remain running in the menu bar and report recording as active while silently producing no screenshots after a macOS dark-wake cycle. This change makes recorder startup contingent on an actual ScreenCaptureKit display and adds a bounded, cancellable recovery path for wake-related failures.
Problem
This failure was observed on Dayflow v2.0.3 installed from the release DMG.
The Dayflow process remained alive, and macOS screen-recording permission remained granted, but screenshot files stopped appearing after the Mac entered clamshell sleep. Opening the application later coincided with a display-change event that allowed capture to recover.
System logs and the recording timeline showed the following sequence:
NSWorkspace.didWakeNotificationscheduled recorder startup after a five-second delay..capturingwithcachedDisplay == nil..paused; the recorder incorrectly claimed to be.capturing.This left Dayflow alive but unable to record until a later screen-configuration event refreshed the display.
Root cause
The recorder state machine treated “the capture timer is running” as equivalent to “screen capture is healthy.”
That assumption was invalid when ScreenCaptureKit temporarily returned no matching display during dark wake. The recorder could enter
.capturingwithout a usableSCDisplay, and there was no successful-capture timestamp or other health signal that could expose the stale state.Delayed wake callbacks also had no cancellation mechanism. A resume scheduled by an earlier wake could still run after the system returned to sleep.
Solution
The recorder now enforces a stronger invariant:
.capturingis entered only after a realSCDisplayhas been resolved and committed on the recorder's serial queue.The recovery flow now:
lastSuccessfulCaptureAtafter both normal and privacy-redacted screenshots;The asynchronous ScreenCaptureKit result is committed only after the recorder rechecks that it is still in
.starting. A late result arriving after sleep or stop therefore cannot repopulate stale display state.Compatibility and risk
The normal screenshot path is unchanged:
The existing preferred-display behavior is preserved: when the requested external display is temporarily absent, Dayflow waits for that display rather than silently capturing another screen.
The main behavioral change is limited to recorder startup and recovery after sleep, wake, lock, screensaver, permission loss, or temporary display unavailability.
Related: #308
Tests added
RecorderRecoveryPolicyTestscovers:Validation performed
The following checks passed without fetching dependencies:
swiftc -frontend -parseforScreenRecorder.swift,RecorderRecoveryPolicy.swift, andRecorderRecoveryPolicyTests.swift;swiftc -typecheckforRecorderRecoveryPolicy.swift;git diff --check;Validation not performed
A real Dayflow application build was not performed.
Specifically:
xcodebuildwas not run;The local environment was intentionally limited to checks that did not require resolving or downloading the Xcode project dependencies. CI and a maintainer build should therefore confirm full compilation and execute the XCTest target before merge.
Suggested manual verification