Callers Ask for a Role
Nobody asking Oriel for a picture should need to know a unique ID. Pippa asks for "the game", Dad's page shows "his camera", a session records "both decks". Those are roles, stored in settings and remembered against unique IDs, so that swapping hardware is a settings change and never a code change.
The interesting part is how the roles are named. The first version named them by what they showed: game, camera, face. That broke as soon as the studio's wiring was understood properly. Each capture card sits behind one deck of an external recorder, and which picture a deck carries depends on the deck's own input selection: the same card can carry the console one hour and a desk camera the next. A role named after its content would lie whenever the deck switched. So on 2026-11-02 the roles were renamed after the thing that does not change, the deck a card is wired to:
right_deckandleft_deck: the two decks. A deck has exactly one holder.look: the look-around pool, any number of movable webcams Pippa can choose between.none: a device that records nothing.
The old names still work everywhere, as aliases, and a database written before the rename is migrated when it opens. And because a deck name alone does not tell a model what it is looking at, every answer that names a deck carries a short line saying what that deck can carry (the inputs its recorder deck may be switched to), so a brain reads the possibilities instead of guessing from a label. The line is fixed text; nothing detects which input a deck has selected right now, so the picture itself is still the evidence.
One Holder, Two Clicks
Because a deck has one holder, giving a deck to an input releases whoever held it. Swapping two identical cards between the decks is therefore two calls, not one clever "swap" operation, and both calls go through the same rule. The engine also refuses to change the role of an input that an open session is recording: a recording that silently changed meaning halfway would be worse than a refusal.
The Pool: Choose by Name, Never by Index
The look-around pool is different by design. Dad's words when it was set up were that Pippa's eyes should switch devices when she wants to. So any number of cameras hold look, and Pippa names the one she means: by a part of its name, by its unique ID, or by input id. look alone means "the one camera that is here", and it works only when exactly one is. With none present it refuses and lists the pool and why each is absent; with several present it refuses and names them all, so the choice is the caller's. Nothing in the resolver ever picks by index.
A Missing Device Refuses; a Fallback Is Named
The most important rule here is about absence. When a role a session would record is held by a device that is not connected (or the recorder is down), start_session refuses and names the role, the device and its unique ID. It does not open something else in its place. With two capture cards that share a name and a model, "something else" would often be the other deck, quietly recording the wrong picture under the right label.
A stand-in is allowed, but only when it is named. The setting role_fallbacks maps a deck role to the unique ID of the one device that may stand in when the holder is absent. Engine.resolve is the single door every caller goes through: holder present, the holder; holder absent and fallback present, the fallback, with a note saying so (a look carries that note inside its budget); both absent, a refusal naming both. A fallback is a decision someone wrote down, never a guess the code makes.
Verified by Looking
How do you know the role table is right? Oriel's answer is blunt: by looking. A command-line tool opens each role's holder by its unique ID and keeps one frame, so a person can see that "the deck with the console" really shows the console. The architecture document records the role table with the note that it was verified by peeking each holder, and the house sign states the principle: a role is verified by looking, never by guessing.