src/preferences/PreferencesPersistenceProbeSpecs.md
PreferencesPersistenceProbe is the pure decision layer behind the launch-time warning that fires when
macOS isn't persisting AltTab's preferences to disk (issue #5790). It takes a list of SuiteFacts (the
filesystem state of each UserDefaults suite's backing plist, gathered by the PreferencesPersistenceCheck
shell) and returns a Verdict: .ok, or .broken naming the offending plist paths. It holds no state and
touches no filesystem — same split as WsEventRouting / DragAndDropResolver.
AltTab writes prefs through cfprefsd, which caches in memory and defers the disk flush. That makes an
in-process "write a value, read it back" probe useless: the read hits the cache and looks fine even when the
value never reaches disk. CFPreferencesAppSynchronize's success return is documented-unreliable, and a
cross-launch canary can't distinguish a genuine first launch from a broken store without an external marker.
So the only signals that are both observable in one launch AND unambiguous are filesystem conditions on the
plist itself.
root-owned plist after a sudo launch. Both are directly
observable, hold across every supported macOS, and are what the user actually hit in #5790..ok. The bias is deliberately toward NOT warning: a false negative
is a missed nag; a false positive is a maddening dialog on a healthy machine, so we never risk the latter.continues after recording the symlink.exists == false short-circuits before either check, regardless of the
isWritable value the shell happened to pass. This is what keeps first-launch users (no plist yet) quiet.standard/preferences, .license, .usage). .broken carries two path lists so the shell can tailor
the explanation: symlinked paths get the "un-sync it" advice, unwritable paths get the "fix ownership"
advice. Either list may be empty, but not both (that would be .ok).