Case note · Written August 2026
Deterministic scaffolding, or let the model work
Where the code stops and the model starts is the most consequential line in an AI system, and it is usually drawn by accident.
Epigraph
The Engineer's Serenity Prayer
Set exactly as written. ASCII only; a typographic pass must not smarten it.
Grant me the discipline to make deterministic what must come out the same every time: the join, the sum, the key, the permission, the ledger; the courage to hand the model what has no right answer, only a good one: the meaning, the draft, the judgment, the question behind the question; and the wisdom to know the difference. Fixing one fact at a time; freeing one judgment at a time; accepting the edge case as the pathway to the rule; taking the data as it is, not as the schema says it should be; never asking the model to count, never asking the code to understand; trusting that if the facts are fixed before the reasoning begins, the answer may be reasonably right today, and, with every probe, better than it was.
01
Situation
The assistant on this site answers questions about my work. It has one job that sounds simple: say only what a versioned set of approved claims establishes, cite the claim behind every sentence, and admit when the record does not cover the question.
It runs on one Lambda. A question arrives, the system chooses a handful of claim records, a model composes an answer from them, and the answer goes back with the records it used. Nineteen claims, a few hundred lines of Python, a rate limit. Not a hard system, on paper.
The first version let the model do all of it: read the whole corpus, pick what mattered, write the answer, and add the citations.
02
Complication
The answers were fluent and the citations were wrong.
Not wildly wrong. The model would cite claim four for a sentence that really rested on claim six, or attach a citation to a sentence the corpus did not support at all, or invent a nineteenth-and-a-half claim by blending two. Read quickly, every answer looked well-sourced. Read against the corpus, too many had a citation that did not hold.
That is the failure mode that matters on a page a hiring manager reads. A wrong fact with a confident footnote is worse than no footnote. And the fix that comes to mind first, a firmer prompt, does not work, because the model is not disobeying. It is doing the thing it is good at, which is producing text that reads as if it were grounded.
The obvious answer, then, was to take the model out and render the claims directly. That answer was also wrong. Claim records read like a filing cabinet. A recruiter asking "how does he think about authorization" deserves a sentence, not a list.
03
The decision
The line moved. Everything that has to come out the same every time became code: which claims are selected, whether every citation points at a selected record, whether every factual sentence is covered by one. Everything that has no right answer, only a good one, stayed with the model: the composition, the emphasis, the order in which to say things.
Concretely, retrieval is deterministic, scored over tags and terms, and returns at most four approved records. The model is asked to write from those four and nothing else, and to return a structured envelope with the sentence-to-claim mapping made explicit. A validator then checks the envelope: every citation resolves to a selected record, every sentence carries one, no record is cited that was not offered. If the envelope fails, the answer is not patched. The system renders the selected claim summaries directly and labels the answer as a deterministic fallback, so the reader knows a person, not a model, chose those words.
The option I rejected was a second model call to check the first. It is a popular pattern and it would have caught most of the errors. It would also have doubled the cost of every answer and replaced a check I could reason about with one I could only sample. A judge model is a good tool for grading a test set. It is a poor tool for guaranteeing a single answer to a single reader.
04
What it cost
The answers are drier than the model would have written on its own. Composing from four records with every sentence accounted for produces prose that is careful before it is warm. I decided that on this page careful is the right register, but it is a real loss and I notice it.
There are two code paths to test instead of one. The fallback has its own rendering, its own copy, and its own way to be wrong, and every change to the claim schema has to be checked against both.
And the site refuses to simulate streaming. An earlier version animated fake tool calls around a single whole-response API call, because a moving trace looks alive. It was deleted for being a lie about the process, and the honest version is less impressive to watch. The receipt under each answer, route, evidence count, generation mode, validation result, corpus version, is the replacement. It does not move. It is simply true.
05
Lesson
The line between code and model is not a technical detail to settle late. It is the design. Draw it by asking, for each step, whether two runs must produce the same result. If yes, it is code, however tempting it is to let the model handle it. If no, hand it to the model and stop trying to make it deterministic with prompts.
Then write the test that tells the difference, because the failure mode of getting this wrong is not a crash. It is a confident answer nobody checks.
Code for what must be the same. Model for what must make sense. Tests to tell the difference.