"CMD+K stopped prompting. Opening Settings still prompted every single time."
Where Secrets Go on a Mac
An app that holds a durable secret — the family's apps keep a PIN for reaching their engine at home — stores it in the Keychain with the Security framework's SecItem API, never in a file or UserDefaults. On the Mac there are two keychains to know about. The login keychain (file-based) protects each item with an access control list that trusts particular applications by their code requirement. The data protection keychain (kSecUseDataProtectionKeychain) behaves like iOS and scopes access by keychain-access-group entitlements — so an unsigned or entitlement-less binary gets -34018 (errSecMissingEntitlement) instead of an item.
The Prompt That Survived Re-Signing
A family editor was moved from ad-hoc signing to the stable self-signed identity so its Keychain reads would stop prompting. One path went quiet; another — the Settings tab that re-read the PIN every time it opened — kept prompting on every read. The requirement was verified stable. The code was fine.
The items themselves were the problem. They had been created by the old ad-hoc build, so their access lists trusted a code requirement that no longer existed. To those items, the newly signed app was a different app, forever. The fast path looked fixed only because it cached a session token in memory and stopped reading the Keychain after the first unlock. The deterministic fix, with no "Always Allow" clicking: delete every item for the service and let the signed app save fresh ones, which it then owns and reads silently.
That deletion must happen on each Mac's own console session. From ssh, the login keychain answers "User interaction is not allowed": the remote session sits outside the GUI login, so the keychain cannot show its access prompt there, and unlocking it from ssh means handing the account password to a script. That is also why signing fails over ssh in the next track.
Missing, Locked, and Unavailable Are Three Answers
A keychain read that treats every failure as "no PIN saved" turns a locked keychain into a first-run experience, and a missing entitlement into a silent reset. The family's shared secret store returns three distinct outcomes, and callers show different things for each: missing asks the user to enter the PIN, locked says the keychain is locked (or the session cannot show UI), unavailable names the status code.