"Application visibility only: no UI tree, clicks, typing, payment or password access." — the doc comment on Tinker's system visibility adapter
Identity and Input
HideApplications calls the root initialiser with the ID applications.hide, the name "Hide applications" and the permission set [.accessibility]. Its input type is a one-field struct, HideInput, holding a list of bundle identifiers. validate accepts an empty list — a preset still being filled in is legitimate saved data — but refuses any entry that is blank or contains no dot, because a bundle identifier is reverse-DNS by convention and a bare word is almost certainly an app name typed by mistake.
prepare: Snapshot, Filter, Flag
Prepare refuses an empty list with a message that says what to do ("No applications are listed to hide yet. Add some in Tinker Settings."), because a key press that silently does nothing teaches the user that the tool is broken. Otherwise it takes one snapshot of the running applications, keeps those whose bundle ID is in the list, and emits a plan for each — key from the app's identity, payload from that identity, needsApply set to not already hidden. Only if at least one plan actually needs applying does it ask the standing-refusal question (secure keyboard entry, covered in track 7). A preset whose apps are all already hidden or not running is not refused; it simply has nothing to do.
apply: Revalidate at the Last Moment
Time passes between prepare and apply — the journal write sits in between, and a preset may have several apps. So apply checks again, immediately before the effect: is this exact process still running and still visible? If it is now hidden, someone else hid it; if it is gone, it quit. Either way Tinker has asked the OS for nothing, and it says so with a specific error type you will meet in the next lesson. Only then does it request the hide.
undo: Only If Still Ours to Undo
Undo checks that the same process is still hidden. If Dad has already brought the app back by hand, or the app has quit, the answer is .noLongerApplicable and nothing is touched. Otherwise it requests the unhide and reports .restored.
The Seam: ApplicationVisibility
HideApplications never calls AppKit directly. It talks to a small protocol — list running apps, ask whether one is hidden, set hidden, give a refusal reason — and the app injects SystemApplicationVisibility, the real AppKit adapter. Tests inject a fake that can simulate pre-hidden apps, relaunched processes, slow confirmations and failures on demand. That one seam is why the engine's hardest cases are covered by fast, deterministic unit tests instead of by poking real apps.