Skip to content

Explain and recover from a quarantined ScreenCaptureKit gate #16

Closed

Description

@iamnbutler

Found in the Ace desktop tools study (githubnext/ace#427), D3c on Canary 0.0.46+684262d, 2026-10-15 at about 14:55 EDT.

Observed: in the middle of a run, after a desktop_menu File → New, every desktop_inspect failed with DESKTOP_ERROR: Capture failed: ScreenCaptureKit is quarantined after an abandoned SCShareableContent.fetchWindowForWindowID call. desktop_apps timed out against its 1.00 s observation budget, and another call returned The operation couldn't be completed. Operation timed out. The agent stopped safely and typed nothing. A few minutes later, inspect worked again through the CGWindowList engine (capture.window 770 ms), and apps took 955 ms, close to its 1 s budget.

Likely cause: Peekaboo coordinates ScreenCaptureKit across processes with a per-user lock at $TMPDIR/boo.peekaboo.sckit-capture.lock (ScreenCaptureKitCaptureGate). At the same time, a separate process on the Mac was running Peekaboo's AutomationKit tests (the patch test run for the pin bump), which do real captures. Any two Peekaboo users on one Mac share that gate and can starve or quarantine each other: Ace dev and Canary, Ace and a Peekaboo CLI, or tests.

Asks:

  • The refusal should say the problem is temporary and caused by another capture, and give a wait-and-retry hint. Today it reads like a broken desktop.
  • When ScreenCaptureKit is quarantined, inspection should fall back to the CGWindowList capture it already uses afterwards, rather than failing.
  • Consider giving the gate a host-specific lock, or one keyed to the host's identity, so separate embedding apps don't block each other. Possibly upstream.
  • The 1 s apps inventory budget leaves no headroom when the Mac is loaded (955 ms when healthy).

Activity

  1. iamnbutler commented on Oct 15, 2026

    @iamnbutler
    ContributorAuthor

    More evidence from the githubnext/ace#427 study: Peekaboo's own test runs on the same Mac block Ace's live desktop tools, not just screen capture.

    • While a swiftpm-testing-helper run of the bridge tests was in progress (most use stubbed services), it held ~/.peekaboo/global.turnstile.lock. An Ace Canary desktop call (desktop_apps) then failed with internalError: Timed out waiting for the desktop operation lane lock at ~/.peekaboo/global.turnstile.lock.
    • In the same window, an Ace agent's screenshot failed with "ScreenCaptureKit is quarantined after an abandoned SCShareableContent.fetchWindowForWindowID call".

    Both locks are per-user and shared by every Peekaboo user (tests, dev builds, Ace's signed runtime), so anyone developing desktop-tools on their own machine disables Ace's desktop tools while their tests run.

    Suggestion: namespace the turnstile and SCK gate per runtime or app (for example under Ace's state dir, or keyed by the host bundle ID), and have tests use a temporary lock root.

  2. iamnbutler commented on Oct 17, 2026

    @iamnbutler
    ContributorAuthor

    Triage against main (after 0.8.0).

    Covered on main:

    Declined by design (reasons in #63 and #58, and in native/patches/README.md):

    • No CGWindowList fallback. Every other capture path also goes through ScreenCaptureKit, so a fallback would run next to the abandoned call, which upstream rules out.
    • The SCK gate stays per-user and the coordination root (~/.peekaboo) stays shared. Keying them per host would let separate apps overlap ScreenCaptureKit calls and desktop operations again.

    Remaining:

    Recommendation: keep open, waiting only on the live check, which #42 already lists. If the test lock root is still wanted, open it as a separate issue.

  3. iamnbutler commented on Oct 17, 2026

    @iamnbutler
    ContributorAuthor

    Closing: the code side is done. #63 makes a new capture wait out the quarantine, explains the refusal and widens the budgets; #58 names whoever holds a lock. The CGWindowList fallback and per-host locks were declined by design, for the reasons in the 07:29 triage above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions