Keep the Factory, Ship the Result
updated
Confidence the pipeline is real and running; the factory-versus-output framing is my argument from building it
“Civilization advances by extending the number of important operations which we can perform without thinking about them.” — Alfred North Whitehead
I built an eval to tell me whether my agent’s skills were earning their place. For a while it said they weren’t — clean, green, confident. Then I looked at how it actually ran: it injected every skill on every case, whether or not the skill should have fired. I’d frozen the wrong test. When I gated it to load a skill only when it should actually trigger, the verdict reversed — the skills clearly helped, most of all for the cheaper models. The eval hadn’t drifted from a moving world; it had frozen the wrong world from the start. But the lesson generalises, because the world moves too: a rule that said use class-based components was right for years and is now simply wrong — hooks and function components moved the standard out from under it. Nobody repealed that rule. The ground did.
An eval is judgment, frozen. A rule is a standard, frozen. A trained agent is judgment frozen at training time. Freeze any of them and it starts going stale — either you froze the wrong thing, as I had, or the world moves out from under the right one, the way a reading eye trained on last year’s idioms stops snagging on the ones since deprecated. Everything you ship is frozen judgment, and frozen judgment drifts. You can’t fix that by refusing to freeze; a standard you can’t write down isn’t a standard. You fix it by putting the ceremony on the right layer — a small principle constitution you amend deliberately and rarely, under process, rather than one you never touch, with the specific, operational rules changing faster underneath it. Constitution versus statute: the two layers change at different rates and with different ceremony — not a core frozen for good and a fluid rest. Freeze everything and you go rigid; freeze nothing and you drift. Get the layer wrong and your evals rot the way a trained reflex rots. That’s the argument, and it’s the part of the current agent excitement nobody is writing down.
A word on where this sits, because the lane next to it is crowded. The workflow-versus-agent line is already drawn, and drawn well — Anthropic’s Building Effective Agents is the canonical cut (workflows are predefined code paths; agents dynamically direct their own processes), and a 21-pattern catalogue covers much of the rest. I’m not re-drawing that line. I’m going a layer down — past the question of what shape your system is, to the thing you verify with, and why that thing expires. One tell the taxonomy writing shares: it shows the happy path and never the failure mode, which is survivorship bias pointed at the writing itself. Here the failure mode is the whole point, so I’ll lead with where it breaks.
Bottom line up front
- Everything you ship is frozen judgment, and frozen judgment drifts. A mechanical check and a trained agent both go stale. The factory lasts longer only because it’s the part you keep maintaining.
- The standard needs a constitution. Anchor a small principle core; let the specific rules change under it. Otherwise your evals rot the way your reflexes do.
- Non-determinism is a generator, not a runtime. You don’t want unwarranted probabilistic behaviour on the critical path — you want output you can check. The agent’s job is to produce something warranted, then get out of the way. The same boundary runs inside the system: decompose the agent the way you’d decompose a function and the model quarantines itself to the stages that need it — in my reviewer, two of the five stages need no model at all.
- Keep the factory, ship the result. The factory — the loop that mines and mechanises the rules and keeps them good — is the half you maintain; the mechanical checks it emits (and, one day, trained agents) are the perishable output you ship. (That this factory also transfers across domains and time is its own argument — The Harness Is the Product.)
- Persistence is a feedback edge. Saving state that later runs read back turns a stateless workflow into a loop — an edge from this run’s output into the next run’s input. That opens a feedback edge you have to govern; the risks are drift, gaming, and lost reproducibility. Keep the fast path pure; quarantine every write into a governed, human-gated outer loop. Two safeguards are weaker than they sound: suggest, never suppress still suppresses if the suggestion eats a finite budget, and the human gate stops the dataflow without breaking the loop of influence.
- The human doesn’t leave; the job moves up. Checking the agent’s code may be temporary. Owning the standard — deciding what “correct” means — isn’t, because an optimiser can’t originate the target it optimises toward.
The standard needs a constitution
Start with the fix, because it’s the load-bearing idea: tier the standard. Keep a small principle core — a mental model and a handful of rules you’ve authored deliberately and amend rarely, under process, not a core you never touch. Let the specific, operational rules change underneath it, derived from current practice but constrained to serve the principles. This is constitution versus statute: the constitution is hard to amend, not never amended; the statutes track conditions but must stay consistent with it. The structure isn’t new. It’s how a legal system works, and it rhymes with Lakatos’s picture of science, a protected hard core wrapped in an adjustable belt of hypotheses (though in that picture whole programmes still get abandoned — nothing is permanent). Constitutional AI is the nearest thing in AI, a small set of principles steering a model’s behaviour, though it uses them to train rather than as a live frozen/mutable split. Freeze everything and you’re rigid — the standard can’t track a moving target. Freeze nothing and you drift — the rules chase fashion and get gamed. The frozen core is what tells you a specific rule has gone stale: a rule that no longer serves a principle is done.
I have a head start here that most people don’t, and it’s the concrete version of all this. My principle core is already written — the mental model and rule set in the two books I wrote about thinking about code. That’s the constitution. The operational rules in the reviewer are the statutes, and the factory’s real job is to keep the statutes consistent with the constitution as the world changes. There’s even a test for whether those principles are really principles: try generating a rule set for a domain the books weren’t written for. A principle that can’t produce a good rule somewhere new is suspect — probably a local habit wearing a principle’s coat. Passing doesn’t prove it’s bedrock, since a merely general heuristic travels too, but failing is a strong tell.
Non-determinism is a generator, not a runtime
The hype treats the non-deterministic system as the destination — the goal is an agent that dynamically directs itself. But for almost anything that matters, an unwarranted probabilistic runtime is the opposite of what you want. You want the code that runs your payments to behave the same way every time — or at least to trip a check when it doesn’t.
Non-determinism earns its place as a generator: you use the messy, probabilistic, occasionally-brilliant agent to produce something you can warrant — a function, a rule, a check — and the thing on the critical path is that warranted artifact, not the raw agent. Usually the artifact is deterministic, because deterministic code is the cheapest thing to warrant: you test it, and it runs the same way at 3am under load. That’s the common case, and it’s why “generate the deterministic thing, then ship the deterministic thing” is the default.
The precise claim is narrower than “determinism good, non-determinism bad.” You can keep a probabilistic component at runtime — a model in the loop — as long as it sits behind a deterministic warrant that catches the specific failure the check encodes. What you can’t ship is unwarranted non-determinism on the critical path, which is exactly what “just run the agent graph in prod” asks for. The agent is good at what non-determinism is good at: exploring, drafting, covering cases you’d miss. The warrant is what makes its output safe to depend on — for the property it encodes, not in general. Confuse the generator with the guarantee and you’ve put the exploration engine where the guarantee should be. The exception is genuinely open-ended work — a brainstorm, an exploratory search, a conversation with no single right answer — where you run non-deterministic and simply forfeit the warrant, because you can’t certify what you can’t check.
And none of this is new — only the layer is. The producer was always non-deterministic: a person writing code is a non-deterministic process that yields a deterministic product, and the product is deterministic on purpose — a machine that does the same thing every time is the whole reason we reach for computers in the first place. “Get comfortable with non-determinism” and “software just becomes English” have it backwards; you can’t run English, you run the artifact. What actually changed is that AI slid a second non-deterministic layer between the intent and the artifact — intent, once through a person, now through a model, and only then the deterministic thing. So the artifact needs checking one layer deeper than before, and that checking — below the AI layer, against the determinism you actually wanted — is where software engineering has moved.
Draw the boundary inside the system
The generator-versus-runtime split has a sharper form once you look inside the system. The useful thing isn’t a graph of five clever agents; it’s a deterministic factory with a couple of deliberately non-deterministic stages inside it. The boundary between “needs a model” and “must not have one” doesn’t run around the agent — it runs through the pipeline, and most of the pipeline lands on the deterministic side.
Concretely. My reviewer began as one do-everything agent: here’s the diff, here are the rules, find the problems. Non-deterministic, expensive, untestable — a monolith. It’s now five single-concern stages. A scout notices candidate sites; a gate prunes them; a deep pass judges what survives; a decision step applies the matrix; a write step renders the verdict into prose. Name what each stage does and the boundary draws itself: the scout and the deep pass need a model, because noticing and judging are perception. The gate and the decision are pure functions — no model at all. The write step is a cheap model doing nothing but rendering text. The expensive, non-deterministic model is quarantined to the two stages that actually need one; the wobble has nowhere else to leak, because everything around it is code.
None of that is a new idea, and that’s the point. It’s the oldest idea in software — make each thing do one thing — applied where people stopped applying it. We treat agents as magic: tell it what you want, paste the whole world into one prompt, and hope. Nobody would build a codebase that way; everybody builds agents that way. Decompose the agent the way you’d decompose a function and determinism, cost, and testability fall out as consequences, not features you bolted on.
The graph itself isn’t the insight — everyone has the graph. DSPy names the pieces (typed signatures, composable modules, optimisers that tune each stage); model cascades route the cheap model to the easy step; the compound-AI writeups make the same model-to-system case. None of them forbids the part that carries the boundary here — plain deterministic code doing the stages that need no model, composed around the ones that do; DSPy wraps ordinary functions around its modules too. So this isn’t a move past any of them. It’s the ordinary engineering they all allow and agent-builders skip, because the pull is to make every stage a model call — the hype is selling the model, and a gate that’s just a function doesn’t look like the product. I rebuilt these shapes by hand before I knew their names, which is the cleanest evidence I can give that it’s engineering, not a framework’s trick.
One of them does come with a number, and it’s a number on the flow rather than on the model. AlphaCodium wraps a fixed, ordered pipeline around GPT-4 — self_reflection, then possible_solutions, then generate_ai_tests, then initial_code_generation, then iterating the code against public_tests and against ai_tests — and on the CodeContests validation set that took pass@5 from 19% to 44% against prompting the same model directly. Same model, better factory. The part I’d underline here is the cost: 15–20 model calls per solution, four orders of magnitude fewer than AlphaCode’s brute-force sampling. The deterministic scaffolding is not the expensive half of the system. It’s the thing that lets you stop paying for the expensive half.
Keep the factory, ship the result
What’s actually reusable isn’t your personal graph. A graph you hand-carve for one task is a scaffold you throw away when the job’s done, and it only ever helped you. The reusable asset is a shared workflow: one box, rules baked in, that your whole team pushes work through. One person shouldn’t rebuild the reviewer for every pull request; the team runs every request through one reviewer. And the value there lies in what the workflow knows (the rules) and the machine that keeps those rules good, not in the topology. That machine is the factory, and it works the opposite way to “run an agent graph in production.”
The learning loop — the part that makes the reviewer better — I run by hand. Slow, deliberate, dev-time work: when the deep pass drops a lead, I look at it, and if it’s a real miss I turn it into a recorded exception and then, where I can, a mechanised check. That loop is non-deterministic and human-gated, and it never runs in production. What runs in production is the output: a set of deterministic mechanical checks, plus a shared workflow the whole team pushes work through, behaving the same way every time.
Two things are easy to conflate, so let me pin them. The factory is that learning loop, the rules it’s refining, and the principle core behind them — dev-time, run by me, never in prod. The output is what the factory emits: the checks and the workflow that do run in prod. (The agent that drafts a rule is a tool inside the factory; the checks it helps produce are the output. The word “result” lands in two places — the generated artifact and the factory’s product — but the rule holds: agent generates, factory ships.)
The loop needs something to feed it, and dropped leads aren’t the only source. Here’s a second one I’m testing, and I’ll label it a hypothesis, because that’s what it is: run the work on a model too cheap to do it, and watch where it breaks.
The reasoning is the boundary again. Where a rule has been reduced to a decision procedure — an explicit list of observable conditions, with the verdict recomputed in code from which ones the model ticked — the model isn’t judging, it’s box-ticking, and a small model box-ticks about as well as a big one. Where the judgment still lives in the model’s head, it doesn’t. So the places a cheap model falls down should be, roughly, a map of the judgment I haven’t encoded yet. And the response to a cheap-model miss would then be to go encode that procedure — permanent, deterministic, improves every model — rather than to pay a nine-times multiple forever so a bigger model can re-derive the same call on every run.
Measured so far, that’s suggestive and no more. On thirteen planted-bug fixtures, three runs each, the strong model caught all thirty-nine and the cheap one thirty-eight — and the single miss landed in the one pass with no rules behind it at all. That’s the prediction. It’s also the subtlest bug in the set, and I can’t pull those apart: the cheap model fails where judgment is unencoded and the cheap model fails on hard things explain the result equally well. Nor was the cheap arm simply worse — it produced no off-target findings at all. What it lost was consistency in naming what it found, and the deterministic fix for that is already in flight, which may take a good part of the gap with it.
So I’m not claiming a router. I’m claiming the factory has a second instrument available to it: cheapness as a probe, where a failure is a question about the work rather than a verdict on the model. The economics pay off conditionally — a procedure has to be reused often enough that maintaining it costs less than repeatedly buying the judgment — but where that holds, encoding compounds and buying a bigger model doesn’t.
I used to describe this as “ship the product, not the harness,” as if the harness were something I kept around out of tidiness. That’s wrong, and the correction is the whole point. The distinction that matters isn’t harness-versus-product; it’s factory versus output. You keep the factory. You ship the output.
You keep the factory because the output is perishable. It freezes the moment you ship it, and a trained agent — the thing I’d like and don’t have yet — would freeze the same way, which is why even a shipped model has to sit behind the checks rather than replace them. Frozen things drift: the framework moves, practices change, and last year’s right check now fires on code that’s fine or misses code that isn’t. The output rots. The factory rots too: its rules, even its principles, can go stale. But the factory is the part you’re actively tending, so that’s where the rot gets caught and repaired. The output is frozen and left to time; the factory is frozen and maintained. That’s the point of keeping it: the output rots on its own, and the factory is where the rot gets caught and repaired.
Ship the output. Keep the factory.
Persistence is a feedback edge
There’s a quiet reason the factory’s slowness is a safeguard, not a limitation. The reviewer is pure across runs: f(input) → output, no history term, one run never changes what the next one sees. That statelessness is a big part of why you can trust it — nothing carries between runs to drift on, because it isn’t feeding on its own past. (Statelessness buys no-drift; replay needs determinism on top — a stateless model call still won’t replay.)
The moment you add memory that later runs read back, it becomes f(input, state) → output, state', and that saved state adds a cycle to the graph: an edge from this run’s output into the next run’s input, routed through the store. You didn’t draw the loop; the store closed it. The edge lives in the storage layer, not the diagram, so it’s easy to miss. And it opens a feedback edge you now have to govern — the risks statelessness was holding off: lost reproducibility (you may not be able to replay without rebuilding the state), drift (the system can start feeding on its own prior outputs), and — because there’s now a cycle — something to game. None of these is automatic; they’re what the edge exposes you to. This is the machine-learning-systems hidden feedback loop, and its cousin CACE: changing anything changes everything.
So the design rule falls out of the topology, not out of taste: keep the fast path pure and stateless, and quarantine every write into an explicit, governed outer loop that a human gates. That is exactly what the factory is. The reviewer doesn’t auto-memorise; its learning — a dropped lead becoming a mechanised check — is a deliberate write in the slow loop, anchored by a person deciding the miss is real. Auto-memory on the fast path is the opposite move: a loop that can drift where you can’t easily reproduce or debug it.
Designing the next version of that outer loop showed me the rule has two holes, and both are in the parts that sounded safest.
The first is the safeguard I’d have called airtight: nomination-only — the stored memory may suggest extra work, never suppress a finding. Suggest-don’t-suppress is not sufficient, because a review runs against a finite budget of turns, tokens and time. Anything steering what gets examined first is spending that budget, and a nomination that fills it is a real finding never reached. You can suppress by scheduling. Concurrency has had a name for this for decades — starvation, a process perpetually denied the resources it needs while nobody ever decides to deny it. There’s no skip to audit, no dropped verdict in a log, nothing shaped like a decision. The finding simply never came up. The fix isn’t to trust the nomination less, it’s to deny it the budget: give derived suggestions their own separately reserved, additive allocation, and let them touch neither the baseline’s ordering nor its share. If the memory can reorder the baseline’s work, it isn’t advisory any more. It’s on the critical path, and it belongs under the same governance as everything else there.
The second hole is in the word gated. I’d drawn the human as the thing that breaks the cycle. On dataflow that holds — nothing writes back on its own. But influence still goes round: the store shapes what gets proposed, the proposal shapes what the person sees, the person promotes, and the promotion lands back in the store. The loop closed anyway — one step slower, and through a human who has now read the machine’s suggestion before forming a view. Calling the human an air gap doesn’t make it one. Human-factors research has been saying a version of this since long before agents — Parasuraman and Riley’s misuse: put a person in front of an automated recommendation and over-reliance is a well-documented failure mode, not an exotic one. In this design the gate buys something narrower than a broken loop, and worth stating exactly: the machinery can create candidates but cannot promote them, and every candidate arrives carrying its provenance, to be judged against fixtures it didn’t choose. That’s a real invariant. The human breaks the feedback loop is not one.
The human doesn’t leave; the job moves up
The standard objection is “you need a person to check the agent’s code, because agents aren’t good enough yet.” True — but the yet is hiding something.
Maybe the correctness check is temporary; I’d bet agents get better at writing correct code and the line-by-line review shrinks. The argument doesn’t lean on that bet, though, because a second job doesn’t shrink either way: owning the standard — deciding what “correct” and “good” and “bulletproof” mean here. Someone has to choose those ends, and it can’t be the system optimising toward them — an optimiser takes its target as given; it doesn’t get to originate it. A person sets the reference and stays accountable for it, in a way a model can’t be. That judgment comes from outside the machinery, from someone who’s seen enough real failures to know what matters. The human never leaves; the job moves up — from “is this line correct,” which agents can take, to “is this the right standard,” which they can’t. And that standard is where we came in: it’s frozen judgment too, which is why it needs a constitution and not just a longer rule list.
What you actually keep
Strip it down. The agent is a non-deterministic generator; its output is the warranted, shared, deterministic thing you ship — perishable, so you re-mint it as it rots. The durable asset is the factory behind it: the rules, the harness that refines them, and the frozen principle core that governs both. A person runs that factory and owns the standard, because the one thing that can’t be frozen or shipped is the judgment of what “better” means.
The hype is selling you the generator — the loop, the graph, the probabilistic runtime. That part’s real, and it’s the cheap part. Keep the factory that makes the rules, ship the checks it mints, and hold onto the standard. That was never the thing for sale.
How sure I am: the reviewer, the manual learning loop, the mechanised checks, and the five-stage pipeline (scout/gate/deep/decision/write — gate and decision are pure functions, no model) are real and running, genericised here. “Factory versus output,” “non-determinism is a generator,” and “persistence is a feedback edge” are my argument from building the thing, not a measured result. The two holes in that section — suppression by scheduling, and the human gate not breaking the loop of influence — came out of designing a persistent store for the reviewer and hardening the design against cross-model review. They are reasoning about the topology, caught on paper before anything shipped; I have not built the store, so I have not watched either failure happen. Cheapness-as-a-probe is explicitly a hypothesis, and I’ve said so in the text: the run behind it is real (thirteen fixtures × three runs per arm, one model pair, one sitting) but it cannot separate unencoded judgment from harder bug, the two candidate explanations for its single data point, and the stability half is confounded by a naming problem I’m still fixing. The routing it implies is designed, switched off, and unmeasured. Two forecasts are wagers, flagged as such — that most software people depend on has a checkable output, and that line-by-line correctness review shrinks as agents improve — and the argument leans on neither. The trained-agent version of the output is aspirational; today the output is the mechanical checks, and I’ve said so rather than imply the model exists. The prior art (the workflow/agent distinction, Constitutional AI, Lakatos, the CACE/hidden-feedback-loop framing, and DSPy / model-cascades as the pipeline backdrop) is real but cited as analogy or antecedent, not proof. AlphaCodium’s numbers are the exception — they are measured, and they are theirs, on GPT-4 and the CodeContests validation set. What they measure is competitive programming, so they establish that a deterministic flow can beat a single prompt on the same model cheaply; that this carries to a review pipeline is my reading, not their result.
Sources
- Anthropic, Building Effective Agents (2024) — the workflow-vs-agent distinction this post goes one layer beneath (“workflows: predefined code paths; agents: LLMs dynamically directing their own processes”). The taxonomy is theirs; the factory/output cut and the eval-drift argument are the additions.
- Antonio Gulli, Agentic Design Patterns (github.com/evoiz/Agentic-Design-Patterns) — a 21-pattern catalogue of agent shapes; the catalogue whose lane this post goes a layer beneath, past what shape to what you verify with.
- Khattab et al., DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines (2023, arXiv:2310.03714) — modular stages with typed signatures and per-stage optimisers; cited as the backdrop, not a foil. DSPy tunes model calls and composes ordinary deterministic code around them; the emphasis here is on the stages that need no model at all — a difference of emphasis, not of what the framework permits.
- Chen, Zaharia & Zou, FrugalGPT (2023, arXiv:2305.05176) — model cascades that route cheaper models to easier steps; cited as prior art for right-tool-per-stage, which here becomes right-tool including no model.
- Ridnik, Kredo & Friedman, Code Generation with AlphaCodium: From Prompt Engineering to Flow Engineering (2024, arXiv:2401.08500) — a fixed, ordered pipeline (
self_reflection,possible_solutions,generate_ai_tests,initial_code_generation, then iteration againstpublic_testsandai_tests) that took GPT-4 from 19% to 44% pass@5 on the CodeContests validation set versus direct prompting, at 15–20 model calls per solution — four orders of magnitude fewer than AlphaCode. Cited as the measured receipt that the win can come from the flow rather than the model, and for the cheapness of the deterministic half. Their task is competitive programming, not review; the transfer to a review pipeline is my reading. - Bai et al., Constitutional AI (2022, arXiv:2212.08073) — a small principle set steering a model’s behaviour; cited as the nearest AI analogue for principle-governed behaviour, not as the frozen/mutable architecture (it uses the principles to train).
- Parasuraman & Riley, Humans and Automation: Use, Misuse, Disuse, Abuse, Human Factors 39(2) (1997); Parasuraman & Manzey (2010) on automation complacency — over-reliance on an automated aid is a well-documented failure mode, catalogued rather than rare. Neither paper establishes it as the modal response, and an earlier version of this line claimed that; corrected. Cited as the human-factors antecedent for why a human gate doesn’t break a feedback loop; the argument here is from the topology, and this is the literature that already knew.
- Resource starvation (concurrency/scheduling) — a process perpetually denied the resources it needs, with no explicit denial anywhere. Standard vocabulary, borrowed here for a review budget; the remedy in this design is a reserved additive allocation rather than the usual aging, because aging doesn’t secure the property under a fixed budget.
- Sculley et al., Hidden Technical Debt in Machine Learning Systems (NeurIPS 2015) — “hidden feedback loops” and CACE (Changing Anything Changes Everything); cited as the antecedent for persistence-is-a-feedback-edge, applied here to agent memory.
- Imre Lakatos, The Methodology of Scientific Research Programmes — a protected hard core wrapped in an adjustable protective belt; a structural analogy for the two-tier standard, not proof that principles are permanent (whole programmes get abandoned).
Related: Rules Are the Alpha (the rules as the moat this post’s factory maintains); A Big Rule Set Is an Attention Problem (how the rules compile into the deterministic checks you ship); Fluent in a Dead Idiom (why frozen judgment drifts — the same rot, in your reading eye); Your Merged-PR History Is Survivorship-Biased Training Data (the bias this post turns on the agent-hype writing itself); Skills Are One-Offs (share the workflow that repeats; let one-offs stay throwaway); The Harness Is the Product (the harness tunes each isolated stage — the why to this section’s how); A Flip Is a Missing Rule (the cheap-model probe without the second model — the wobble the quarantined stages still have, read as a pointer at the unencoded judgment).