Compare
Symptom
Human

Data structures whose fields are reassigned across the codebase, with no clear owner of the mutation. Every reader of the data carries a different mental model of when it's valid; the surface expands with every writer, and code that looked correct in isolation breaks when a different writer runs first or runs concurrently.

Agent

Fields the agent finds reassigned across multiple files with no obvious owner; reasoning about state at any moment requires across every writer. The agent generates code against the writer set it discovered, missing concurrent writers and writers in cold paths; downstream reads compose against the agent's partial timeline and fail at runtime.

Goal
Human

Mutation happens in one place behind a named function (or returns a new value), so the moment of change is clear. The encapsulating function owns the ; downstream readers compose against the guarantee rather than against the raw mutable shape, and concurrent reasoning becomes tractable because the mutation surface is one named call.

Agent

Mutation happens behind a named function with a clear contract, or the data is replaced rather than modified — the agent locates every change in one place. The agent's per-edit count drops because state transitions verify against the wrapper's contract rather than the full timeline of every writer.

Smellier version

const order = { total: 100 };
applyDiscount(order); // mutates total
addTax(order); // mutates total

Fresher version

const order = { total: 100 };
const final = addTax(applyDiscount(order));
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure
Human

Reasoning about state requires tracing every writer; and the team's both scale with writer count, and concurrent code becomes a hazard area. Reviewers pass changes that work for the call sequence in front of them; production runs a different sequence and produces behavior the reviewer never considered. The team's compounds across the writer set.

Agent

The agent cannot answer 'what is this value here?' without modeling the full timeline of writes; concurrent reasoning hits the same at every read. Edits the agent generates against a partial timeline ship as plausible code that fails under the actual interleaving of writers — a silent bug class the targeted test won't catch.

Tradeoff
Human

Encapsulating mutation can force the team to learn a less ergonomic API for what was previously a direct write; immutability has migration cost in performance-sensitive code. The team trades for runtime overhead; in hot paths the trade may invert, and the team must choose between encapsulation discipline and per-operation performance.

Agent

Switching to immutable or encapsulated mutation forces the agent to construct new objects on every change; for hot-path mutation this trades reasoning clarity for runtime overhead. The agent pays extra on every write that allocates a new value; in performance-sensitive code the cost surfaces as latency the user notices, not just compute the agent pays.

Relief
Human

Bugs stop being 'who set this field?' and become local to the encapsulating method. The team's drops because the audit surface contracts to one call instead of N writers, and downstream code composes against the encapsulating contract without re-checking the underlying mutation. Concurrent reasoning becomes possible because the moment of change is named.

Agent

State changes become locatable; the agent traces one entry point instead of N writers when reasoning about behavior. The verification surface contracts to the wrapper's contract; the agent verifies edits against a single named invariant rather than reconstructing the mutation timeline, and on state-related queries drops sharply.

Trap
Human

Wrapping mutable fields with passthrough setters that change nothing — the hides the same mutation everywhere behind syntactic sugar. Reviewers grant the safety presumption; runtime shows the underlying mutation still leaks through every direct field access that bypassed the setter, and the codebase carries an extra ceremony layer without the protection it advertised.

Agent

Wrapping writes in passthrough setters leaves the mutation everywhere while looking encapsulated; the API's signature suggests safety the implementation doesn't deliver, and verification-surface cost stays as broad as before. The agent reads the wrapper's name and reasons as if the contract holds; runtime ships behavior that violates the assumed contract.