"You granted Accessibility to an app yesterday. Today macOS asks again. Nothing is broken — you shipped a different app."
Every Binary Is Signed, Whether You Asked or Not
On Apple silicon, native code must carry a code signature to run at all. If you never mention signing, the linker signs your binary anyway — an ad-hoc signature with no certificate behind it. Run codesign -dv on a fresh swift build product and you will see Signature=adhoc. The program runs. Everything looks fine.
The trap is what an ad-hoc signature is worth as an identity. A signature carries a designated requirement: the rule a future copy of the code must satisfy to count as "the same app". For ad-hoc code that rule is a hash of the exact bytes — cdhash H"e3e8…". Rebuild, and the bytes change, the hash changes, and the requirement names a program that no longer exists.
Who Uses That Requirement
- TCC — the privacy system behind Accessibility, Microphone, Screen Recording, Input Monitoring, Calendars. A grant is stored against the app's code requirement.
- The Keychain — an item's access list trusts the requirement of the app that created it.
- Gatekeeper and notarization — whether a downloaded app may open at all.
- Launch constraints, App Groups, provisioning on iOS — all keyed to a signing identity and a team.
So an ad-hoc menu-bar utility that needs Accessibility behaves like this: you grant it, it works, you rebuild, and macOS treats the new build as a stranger. A family dictation app re-prompted for Accessibility on every single rebuild until it was signed with a stable certificate. After that, one grant lasted forever.
Three Shapes of Requirement
| Signed with | Designated requirement looks like | Survives a rebuild? |
|---|---|---|
| Nothing (linker ad-hoc) | cdhash H"…" | No |
| A self-signed certificate | identifier "com.example.spark" and certificate leaf = H"…" | Yes, on every Mac that signs with that same certificate |
| An Apple-issued certificate | identifier "com.example.spark" and anchor apple generic and … certificate leaf[subject.OU] = EXAMPLE_TEAM | Yes, for that team |
The identifier plus a certificate is what makes an app itself across builds. Track 6 goes all the way down: the self-signed identity this family uses on the Mac, how TCC stores its three states, why a stable requirement still does not prove a grant exists, and the roads (hardened runtime, notarization, sandbox) the family deliberately does not take.