The main video-generation service was built around a single on-camera presenter. Every schema field, every gate, every critic assumed one person speaks, one voice binds, one face gets checked. A real reference ad — a mother-daughter interview, one continuous take, zero cuts — needed two. Extending "one presenter" into "a cast of N" turned out to touch almost every layer of the pipeline at once: voice cloning, plan authoring, the review gate, the render path, and the critics that grade the output. And nearly every layer, once touched, turned out to have already been touched incorrectly at least once before anyone noticed.
A feature that is correct, tested, and merged is not the same claim as a feature that fires on the input it was built for. Check the second claim separately, every time.
The probe that made the whole feature affordable
Before any of this was worth building, one question had to be answered: can the vendor even render two distinct, speaking people in a single generation, or does a two-person ad have to be stitched from two separate one-person clips? PR #487 answered it with a single paid probe — about $1.30 for one Kling v3/pro clip — using two image-set elements, each carrying its own bound voice, dialogue written as Name: "line", and @Element1/@Element2 naming which element carries which line. It worked: Kling v3 renders two people with two bound voices in one generation. That result is what let a mother-daughter exchange live inside a single scene rather than being assembled across a cut — which mattered immediately, because the actual reference this feature was built against has zero cuts at either of the pipeline's own scene-detection thresholds.
The same PR closed a smaller, sharper bug hiding underneath the probe: minting a Kling voice clone from a sample under five seconds returns a 422, and the function responsible for minting one caught that throw and silently returned undefined instead of propagating it. Whether a voice could be minted at all had been decided, invisibly, by how fast that particular voice's picker-preview line happened to be read aloud — one voice minted with 0.29 seconds of margin, another failed outright and silently fell back to the vendor's native voice with nobody told. The fix is a dedicated, separately-cached line built to be long enough for every voice in the catalog, so the mint step is never gambling on a sample recorded for a different purpose.
The defect that had nowhere to be flagged
PR #488 is where "cast" becomes a real concept in the schema, and the PR description states the motivating defect in numbers worth sitting with: on one measured job, the reference analysis correctly saw both people in a scene — the persisted prompt literally read "daughter turns her head to the mother to ask her age" — and then the same prompt asserted "one identical speaker for the whole shot," handing one avatar both halves of a two-line exchange. Eight of sixteen scenes in that plan carried a question mark that should have been two different people asking and answering. Nothing in the pipeline's own contradiction-detection flagged any of it, for a reason worth internalizing: the schema had nowhere to put a second person, so no guard could contradict a claim the schema couldn't even represent. A validator can only catch a value disagreeing with another value it's allowed to hold.
What landed is a single derivation point — resolveCast, sceneCast, sceneSpeakers, and a cast-aware identity reference sitting beside the existing single-person one, built so that cast.length === 1 is simply the ordinary, common case rather than a special one requiring its own code path. And landing beside that feature, in the same PR, is a hard 400-line file-size cap enforced at lint — a deliberate choice to pair a significant new capability with a structural constraint on how large any one file touched by it is allowed to grow, rather than treating code-quality discipline as a separate cleanup pass to get to later.
Inert because the stored reference already knew
PR #490 is the first of several PRs in this arc with the same shape, and it's worth naming that shape explicitly: a feature ships correct and tested, and then a sweep across real references finds it produces nothing, on every single input it was built for. Six references parked at the plan gate, $1.75 spent, and castProposal: null on all six — including the two-hander this entire feature exists for. The cause: the field that should have carried cast inference was hardcoded undefined specifically on the "stored rip" code path, and every one of the pipeline's six fixed references uses a stored rip. Correct, tested, merged — and structurally unable to fire on the only inputs available to test it with.
The fix is a schema-version bump rather than a quiet backfill, and the reasoning behind that choice matters: making the new field optional-and-absent would leave a reference with "no cast recorded" looking identical to a reference with "one person, measured." Those are different claims — one is missing data, the other is a positive result — and conflating them is exactly what let this go unnoticed. Bumping the schema version forces every existing stored reference to re-derive once, at roughly $0.46 each, after which cast: [] means measured-and-one-person rather than never-checked.
Two writers, and the second one wins by saying nothing
PR #491 is a smaller bug with a classic shape. On the reference this feature targets, the blueprint inferred the cast correctly — "reference casts 2 people: A=woman, mid-40s, B=woman, mid-70s," apparent age and sex only, exactly as specified — and the persisted result was null anyway. The proposal object was read and modified by one function earlier in a call chain, and then a second function further down rebuilt the same overall object from a literal that didn't share the first function's snapshot. Two writers touched the same field; the second didn't know the first had written anything, so its omission silently won. The fix collapses cast-proposal writing to the one literal that actually persists, removes the earlier write entirely, and adds a test that plants the old two-writer shape specifically so it can watch that shape fail before trusting the fix.
An honest handoff about what isn't built yet
PR #492 is a documentation PR, and it earns a place in this story for what it leads with: everything merged on the main branch up to that point detects a cast and parks it as a proposal, and nothing yet binds that proposal to actual avatars — every plan still renders single-presenter. The handoff frames that gap as a designed fail-safe rather than a shortfall: a guessed second person must never reach a paid frame without a human confirming it first. It also writes down, in advance, two traps the next PRs would otherwise rediscover the hard way — that a stored rip hides new inference unless the schema version is bumped, and that the literal-rebuild pattern from #491 will silently discard anything patched earlier in the same function. Naming a trap once, in writing, before someone re-falls into it, is cheaper than debugging it twice.
Face models that had never run anywhere
PR #493 is where rendering catches up to detection, and it surfaces an infrastructure gap that had been invisible because the check it belonged to always reported the same safe-looking value. The identity-drift check — verifying a rendered face actually matches the reference face — depends on two ONNX face models under an environment-configured directory that had never been set on any machine, in any deployment. Every run for the check's entire history had simply recorded "not checked" rather than failing loudly, which is its own quiet failure mode: a check that can't run and says so cleanly is very different from a check that silently reports green. Once the models were provisioned through the same Drive-folder pattern the pipeline already used for avatars, rips, and products, the check immediately started producing real numbers — a same-person control pair scoring 0.899 cosine similarity, a different-person control pair scoring 0.319, and the new two-shot's left-side face scoring 0.742 against the intended presenter, turning "does this look right to me" into an actual measurement for the first time.
Cast-aware critics, and a rule against never quite paying down debt
PR #494 extends the pipeline's automated critics so they stop asserting there is exactly one person in every frame — a hardcoded assumption that would otherwise fail every two-person shot by definition, regardless of whether the shot was actually good. The same PR adds a second, unrelated but complementary discipline rule to the 400-line file cap introduced in #488: a file may shrink, but a file you touch may not grow, measured against its state at the merge-base rather than its state at the start of the session. The PR's own description is candid about why that specific rule was needed — it names three separate times, in that same session, the author had kept a 2,700-line file's line count flat by trimming a comment elsewhere to win back the one line a real change had added, which is compliant with "must not grow" in letter while defeating it in spirit. Closing that loophole meant the four files that had been carrying debt finally got split into real leaf modules instead of staying whole under a technicality.
The plan gate that finally has one writer, and the UI that calls it
PR #497 fixes a gap that had made every mechanism built so far unreachable from a real job: the field meant to hold a confirmed cast had no writer at all. An earlier detection step wrote a cast proposal and left a comment saying the operator binds each slot at the plan gate — except that gate didn't exist yet, so the pipeline always fell back to its legacy single-person path regardless of what had been detected. The PR adds the missing route, deliberately built as the single writer for that field, specifically because the proposal had already been clobbered once by a second writer in #491. The route also refuses two specific unsafe requests outright: re-casting after any clip has already been paid for — because the first scene's voice and frame are inherited by every later scene, so a mid-run recast would produce an ad whose first half is one person and second half another — and binding an avatar with fewer than two reference photographs, since the vendor 422s on a single frontal photo alone.
PR #498 is the honest follow-up: the route from #497 shipped, and nothing called it. This PR is the UI screen that does — one row per proposed cast slot, an avatar picker restricted to avatars the vendor will actually accept, and a voice picker with audition built specifically because a paid probe had found Kling capable of producing two clearly distinguishable speakers that matched neither of the two voices actually bound. Placed at script review, the last free moment before the frame step starts spending money, because the same re-cast restriction from #497 applies here too.
Wired, bound, confirmed — and still inert
PR #500 is the PR I'd point to as the center of this whole story, because of what a fresh sweep found after every piece above had already shipped and looked complete. On a real plan-gate sweep, the reference was read correctly as a mother-daughter two-hander and the cast proposal was correct. The planner then produced fifteen presenter scenes with cast: undefined and lines: undefined — a solo monologue, cast and all. The cause: the planner is only told about a confirmed cast, correctly, so an unconfirmed proposal can't change a plan the operator hasn't approved yet — but on the very first pass nothing is confirmed yet, so the schema handed to the planner strips the cast and lines fields entirely, and the planner is literally unable to author a two-hander on that pass. Nothing re-planned afterward to give it a second chance. Binding a cast against a plan authored under that stripped schema changed nothing that would ever render: every scene fell back to the first cast member, and the second person never reached a frame. Every PR from #493 through #498 was individually correct and, end to end, inert — the exact failure shape #490 had already produced once, now recurring one layer higher in the stack.
Moving the slow step out of the request that can't wait for it
PR #503 fixes the mechanism that #500 required: re-authoring a plan around a newly bound cast. That re-authoring is a vision call over the reference's keyframes, and it takes minutes — which is far too long to run synchronously inside an HTTP request, and a request that dies partway through a re-plan is also exactly the window where the cast binding itself could be lost, because the object rebuild that already caused #491's bug doesn't wait for anything to finish before it runs. The fix splits the operation cleanly: binding itself stays synchronous, because every refusal needs to name a specific clip up front rather than fail invisibly in a background job nobody is watching; re-planning moves into the job's own existing background worker, where retry, resumption, and container restarts are already handled rather than needing to be reinvented for this one feature.
The fields that reached the schema and not the scene
PR #504 closes the arc by finding a fourth and final way the same intent — a genuinely correct two-hander plan — failed to reach an actual scene. On this job, the planner authored real, correct two-person dialogue, and the pipeline's own plan-consistency scanner flagged five scenes for wanting two people from a scene the code still read as casting one. The cause, again: a function that maps a planned beat onto a job scene does so by naming each field it carries over by hand, and any field it doesn't explicitly name simply doesn't exist on the other side — the exact same shape as an earlier, unrelated bug where a persist step dropped an energy-curve field for the identical reason, a fact the file's own comment already recorded one block up. The fix stops relying on a second hand-maintained list of fields to carry over and derives the guard from the schema itself, so a new field fails loudly by default until someone deliberately marks it either carried or intentionally dropped. It caught a third silently-dropped field, unrelated to cast, on its very first run.
The pattern: wiring is a claim, and it needs its own proof
Every stage of this feature — inference, proposal, binding, re-planning, scene construction — was, at the moment it merged, individually correct against its own tests. And at four separate points in the sequence, the thing built on top of it found that the previous stage's correct output never actually reached it: a stored reference that skipped inference entirely, a second writer that silently discarded the first, a stripped schema that made the planner incapable of using a confirmed cast, and a hand-written field mapper that dropped exactly the two fields the whole feature depends on. None of these were caught by unit tests, because each stage's own tests only ever exercised that stage in isolation. They were caught by sweeps — running the real pipeline against real references and reading what actually got persisted at each hop, rather than trusting that a green test suite at each layer implies a working feature end to end. Adding a cast wasn't hard because casting two people is conceptually hard. It was hard because "wired all the way through" is a separate claim from "correct," and this pipeline had to verify that claim four times before it was actually true.