Skip to content

The Drift Log · Audit, then actually repair

Closing the Loop from Repository Audit to Merged Repair

1 September 2026 · 6 min read · 1347 words · established

A repository drawn as stacked file strata with a blue scanning plane sweeping through

Static audits fail because they catalog symptoms instead of isolating boundaries. Here is how to convert legacy audit findings into verifiable, merged patches.

Every team with a five-year-old codebase has lived through the audit ritual.

An external consultancy delivers a 90-page PDF, or a static analysis tool runs across the repository and opens 1,400 low-severity issues. The executive summary notes that code health is declining, cyclomatic complexity is high in the billing module, and test coverage has dipped below 40 percent.

The engineering lead reads the document, creates an epic titled "Q3 Technical Debt Remediation," copies twelve high-level findings into Jira, and closes the tab. Six months later, zero of those tickets are closed. The codebase is larger, the original authors have left, and the team begins whispering the most dangerous phrase in software engineering: we need to rewrite this from scratch.

An audit that terminates in a static document is an expense that produces exhaustion. It catalogs symptoms without altering outcomes. A repository audit creates value only when it directly informs an extraction, proves that the extracted capability satisfies its invariants, and lands as a merged pull request.

Everything else is administrative noise.

The Two False Exits

When confronted with legacy code that has decayed past the point of casual understanding, teams almost always take one of two bad exits: ticket bankruptcy or the greenfield rewrite.

[ Traditional Audit ] ──> 1,200 Static Findings ──> Backlog Graveyard
                                               └──> "Total Rewrite" Mirage (2 Years, High Risk)

[ Closed-Loop Audit ] ──> Isolate Core Capability ──> Executable Harness ──> Merged Patch

1. Ticket Bankruptcy

Static analysis tools are exceptional at counting things that do not matter. They will flag missing docstrings, inconsistent indentation, and variable naming conventions with the same urgency as an unhandled race condition in an inventory ledger.

When an audit produces hundreds of discrete items, developers suffer triage fatigue. The team cannot distinguish between load-bearing structural flaws and cosmetic lint. The tickets sit in the backlog until someone cleans house during a sprint-planning session eighteen months later by bulk-closing them as "Won't Do."

2. The Greenfield Mirage

The opposite reaction is institutional panic. Leadership sees the audit, concludes the existing system is unmaintainable, and funds a parallel team to build "Version 2.0."

The fatal flaw of the rewrite is the assumption that legacy code is merely old code. In reality, legacy code is an executable record of every edge case, failed third-party integration, compliance requirement, and production bug your business has encountered over its lifetime.

When you throw away the implementation, you throw away the institutional memory embedded in those branches. The rewrite team spends eighteen months building the obvious 80 percent of the system, runs out of runway when they hit the undocumented 20 percent of real-world edge cases, and eventually ships a system that has all the bugs the original system solved in 2019.

Refactoring does not mean making the code pretty. It means preserving the hard-won domain behavior while stripping away the structural rot.

The Audit as an Extraction Boundary

To make an audit useful, you must change what the audit is looking for.

A traditional audit treats every file in the repository as equally important. A correct repository audit treats the codebase as an uneven distribution of assets: high-value, load-bearing domain logic buried inside layers of obsolete framework bindings, obsolete transport protocols, and abandoned abstractions.

The goal of the audit is not to inventory every defect. The goal is to identify and isolate the capability boundary.

+--------------------------------------------------------+
| Legacy Web Controller / Framework Glue (Rotting)      |
|   +------------------------------------------------+   |
|   | Domain Logic & State Machine (Load-Bearing)    |   |
|   |  - Price tier resolution                       |   |
|   |  - State transition invariants                 |   |
|   |  - Idempotency checks                          |   |
|   +------------------------------------------------+   |
|   +------------------------------------------------+   |
|   | Database I/O & Side Effects (Coupled)          |   |
+---+------------------------------------------------+---+

Consider a common scenario: a checkout processor inside a monolithic Rails or Django application. The file is 3,000 lines long. It interacts directly with the database, sends emails, calls three third-party APIs, and updates an internal ledger.

A static audit will flag the file for length, complexity, and missing tests. That is diagnostic trivia.

A functional audit asks precise mechanical questions:

  1. What is the pure state transformation occurring here?
  2. What are the inviolable business rules (for example: a ledger entry cannot be negative, and a finalized state cannot transition back to pending)?
  3. Where does the business logic end and the transport/persistence framework begin?

Once you answer those questions, you have not created a task list of 50 cosmetic refactorings. You have drawn a perimeter around a single, reusable capability.

Executable Contracts Over Documentation

Once a capability is bounded, the loop between audit and repair requires an executable contract.

You cannot safely refactor legacy code using human review alone. Humans are systematically bad at spotting the one edge condition out of forty that depends on an implicit type coercion or an unstated ordering assumption.

If an audit says, "This calculation is fragile," the immediate deliverable is not a patch; it is a characterization harness.

// Define the invariant boundary before modifying legacy implementations
interface SettlementContract {
  calculateNetBalance(input: LedgerBatch): Result<BalanceSheet, SettlementError>;
}

// The harness executes the legacy path and the candidate path against the same assertions
function assertInvariantParity(legacyOutput: BalanceSheet, candidateOutput: BalanceSheet): void {
  if (legacyOutput.settledCents !== candidateOutput.settledCents) {
    throw new InvariantViolation("Settlement calculation mismatch across boundary");
  }
}

Before touching the source code:

  1. Define the inputs and outputs strictly. Strip the external side effects (HTTP calls, raw database connections) behind simple interfaces.
  2. Capture real inputs. Run real historical inputs through the existing implementation to establish the baseline truth.
  3. Assert the invariant. The invariant is the core business rule that must hold true regardless of how the underlying code is structured.

This is the standard we apply in our own certification harness: a repair is not an opinion about clean code. It is an artifact subjected to deterministic execution. If an extraction cannot pass its invariants through automated execution, it does not get merged. A repair without a harness is just another mutation of technical debt.

When you have an executable contract, refactoring ceases to be an act of bravery and becomes a mechanical verification problem.

The Patch Must Be Atomic

The final point of failure in the audit cycle is scope creep.

When developers finally get permission to work on code health, they try to fix everything at once. They upgrade the runtime, swap the ORM, change the folder structure, and refactor the business logic in a single PR spanning 4,000 lines across 82 files.

These PRs never get reviewed properly. They sit open for weeks, suffer merge conflicts against ongoing feature branches, and are eventually rubber-stamped out of desperation—only to introduce an outage within 48 hours of deployment.

A closed-loop repair conforms to three constraints:

  1. Zero structural changes mixed with behavioral fixes. Do not rename folders and re-architect state machines in the same commit. Extract the component as-is first; improve its internals second.
  2. Self-contained boundaries. The patched capability must depend only on explicit arguments passed to it, not on ambient application state, globals, or hidden database triggers.
  3. Definitive verification. The PR must include the harness that proves the new component replicates the required behavior while rejecting invalid states.

If an audit finding cannot be expressed as a patch that alters fewer than 300 lines of code and includes its own verification, the finding has not been broken down far enough.

You can run a free repository evaluation to see this distinction in practice: an inventory tells you where code looks strange; an extraction strategy isolates the exact boundaries where logic can be safely cut away from the framework.

Monday Morning: Closing Your Own Loop

If your team is sitting on an audit report, a SonarQube dashboard with thousands of warnings, or a backlog of generic debt tickets, stop working the list from the top down.

Take one load-bearing capability and run this sequence:

  1. Pick the transaction that matters most. Find the piece of code that the business cannot afford to break (the pricing calculation, the permission gate, the reconciliation job).
  2. Strip the framework away. Write an interface that expresses what that logic does without mentioning your database, your web framework, or your HTTP client.
  3. Write five invariant tests. Do not test implementation details. Test the rules that must never be violated under penalty of business failure.
  4. Extract the pure logic. Move the domain logic into an isolated file or package that implements the interface. Leave the old framework-facing file as a thin shim that calls the new package.
  5. Merge the shim.

The audit is no longer a document on a shared drive. It is a closed loop: a vulnerability discovered, an invariant defined, a capability isolated, and a clean patch merged into your main branch.

Repeat that process twenty times across a year. You will not need a rewrite. You will have built one, piece by verified piece, without ever taking the system offline.

Keep reading

Next in the log

The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.