Skip to content
C.W.K.
Lesson 01 of 06 · published

Changes Never Wait for the Eyes

~14 min · latency, watchfire, before-after, shared-requests

Level 0Idle Hands
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"A change never waits for an observation." — Tinker architecture

Measured, Then Moved

Tinker reports a before/after comparison from Watchfire around every command, so Dad can see whether hiding the editing distractions changed anything. The first version took the comparison literally: read Watchfire, then hide, then read Watchfire again, then report. The review pass measured what that cost. One reading is a fresh worker process plus an SSH round trip to the Watchfire host: 1.08 to 1.24 seconds on the workbench, and up to the worker's 25-second timeout when Watchfire cannot be reached. A shortcut that does nothing visible for over a second reads as a missed key press; Dad presses again, and a toggle pressed twice is a toggle undone.

The New Order

Now the change starts at once. The "before" sample is chosen without waiting: if a reading finished within the last five seconds and reported no problem, that is the before; otherwise a reading is requested as the command starts, running alongside the hide rather than in front of it. The "after" sample is always requested after the command ends — and if a reading is already in flight, Tinker waits for it and requests a fresh one, so "after" is never a sample that started before the change. The status line moves through three states: what is being applied, what was applied ("Final Cut editing applied (3 changes) · reading Watchfire…"), and finally the comparison when both samples are in.

Is a Concurrent "Before" Still Honest?

A before-sample that completes after the hide began might already include some of the hide's effect. The architecture addresses this directly: such a sample "can only narrow the measured difference, never invent one." If the before is partly after, the difference shrinks toward zero; it cannot grow. An honest comparison is allowed to understate.

One Request, Many Askers

While Settings is open, Tinker refreshes the observation every five seconds, and commands may ask for samples at the same time. Concurrent readers share one worker request: the first caller starts a task, later callers await the same task, and the task clears itself in the same main-actor turn that publishes its result, so nobody can join a request that has already answered. The app door's answer for a command waits for the full summary, so Pippa gets the comparison, while Dad's key press got its effect immediately.

Code

Choosing the before-sample without waiting for it·swift
/// A sample that finished moments ago and reported no problem.
private var recentObservation: WatchfireSnapshot? {
  guard observationTask == nil, observation.problem == nil,
        let finished = observationFinishedAt,
        Date().timeIntervalSince(finished) < 5 else { return nil }
  return observation
}

let before: Task<WatchfireSnapshot, Never>
if let recent = recentObservation { before = Task { recent } }
else { before = Task { await self.observe() } }   // runs beside the change

// ...engine.apply / engine.restore runs now, not after the reading...

return Task {
  let first = await before.value
  let second = await self.observeFresh()          // requested after the change
  return outcome + " · " + WatchfireSnapshot.comparison(first, second)
}
One in-flight request shared by every caller (simplified)·swift
func observe() async -> WatchfireSnapshot {
  if let task = observationTask { return await task.value }   // join it
  observing = true
  let task = Task { @MainActor [weak self] () -> WatchfireSnapshot in
    let sample = await self?.readWatchfire() ?? WatchfireSnapshot(problem: "stopping")
    // Publish and clear in the same turn: nobody joins an answered request.
    self?.observation = sample; self?.observing = false
    self?.observationTask = nil; self?.observationFinishedAt = Date()
    return sample
  }
  observationTask = task
  return await task.value
}

/// A read requested after this call, never one that was already in flight.
private func observeFresh() async -> WatchfireSnapshot {
  if let inFlight = observationTask { _ = await inFlight.value }
  return await observe()
}

External links

Exercise

Settings is open, so a 5-second refresh is running. Dad presses the editing toggle 2 seconds after the last refresh finished, and again (restore) 4 seconds later. For each command, say which sample is its 'before' and which is its 'after', and whether any worker request is shared.
Hint
First command: the last refresh finished 2 s ago with no problem, so it is the 'before'; the 'after' is a fresh request when the hide ends (possibly joined by the next timed refresh if it starts at the same moment). Second command, 4 s later: if that 'after' or a refresh finished under 5 s earlier, it becomes this command's 'before'; its own 'after' again waits out any in-flight read and asks anew.

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.