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

The Neighbors

~16 min · system-context, failure-modes, data-ownership, documentation-drift

Level 0Idle Phone
0 XP0/45 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

Six neighbors, one caller

A body never stands alone, so the architecture document draws its System Context: every neighbor, what crosses the boundary, and what happens when that neighbor is down. Here it is, with the last column as the face says it.

NeighborWhat crossesWhen it is down
cwkOriel, on Pippa's home MacEverything, as the only caller: status, photo, clip, fix, audio, face state, on port 4610The face says when Oriel last asked, or that it has not. Nothing else happens.
Oriel's phone hands (WebDriverAgent on the same device)Taps and reads through accessibility ids, on demandThe body stays where it is, and Oriel reports it silent.
cwkPippa, through OrielThe one shared On Air state, Dad's turns, the brains Think may offerThe switch reads "On Air ?" and says why. Nothing is toggled.
cwkBellows, through OrielMy voice, as finished audioOriel refuses the line and says why.
cwkSiblingKit's CwkKitShared Swift as a path dependencyBuild time only.
cwkFirelinkThe member card and the mobile_app declarationNothing changes at runtime.

Look at the second column again. At runtime every other neighbor reaches the body only through Oriel: cwkPippa and Bellows by Oriel's relay, the phone hands as Oriel's own tool. The kit and Firelink never reach it at runtime at all. That is the point of having one caller: the body has exactly one way to fail at its boundary, and one line on the face to say so.

When a neighbor is down, the face says so

The first block is that line. Before any request arrives, the face reads "Opening the door · Oriel has not asked yet". After one, it reads something like "Oriel asked over Wi-Fi GET /status 200 · 12 s ago": which link, which route, which answer, how long ago. Oriel probes every body's status every 10 seconds, so a number that keeps growing is itself the alarm. No error dialog is needed.

The second block is the same rule for cwkPippa. OnAirState.from reads the onair object Oriel relays. A state Oriel could not read arrives as unread with a reason, and the switch shows "On Air ?" with that reason in one line. An Oriel that relays no On Air at all sends no object, and the face keeps what it had. Neither case is ever shown as "Off air", because off is a fact about the broadcast and unread is a fact about the wire. A tap on an unread switch does nothing.

Bellows is one hop further away. Bellows answers a caller off the service host only with a family PIN session, so Oriel holds one session cookie that Dad unlocks once on its page, and never the PIN. Without it, a spoken line is refused before it reaches the body, and the refusal names the missing grant. The kit and Firelink cannot fail at runtime at all: one is compiled in, the other is a declaration.

The phone hands, by name and by fact

Here the document and the code part ways, and the code wins. Cordelia's architecture says Oriel's watchdog asks the phone hands to bring Cordelia back to the front, at most once every two minutes. The third block is what Oriel actually runs. After five silent minutes (REVIVE_AFTER, 300 seconds), and at most once every five (REVIVE_EVERY), Oriel launches Cordelia with devicectl over CoreDevice, on the cable or off it. It leaves the body alone while the hands' driver is running, because that driver dims the whole screen. It reads the lock state first and counts a revive only when the body's door answers, because a locked device takes the launch and stays behind its lock screen: on 2026-11-03 that produced an hour of false "brought to the front". No automation ever unlocks a body.

Notice the method's name: _revive_with_hands. The docstring of watch, which calls it, still says "through the phone hands" too. Oriel switched to devicectl on 2026-11-02 at 23:00, about an hour after the design was written down. The method kept its old name and the body's document kept its old sentence. Read names and prose as history, and read what the function calls as the fact.

Who owns what

Data or responsibilityOwnerWhat the body does
Product identity and visible versioncwk-product.jsonShows it through the kit's version line
Pippa's identity, conversations, memory, routingcwkPippaNever touches them, and has no brain
Which device is a body, its token, every request it served, its picturescwkOrielHolds only its token, its settings and the request in flight
Pippa's voicecwkBellows, reached by OrielPlays the audio it is given
Camera and location grantsiOS, answered once by a personNever routes around a denial
Runtime and deployment declarationscwkFirelinkMirrors none of it

Read the context table against the build

Two more rows have drifted, and both are easy to check. The kit row lists three modules: CwkKitCore, CwkKitAbout and CwkKitLocation. The target in project.yml links seven: those three plus CwkKitMicrophone, CwkKitVoice, CwkKitVoiceUI and CwkKitWake, the ears and voice mode's root that v2 brought in. And the Oriel row says the HTTP rides usbmuxd over the cable or the home Wi-Fi, while off the cable it rides CoreDevice's tunnel (track 3 has the measurement). When you inherit a System Context table, check each row against something that cannot drift silently: a build file, an import list, the caller's code.

Code

cwkCordelia, clients/apple/CordeliaMobile/Sources/Views/FaceView.swift: the face's one line about its only caller (verbatim, lines 427-433)·swift
  private func contactLine(at now: Date) -> String {
    guard let last = model.lastContact else { return "\(model.doorLine) · Oriel has not asked yet" }
    let seconds = Int(now.timeIntervalSince(last))
    let ago = seconds < 60 ? "\(seconds) s ago" : "\(seconds / 60) min ago"
    let link = model.link.map { " \($0.shown)" } ?? ""
    return "Oriel asked\(link) \(model.lastRoute) · \(ago)"
  }
cwkCordelia, CordeliaKit/Sources/CordeliaKit/OnAir.swift: an unread On Air state stays unread, never off (verbatim, lines 46-61)·swift
  /// From the face's `onair` object; nil when Oriel sent none (an Oriel that
  /// does not relay On Air yet: the face keeps what it had).
  public static func from(_ object: Any?) -> OnAirState? {
    guard let object = object as? [String: Any] else { return nil }
    func word(_ key: String, _ limit: Int) -> String? {
      (object[key] as? String).flatMap { $0.isEmpty ? nil : String($0.prefix(limit)) }
    }
    let phase = word("phase", 16).map { $0.lowercased() }
    let unread = word("unread", 160) ?? word("error", 160)
    let on = unread == nil ? (object["on"] as? Bool ?? object["on_air"] as? Bool) : nil
    guard on != nil || unread != nil else { return nil }
    return OnAirState(on: on, phase: on == true && stageWords[phase ?? ""] != nil ? phase : nil,
                      since: word("since", 40), by: word("by", 24),
                      unread: on == nil ? (unread ?? "Oriel sent no On Air state") : nil,
                      answered: OnAirAnswer.from(object["answered"]))
  }
cwkOriel, backend/cordelia.py: the revive is devicectl, whatever the method's name says (verbatim, lines 939-950)·python
    def _revive_with_hands(self, body: Body) -> str:
        """Bring Cordelia to the front with devicectl, not the phone hands: the
        hands' driver dims the whole screen while it runs. A running driver
        means someone is using the hands, so the body is left alone then."""
        from .phone import Phone, PhoneError, load_config

        try:
            if Phone(load_config(self.engine.settings.data, body.key), mux=self.mux).driver_alive():
                return "the phone hands are in use (their driver is running); left alone"
        except PhoneError:
            pass
        return revive_by_devicectl(body.udid, lambda: self._door_answers(body))

External links

Exercise

Draw the System Context table for a device or service you own: every neighbor, what crosses the boundary, and what the user sees when that neighbor is down. Then verify each row against something that cannot drift silently: the build file's dependency list, the caller's code, an import statement. Mark every row where the document and the code disagree, and fix whichever one is wrong.
Hint
For the last column, write the exact words the screen shows, not "an error". If you cannot name the words, the failure is probably silent today. For the verification, grep the caller for the function that actually runs and ignore its name and docstring until you have read its body.

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.