Skip to content

Fix Screen Recording permission cache never downgrading after revocation#29

Merged
execsumo merged 1 commit into
mainfrom
claude/macos-screen-recording-perms-jy1r8c
Jun 12, 2026
Merged

Fix Screen Recording permission cache never downgrading after revocation#29
execsumo merged 1 commit into
mainfrom
claude/macos-screen-recording-perms-jy1r8c

Conversation

@execsumo

Copy link
Copy Markdown
Owner

Summary

The persisted screenCaptureTCCGranted flag seeded the in-process granted state at launch and could never be cleared — so revoking Screen Recording in System Settings while Heard wasn't running left the app showing Granted forever, across restarts.

This replaces the boolean with ScreenCaptureGrantCache, a pure, unit-tested state machine that distinguishes the two cases the old code conflated:

  • Grant confirmed live this session → sticky for the process lifetime, exactly as before. macOS only applies revocations after an app restart, so a mid-session false probe is always stale. (Preserves the v0.2.3 stale-"Not Granted" fix — no regression.)
  • Grant cached from a previous session → trusted only for a ~30 s reconfirmation window after launch (10 poll ticks × 3 s, enough to ride out the window-list probe's transient false negatives). If no probe confirms within the window, the cache and persisted flag are cleared and the UI downgrades to Not Granted. A later successful probe re-confirms and re-persists, so a rare over-eager downgrade self-heals.
  • The authoritative SCShareableContent check after the "Grant…" flow now clears a stale cache immediately on a definitive false, instead of being ignored.

Changes

  • Sources/HeardCore/Services.swift: new ScreenCaptureGrantCache value type; PermissionCenter migrated off the sticky boolean; UserDefaults writes centralized in applyScreenCaptureProbe
  • Tests/HeardTests/PermissionCenterTests.swift: 9 new tests covering revocation-while-not-running, confirmation stickiness, budget exhaustion, recovery after downgrade, and authoritative-probe semantics
  • handoff.md: documented the grant-caching behavior

Testing

https://claude.ai/code/session_01UMbvMVowzQq3LgFpaQA8aE


Generated by Claude Code

The persisted screenCaptureTCCGranted flag seeded the in-process granted
state at launch and could never be cleared, so revoking Screen Recording
in System Settings while Heard wasn't running left the app showing
Granted forever.

Replace the boolean with ScreenCaptureGrantCache, a pure state machine:
a grant cached from a previous session is trusted only for a ~30 s
reconfirmation window after launch (10 poll probes), then cleared if
probes keep failing. A grant confirmed live within a session remains
sticky for the process lifetime, and the authoritative SCShareableContent
check after the Grant… flow now clears a stale cache immediately on a
definitive false.

https://claude.ai/code/session_01UMbvMVowzQq3LgFpaQA8aE
@execsumo execsumo merged commit 35e4649 into main Jun 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants