Skip to content
C.W.K.
Stream
Lesson 06 of 07 · published

The Client Owns No Roster

~14 min · ownership, configuration, provenance, evolution

Level 0Cold Workshop
0 XP0/51 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Three Choices the Workshop Was Still Making for Itself

The earlier lessons of this track are about borrowing: voice from one sibling, images through one route, no keys held locally. By the middle of September the workshop was still deciding three things on its own, and none of them looked like a borrowing problem. It chose which image route a producer used, because one particular brain had been given its own native tool on 2026-09-05. It chose which voice model narrated, through a default model constant in its own toolkit. And it chose which brains could review a script and with what command line, through a roster and an argument map in its own client.

Each of those is a list the workshop kept a copy of. Within one week, each copy was removed and the choice went home to the sibling that actually owns it: images on 2026-09-23, the reviewer list on 2026-09-28, the voice model on 2026-09-28 and 29. The pattern is worth naming because it is the consumer's view of capability extraction, one level up from keys and calls. A client can borrow every capability correctly and still own the decisions about them, and those decisions drift exactly the way forked code does.

One Image Door, Again

The native-tool exception lasted eighteen days. Now every producer, whichever brain is driving, writes the complete prompt — every label, every reference and its role, the composition and its constraints — and submits it through the family image engine's shared Codex tool. The engine's own settings choose the calling model and its reasoning effort; the producer's brain does not override them. There is no native-harness shortcut and no automatic paid fallback: when the shared route fails, the failure is reported, not routed around. And because the model that calls the image tool is not the renderer inside it, a production record may never claim a renderer model the tool did not report.

What the producer still owns is exactly what a producer should: the spec and the judgment. Every new generated image is recorded with the identifiers the engine returned for the image and its history entry, the actual provider, the prompt, the references, the original file, and the accept-or-reject verdict with its reason. New production records state the shared image policy as a field. Older productions made through the native route are left as they were, with their real provenance, because rewriting an archive to match a newer rule would be fabricating lineage.

The Voice Model Belongs to the Voice

The toolkit had carried a default model for speech. It was deleted on 2026-09-28, and new takes now inherit the voice engine's own per-profile choice: the newer model for Pippa and the channel's owner, the older one for every other voice unless it is chosen individually, and the owner can change either. A deliberate model test can still pin a model in one episode's script — the first such test compared two films on the newer model — and the pin is treated as identity, not a hint. It travels through normalization, synthesis, and every reroll; it forms its own cache identity; and a take is saved only after the voice engine's completed job receipt confirms the profile, the cache identity, and the model that actually ran. A missing or different receipt stops reuse of that take and stops the timeline from being built. It never triggers a quiet downgrade. Archived productions keep their audio and their provenance untouched.

The Reviewer List Belongs to the Arena

The review command used to carry its own list of reviewing brains and the command line for each. Since 2026-09-28 it carries neither. It asks the family's multi-brain arena for its published catalog of review routes — which harness reaches which brain, with what arguments, under what record policy — and turns the chosen route into a local process. A brain with no command line of its own is reached through the family's coding engine; a brain the catalog holds back is refused with the catalog's stated reason; and there is no local fallback table. If the catalog cannot be reached, the call fails and says where it looked.

That pairs with a ruling from two weeks earlier: a review runs the brain the operator named, and nothing else. A reviewer swapped silently because the named one was unavailable is a bug, not resilience, because the record then names a reviewer who never read the script. A stale local roster is the same bug one layer down — it makes the swap at install time instead of at run time.

A client should hold requests, not rosters. Every list a client keeps of what its owner offers — models, routes, reviewers, providers — is a second source of truth, and the day the owner changes its mind the client will be confidently wrong. Ask the owner at the moment of use, record what it answered, and fail loudly when it cannot be asked.

Code

Three local copies, and what replaced each·python
# BEFORE (mid-September): the client decides
IMAGE_ROUTE = {"codex": "native", "*": "engine"}   # per-producer exception
TTS_MODEL = "<older model>"                          # toolkit default
REVIEWERS = {"claude": ["<argv>"], "codex": ["<argv>"]}  # local roster + argv


# AFTER (2026-09-23 .. 09-29): the owner decides, the client asks
def make_board(spec):
    return image_engine.generate(spec, tool="codex_image_gen")  # every producer

def synthesize(take, script):
    pin = script.get("tts_model")          # None -> the voice profile's own model
    job = voice_engine.speak(take, model=pin)
    if pin:                                # a pin is identity: prove what ran
        r = voice_engine.job(job.id)       # the durable job row, not the reply
        if (r.id, r.cache_key, r.profile_id, r.state) != (
                job.id, job.cache_key, take.voice, "completed"):
            raise ReceiptMismatch(take.key)        # not this synthesis: stop
        if r.model_id != pin:
            raise ModelReceiptMismatch(take.key)   # stop; never downgrade
    return save(job.audio, job)

def review(script, reviewer):
    route = arena.catalog(task="review").route(reviewer)  # no fallback table
    return route.run(script)               # the NAMED reviewer, or a recorded failure
What an accepted generated board records·json
{
  "b07": {
    "sha256": "<hash of the accepted file>",
    "route": "ember",
    "verdict": "accepted",
    "review_note": "<what was read back, at what magnification>",
    "prompt": "<the complete prompt, labels quoted>",
    "references": ["<each reference and its role>"],
    "provenance": {
      "image_id": "<returned by the engine>",
      "history_id": "<returned by the engine>",
      "provider": "codex_image_gen"
    }
  }
}

External links

Exercise

List every place a client you maintain keeps a copy of something its provider decides — a list of models, regions, plan tiers, feature flags, available reviewers, supported formats. For each, write down who changes the real list and how the client finds out. Pick the one whose copy has already drifted, replace it with a lookup at the moment of use, record the answer the provider gave, and decide what the client does when the lookup fails.
Hint
The tell is a hardcoded list with a comment like "keep in sync with". That comment is an admission that two sources of truth exist. The failure mode to design for is not the lookup being slow; it is the client silently choosing something the provider would have refused.

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.