Skip to content
C.W.K.
Lesson 02 of 05 · published

Prepared and Applied — Two Phases, Two Meanings

~12 min · phases, uncertain, recovery, resume

Level 0Idle Hands
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Incomplete receipts stay visible for recovery." — Tinker architecture, hide invariant 3

Only Two Phases

A receipt is either prepared or applied. There is no "failed", no "rolled back", no "pending retry". That spareness is deliberate. Applied means the OS confirmed the change and Tinker owns it: it will appear under "Changes Tinker will restore" and be undone when its last owner releases it. Prepared, once no action is running, means exactly one thing: an intent was recorded and its outcome is unknown. A receipt that was dropped because the capability proved it asked for nothing is not a third phase — it is simply gone. Everything else is one of the two.

What Prepared Does to the Engine

When the engine is constructed from the saved journal, it checks for any prepared receipt. If there is one, the engine starts stopped. Hotkeys are not registered and every apply is refused with "Tinker is stopped. Resume it in Settings." Restoring stays possible — the menu's Restore item still works — because taking back a confirmed change never needs the engine's trust. The reasoning is that an uncertain record describes a situation where Tinker's own understanding of the screen may be wrong, and acting on top of a possibly-wrong understanding is how one uncertainty turns into two.

Resume Has Conditions

resume() refuses while an action is executing, while the engine has a persistence fault, and while any prepared receipt remains — "Resolve uncertain changes before resuming." So the path out of an uncertain state is always the same: look at the app named in Recovery, decide what its visibility should be, use the ordinary Mac controls if anything needs changing, then Forget the record, then resume. Tinker's job in that path is to explain, not to act.

Uncertain Records Are Not Restored Either

Restore, release-all and Quit all walk the journal, and all of them skip prepared receipts with the message "Uncertain change …: inspect it in Recovery." Undoing a change you are not sure you made is the mirror image of the bug the whole design avoids: it could unhide an app someone else hid. So emergency release, which is otherwise the most forceful command Tinker has, still leaves uncertain records exactly where they are and reports that it did.

Names for People

A receipt's key is a machine string. For Recovery, Activity and the app door's change.list, the receipt offers a displayName: the name field from its payload if the capability put one there, otherwise the key. It is a small courtesy that keeps the root ignorant of apps while letting the screen say "Voyager" instead of a colon-separated identifier.

Code

Launch: an uncertain record starts the engine stopped·swift
journal = try persistence.read()
guard journal.schemaVersion == 1,
      Set(journal.changes.map(\.key)).count == journal.changes.count,
      journal.changes.allSatisfy({ !$0.key.isEmpty && !$0.owners.isEmpty
                                   && $0.owners.isSubset(of: journal.active) }) else {
  throw TinkerError("Invalid change journal; automatic actions are held.")
}
stopped = journal.changes.contains { $0.phase == .prepared }
Resume refuses until the uncertainty is resolved by a person·swift
public func resume() throws {
  guard !executing else { throw TinkerError("Wait for the current action to finish.") }
  guard fault == nil else { throw TinkerError(fault!) }
  guard !journal.changes.contains(where: { $0.phase == .prepared }) else {
    throw TinkerError("Resolve uncertain changes before resuming.")
  }
  stopped = false
}

extension ChangeReceipt {
  /// A capability may put a `name` in its payload for people; the key is the fallback.
  public var displayName: String { payload.string(at: "name") ?? key }
}

External links

Exercise

Tinker relaunches with one applied receipt (Voyager, owned by edit) and one prepared receipt (Eagle, owned by edit, error 'did not confirm its visibility change'). Walk through, in order, what Dad sees in Settings and what each of these does: pressing the editing shortcut, choosing Stop and restore everything, forgetting Eagle's record, choosing Resume.
Hint
The shortcut does nothing (engine stopped, hotkeys not registered). Stop and restore everything restores Voyager and reports Eagle as uncertain; edit stays active because Eagle's record still names it. Forget removes Eagle's record — and since no receipt names edit any more, edit leaves the active set — without touching Eagle's visibility. Resume then succeeds, because no prepared receipt remains.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.