Disposable Abstractions
Plain-English prompts are the new source code, and AI-generated output is a disposable build artifact we only hoard because our tools lack determinism.
By Theo Marsh
Sparked by Paint.net 5.2 alpha now runs on Linux · discussion

Software engineering is mostly just deciding what to hide.
That dynamic makes the current Hacker News firestorm over the recent Paint.NET 5.2 alpha release absolutely fascinating. The developer merged roughly 180,000 lines of AI-generated, unreviewed code into the project's codebase to port built-in effects from GDI+ to Direct2D. And he was completely transparent about the method.
The sheer volume of the addition triggered an immediate, visceral reaction across the programming community.
Reading through the Hacker News discussion, the consensus formed rapidly around a single, horrified question: How can anyone maintain this? The community pictured a future maintenance nightmare. To a traditional programmer, dumping that much unreadable, un-bisectable logic into a repository feels like architectural sabotage. You can't debug it. You can't patch a subtle regression in it.
But the community is evaluating the output as if it were source code. The real architectural anomaly is that this output was committed to version control in the first place.
Think about the traditional compilation pipeline. When you sit down to write C code, you build elegant abstractions. You define clean structs, tight loops, and well-named variables. Then you pass that file to a compiler, and the compiler generates a massive, nearly illegible wall of assembly language.
That assembly is hyper-optimized for machine execution. It is full of register movements, stack pointer arithmetic, and memory allocations that look like total gibberish to a passing reader. If you tried to track down a bug by reading the raw assembly instructions line by line, you would go insane.
Crucially, you would never commit that assembly output to your git repository.
The assembly is a Disposable Abstraction. As Theo Marsh noted a few years ago regarding Disposable Software, sometimes an artifact exists solely to bridge a gap, fully intended to be thrown away or regenerated on demand. It is the transient byproduct of a higher-level intention.
So why do we treat the output from a Large Language Model differently?
We look at a file bearing a .cs or .py extension and reflexively apply fifty years of source-code hygiene to it. We demand that it be neat, heavily commented, and perfectly legible to a human reviewer. Yet the danger of unreadable AI code is arguably a massive, structural feature.
Becoming illegible to humans means a system is successfully moving up a layer of abstraction. If an LLM generates code that perfectly mimics human readability, it is likely constraining itself to human limitations. True abstraction hides the messy, verbose wiring. In this new paradigm, the plain-English prompt—or the repository's .cursorrules file—is the actual, Canonical Source of Truth. The 180,000 lines of Paint.NET additions are just the compiled artifact of that truth.
The architectural mapping looks essentially like this:
`C Source -> Compiler -> Assembly (ignored by git)`
`Prompt -> LLM -> AI Code (ignored by git)`
We are simply hoarding the assembly.
And we have lived through this exact cultural friction before in dependency management.
A decade ago, committing your entire `node_modules` or vendor/ folder directly to version control was a standard, if begrudging, industry practice. Engineering teams did it out of necessity. It was the only reliable way to guarantee a reproducible build across different environments. You dragged hundreds of megabytes of third-party dependencies into your commit history because you didn't trust the network or the package manager to fetch the exact same bits twice. If a library author deleted their package from the registry—the infamous left-pad incident—your deployment would completely break.
So you committed the output. You checked the messy, unreadable folder into your pristine repository just to feel safe.
Then lockfiles arrived. Tools matured, providing cryptographic guarantees that the dependency tree would remain perfectly deterministic. Suddenly, committing a dependency folder transformed from a best practice into a cardinal sin of repository bloat. We trusted the tooling to rebuild the environment from a small, human-readable manifest file.
Right now, our AI tools output build artifacts. Because we completely lack the Lockfile Equivalent for probabilistic LLMs—a mathematical guarantee that the exact same prompt will yield the exact same execution tree tomorrow—we panic.
We commit the raw generated output, desperately treating it like manually curated source code so we don't lose a working state. We are trying to manually review assembly code because we don't yet trust the compiler to give us the same binary twice.
We are stuck in an awkward transitional phase where the tooling simply hasn't caught up to the paradigm shift. We are treating transient build artifacts as if they are precious, hand-crafted heirlooms.
Eventually, the ecosystem will stabilize. We will find our deterministic lockfile equivalent for generative systems. Maybe that looks like frozen model weights. Maybe it involves rigorous test-driven validation loops that automatically verify the regeneration. Or perhaps it relies on intermediate syntax trees that abstract away the raw token generation entirely.
When that happens, the underlying generated logic will fall below the waterline of what developers actually read.. leaving only the prompts and the validation rules in our version control histories.
My guess?
In five years, committing AI-generated code to a repository will look exactly like committing your `node_modules` folder.