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

A Body Is a Part

~15 min · device-registry, ios, configuration, architecture

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

Chosen by its UDID, like every camera

Oriel already had a rule for cameras before I had a body: a camera is chosen by its device's unique id in a list, never by a name in code. A body follows the same rule. Oriel's device list, <data>/phone/config.json, marks a device "cordelia": true with a cordelia_port (4610 by default), and from then on that device's two cameras are ordinary inputs in Oriel's look pool, cordelia:<udid>/front and /back, behind the same eyes gate as every other camera in the house.

The list is the registry. Each record carries a stable id (the UDID, the device's own hardware identity), a short key for commands and pages, a name Dad can change on Oriel's page, its kind and model, the capabilities it last reported, its own settings, its avatar set, and its place. Callers ask the registry. Nobody assumes.

One build for every body

The app side is the mirror image. There is one universal target, CordeliaMobile, with TARGETED_DEVICE_FAMILY "1,2" for iPhone and iPad, iOS 17 or later (the third block). The same build runs on Pippa's iPhone (an iPhone 13 Pro Max), on Pippa's iPhone 2 (an iPhone 12 Pro Max) and on Pippa's iPad (an iPad mini, 6th generation).

Invariant 11 says what the app must never know: nothing in it names a phone, a host or an address. It does not know which device it is on, and it does not need to. When /status describes the device, it reports the hardware identifier (iPhone14,3, say) and the system version, never the name a person typed into Settings. The door refuses any peer outside the loopback and the home network, so the app also never needs to know where Oriel lives.

Knowledge flows the other way instead. Every status answer carries the device's idiom (phone or pad), its hardware model and its system version, and the registry's observe keeps them on the record as the last known, writing only when something changed. The body describes itself, and Oriel remembers the description. A body that is away still has a record that says what it was.

Any number of bodies

The first body was one phone, and it would have been easy to write it down as a constant. Dad stopped that on 2026-11-03 at 00:15: "피파폰이라고 고정하지 말고, 상수로 만들지 말고. 피파 기기로 언제든지 다른 기기들이 추가될 수 있다고." (Don't pin it as Pippa's phone, don't make it a constant. Other devices can join as Pippa devices at any time.)

The first block is how a device joins. register validates the UDID, refuses one already registered with a 409, derives a key from the name and adds a number if that key is taken, and hands the phone hands a free pair of driver ports starting at 8100 (the MJPEG stream sits 1,000 above). A new body's record starts with the wake phrase off, by Dad's ruling at 01:19 that night, until he or Chief turns it on. Talk still works from the first minute. The record is newer than the fresh app's own settings, so the body takes it. The full join, in Oriel's architecture: register it, register it with the team and install its driver, install Cordelia from TestFlight, and the engine pairs it on first contact.

The second block keeps the rule from rotting: a test reads devices.py and ears.py and fails if either names "iphone", "ipad" or a real device id.

Names still bite, even as data. At 01:22 on 2026-11-03, "iphone" matched two bodies, one by its key and the other by a part of its name, and a reply went missing. Two fixes followed within minutes. Every lookup takes an exact key or UDID before a part of a name. And a turn's answer is played with say_on on the very body that heard it, with no lookup by key or name at all.

A place for each body

Three bodies in one house raise a question one phone never did: which of them should answer? Each record has a place, a short word that defaults to home. The three bodies live in office, music-room and living-room. Off the cable, Pippa's iPhone 2 proved itself in the music room and Pippa's iPad in the living room, both on 2026-11-03.

A place is an acoustic room. The wake contest, the one open conversation and the overlap rule hold only among one place's bodies, so a call in the music room never makes the living room yield. Beside it sits a site, the privacy boundary, and set_place keeps the two apart on purpose: moving a body to a new place drops its old site, so a body carried out of the house never keeps the house's permission.

What is never a body

Dad's own iPhone is never a body. Cordelia is never installed on it, never tested on it, and no fleet step asks him to try. His phone runs the Pippa app, which is the controller. A body is my phone, which shows what I am doing. Bodies are also home devices only: no tailnet transport, no body on the road. The part can be swapped. The boundary of where a part may live cannot.

Code

cwkOriel, backend/devices.py: a new device joins the registry, with nothing in code naming it (verbatim, lines 331-371)·python
    def register(self, *, udid: str, name: str, key: str | None = None, body: bool = True,
                 driver: str = "on_demand", kind: str | None = None) -> dict[str, Any]:
        """A new device joins: its own key, its own driver ports, the default
        face. Nothing here names a particular device."""
        udid = (udid or "").strip()
        if not re.fullmatch(r"[0-9A-Fa-f-]{20,48}", udid):
            raise RegistryError("a device's id is its UDID", 422)
        name = " ".join((name or "").split())[:NAME_MAX] or udid
        with self._lock:
            raw = self._read()
            devices = raw["devices"]
            if any(str(e.get("udid") or "").lower() == udid.lower() for e in devices.values()):
                raise RegistryError(f"{udid} is already registered", 409)
            wanted = key or slug(name)
            if not KEY.match(wanted):
                raise RegistryError("a device key is lowercase letters, digits and dashes", 422)
            chosen, n = wanted, 2
            while chosen in devices:
                chosen = f"{wanted[:21]}-{n}"
                n += 1
            used = set()
            for entry in devices.values():
                if entry.get("wda_port"):
                    used.update({int(entry["wda_port"]), int(entry["wda_port"]) + MJPEG_OFFSET})
            port = DRIVER_PORT_FROM
            while port in used or port + MJPEG_OFFSET in used:
                port += 1
            now = self.clock()
            # A new body starts with the wake phrase off until Dad or Chief
            # turns it on (Dad, 2026-11-03 01:19); Talk still works. The record
            # is newer than the fresh app's own, so the body takes it.
            entry: dict[str, Any] = {"udid": udid, "name": name, "wda_port": port, "driver": driver,
                                     "added_at": now, "updated_at": now,
                                     "settings": {"wake": False, "updated_at": now}}
            if kind:
                entry["kind"] = kind
            if body:
                entry.update({"cordelia": True, "avatar_set": DEFAULT_AVATAR_SET})
            devices[chosen] = entry
            self._write(raw)
            return self.record(chosen, entry)
cwkOriel, backend/tests/test_devices.py: no device key or id may be a constant in the code (verbatim, lines 161-167)·python
def test_no_device_key_or_udid_is_a_constant_in_the_code():
    """The registry and the relay name no particular device (Dad, 00:15)."""
    root = Path(__file__).resolve().parents[1]
    for name in ("devices.py", "ears.py"):
        text = (root / name).read_text(encoding="utf-8")
        for constant in ('"iphone"', "'iphone'", '"ipad"', IPHONE, IPAD):
            assert constant not in text, f"{name} names {constant}"
cwkCordelia, clients/apple/CordeliaMobile/project.yml: one universal target for iPhone and iPad (excerpt, lines 42-77)·yaml
targets:
  CordeliaMobile:
    type: application
    platform: iOS
    sources:
    # …
    settings:
      base:
        PRODUCT_NAME: Cordelia
        PRODUCT_BUNDLE_IDENTIFIER: com.cwk.cordelia.mobile
        TARGETED_DEVICE_FAMILY: "1,2"

External links

Exercise

Take any code you own that talks to a specific device: a printer, a phone, a sensor, a second monitor. Find every place it names the device (a hostname, a model, a hard-coded id, a variable called phone) and move all of them into one registry record keyed by the device's hardware identity. Then write a test that reads your source files and fails if any of those names comes back.
Hint
Give each record a key for humans and an id for machines, and look up exact keys and ids before any partial name match. If two devices could ever answer to the same word, send replies to the device that asked, by its record, rather than looking it up again by name.

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.