Hosted ongabo.esvia theHypermedia Protocol

From Operators to Supervisors: Code Becomes an Artifact

Abstract

If you spend any time on developer X, you'll find a recurring anxiety: AI is going to generate code faster than anyone can review it. The fear is real, but it's misplaced. Software engineering has lived through this transition before — multiple times — and each time the answer was the same: when production scales, control moves up. Programmers stopped reviewing assembly. Designers stopped setting type by hand. Elevator passengers stopped trusting operators and started trusting buildings. In each case, the craft didn't disappear; it relocated. This essay argues that AI-generated code is the next chapter of that story, but only for engineers who do the work of making their systems legible. The tools that matter most right now aren't new — they're state machines and the actor model. Together they turn software from an opaque mass of conditionals into a system you can supervise. Code becomes an artifact of an explicit design, not the design itself.

The anxiety of unlimited code

I asked on X what would happen if we had unlimited tokens to spend on LLMs. The most honest answer I got back was a worry: that the model would generate code faster than the developer could review it. I think a lot of engineers feel some version of this even when they don't say it.

The fear sounds like it's about throughput, but it isn't. Code review has always been a bottleneck. The real fear is about control. For most of our careers, understanding a system has meant being close to its implementation — writing the lines ourselves, tracing the conditionals, watching the diff. Confidence and proximity were almost the same thing.

AI breaks that. When a machine can write the function, the developer's hand is no longer on every keystroke. The piece may work, but the feeling of mastery is gone. What's collapsing isn't engineering; it's a specific mental model of what engineering looks like — one built around manual authorship.

This is uncomfortable, but it isn't new. We've felt it before, and we already know how it resolves.

We have already done this — to ourselves

The clearest precedent doesn't come from another industry. It comes from the history of our own.

Programmers once wrote machine code directly. When compilers arrived, there was genuine resistance. How could you trust a piece of software to translate your intent into instructions correctly? You couldn't see what it was doing. Early compilers produced inefficient code, and skilled assembly programmers could beat them. The objection sounded a lot like the objection to AI today: the machine doesn't really understand what I mean, and I won't be able to check its work.

The way out wasn't to keep reviewing assembly. It was to trust the rules of the source language, test the behavior, and treat the compiled output as an artifact. Today, almost nobody reads the assembly their compiler emits. We accept it.

The same thing happened again, smaller. TypeScript compiles to JavaScript. Nobody opens dist/ to verify the transpilation. We trust tsc, we trust our tests, we ship.

It happened again with CI. The artifact a user actually runs — a bundled, minified, tree-shaken blob — has been produced by a chain of tools nobody inspects line by line. The build pipeline is trusted because we trust the inputs, the configuration, and the observable behavior of what comes out.

At every step, the engineer's job didn't shrink. It moved up. We stopped reviewing the lower-level output and started defining the higher-level system that produced it. We gained leverage in exchange for surrendering proximity.

AI-generated code is the next step in that sequence. The reason it feels different is that it's written in the same language we write — so the obligation to read it feels stronger than the obligation to read assembly. But that's a representational accident, not a principle. If the same model emitted WebAssembly directly from a behavioral spec, no one would ask whether they should review every instruction. They'd ask whether the spec was right.

Other industries already moved control up

The same pattern lives outside software, and the parallels sharpen the point.

When desktop publishing arrived in the 1980s, professional typesetters had real reason to be nervous. Setting type was a craft with centuries behind it. Early DTP output was worse than what skilled typographers could produce by hand. But the role didn't disappear. It moved up. Typographers stopped placing individual letters and started designing the systems — typefaces, grids, style guides — that anyone with a Mac would use to set type. The volume of published material exploded. The expertise relocated to a higher level of abstraction.

Mass manufacturing did the same thing. A car built by a master craftsman in 1900 was a different object than a Toyota in 1995, but the Toyota is more reliable. Reliability moved out of the individual worker's hands and into process: standardized parts, tolerances, inspection points, statistical quality control. The control didn't vanish. It became the design of the production system itself.

Even elevators went through this. Early elevators had human operators not because the mechanism required them, but because passengers didn't trust the machine. When elevators became automatic, the trust had to move somewhere — into sensors, doors, brakes, regulatory standards, redundancy. The operator became invisible because the system became trustworthy.

Each of these transitions felt like a loss of control at the time. None of them were, in the end. What they really were was a relocation of control from the hands of the individual to the design of the system around them.

The actual problem isn't review — it's legibility

Once you see the pattern, the question for AI changes. The risk is not that AI will write a bad function. We have bad functions today, written by humans, and we manage them. The risk is more specific: AI can produce a great deal of code that is plausible in isolation while making the global behavior of the system harder to understand.

A model will happily add a flag to handle an edge case. It will introduce a shortcut between two modules because that solves the immediate prompt. It will satisfy the test in front of it without preserving the invariants that aren't written down. None of those moves is obviously wrong locally. Globally, they erode the model of the system.

The hardest questions in software are not whether some particular function can be written. They are:

    What states can this system be in?

    Which transitions are allowed, and which are forbidden?

    Who owns each piece of state?

    What messages cross each boundary?

    What happens when something fails?

If those questions are only answered by reading the code, then any sufficiently large system becomes unreviewable — whether AI helped write it or not. AI doesn't introduce that problem. It exposes it, at a speed that doesn't give us time to pretend.

The answer is not to slow the AI down. It's to make the system itself legible.

Explicit behavior: state machines

This is where state machines stop being an academic curiosity and start being a survival tool.

Consider a booking flow. At first it looks trivial: check membership, check capacity, reserve a seat. A few if statements. But real bookings need to handle expired memberships, payment failures, cancellations, no-shows, administrative overrides, check-ins without prior reservations, classes that fill mid-flow. After a few months, the logic is scattered across files in the form of flags: isLoading, isConfirmed, isCancelled, isExpired, hasError. The flags don't tell you which combinations are valid, what transitions are legal, or what should be impossible.

A state machine names the states directly:

idle → checkingMembership → reservingSpot → confirmed confirmed → checkedIn → completed confirmed → cancelled confirmed → noShow

This is a small change in notation and a large change in what you can supervise. With explicit states and transitions, you can ask AI to implement the booking flow, not to invent it. The prompt is no longer "generate booking logic." It's "implement this state machine; these transitions are allowed; these are forbidden; here are the failure modes."

The review question changes too. You're no longer trying to trace the behavior out of the code line by line. You're asking whether the implementation respects an explicit model. That's a question a human can answer at scale. The first kind isn't.

Explicit boundaries: actors

State machines handle behavior over time. The actor model handles ownership and communication.

A common failure mode of AI-assisted development is that everything starts talking to everything else. A function reaches into another module to read a value. A service hard-codes a dependency on the internals of another service. A component owns state that should belong elsewhere. Each shortcut makes sense in isolation. Together they produce a system where no part can be changed without understanding the whole.

Actors push back on that. An actor owns its state. It communicates by sending and receiving messages. It has a defined responsibility, and a defined surface. A booking system designed this way might have a BookingActor coordinating the flow, a MembershipActor answering eligibility questions, a CapacityActor owning seat counts, a NotificationActor reacting to events. None of them needs to reach into the others' internals.

The point is not the framework. The point is that responsibility and communication become visible. When AI generates code inside one actor, the reviewer doesn't have to understand the whole system to evaluate it. The actor's boundary tells them what's allowed and what isn't. Violations show up as messages that shouldn't exist, or state access that shouldn't be possible, rather than as subtle behavioral drift.

Supervision requires legibility. The actor model is one of the few patterns we have that produces legibility by default rather than by discipline.

Code as artifact

Once behavior is explicit and boundaries are explicit, something interesting happens to the code itself.

The code is no longer the place where the system is defined. The state machine is. The actor topology is. The invariants, the messages, the failure cases. The code becomes the implementation of those — one expression of the system, not the system itself.

This is the same status compiled output has had for decades. The C source is the source of truth; the assembly is an artifact. The TypeScript is the source of truth; the JavaScript is an artifact. In the next step, the behavioral model is the source of truth, and the implementation — whether written by a human or generated by a model — is the artifact.

This doesn't make code unimportant. Generated code can still be wrong, insecure, slow, brittle. It still needs tests, observability, and review for the things review is actually good at: security boundaries, performance characteristics, integration with the surrounding system. But the question shifts from "did the model write the function I would have written" to "does this implementation faithfully express the system I designed".

That's a much smaller question. It's also one that a human can keep up with even when the code itself is being produced at machine speed.

The supervisor's habit of mind

The shift this asks for isn't really technical. It's about where you put your attention.

When code was expensive, manual authorship was a reasonable proxy for control. You wrote the implementation, so you understood it. As code becomes cheap, proximity stops being a proxy for anything. The developers who do well in this transition will be the ones who stop trying to recover the old feeling of control and start building systems that don't require it.

That means more thinking about states and fewer flags. More named transitions and fewer booleans. More message boundaries and fewer cross-module reaches. More invariants written down and fewer assumptions in someone's head.

This is not less engineering. It's more explicit engineering. The craft moves where it has always moved when production scales — up, into the design of the system rather than the construction of the parts. The assembly programmer became a C programmer. The typesetter became a typographer. The elevator operator became a building engineer.

The next move is already in progress. Code is becoming an artifact. The work is to design systems worth generating code into.

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime