The Drift Log · Audit, then actually repair
From Audit Findings to Automated Refactor Pull Requests
7 November 2026 · 3 min read · 648 words · established

Transform static audit diagnostics into verified, scoped pull requests using AST codemods and pre-flight test verification.
Audit tools usually stop at the diagnostic. They parse an abstract syntax tree, identify an anti-pattern or deprecated interface, count the violations, and write a report. Some output SARIF files; others generate HTML dashboards or log thousands of lines to CI output.
The team reviews the report, files three Jira tickets to represent two hundred disparate issues, and returns to sprint work. The audit becomes a static ledger of technical debt that everyone acknowledges and nobody fixes.
Audits fail to resolve debt because the translation layer—moving from a diagnostic message to an executable change across dozens of files—is treated as manual labor. To turn an audit into an asset, the diagnostic engine must feed directly into automated refactor pipelines that generate reviewable, verified pull requests.
From Diagnostic Records to Transform Targets
Static analyzers emit records containing basic metadata: file, line, column, rule_id, and a descriptive message. When audits stop there, the developer must locate the file, understand the rule, determine the replacement pattern, rewrite the code, and run tests.
To automate the repair, an audit finding must carry transformation semantics. This requires treating static rules not as linters, but as match criteria for concrete AST transforms or codemods.
Consider an audit finding that flags an unsafe internal utility call:
{
"rule_id": "deprecated-buffer-alloc",
"file": "src/net/codec.ts",
"start": { "line": 42, "col": 12 },
"end": { "line": 42, "col": 35 },
"context": "new Buffer(size)"
}
A passive audit leaves this in a table. An active audit repair pipeline maps deprecated-buffer-alloc to an explicit transform script: replace new Buffer(size) with Buffer.alloc(size), ensure the global import exists, and format the modified file.
If a rule cannot be expressed as an unambiguous transform, it belongs in a human review queue. If it can, it should never be presented as a text report.
Enforcing PR Blast Radius
The most common failure mode in automated refactor workflows is over-batching. An automated tool identifies 400 instances of a pattern across a monorepo, applies the transform everywhere, and opens a single 12,000-line pull request.
Large automated PRs do not get merged. They sit open, accumulate merge conflicts, touch unrelated domain boundaries, and break obscure edge cases. Reviewers reject them because the verification cost is too high.
Effective PR generation requires strict boundaries:
- One invariant per branch. Do not combine an API deprecation fix with formatting changes or unrelated lint fixes.
- Package-level isolation. If a repository contains multiple packages or distinct service modules, generate separate branches for each boundary.
- Bounded sizing. Cap automated pull requests at a manageable number of call sites (typically 10 to 30 files maximum).
As outlined in scaffolding surgical refactor branches from static audit outputs, constraining the diff size shifts the reviewer’s job from deep debugging to rapid verification.
Verifying the Patch Before Opening the Branch
An automated PR that fails CI or breaks runtime behavior destroys developer trust in the automation. Once a team sees two broken bot PRs, every future automated repair gets ignored or closed.
Before a branch is pushed to origin and opened for review, the automated refactor pipeline must execute a local verification gauntlet:
- Apply the transform. Mutate the AST and write the source files.
- Re-run the audit. Confirm that the specific
rule_idfinding count drops to zero for the touched files. - Execute local checks. Run type checking, linters, and the targeted unit test suite for the modified subtrees.
- Inspect the structural diff. Ensure no unexpected syntax changes leaked into the patch.
A concrete pre-PR verification step runs in the pipeline runner before any branch creation:
## 1. Apply transform to target files
npx jscodeshift -t transforms/buffer-alloc.ts src/net/codec.ts
## 2. Confirm the audit rule no longer triggers on the modified file
node ./tools/audit.js --rule deprecated-buffer-alloc src/net/codec.ts --assert-clean
## 3. Type check and run only tests matching the affected subtree
pnpm tsc --noEmit
pnpm vitest run src/net/codec.test.ts
If any step fails, the branch is aborted and logged for manual inspection. No pull request is opened.
This process is critical to closing the loop from repository audit to merged repair. When a pull request lands in GitHub with passing CI checks, a strictly scoped diff, and pre-verified test coverage, reviewers can merge with confidence in seconds rather than spending days untangling a noisy report.
Keep reading
Next in the log
- From Audit Report to Auto‑Generated Refactor PR
Turn static audit findings into repeatable, certified refactor PRs using SHPBL’s harness and API.
- Validating AST Structural Equivalence After Automated Refactoring
Run an AST‑capture‑compare harness before automated refactors to catch silent structural changes that can break code.
- Consolidating Duplicate Internal Utilities into Monorepo Packages
A concrete method for auditing, supersetting, and consolidating duplicate monorepo utility functions without breaking subtle consumer invariants.
The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.