The Ledger · No. 002 Engineering
Engineering09 Jun 2026·3 min read

The permission that disappears every time you rebuild.

macOS showed a ticked box for Screen Recording. The tick belonged to a binary that no longer existed, and the app it named could not capture a thing.

The WorkTrack HQ teamDesktop engineering
Two antique iron keys resting on a sheet of handwritten paper.
Photo: Ylanite Koppens / Pexels

For weeks, the sequence went like this. Grant Screen Recording. Verify it works. Change one line of Rust. Rebuild. Screenshots come back as the desktop wallpaper — no windows, no content, nothing. Open System Settings to check, and there is our app, listed, with the toggle firmly on.

The setting was true. The app it referred to was gone.

§ 01What a TCC grant is attached to

macOS does not grant Screen Recording to "an app" in the way the Settings pane implies. It grants it to a code signing identity, and specifically to whatever that identity's designated requirement resolves to. You can read yours:

codesign -d -r- "/Applications/Your App.app"

For a properly signed application, the requirement is roughly this bundle identifier, signed by this certificate. Both halves are stable across rebuilds, which is why granting Screen Recording to a normal Mac app is a thing you do once.

Ours was ad-hoc signed. In that world there is no certificate and no team, so there is nothing stable for TCC to bind to — and rather than refuse, it falls back to the only identity available: the binary's cdhash. A content hash. Of the executable.

Change one byte of code and you have a different application, as far as the permission database is concerned. Every single rebuild silently revoked the grant.

Nothing was broken. Everything was working exactly as specified. The specification was that our app was a new app four times an hour.

§ 02Why it looked like a bug in our capture code

The stale row in System Settings is what cost us the most time, and it is worth understanding why it is there rather than treating it as a lie.

The pane lists what the permission database contains. The database contained a grant, keyed to a hash of a binary that had since been overwritten. Nothing in that record says "this refers to a file that no longer exists" — it is just a key that will now never match again. So Settings correctly displays a grant that can never apply to anything, and there is no state in the UI for that.

The tell is one command:

codesign -dv "/Applications/Your App.app"

If you see Signature=adhoc and TeamIdentifier=not set, stop debugging your capture code. It is not your capture code. Two lines of output would have saved us most of a week, which is exactly why they are now the first step in our own runbook: if a permission you know you granted says "Needs attention", check the signature before you check anything else.

§ 03The fix, and the thing the fix does not fix

The fix is to sign with a real Developer ID certificate. The designated requirement becomes identifier plus certificate, contains no hash of anything, and grants survive rebuilds the way they do for every other app on the machine. We put the signing identity in the base Tauri config rather than the release-only path, so every build carries it — a debug build with no identity is precisely how this comes back.

Then the second act. A signed app is not a distributable app:

spctl -a -t exec -vv "/Applications/Your App.app"
# rejected
# source=Unnotarized Developer ID

Locally built copies run fine, because a file you produced yourself never picked up the quarantine flag that triggers the check. A copy somebody downloads carries that flag and gets stopped. So the machine where you do all your testing is the one machine in the world that cannot tell you whether your app will open for anybody else.

§ 04What we actually learned

Not "sign your app", which everybody already knows and which is on every checklist. The lesson is about a specific shape of bug: the system was reporting the state of a record, and we read it as the state of the world.

The permission row existed. The permission was real. It simply pointed at something that had ceased to exist, and no layer of the stack considered that worth mentioning — not the Settings pane, not the capture API, which returned a perfectly valid image of a desktop with no windows in it.

We have hit the same shape twice more since, in unrelated code, and both times we found it faster for having named it. When a system tells you a thing is true, it is worth asking what object that truth is attached to, and whether you are still holding the same one.

The WorkTrack HQ teamDesktop engineering

Questions, corrections, or a war story of your own? Write to hello@worktrackhq.com — a person reads every message.