Two related defects in the mid-session TCC lifecycle:
Wrong notification observed. The watcher listens for AVCaptureSessionRuntimeError instead of AVCaptureSessionWasInterrupted. When the user toggles camera access off mid-session, WasInterrupted fires (not RuntimeError), so the revoke event is missed silently — the camera session keeps thinking it's healthy.
becameAuthorized() has no production callsite. The re-grant path exists in code but never fires in production, so a user who denies + later grants access mid-session never recovers.
Switch the watcher to observe AVCaptureSessionWasInterrupted. Check the interruption reason; surface .cameraRevoked banner on .videoDeviceNotAvailableInBackground / authorization-related reasons.
Wire becameAuthorized() to fire on AVCaptureDevice.requestAccess(for: .video) completion when status flips from .denied to .authorized. Hook the TCC change observer too (macOS doesn't publish a direct authorization-change notification — likely needs to be polled from the audio-graph mic-regrant pattern that's already proven).
## Summary
Two related defects in the mid-session TCC lifecycle:
1. **Wrong notification observed.** The watcher listens for `AVCaptureSessionRuntimeError` instead of `AVCaptureSessionWasInterrupted`. When the user toggles camera access off mid-session, `WasInterrupted` fires (not `RuntimeError`), so the revoke event is missed silently — the camera session keeps thinking it's healthy.
2. **`becameAuthorized()` has no production callsite.** The re-grant path exists in code but never fires in production, so a user who denies + later grants access mid-session never recovers.
## Evidence
- Audit `.planning/audit-2026-05-12/vision-audit.md` (2026-05-12) — exact file:line pending, agent flagged the pair.
## Recommended fix
1. Switch the watcher to observe `AVCaptureSessionWasInterrupted`. Check the interruption reason; surface `.cameraRevoked` banner on `.videoDeviceNotAvailableInBackground` / authorization-related reasons.
2. Wire `becameAuthorized()` to fire on `AVCaptureDevice.requestAccess(for: .video)` completion when status flips from `.denied` to `.authorized`. Hook the TCC change observer too (macOS doesn't publish a direct authorization-change notification — likely needs to be polled from the audio-graph mic-regrant pattern that's already proven).
## Source
Audit `.planning/audit-2026-05-12/vision-audit.md` (2026-05-12)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Two related defects in the mid-session TCC lifecycle:
Wrong notification observed. The watcher listens for
AVCaptureSessionRuntimeErrorinstead ofAVCaptureSessionWasInterrupted. When the user toggles camera access off mid-session,WasInterruptedfires (notRuntimeError), so the revoke event is missed silently — the camera session keeps thinking it's healthy.becameAuthorized()has no production callsite. The re-grant path exists in code but never fires in production, so a user who denies + later grants access mid-session never recovers.Evidence
.planning/audit-2026-05-12/vision-audit.md(2026-05-12) — exact file:line pending, agent flagged the pair.Recommended fix
AVCaptureSessionWasInterrupted. Check the interruption reason; surface.cameraRevokedbanner on.videoDeviceNotAvailableInBackground/ authorization-related reasons.becameAuthorized()to fire onAVCaptureDevice.requestAccess(for: .video)completion when status flips from.deniedto.authorized. Hook the TCC change observer too (macOS doesn't publish a direct authorization-change notification — likely needs to be polled from the audio-graph mic-regrant pattern that's already proven).Source
Audit
.planning/audit-2026-05-12/vision-audit.md(2026-05-12)