"Normal Quit releases first; forced termination leaves the durable journal for visible recovery on the next launch." — Tinker architecture, hide invariant 7
A Quitting Actuator Owes a Restore
If Tinker quit with editing mode active, Claude, Voyager and Eagle would stay hidden with nobody running who remembers hiding them. The journal would remember, and the next launch could restore them — but "next launch" might be days away. So when Dad chooses Quit from Tinker's menu, Tinker restores everything it owns first, using the same release path as the emergency command, with its trigger recorded as system.
Why Quit Starts by Cancelling
AppKit asks an app whether it may terminate through applicationShouldTerminate(_:), and the obvious answer for "I need a moment" is .terminateLater, which keeps the app alive until it later calls reply(toApplicationShouldTerminate:). The comment beside Tinker's delegate records the catch. While a terminateLater is pending, AppKit spins a nested run loop, and a main-actor Task started from inside the termination request did not get to run in it — the asynchronous restore was starved. So for an ordinary Quit, Tinker answers .terminateCancel, lets the delegate method return, runs the restore on the main actor in peace, and then calls terminate again itself, this time answering .terminateNow. A guard flag makes sure a second terminate request arriving mid-restore is cancelled rather than started twice.
When Something Can't Be Restored
If the restore leaves something behind — an app refused to show, an uncertain record exists — Tinker does not quit and does not refuse forever. It shows the reason: "Some changes could not be restored and remain in Tinker's journal (…). Choose Quit again within 30 seconds to leave them for the next launch." The first Quit explains; a second Quit within 30 seconds proceeds and leaves the remainder to the durable journal. It is the same two-step shape as Delete and Forget: the destructive outcome takes a second, informed click.
Force Quit and Updates
Force Quit, a crash or kill -9 cannot run any of this. That is why the journal is durable and why the next launch shows what is left: confirmed changes can be restored from the menu, uncertain ones wait in Recovery. It is also why Tinker is never updated by signalling it. The family native deploy asks a running Tinker to quit politely — a quit Apple event, which takes the logout path in the next lesson — and installs over it only after it has left; a copy that does not quit is skipped and keeps its old bundle. Booting out its login agent or sending a signal would end Tinker before it restored what it owns.