METHODOLOGY
The Multi-Agent Audit
Point sixty-seven read-only agents at one codebase, slice it eight ways, and let each agent look at exactly one thing. The output is not opinions — it is a single prioritized report with a technical-debt score. This is how the audit runs, and what two real ones found.
One Read, Many Eyes
An audit is a read fan-out: many agents looking, nothing changing. The pattern is mechanical. Partition the codebase into disjoint slices, assign every slice to every analysis domain, run the resulting grid of agents in waves, then hand all of their findings to a single synthesis agent that collapses them into one report. The same machinery, run in the opposite direction, becomes autonomous remediation — see the companion field report for the write half.
Every agent runs in the background and writes its findings to a file; the main context stays clean and is notified on completion. A manifest.json records which agents finished and which are pending, so an interrupted run resumes from the last wave instead of starting over. Nothing the agents touch is mutated — the entire pass is non-destructive by construction.
Eight Domains, One Pass
Each domain is a lens — a fixed set of questions an agent asks of the code in front of it. Eight lenses sweep every partition; a ninth, axial drift, gets its own two-step pass (see §4). The lenses do not overlap, so two agents never report the same class of issue from different angles.
| Domain | What it looks for |
|---|---|
| Architecture | Layer violations, circular dependencies, coupling |
| Security | OWASP categories, credential handling, injection vectors |
| Code Smells | God classes, long functions, DRY violations |
| Type Safety | Any usage, missing hints, type: ignore |
| Async Patterns | Race conditions, blocking calls inside async, resource leaks |
| Error Handling | Bare excepts, swallowed exceptions, missing context |
| Test Quality | Coverage gaps, flaky patterns, mock overuse |
| Tech Debt | TODOs, deprecated APIs, magic numbers |
| Axial Drift | Wrong-axis duplication — the N×M trap (§4) |
Partition and Wave
The codebase is cut into source partitions and test partitions — slices by code area, not by size. One agent gets one (domain × partition) cell: a security lens over the adapters, a type-safety lens over the hub core. That keeps every prompt narrow and every finding traceable to a place. Agents launch five at a time — enough parallelism to finish in minutes, not so much that the final synthesis drowns in context.
P1–P8 and tests into T1–T6 by code area, so no two agents read the same files.Partitioning by code area is what makes the audit cheap to read at the end. Each finding already carries a file and a line; synthesis is a merge, not a re-investigation.
Two-Step Drift, Second-Opinion Search
Axial drift is the duplication of a cross-cutting concern across siblings on the non-primary axis — the same retry logic copied into the NATS store and the Redis store, the same auth check pasted across three adapters. It is the one class of issue a single-file lens cannot see, so it gets two passes and a confirmation.
importlinteraxial-adr-reviewccc) measures how alike the suspected siblings actually are, turning a hunch into a similarity score.That third step is also a cross-domain referee. Any finding a primary lens raises — a security smell, a DRY violation — is checked against semantic search, and the score decides its fate:
| Similarity | Verdict |
|---|---|
| > 0.90 | Confirmed duplication / exact pattern match |
| 0.70 – 0.90 | Probable — manual review required |
| 0.50 – 0.70 | Weak signal — likely false positive |
| < 0.50 | Discard |
finding(domain) → ccc.confirm(top-5)
→ no match in top-5 ⇒ severity −1 # downgrade an unconfirmed claimA claim no second opinion can corroborate is not deleted — it is demoted. The audit prefers an under-stated finding to a confident wrong one.
The Report It Produces
Sixty-six findings files are useless as a deliverable. The synthesis agent reads them all and writes a single AUDIT-SUMMARY.md — the only artifact a human is meant to open first.
- Executive summary. Overall health, security posture, test-coverage status, the headline debt items.
- Severity buckets. Every finding sorted into P0 (critical), P1 (high), P2 (medium), P3 (low) — with file and line.
- Axial-drift summary. Contracts kept versus broken, N×M traps, and which were confirmed by semantic search.
- Metrics dashboard. Issue counts per domain, the severity distribution, and a single technical-debt score on a 0–100 scale where 100 is pristine.
- Recommended actions. Prioritized, each with an effort estimate, plus a top-10 quick-wins list: high impact, low effort.
The debt score is the one number you can track release over release. Everything else tells you what to fix; the score tells you whether the codebase is getting healthier.
Two Real Audits
The pattern is not theoretical. Roxabi runs it on its own agent factory, and the recaps live in the open. Two are worth reading in full.
A — Quality audit, 2 June 2026. A full sweep of the factory codebase: 3,291 files, every domain, every partition.
The severity split was 2 · 172 · 664 · 427 across P0–P3, and all eleven import-linter contracts held — the architecture was sound, the debt was volume, not collapse. The two P0s are the kind of bug a single test run hides. One was a 165-line process_one method fusing streaming and non-streaming paths, processor hooks, session-ID updates, and error handling into one unreadable block. The sharper one: _log_turn caught every exception, logged it, and returned — and the caller then ack()'d the JetStream message. A failed SQLite write therefore permanently lost the conversation turn, with a green log line to mask it. Green ≠ correct, found by reading, not by running. This audit is the precursor the Autonomous Remediation report later paid down.
Read the recap: 2026-06-02-quality-audit/AUDIT-SUMMARY.md →
B — Codebase audit, 18 May 2026. A narrower, transversal pass on three axes — hexagonal purity, code mutualization, simplification — and a different kind of result.
This one scored no debt number; it produced a refactor map. The verdict was reassuring: zero import-linter violations, clean layers, isolated packages — the debt was localized, not systemic. Three jobs stood out: ~350 lines of dead code from a retired routing cluster, removable with zero risk; a handful of implicit ports scattered outside core/ports/; and a NATS heartbeat lifecycle copied verbatim across four clients, begging for a shared base class. What makes the recap worth reading is its discipline about false positives — two apparent duplications turned out to be deliberate role interfaces (Fowler) distinct from driven ports (Cockburn), and were renamed to break the homonymy rather than merged. An audit that cannot tell drift from intent generates busywork; this one drew the line and shipped seven PRs the next day.
Read the recap: 2026-05-18-codebase-audit/summary.md →
Every recap — quality sweeps, cluster audits, token-isolation reviews — sits in one folder, alongside the playbook that defines the method.
- All audit recaps · roxabi-factory / artifacts / audits →
- The playbook · multi-agent-audit-playbook.md →
What Scales
Agent count tracks codebase size, not ambition. The wave width stays roughly constant; only the number of waves grows.
| Codebase | Agents | Wave size | Duration |
|---|---|---|---|
| < 50 files | 18 | 4 | ~12 min |
| 50 – 200 files | 34 | 4 | ~22 min |
| 200 – 500 files | 50 | 5 | ~45 min |
| 500+ files | 69+ | 5 | ~65+ min |
The findings are specific to one repository. The shape is not — these are the parts that carry to any codebase.
- Partition by area. One agent, one lens, one slice. No duplicate work, every finding pinned to a place.
- Five-by-five waves. Parallel enough to be fast, bounded enough that synthesis still fits in one context.
- Manifest-tracked. An interrupted run resumes from the last wave instead of starting over.
- Two-step drift. A linter catches structure; a semantic agent catches intent; search confirms both.
- Second-opinion gating. An unconfirmed claim is downgraded, not asserted — high recall without the false-positive tax.
The audit is only the read half. Once the report exists, the same fan-out runs in reverse to pay it down — that run is the Autonomous Remediation report. Read, then write, fully on the record.