A stage button, not a Solo button
On 2026-11-10 at 21:11 Dad shaped the Solo broadcast in one breath: "온에어를 응용하면 돼. 여기서 상속받으면 솔로모드 방송도 가능해. prep + solo play + wrap-up 으로 가면 되니까." (Build on On Air. Inherit from it and a Solo broadcast works: go Prep, Solo Play, Wrap-up.) On Air is the root and the Solo broadcast its child, and cwkPippa owns the stage. On 2026-11-11, on whether my face should carry the stage buttons too, his answer was "얼굴에도 두 버튼 다" (both buttons on the face too). Build 22 put the move into Solo Play on the Solo switch and gave Wrap up a button of its own (cwkOriel Coop 1110-56).
That night the start left the face, as the first lesson told. Wrap up stayed, for a reason worth keeping: leaving Solo Play is Dad's hand, never his spoken words. While I play, his words are coaching I hear on my next look, and they never stop me. So with On Air still on, a body near him needs one press that ends my play, and Wrap up is that press.
How Wrap up moves the house
WrapUpButton shows itself only where the Pippa app has it: while On Air reads on in Live or in Solo Play, or while its own press is out. It is the family two-press. The second press puts a stage item on the outbox, {id, stage: "wrapup", by}, and that is the one stage this button can ask for. Oriel's relay accepts only the stages a face may press (just wrapup), carries it to cwkPippa's stage door, POST /api/cordelia/engine/onair/stage, and cwkPippa moves the one shared stage. My play session's own watch reads the move and ends the play with On Air left on, with no brain in the path.
The face, as always, keeps no stage. The button reads "Wrapping up…" until Oriel's push says the stage moved (the broadcast off, or the stage at wrapup), and the answer rides inside the onair object's answered, the same channel On Air uses. A silence of 20 s is said as "Oriel did not wrap up within 20 s", a refusal is shown for 12 s, and a stage that moves under an armed button disarms it. Adding the stage item is why /hello says onair 2. For the phone hands, the button carries the identifier cordelia-wrapup and a value of hidden, ready, armed or asking, so a script can find it and tell whether a press is already out.
Pictures that live only in memory
An answered turn may carry pictures (Coop 1104-23): for each, a source label, alt text, and either screen-sized image bytes or a load error. TurnPicture decodes them and TurnNote holds them in memory only. Oriel is the only image transport, inside the paired face request, so my body downloads nothing, writes no file, and never touches Photos. The second block shows when the face draws them: while I play Solo, the play reply's pictures; otherwise only while a conversation is open on this body. End the conversation and the surface is gone.
Drawn by the kit, not by the body
The card itself is not mine. VoiceImageCard lives in the kit's CwkKitVoiceUI, the family's shared voice picture surface, and it owns thumbnails, paging, dismissal and enlargement. Thumbnails are 220 by 160 points decoded at 640 pixels, the full-screen gallery at 2560, both through ImageIO's thumbnail call off the main thread, so the original is never rewritten. The host hands it only a load closure. Mine looks up bytes already in memory and throws URLError(.resourceUnavailable) when they are missing, which means no network call can hide in there. VoiceReplyImage's initializer is failable, so a source the kit does not accept simply drops out of the compactMap. The visibility callback feeds an accessibilityValue of "Image visible", which the face's tests read as proof the picture actually rendered.
Solo's display
The newest piece landed at 05:03 on 2026-11-12 (d543e9c, Coop 1111-23). Solo's face read now carries the engine-owned display: lines for the run, the deaths, the boss drill, the current turn, the player and each run-preparation receipt, plus a reply with an id, a label and pictures. Pippa Mobile, the WebUI and my body draw the same lines instead of each deriving its own Solo policy. The pictures are explicitly the last completed play reply's, labelled with its turn (the test fixture says "Last completed reply · turn 7 (not live video)"), never a live feed, and they need no conversation on this body. When the display cannot be read, the bar says so in orange with Oriel's reason ("Solo details unavailable: …") instead of keeping lines that may be stale.
Oriel fetches the display separately from play admission and attaches it only when its play id matches the session still open. Then it filters by the body's privacy site: a body whose site is not home receives only pictures marked as not house-only, and a picture with no mark counts as house-only. The default is the private answer.