DEV Community

Cover image for Agentic Coding Needs a Decision Core and a Disposable Perimeter
Savio Resende
Savio Resende

Posted on

Agentic Coding Needs a Decision Core and a Disposable Perimeter

Agentic AI has changed the bottleneck in software development. For most of our history, writing code was expensive and reviewing it was comparatively cheap. A developer might spend days implementing a feature that a colleague could review in an hour. Coding agents are reversing that relationship. They can produce a surprising amount of code in minutes, but a human still needs time to understand whether that code preserves the rules of the business. DORA has reported that faster AI-assisted generation can produce larger batches that are slower to review and more prone to instability.

We cannot solve this by reading faster. We need architectures that tell us where human attention matters most.

My argument is that agentic coding needs architectures with explicit trust boundaries: human-reviewed decisions, retained historical facts, rebuildable derived state, and tightly controlled external effects. Together, these properties belong to the broader family that Michael L. Perry explores as immutable architecture. Event sourcing offers one practical way to create those boundaries. It gives us a small decision core that deserves intense review and a much larger derived layer that we can allow AI to generate more freely. When code in that derived layer is wrong, we can often replace it and rebuild its state from the event history. This does not make AI hallucinations harmless. It gives their consequences a boundary.

The problem is not how much code AI writes

The obvious concern with AI-generated code is that it can be wrong. That concern is valid, but incomplete. Human-written code is also wrong.

The more important question is: what happens when this particular piece of code is wrong?

Some code makes authoritative decisions. It decides whether an order may be placed, which price the customer agreed to, whether inventory can be reserved, or where a parcel must be shipped. Mistakes here become mistakes in the history of the business.

Other code derives a useful view from facts that already exist. It categorizes products, builds a revenue report, creates a search index, or prepares a dashboard. A mistake in this code can still cause damage, but the underlying facts remain available. We can correct the implementation and calculate the view again.

In a conventional CRUD application, business rules, database updates, reports, and integrations often accumulate around the same mutable model. That can make the boundary between decisions and derived views difficult to see.

Event sourcing forces us to separate the decision from its consequences.

A smaller core to review

Martin Fowler describes event sourcing as capturing every change to application state in a sequence of events. The current state is derived from events such as OrderPlaced, PaymentAccepted, ShippingAddressChanged, and ProductCategorized. These events are facts the system has decided to retain.

Before recording a new fact, the system receives a command. A command is a request such as PlaceOrder or ChangeShippingAddress. The command is evaluated against the current state and the business rules that must always hold.

These rules protect the integrity of the business. An order cannot ship before payment is accepted. An order total must equal the prices of its items after discounts, tax, and shipping. A product cannot reserve more inventory than the business permits.

Commands, business rules, and event contracts form the decision core: the code that decides which facts enter the system's history. If an AI-generated handler calculates the wrong order total and records it in OrderPlaced, replay will not save us. Replay will faithfully reproduce the wrong decision.

This is the code we humans must remain on top of. It should be small, explicit, heavily tested, and reviewed with an understanding of the business—not just verified for correct syntax.

Event contracts require the same care because events outlive the code that created them. Suppose OrderPlaced originally contains a numerical total but later needs a currency. Old events do not disappear when the new version is deployed. The system needs a defined interpretation of the old event, or an upcaster that translates its old shape during replay.

This is event evolution: changing the software without making its retained history unintelligible.

The important result is not that event sourcing eliminates review. It concentrates review on the code whose mistakes become durable.

A larger layer we can afford to replace

Once events have been recorded, projections can transform them into models optimized for particular uses. One projection may build the product catalog. Another may calculate revenue. Another may create the inventory view used by the storefront.

These projections can contain much more code than the decision core, but they do not have the same authority. They interpret facts; they do not create them.

That makes them unusually compatible with coding agents.

Imagine that an AI-generated catalog projection puts products in the wrong categories. Customers have difficulty finding what they want, and conversion may suffer. That is a real problem. But if the product events remain correct, we can fix the categorization logic and replay the history to rebuild the catalog.

Or imagine a revenue report that double-counts refunds or ignores discounts. Executives may see the wrong numbers and make poor decisions. Yet the OrderPlaced, PaymentCaptured, and RefundIssued events still contain the underlying facts. A corrected projection can recompute the report from the beginning.

Because the underlying facts remain intact, both implementations can be replaced and rebuilt. That lets us rely more on automated verification for deterministic projections and reserve intensive human review for durable decisions.

Rebuildable does not mean harmless

The boundary is useful only if we are honest about where it ends.

Suppose an AI-generated inventory projection becomes stale and the storefront accepts an order for a product that is no longer available. The view can be rebuilt, but the promise made to the customer cannot. The business may need to cancel an order, delay a shipment, or repair damaged trust.

The same distinction becomes even sharper with external side effects.

If a shipping consumer ignores ShippingAddressChanged and dispatches a parcel to the customer's old address, the event history will make the mistake explainable. It will not bring the parcel back.

An immutable log is not an undo button for the physical world.

This is why “generated perimeter” cannot mean “unreviewed perimeter.” Deterministic, side-effect-free projections are the safest place to relax human review. Consumers that send emails, capture payments, grant access, disclose personal information, or initiate physical actions still require strict controls.

The useful division is therefore not simply between event producers and event consumers. It is between:

  • code that decides which facts become part of the system's history;
  • code that produces rebuildable, derived state; and
  • code that causes irreversible external effects.

The first and third categories demand close attention. The middle category gives us room to use coding agents aggressively.

Every architecture chooses where complexity lives

Event sourcing has a reputation for complexity, and that reputation is not entirely undeserved. Teams must understand ordering, idempotency, event evolution, replay, snapshots, and eventual consistency.

But every architecture has a conceptual load. A traditional CRUD system places much of it in mutable database state, lifecycle callbacks, migrations, transactions, synchronization, and the question of how a record arrived at its current value.

Event sourcing does not invent complexity as much as choose a different place for it. History and time become explicit parts of the model.

The honest disadvantage is that event sourcing lacks the standardized path available to CRUD applications. Mature web frameworks provide established conventions for controllers, models, forms, and database updates. Event-sourcing libraries vary significantly, and teams often need to make more architectural decisions themselves.

That cost matters. Agentic AI does not make it disappear. In fact, an agent can confidently implement the wrong event-sourcing pattern just as easily as it can confidently produce the wrong CRUD code.

The reason to accept the cost is practical: event sourcing preserves business history, separates the decisions that require close review, and lets us rebuild everything derived from those decisions. That becomes more valuable when AI can generate code faster than we can read it.

Architecture as an allocation of trust

We often discuss software architecture as an allocation of responsibilities. In an agentic environment, it must also become an allocation of trust.

Before accepting AI-generated code, ask whether it records a durable fact, builds disposable state, or causes an irreversible effect.

Event sourcing gives us unusually concrete answers. We review the decision core intensely because it decides which facts enter the history. We give coding agents more freedom in deterministic projections because those projections can be corrected and rebuilt. We restore strict controls wherever software causes irreversible effects in the outside world.

This is not permission to stop caring about generated code. It is a way to spend our care where it has the highest value.

The future of software development will not be defined by agents that never hallucinate. It will be defined by systems that remain understandable and recoverable when they do.

That is why event sourcing matters for agentic coding: it preserves the facts, exposes the irreversible decisions, and lets us rebuild the rest.

Top comments (0)