On July 9th, a merge landed in RISE that deleted the legacy scene parser. That parser was the renderer’s front door for twenty-five years; I hand-wrote the first version of it, and every scene the renderer has ever drawn came in through it or its descendants. The branch that replaced it carried 426 commits. At the end, the runtime speaks only the new path, the corpus is migrated (the new parser retains controlled compatibility with older headers), and the intent held throughout was that nothing about anyone’s workflow should break; where behavior did change, it changed on purpose, with a decision attached. This essay is about how.
This is the third essay in a series about rebuilding RISE as an agent-native tool. The first covered the destination, one canonical scene document that the human, the GUI, and the agent all edit through; the second covered the design review that shaped it on paper. This one is about paper meeting machine, and it is organized around five decisions that made an irreversible change safe: build the oracle before the kernel, put a clock on the architecture’s own headline, measure the migration before building it, treat divergence as a product decision, and sequence reversible work first.
The rhythm underneath all five was constant: build a small increment, measure it, put it in front of fresh adversarial reviewers with no stake in the change, fix, commit, repeat, with my own independent review at checkpoints. If the design review of the last essay transformed promises, this loop’s job was blunter: falsify implementation claims. Every major slice before the cutover produced at least one material correction under independent review, which is not an indictment of the builder; it is the base rate of building anything nontrivial, finally made visible because someone was looking.
The oracle before the kernel
The new kernel had one non-negotiable job: parse a scene into the lossless document and derive what the legacy parser derives. The first sequencing decision, made on the advice of an external review that refused to accept prototypes as evidence, was to build the comparison harness before the kernel it would judge: run both parsers, compare the derived scenes structurally, and let the diff arbitrate. “Matches the old behavior” is a claim people wave at constantly, and it means nothing until something can falsify it.
The oracle promptly earned its keep. The first in-tree kernel passed on the test scene, and a reviewer found three ways it silently disagreed with twenty-five years of precedent, all on plain sphere scenes. It derived chunks that were commented out. It took the first value of a repeated parameter where legacy takes the last. And a value-less line swallowed the next line’s token, producing a sphere named “radius”, which sounds harmless until you imagine an agent confidently editing the radius of a sphere named radius.
The verifier itself then went through review, which is the part I did not expect. The structural comparison was blind to a swath of render-affecting state (refractive indices, light power, camera intrinsics, accelerator settings), so equivalence-by-structure was a weaker claim than it looked, and the gates grew: structure first, then the values structure cannot see, and eventually pixels. An oracle is a claim like any other; the only difference is that when you strengthen it, everything behind it gets honest at once.
Four words and a demoted headline
The architecture was sold on one claim: editing one thing in a big scene costs on the order of that thing’s dependency closure, not the scene. Several correctness slices came and went without testing it, which the reviewers pointed out with increasing impatience, and when the cost work finally landed, the last measurement had been written as a reference to a known engine cost rather than a measurement, with a perfectly reasonable argument for why that was fine. I said four words: let’s do wall clock measurements.
The clock confirmed the claim and demoted it in the same breath. On the benchmark scenes, the incremental apply, the expensive-sounding part, ran at about four microseconds and stayed flat as the scene grew sixteen times, roughly ten thousand times cheaper than a full re-derive. And the cheap-sounding part, computing which chunks to re-apply, re-traced the whole reference graph on every edit and dominated the operation. The expensive part was already cheap; the bottleneck was hiding in the bookkeeping. Asymptotic analysis alone could not rank the two, because both had defensible complexity stories; only a measurement orders them. The fix came later (a maintained reverse-adjacency graph answers a closure in about 0.2 microseconds against 17,000-plus microseconds from scratch, on the same scenes), but the lesson stuck: a measurement is a claim that outranks the argument it replaces.
Measure the migration before building it
The migration plan inherited an assumption: the problem was the handful of scenes using imperative FOR loops and macros. Before writing the migrator, we built the gate first and ran all 376 corpus scenes through both parsers. The ground truth reframed the effort: 145 scenes already derived identically with no migration at all, and the dominant blocker was not FOR or macros; it was include directives, which the new single-file model does not follow. Flattening includes, a problem the plan barely mentioned, was the lever, and the first flattener that “worked” moved nothing because the corpus’s shared color library arrives through a bare legacy form of the load command that it silently dropped; handle that one obscure construct and 179 scenes converged at once. You do not find the lever by reading the plan; you find it by diffing reality against the plan and chasing what the diff says.
Faithfulness turned out to mean faithfulness to the quirks, not the math. The migrator folds old expression syntax through the legacy evaluator with its exact intermediate rounding, because a more accurate evaluator diverges from history at the fifteenth digit, and geometry is downstream of those digits. The strangest case: one scripting function draws from a process-global random sequence that is never reset, so a value depends on every call before it in the run, and the migrator has to replay the exact legacy state progression in corpus order rather than merely evaluate each scene correctly in isolation. There is something clarifying about maintaining bug-for-bug compatibility with your own twenty-year-old decisions.
Divergence is a product decision
Two scenes refused to converge, and they were the most interesting mismatch of all: the new path was more correct. The old parser pulled the color library in through a sub-parse that never populated a particular lookup table, so a translucent material silently skipped its energy conservation; flattening put the colors in the main parse, the table populated, and the material behaved as designed. Same chunks, different render, because the old behavior depended on a parse-order accident. The finding was engineering; the call was not. Accept the more-correct result, or suppress a correctness feature to reproduce an accident? I accepted the divergence, and the gate encodes that acceptance explicitly, so it fails only on genuine regressions rather than on ratified history.
Verifying any render-affecting change had its own twist, and readers of my earlier essay on stochastic products will see it coming. You cannot byte-compare two renders; rendering the same scene twice differs in ninety percent of bytes, because Monte Carlo noise is the medium. The parse is deterministic, the render is stochastic, so the oracle became statistical: the mean absolute luminance difference across the image, stable by the law of large numbers, separated migrated-versus-original from a deliberately broken control by a factor of about eight hundred. Building gates for a stochastic core means knowing which of your quantities converge.
Reversible first
The plan said drop the legacy parser once the corpus converts. The verification work redrew that map: the GUI’s save path did not serialize anything, it byte-spliced edits into source spans that only the legacy parser builds during a load, so deleting the old parser would cut the editor’s save out from under it. The deletion was not a parser move at all; it was gated on the editor serializing the document, which sat at the far end of the redesign. So the reversible work went first (the migrator as a real tool, the gates, the corpus conversion), and the irreversible part waited its turn. The sequencing constraint was invisible in the plan and became visible only by doing the verification, which is the general argument for doing verification early: the gates are not just things to pass, they are how the real boundaries show themselves.
The conversion had one moment of measured restraint: folding every include into every scene would have grown the corpus by 245 percent, to roughly three and a half times its size, mostly by inlining the same colors everywhere. That was measured before a single file was written; I said keep it lean, and each scene got only the colors it references.
The riskiest slice, pivoting the live edit path onto the document, is where “tests pass” and “done” parted ways most instructively. The staged version passed its tests and failed the two cases that actually matter: a property the scene file omits (most properties in most files) silently did nothing while reporting success, and the flagship watch scene could not be edited at all, because it routes edits down a fallback path the staging had not built. Later rounds added the same lesson twice more, as full re-derives kept resetting session state an edit must preserve, the active camera and the animation scrub position. Neither failure was in the code that was written; both were the cases that were not, because tests written from the implementation’s mental model share the implementation’s blind spots. The reviewer question that kept earning its keep was never “do the tests pass”; it was “what does the panel actually send, and does the hero scene work?”
Coming home
The merge that brought it all back was gentler than it had any right to be: five conflict hunks across the whole branch, because the semantic collisions had been scouted before the compiler saw them. The one moment of drama was sixteen spectral scenes whose golden checksums had moved about one percent, and the discipline held: a changed golden is a claim to prove, not a diff to accept, and an A/B derivation against the pristine branch traced the delta to a specific loader fix from the prior week. The goldens stayed honest, and so did the merge.
The parser is gone, and the renderer never noticed, which is a strange feeling for something whose first version I typed in graduate school. But the feeling worth ending the series on is different. The agent did not make this replacement safe. What made it safe was the system around the agent: an oracle built before the thing it judges, claims put on a clock, a migration measured before it was written, divergences decided rather than discovered later, reversible work sequenced ahead of irreversible, and independent review falsifying something in every major slice. Code generation was the least remarkable part. The decisions were the work, and they did not delegate.
A follow-up piece, separate from this series, will take the last question head-on: which models can actually run a loop like this, measured on real RISE agent tasks.