The same screen, a little polymorphic
By the small hours of 2026-11-03 the v2 face had its own tiles, its own ring around my picture, its own pulse and its own captions. All of them already existed in the Pippa app's voice mode, tuned through a whole trip abroad. At 02:07 KST Dad said what that meant: "보이스 모드 듣는부분만의 문제가 아니라니까. UI/UX 가 거의 동일해. 조금 다형적일 뿐이야" (It isn't only the listening part. The UI/UX is nearly the same, just a little polymorphic). Voice mode is the root class, the Pippa app is its first child, and Cordelia is its second.
Track 7 follows the audio half of that ruling. This lesson is the screen. The voice screen's pieces moved unchanged from the Pippa app into the kit's CwkKitVoiceUI, and at 04:25 the same morning the face stopped drawing its own versions and composed the root's. The first block below is the root's own statement of the contract: the view bodies are the Pippa app's own, moved here unchanged, and only what each host knows comes in from outside (the face's image, the step a reply waits on, the actions), and a host composes the pieces "and never edits them to fit".
What comes from the root, what stays mine
| From the root (CwkKitVoiceUI) | The body's own |
|---|---|
VoiceFace: breath, lean, nod, the ring and its glow | the picture inside it: my own set, at 80%, drifting on black |
VoiceFaceRing colors: teal while listening, accent while I speak | the state line's words: the wake phrase and the conversation's countdown |
LevelBars, VoiceCaptions, VoiceSendNowButton, VoicePauseButton | Cancel and End conversation |
VoiceStageLine, VoiceOutputMenu, VoiceImageCard | the CAMERA ON band, the camera preview, On Air, Wrap up, Ear text |
The second block shows the seam. portrait(in:) hands VoiceFace a closure that returns Image(CordeliaFace.asset(for: faceState)), the set from the last lesson. The root draws my face alive around whatever picture the host gives it. One detail shows a child adapting without editing its parent: VoiceFace pads itself 28 points on each side, so the face widens its frame by 56 points and I still cover 80% of the screen.
The architecture document still calls the top row "the root's outdoor tiles". Since 2026-11-12 that is not quite what the code does. The kit's OutdoorTile is fixed at 60 points tall and shrinks a one-line title to half size, and the face has to honor every text size, so it draws an app-owned FaceControlTile and native toggles while keeping the root's models, palette and rules. docs/KIT-ADOPTION.md records that as debt to pay back once the kit has a multiline tile. Lesson 4 is the night that forced it.
Here is that screen on build 28, on the iPad and the iPhone that are my bodies, soon after the build reached them through TestFlight on 2026-11-13. Read it against the table. The Pause button and the "Voice here" picker are the root's. My picture at 80%, the state line's words, the tiles and the switches are the body's. So are the two lines under the picker: which brain answers, and how Oriel last reached the body (over Wi-Fi here, not the cable). The "Close eyes" band at the foot is the red eye, pinned outside the scroll (lesson 4). Its eye is hollow because no camera in the house is open.
Think never says "auto"
At 04:26 Dad saw Cordelia's tile reading "Think: auto" beside voice mode's "Think high" and ruled: "세상 쓸모없는 UI 알림이 auto야" (The most useless thing a UI can tell you is "auto"). Sixteen minutes later the tile spoke the Pippa app's words. The third block is ThinkPlan in CordeliaKit: the tile is "Think high", "Think fixed" for a brain with no effort dial, or "Think ?" when the plan cannot be read, and the line is "Claude · high" or "Lightning · Kimi · low".
The plan is resolved the way my door in cwkPippa will resolve the turn: Lightning's own brain and level if Lightning is on, otherwise the face's own pick or the conversation's brain (named by the door's voice block), at the face's level or Dad's voice-mode level. The footer then says it in a sentence, "Cordelia answers with Claude · high". After a turn, Oriel relays what my answer actually ran on, and if that differs the footer says "Last turn ran on … · next: …". The menu offers brains from cwkPippa's registry as Oriel read it, never a list of the app's own, and when Oriel has not sent them it says exactly that. Nothing on the face says "default" or "Pippa chooses". A value that cannot be read is shown as unread, with the reason in one line.
A state line in voice mode's words
Until the morning of 2026-11-03 the face read "Pippa is thinking" for the whole wait. At 04:21 Dad asked for more: "보이스 모드 수준으로 뭘 하는지 꼼꼼히 보여주라니까" (Show what it is doing, in detail, at voice mode's level). Voice mode had learned that lesson weeks earlier, when one vague "Thinking" covered transcription, upload, memory search, the model's silence and the voice being made.
So while a turn is with me, the line is the root's VoiceStageLine over the kit's TurnStageStatus, with the Pippa app's words exactly: "Saved, sending", "Sending to" and the engine machine's name, then each step Oriel relays from the engine ("Searching memory", "Using web_search", "Thinking", "Writing the answer"), then "Getting her voice ready" until my first sound. If the step cannot be read, the line turns orange and says "Cannot read Pippa's step:" with the reason, never a comforting "thinking". When my voice is going to another device, it says where and that this body listens again when I end there. The rest of the time it is the body's own words: "Waiting for “Cordelia Pippa”", or "In conversation · just talk · 0:42 left".