The main video-generation service's animated lane shipped and worked — for a solo presenter. The moment a real multi-person cast ran through it, the feature's own single-presenter assumption surfaced as a visible, embarrassing defect: three people in one frame, one prompt, and only one of them actually drawn as a cartoon. Getting from "works for one person" to "works for a cast" touched the stylization pipeline, the identity references handed to the clip model, the planner's own vocabulary, and a caching layer that was quietly re-buying the most expensive image a run makes every time the container restarted.
A bail-out guard written for "this isn't supported yet" and a bail-out guard written for "this is intentionally out of scope" look identical in a diff. Only one of them should still be there once the feature ships.
A guard that quietly made multi-person impossible
PR #1067 found the root cause sitting in a single early return. ensureStylisedCharacter bailed immediately whenever a job's cast had more than one member, with a comment explaining the deferral: a multi-member animated cast would render from raw photographs "exactly as it does today," rather than from stylized twins nobody had built yet. That comment was accurate the day it was written and had quietly become a landmine, because castIdentityRefFor pins a cast member to its photograph for the entire run unless that member's first appearance happens to be solo — and in an ensemble, nobody's first appearance is solo. A run on three men at one table proved it by accident: one member's identity reference happened to already be a stylized image, so he rendered "unmistakably Pixar" — round eyes, smooth bald head, caricatured features — while the other two, pinned to ordinary stock photographs, rendered fully photoreal. Same frame, same prompt, three different identity references producing three different mediums.
Fixing the frames alone would have shipped a new, subtler version of the same bug. PR #1068 found the other half: the two code paths that resolve a cast member's reference photographs for a clip — as opposed to a still frame — had never asked the question at all, reading straight from the catalog. A single-presenter module had already worked this out explicitly, with a comment reasoning that handing back real catalog photographs "would bind the voice at the price of the look, and the look is what the operator asked for." That reasoning simply hadn't been copied to the cast paths, so an animated two-hander would have opened on a stylized start frame and then handed the clip model several photoreal stills of the real people as the thing to match motion against — the exact failure mode a decision-log entry already called "the standing failure," now proven on a cast rather than a solo. The fix made one identity-twin derivation answer the question once, with three consumers reading the same answer instead of three places re-deriving it differently.
Independently stylized is not consistently stylized
Even after every member in frame was correctly drawn rather than photographed, a reviewer flagged that "the friends looks differently animated" — the protagonist fully stylized, a companion barely so. PR #1122's own first diagnosis was wrong, and it says so directly: the author expected a member had fallen back to a raw photograph, and the cost ledger disproved it before any code needed to change — every member had in fact billed a stylized-twin render. The actual defect was structural: each twin came from an independent, unseeded image-edit call over the same fixed prompt and a different source photograph, with nothing comparing the three outputs to each other. Three independent calls against one text description land at three different points on a photoreal-to-stylized spectrum, the same way three artists working from one written brief and no reference sketch will draw three visibly different styles. The fix didn't touch the prompt at all — it passed the first finished twin along as a second reference image to every subsequent member's stylization call, so the second and third renders have something concrete to match rather than another independent roll of the same dice. The number of paid vendor calls didn't change; what each call was given to work from did.
A plan that widened the cast and forgot to tell everyone
A separate pass, holdCastAcrossNarration, exists to keep the same person's face on screen across a narrated sequence — real identity continuity, and the reason the pass exists at all. PR #1086 found it conflating that fact with a second, unrelated one: "all of the cast are present." On one run, the planner wrote a beat as a two-shot of two specific friends; the hold shipped it as three people, discarding which pair the planner had actually staged while quietly widening the headcount. The root cause was a regex trying to infer shot size from the prose description of motion, returning nothing usable on ten of twelve beats — so the pass fell back to taking the full cast union almost every time, which is precisely the "uniform three" its own code comment says it exists to prevent.
Widening the cast without updating everything downstream that described the old, narrower staging produced two more bugs in the same shape. PR #1070 caught frames being graded against acceptance criteria the plan itself had made impossible — eight beats in a row scored against "one person," rendered with two or three people in frame, because the hold rewrote the cast list but nothing touched the grading criteria that referenced the cast size directly. PR #1072 found the shot's own motion description — the field that tells the image model how the shot should actually look — suffering the identical staleness, and called out why it's a harder fix than the acceptance criteria: criteria can simply be dropped when they go stale, but motion is the entire shot description and can't be discarded, so the fix moves the cast to match the shot's declared size instead, always trimming to the same anchor member in a consistent order rather than an arbitrary one.
Teaching the planner to say who a shot is about
Once a shot could legitimately hold two or three people, a new question had no owner at all: of the people present, who is the shot actually about? PR #1087 found every downstream consumer of that question — which member gets photographs, which gets the element label, which gets the voice — silently defaulting to index zero in the cast array, agreeing with each other by coincidence rather than by any actual contract. A reviewer's real complaint, "who is John? we're zooming in on the guy in the middle, but apparently John is the one in the blue collar," was this exact bug: the shot's composition followed array order, and array order read left-to-right by whoever was authoring the frame.
The fix had to clear a real constraint first. The team had already ruled out solving this with more prompt injection — the project's own decision log states the principle plainly: "a prompt guard is a guess; a measurement is not" — and a vendor capability sweep across five different providers confirmed there was no structured subject-of-camera binding available anywhere to lean on instead. So the planner itself was given a new field to declare which specific member a shot is about, rather than asking a human to intuit it from prose or asking a model to infer it from context. PR #1088 found two fresh bugs in that same change within a day of shipping it: the new directive told beats to say "the subject" while every existing substitution pass still only recognized the literal phrase "the presenter," so the new field fired on zero live beats until the vocabulary was widened; and the directive itself had quietly asked for two different things — "whoever the camera favors" and, separately, "whoever the line is about" — which genuinely diverge on a reaction shot. PR #1079 is the honest coda to the same arc: an earlier subject-clause fix had been reported as working, verified off the rendered board frames, and the report was wrong — the clause had never actually reached the vendor request at all, because it had been attached to the wrong one of two parallel prompt-assembly paths, and the real improvement that run showed came from an unrelated change in setting and cast size.
A redeploy that silently re-bought the most expensive image in the run
PR #1093 is the sharpest bug in this cluster because nothing about it is visible in the output — only in the bill. The stylized "twin" is the single most expensive image a run generates, and the code cached it by checking whether the file already existed on disk. That check was written against Railway's ephemeral container filesystem, which a mid-run redeploy wipes clean. A real run showed the signature directly in its cost ledger: the same stylized-character render, for the same member, billed twice at the same price, tagged with two different process identifiers — the unmistakable fingerprint of a container restart. The fix had, in fact, already been half-written down as a TODO in an unrelated module months earlier, explicitly anticipating this exact failure for text artifacts and noting that binary artifacts like images would need the same treatment "later." Later had arrived in the form of real paid, wasted spend, and the fix extended the existing download-and-restore-from-Drive path to cover binary files the same way it already covered text ones.
Letting a mascot share the frame instead of banning it
The last gap in this arc wasn't about people at all. PR #1095 found that a mascot character sharing a frame with human cast members fell into the pipeline's "people-free" rendering branch by construction, regardless of what the actual plan called for — meaning an ad whose reference genuinely depends on its mascot appearing alongside its humans in most shots could not be reproduced at all under the existing binary. A second, related bug fell out of fixing the first: a mascot-only beat with no human cast was being given the generic product negative prompt, which explicitly bans "arm, silhouette, figure" — banning the exact anatomy a mascot character is made of, because the two files responsible for choosing the right branch disagreed on what information they even had access to decide with.
The pattern: a feature isn't done at one, it's done at N
Every bug in this arc has the same shape: a path built and verified against exactly one cast member — one presenter, one identity reference, one subject, one cached twin — that silently stopped being correct the moment a second or third person entered the frame. None of these were algorithmically hard problems. They were places where "the" quietly meant "the one," and nobody had gone back to ask what happens when there's more than one. The through-line that actually closed each gap wasn't a smarter model or a cleverer prompt — it was measuring the real artifact a run produced, over and over, instead of trusting that a fix verified on a solo presenter would generalize for free.
Top comments (0)