A phone cannot be rebuilt on the day of the move
Every family iOS app carries tables compiled into it: which Mac each member runs on, and which MagicDNS name and port its HTTPS twin answers on. Those tables name the Macs the family ran on the day the app was built. A Mac follows a move by reading the port ledger at the moment it asks (backend track, lesson 9). A phone has no ledger, no host profile file, and no way to be rebuilt in a hotel on the morning of a switch. Left alone, every app on Dad's phone would keep dialling the old Pippa machine after the move had taken that Mac's doors away.
The gap showed first on the Ark. On 2026-10-20, in Málaga, stage 1 of Pippa's Ark had closed with its switch in the WebUI only (backend track, lesson 10), and Dad asked the obvious question:
근데 방주 모드 stage 1 에 폰 앱도 포함돼야 하는 거 아니야? 지금 웹UI에만 방주 모드가 있어. 폰은 여전히 office로 연결할 텐데? — 아빠
("But shouldn't stage 1 of Ark mode include the phone apps? Right now it lives only in the WebUI. The phone will still connect to office, won't it?") He was right. The only way to point a phone at the Ark was typing the Ark's address into one app's Custom host, app by app. Between 2026-10-19 and 10-21 the phone learned three things, each kept where every family app on the device can read it: where the Ark is, which Mac is the Pippa machine, and the host profile of the Mac it is pointed at.
Three layers, one precedence
The kit states the order once, and every address a family app resolves goes through it: Dad's Ark preset while it is on, over the family's roles, over the compiled table. In the kit's own words, "the Ark moves every host onto one Mac; the roles move a role; the compiled table is the day the app was built." On iOS, while the Ark preset is on, the roles are not consulted at all.
The roles are a document the Pippa machine serves at GET /api/family/roles: a version and, for pippa and workbench, the machine, its fleet label, and the MagicDNS name and tailnet IPv4 when the registry knows them. It is its own versioned endpoint, never a new key in /api/host-profile, because the Swift parser of the host profile refuses unknown keys, and every phone app already installed would have thrown the whole profile away. A client that meets another version refuses the roles document whole, so an old app never half-reads a later shape.
Not every member moves with the Pippa machine. Only the members the port ledger spells by role, @pippa, and that serve the family through an HTTPS twin follow it. A member with no twin belongs to its own Mac (Cinder's Photoshop sidecar, the per-Mac Smolder and Firebrand gateways) and stays, and a member pinned to another machine stays where its table puts it.
Asked on every foreground, believed only from the right Mac
Each time the Pippa app comes to the front it asks Pippa where the Ark is, then asks for the family's roles. The second question goes to every machine the device knows: wherever the kept roles place Pippa now, the kept Pippa machine, and every Mac in the compiled table. A document counts only when it names the machine that served it as the Pippa machine. That one check is what makes a move safe to follow. After a switch the new Mac answers that way, the old Mac's Pippa is stopped and answers nothing, and a document from any other Mac is passed over. If nothing answers, the phone keeps what it knew, so the app still works on a day the family cannot be reached.
When the answer moves the Pippa app's own connection, the PIN goes with it. The family PIN is one secret, so the PIN saved for the old host is copied to the new host's keychain account, only when the new host has none and never over one it has. Dad sees the result in Settings: a Pippa machine row with the label of the Mac the phone dials, how long ago Pippa named it, and Use this build's default, his reset, which forgets the learned roles until Pippa answers again. One fallback had to go before that row could be trusted. The label code used to fall back to a constant machine name when the table had no row for cwkPippa, and the code now records that a constant fallback is how the old name outlived the move on screen; it falls back to the compiled table's Pippa machine instead.
The host profile of the Mac it points at
The roles answer "which Mac is the Pippa machine". A Mac also carries a host profile, the file that remaps every family host onto another Mac; that file is how the Ark works on a Mac. A phone has no such file, so since 2026-10-19 the Pippa app reads one. At launch, and again whenever its saved endpoint moves, it asks GET /api/host-profile on the host its settings dial. A host the ledgers know, by any spelling, or loopback clears any kept profile; any other host is a Mac Dad pointed the phone at, the Ark among them, and its profile is kept. Before this, the profile was adopted only inside a PIN connect, so a launch with a kept session, or a custom host saved in Settings, never refreshed it.
That route and the Ark's address, GET /api/host-profile/ark, answer without a PIN in every mode but deep lockdown, because the apps that need them hold no Pippa session: Easel, Haven, Inkwell, Loomis, Sizzle, Smolder, Spark and Firebrand talk only to their own engines and read the profile beside them. Opening them took two commits. The first opened the paths in cwkPippa's own middleware branch. Measured from the MacBook against the Pippa machine's twin, every remote phone still got 401, because the family's shared auth policy runs first and had never heard of them. A door left open behind a closed one is a closed door. The second commit opened them in the family policy itself.
One switch for the Ark, kept in the family keychain group
On a phone the Ark switch is one preset in the shared kit, and it moves every family app on the device at once. Flip it in the Pippa app, and Spark, Haven and the rest dial the Ark Mac; flip it back, and they return to the ledgers. The Pippa app learns the Ark's address from Pippa on every foreground, so the switch still works on the day the family's own Macs do not answer, and it never turns the switch on by itself. Flipping it moves the Pippa app's own connection at once and carries the PIN, so the Ark asks for nothing.
The first cut kept the preset in a new App Group, group.com.cwk.family, the usual iOS place for data several apps share. It lasted forty minutes. A new App Group has to be registered with Apple through an Xcode account session; the key-based TestFlight pipeline cannot do that, and no fleet Mac had such a session, so the next archive would have failed. The preset moved to a keychain access group, $(AppIdentifierPrefix)com.cwk.family, which is team-prefixed and already in every profile the family's apps are signed with. The Pippa app lists its own group first, so its PINs stay where they always were. The item is readable after first unlock, so an app launched in the background still follows the switch, and each app reads it through a two-second memory, so another app's flip shows within two seconds. The roles live beside it in the same group, as a second item. The header comment of the Pippa app's FamilyArk.swift still says "App Group" as of 2026-10-27; the entitlements and the kit say keychain group, and they are what runs.
On 2026-10-21 the switch was rehearsed on an iOS 27 simulator, with the MacBook as the Ark Mac. The Pippa app learned the Ark from the Pippa machine in 0.05 s. Switching on moved the Pippa app and every member to the MacBook; Spark, a separate app, followed the switch from the keychain group and reached its own engine there (health 200); switching off returned both. A held member, an outward writer the Ark keeps off until Dad turns it on, reads as held in the phone's family check: its twin's 502 is never counted as an answer.
The watch follows the phone
No family watch app dials an engine. The iPhone does, and relays to the wrist (lesson 4 of this track), so the watch needs no step of its own: when the phone's addresses move, the wrist's words move with them. That is the shape the wrist was built with, and on a move it pays out as one device fewer to follow.
Built before the move, not after
The migration plan made this a gate. An app built before clients learned roles keeps dialling the old Mac, and the switch takes that Mac's doors away, so the switch waits until the builds on Dad's devices carry the roles, and the plan asks for a compatibility matrix first: an old build against the new engine, a new build against the old engine, a new build after a rollback. The role-aware builds went onto Dad's phone by cable from the hotel before the switch (lesson 6 of this track) and through TestFlight after it.