The Ratchet Principle: How AI Mistakes Become Better Software

Fixing an AI-generated defect repairs the present. Ratchet Development encodes the lesson as a durable control that improves the environment inherited by future work.

Table of Contents

Part two of a series on Ratchet Development, a governed approach to building software with AI agents.

In part one I introduced Ratchet Development, short for Ratchet Governed Agentic Development.

The basic idea is simple:

Every meaningful failure should leave behind a durable control that future work inherits.

An AI agent makes a mistake. The mistake gets discovered. The immediate defect gets repaired. Most development processes stop right there.

Ratchet Development asks one more question:

What did the surrounding system allow this mistake to mean, reach, or affect?

That question changes the nature of the correction. A local repair changes one implementation. A ratchet changes the environment that future implementations get built in.

The lesson might become a stronger contract, a negative test, an architectural boundary, a permission check, a database constraint, an approval gate, or a new rule for how future work has to be verified.

The form varies. The principle doesn’t:

Fixing the defect repairs the present. Encoding the lesson improves the future.

The defect is not always the real failure

When an AI agent produces incorrect code, the visible defect grabs attention first.

A validator accepts the wrong value. A test gives a false sense of safety. A transaction leaves partial state behind. An identifier changes meaning when a list gets reordered.

Those defects need fixing. But they may only be symptoms of something bigger.

Maybe the contract was described in prose but never expressed structurally. Maybe the test proved an output without proving the property named in the test. Maybe an architectural rule lived in someone’s head but not in the repository. Maybe the system let a display label become persistent identity. Maybe the agent had enough freedom to pick an interpretation, but not enough context to pick the right one.

The code is where the failure showed up. The development environment is often where the failure became possible in the first place.

Ratchet Development treats the mistake as evidence about both.

Almost correct is the dangerous category

Obvious failures are usually cheap. The code doesn’t compile. The test crashes. The interface won’t load. The database rejects the mutation.

The dangerous failures are the plausible ones. They compile. They pass a test. They produce polished output. They satisfy the visible wording of the task. They might even survive a casual review.

AI agents are especially good at producing work in this category. They can generate implementations that are locally reasonable while quietly violating a larger assumption the model didn’t see, remember, or prioritize.

That doesn’t make agents uniquely broken. Humans make the same kind of error. The difference is speed. An agent can generate plausible implementations faster than a human can manually check every assumption inside them.

So the surrounding system has to do more than catch obvious breakage. It has to help tell the difference between:

  • Code that runs and a property that is proven
  • A value that looks valid and a value that satisfies the contract
  • Deterministic behavior and backward-compatible behavior
  • Multiple database sessions and an actual concurrency test
  • A convenient identifier and a stable identity
  • A proposed design and an authorized architectural change

These distinctions are where ratchets get created.

A validator that enforced the shape of the description

One failure in my build involved a value described as a complete cryptographic identifier. The implementation checked the expected number of characters. It didn’t fully verify that those characters belonged to the permitted format.

The validator looked reasonable. The test suite covered normal examples. The name of the check implied a stronger guarantee than the implementation actually delivered.

The immediate fix was easy: enforce the complete format. But that only repairs the local condition.

The ratchet needed more:

  • The contract had to state the accepted form precisely.
  • Malformed values had to be represented in negative tests.
  • Path-shaped and hostile inputs had to be rejected.
  • Rejection had to occur before the value reached the storage boundary.
  • Other consumers of the same value had to inherit the same definition.

The lesson stopped being “fix this regular expression.” It became:

A contract should enforce the property it claims to represent, not a convenient approximation of that property.

That rule can now catch other mistakes that look nothing like the original line of code.

A green concurrency test that proved no race

Another failure involved a test that was supposed to demonstrate concurrency safety. It used more than one database session. It passed. On the surface, it looked like it proved the intended guarantee.

But the test never created the dangerous interleaving. One operation exited before the contested sequence happened. The test involved concurrency machinery without ever exercising the race condition it was meant to verify.

The visible problem was a weak test. The deeper problem was a weak definition of proof.

The ratchet required the test to establish the exact sequence that mattered:

  1. The first mutation reaches the relevant state.
  2. A competing mutation attempts the conflicting transition.
  3. The system rejects, serializes, or safely resolves it.
  4. The final state is inspected from a fresh session.
  5. The test fails under the previously unsafe behavior.

The durable lesson became:

A concurrency test must prove the contested interleaving, not merely involve concurrent objects.

That principle now applies to future work involving atomicity, locking, idempotency, and state transitions.

The test got repaired. More importantly, the project gained a stronger standard for what concurrency evidence actually means.

A compatibility test that only proved determinism

Another test compared the result of a serialization function against the result of calling the same current function again. The values matched. The test passed.

It proved the function behaved consistently with itself. It didn’t prove the function stayed compatible with data created by an earlier implementation.

The test’s name claimed compatibility. Its structure only showed determinism.

The immediate correction introduced an independent historical reference. The stronger correction also needed a sensitivity check: the test had to prove that a meaningful change in the source content would change the result, while unchanged historical content kept producing the expected identifier.

The ratchet was the principle underneath it:

A system cannot prove backward compatibility by using itself as its only witness.

That applies to a lot more than serialization. It applies to schemas, hashes, exported artifacts, API responses, migration behavior, and any system where current code is expected to preserve a previous agreement.

When display order became identity

One of the subtler failures involved an ordinal label. A generated item got an identifier based on its position in a sequence. It looked like a harmless convenience, a way to refer to the first, second, or third item.

Downstream, persistent records started deriving identity from that label. Now order mattered.

If the source items got rearranged, the same identifier could point to a different underlying statement. An existing governed record could look stable while its actual meaning changed underneath it.

The code worked. The identity model didn’t.

The correction derived identity from normalized meaning instead of display position.

The ratchet became:

Anything used to derive persistent identity must represent what the object is, not where it happened to appear.

That principle can govern findings, claims, artifacts, recommendations, and any other record that needs continuity across runs.

Again, the important part wasn’t replacing one identifier. The system gained a more accurate theory of identity.

Architecture can ratchet too

Not every ratchet starts with a bug.

Sometimes the agent proposes a locally convenient design that would create an unhealthy dependency. A component needs information owned by another part of the system. The shortest path is a direct import. But the architectural model prohibits that dependency direction.

Without an enforceable boundary, the import might get accepted because it works. Over time, those convenient edges turn the system into a web of accidental ownership.

In a governed environment, the proposed dependency gets checked against explicit architecture rules. The agent has to find an allowed path, or the architectural law has to be changed on purpose.

The ratchet isn’t simply “don’t use this import.” It’s:

Architectural ownership should be enforceable outside the memory of the current developer or agent.

That lets future work move faster, because the repository can answer questions that would otherwise mean rediscovering intent from scratch.

The forms a ratchet can take

A meaningful failure should change the layer best positioned to prevent it or contain it.

Contract ratchets

A contract ratchet makes an invalid, ambiguous, or dishonest state harder to express. A value described as a complete identifier has to satisfy the complete format. A field that might truthfully be unknown should allow an unknown state. A proposed output shouldn’t carry the same status as an approved one.

Test ratchets

A test ratchet makes prior defective behavior fail. The strongest version proves the underlying property, not just the specific example that exposed the defect.

Architecture ratchets

An architecture ratchet turns intended ownership into an enforceable boundary. It keeps the system from drifting toward whatever dependency was most convenient during the last task.

Governance ratchets

A governance ratchet changes who or what may perform an action. That might be a permission, an approval requirement, a denial path, or a distinction between a proposal and an authorized mutation.

Evidence ratchets

An evidence ratchet raises the bar a claim has to clear before it can influence decisions. It might require provenance, freshness, source identity, or an explicit representation of uncertainty.

Process ratchets

A process ratchet changes how future work has to be authorized or verified. A design doesn’t automatically authorize implementation. A hermetic test doesn’t automatically establish live behavior. A passing targeted test may not be enough when a shared contract changes.

Memory ratchets

A memory ratchet makes sure a lesson survives the session that produced it. The current agent might understand the correction perfectly. That knowledge is worth little if the next session has to rediscover it through another failure.

Choosing the correct ratchet

Not every defect deserves a new global rule. A development environment can get just as unhealthy from too much governance as from too little. The hard part is diagnosing the right scope.

When a failure shows up, I ask questions like:

  • Was this a one-line implementation defect or evidence of an ambiguous contract?
  • Could the same reasoning error appear elsewhere?
  • At what boundary should the invalid state have become impossible?
  • Did the test fail to reproduce the defect, or did it fail to define the property?
  • Is the current fix dependent on someone remembering why it exists?
  • Can the control be enforced deterministically?
  • Will the next agent inherit the lesson without rereading the original conversation?
  • What evidence would prove the new control is effective?

The goal isn’t to answer every error with another layer of process. The goal is to place the smallest durable control at the highest useful boundary.

A local defect might need a local test. A broken invariant might need a contract or a database constraint. A recurring ownership problem might need an architectural rule. A dangerous action might need a permission and approval boundary.

The ratchet should match the failure.

Bad ratchets are possible

A ratchet resists backward movement. That’s only valuable when it’s moving in the right direction.

A badly diagnosed failure can produce a bad rule:

  • A test can pin an accidental implementation detail.
  • A contract can eliminate a legitimate state.
  • A permission can block necessary work.
  • An architecture rule can preserve an obsolete design.
  • A process gate can add cost without reducing risk.
  • A historical lesson can become misleading after the system changes.

Ratchet Development isn’t about making every rule permanent. It’s about making changes deliberate.

A control can be revised, superseded, or removed. But the reason for the original control shouldn’t vanish silently. The system should keep enough history to answer:

  • Why was this rule introduced?
  • What failure did it address?
  • What assumption did it encode?
  • What changed enough to justify replacing it?
  • What new control now preserves the intended property?

Progress isn’t the same as immutability. A ratchet should prevent accidental regression, not thoughtful revision.

A test suite is not the ratchet

It’s tempting to reduce all of this to test-driven development with AI. That’s too narrow.

Tests are one way to preserve a lesson, but they aren’t always the best one. A test might prove that bad behavior stays absent while leaving the invalid state structurally possible. A contract might be stronger. A database constraint might be stronger still. A permission boundary might be the right answer when the problem is authority rather than correctness. A source requirement might be necessary when the failure came from unsupported inference.

The deeper objective:

Change the future environment so the same class of failure becomes harder to create, easier to detect, or less capable of causing harm.

Sometimes that happens in code. Sometimes it happens in the operating model around the code.

The value compounds across agents

An isolated AI coding session can be really productive. But without durable controls, each new session starts with many of the same weaknesses:

  • The same ambiguous terminology
  • The same invisible assumptions
  • The same unproven architectural boundaries
  • The same opportunities to confuse proposals with truth
  • The same tests that check examples without proving properties

Ratchets let those sessions compound instead. The first agent might surface an ambiguity. The second inherits a stronger contract. The third hits a new edge case and adds a negative test. The fourth gets blocked from creating an invalid dependency. The fifth starts inside an environment shaped by all four earlier lessons.

The intelligence of the system isn’t located only in the current model anymore. It’s also embedded in the accumulated constraints, tests, contracts, permissions, and recorded decisions around it.

Better software from imperfect intelligence

Ratchet Development doesn’t require AI agents to become infallible. It assumes they’ll keep producing plausible mistakes. It assumes humans will keep making mistakes too.

The opportunity is to turn those failures into structure. Each meaningful error can expose a missing distinction. Each missing distinction can become an explicit rule. Each explicit rule can strengthen the environment future work inherits.

That’s the Ratchet Principle:

A failure is not fully resolved until the lesson has changed the future.

Series

Part 1:

Beyond Vibe Coding: How Ratchet Development Turns AI Fallibility Into Governance

Part 3:

Autonomy Is Not Authority: The Human Role in Agentic Software Development

Some of my favorite projects.

UI/UX. Video. Photography. Branding. Strategy. And More.

During my 11+ year career, I’ve been fortunate to play a role in hundreds of fun, exciting, and innovative projects. Below are some of my favorite projects that I’ve been a part of.

Vixory

Logo and Branding
See the Project

Route 66 Car Museum

Video production for a social media ad campaign ahead of a related new movie coming out.
See The Project

Geared

Successfully Funded Kickstart Project
See the Kickstarter

Faces of 417-Land

Photography

BigPxl

Logo, Branding, Website Design

Immersyve Health

Lead generation strategy focused on reducing Nurse Manager burnout.