A bug report used to start a small transaction. Reproduce it, find the root cause, write the smallest change that stops the symptom, ship, close. Engineers get trained into that motion so early that it feels like professionalism itself. I think the minimal patch is something else: a habit left over from a cost structure that no longer exists. When a defect arrives now, there is a real decision to make (patch this, or redesign what is underneath it), and most of us never consciously make it.
The habit had honest origins. The expensive part of fixing a bug was never the fix. It was the understanding: reading the subsystem, rebuilding the mental model, holding enough in your head to change the code safely. The reading could cost a day; the typing, minutes. Under those economics, rationing understanding was the responsible move. You scoped the read narrowly, changed as little as possible, and got out. Anything more was risk without budget.
Working with an AI coding agent inverts this. The agent reads the entire subsystem: every module, the tests, the docs, the commit history if you point it there. The agents I work with hold as much as a million tokens of context, more than most subsystems, and build the full picture in minutes. Understanding stopped being the scarce input. What stays expensive is judgment about what to do with it, and review of what gets built. The minimal patch made sense while comprehension was rationed. It keeps getting chosen out of habit after the ration ended.
Three moves
The discipline I’ve settled into is part of what I call synthesis coding, AI-assisted development done to engineering standards. It has three moves.
The first: treat the defect as a question about the design underneath it. The report says X fails. The question is what property of the design allowed X to fail, and what else that property is quietly doing. Sometimes the answer is “nothing, a header was missing,” and the patch is the whole story. Sometimes the answer indicts an assumption the subsystem is built on.
The second: let the agent read the whole subsystem before you choose. Not the failing function, the subsystem. This costs minutes, and it converts patch-or-redesign from a guess into an informed decision. The old discipline scoped the read to control cost. Scoping the read now recreates artificial ignorance and saves almost nothing.
The third: decide, deliberately, which moment this is. A patch moment or a redesign moment. Both are legitimate. The failure mode isn’t choosing wrong; it’s not choosing at all, defaulting to the patch because triage under scarcity is muscle memory.
A worked day, with timestamps
Here is one specific day, in a codebase where every commit is public.
Synthesis Console is an open-source tool I built that renders the markdown and YAML of my project management system as browsable pages. One morning at 11:45 I shipped a new screen for it: a cockpit view that turns the day’s plan file into decision cards, task lists, and message drafts. Then I spent the day using it, which is how the bug reports started arriving. The reporter was me.
The first defect was ordinary. Edit the plan file outside the tool, reload the page, see the stale version: the browser was caching pages that a local, disk-reading tool should never let it cache. About ninety minutes after the release, the fix shipped as no-cache headers. That was a patch moment. The design underneath was sound. Recognizing a patch moment matters as much as recognizing the other kind.
The second defect looked equally ordinary and wasn’t. Message drafts written into topical sections of the plan file were missing from the cockpit’s drafts region. The narrow fix would teach the collector about one more heading. The subsystem read said something different. These plan files are written by an LLM-driven workflow, and that writer places drafts wherever they make narrative sense, not under one canonical heading. The collector’s core assumption, that drafts live in the drafts section, was the actual defect. The shipped fix walks the entire document and collects drafts from anywhere.
The next release, nine minutes later, took the same reframing to full scale. An audit showed the parser classified only about 85 percent of the section headings in my real plan corpus; the rest fell into an untyped bucket and rendered generic: no decision cards, no task checkboxes. The patch path was obvious: add the missing synonyms and move on. The design question had a better answer. This parser is deterministic software consuming documents produced by a probabilistic writer. It will never see a closed vocabulary, so strictness is a permanent mismatch, not a defect to whittle away one synonym at a time. That afternoon the parser was redesigned around tolerance: strip decoration before matching, recognize families of synonyms, synthesize sensible structure when a section arrives half-formed. The vocabulary became a documented contract between the producing workflow and the consuming tool, with one authoritative table both sides mirror. The audit became a regression script that keeps coverage measured. Coverage rose to 94.4 percent; the remainder was verified as intentional catch-alls.
By 18:41 there was one more mismatch to act on. The day’s work had made the access patterns explicit, the surfaces I act from constantly and the reference I only glance at, and the layout didn’t match them. The evening release restructured the screen into a three-column shell built around those access patterns. The redesign wasn’t the day’s last word: four smaller releases followed it into the evening, two of them fixing regressions I flagged while using the new layout. Thirteen numbered releases shipped between late morning and evening, each separately, so no fix ever waited on a redesign. What arrived as small defect reports ended, inside one working day, as a subsystem redesigned twice: once in its parsing contract, once in its layout.
When the patch is the right call
None of this argues for maximalism. The methodology earns the name only if it knows its own boundaries, and I patch, just patch, in several recurring situations.
When I don’t own the code. Redesign is only safe on top of real understanding, the same reason I start new projects foundation-first, and in a system another team owns, my redesign becomes their maintenance burden and their pager. The right deliverable there is the fix plus the design question, handed to the owners. The subsystem read is still worth doing: it turns “this is broken” into “this assumption is doing damage,” which the owning team can act on.
When a stability freeze is on. A redesign is new risk by definition, and a freeze is a declaration that new risk is currently worth less than usual. The defect still gets the full diagnosis. The redesign gets a ticket with that diagnosis attached, scheduled for when the freeze lifts, written down where planning happens.
When review bandwidth can’t absorb it. A fix that touches a few lines, buried inside a redesign that touches everything, is hostile to the person reviewing it. Separability is what keeps redesigns reviewable: the fix ships first as its own change, the redesign follows as its own series. That is why the console day produced thirteen releases instead of one.
When no observed pain sits behind the improvement. Every redesign move in that day traced to something that happened: a stale page, missing drafts, misclassified sections. “Wouldn’t it be nice if” traces to nothing, and building it is scope creep wearing the methodology’s clothes.
When I can’t test it properly. A patch with a test beats a redesign without one. An untested redesign trades a known small risk for an unknown larger one.
The question to carry
The next defect that lands on you is the best chance you’ll get to ask what it says about the design underneath: it arrives with observed pain attached, and the understanding needed to answer is nearly free now. Ask the question. Let the agent do the reading. Then decide which moment you’re in, on purpose. Most of the time the answer will still be a patch, and that’s fine; the difference is that you chose it. But when it’s a redesign moment and you take it, the code gets permanently better inside the ordinary motion of maintenance. That return compounds, and no scheduled rewrite project matches it.
Updated July 2026: the discipline has since held at higher stakes. A live test in Ragbot, an open-source AI assistant I build, caught freshly written row-level-security policies doing nothing (Postgres disables them for superusers, and the runtime connected with the same superuser identity the migrations use); the patch would have been pointing the runtime at any non-superuser login, and the fix that shipped just over twenty minutes later was a redesigned connection model: a restricted application role for runtime queries, migrations on a separate elevated connection, and a test that fails against the superuser so the bypass cannot return unnoticed.