Building with AI · Part 3
Findings Become Features: the audit loop gets teeth
Posted March 1, 2026
January proved aidd could produce volume. February was about making the volume mean something. It's the month the core loop - build, audit, remediate, verify - stopped being a workflow I followed and became a machine I operate. It's also the month I deliberately broke 25 "passing" features, and that one decision taught me more than the two thousand commits around it.
Choose for fit, not familiarity
On February 1, I started Spernakit v2 from scratch. Not a migration, a rewrite. The v1 mistake wasn't any specific technology; it was choosing every technology for familiarity instead of fit. v2 chose for fit:
| v1 | v2 | Why |
|---|---|---|
| Express | Elysia | Bun-native, end-to-end type safety |
| Prisma | Drizzle | No codegen, SQL-like TypeScript API |
| Winston | Pino | Light, structured JSON logging |
| DaisyUI | shadcn/ui | Components live in source, full control |
| Axios | native fetch | Zero dependencies |
| React Context | Zustand | Selector subscriptions |
| Zod routes | TypeBox | Elysia-native, no adapter |
| .env files | JSON config | Type-safe, no dotenv parsing |
Fifty-eight dependencies dropped. v2.0.0 shipped in six days - 67 commits on day one, 86 on day two, 121 on day three. Six days was possible because v1's 523 commits had already taught me what to build. That's the house rule now: the lessons are the blueprint - the code itself is not.
Day one also established the quality gate everything now hangs off of: bun run smoke:qc - typecheck, lint, build, format. One command, one answer.
The audit blitz
Over the next ten days, v2 went through twelve releases and ten comprehensive audit passes, a different lens each time: security, architecture, code quality, performance, frontend patterns, database design, React practices, tech debt, dead code, feature integration. Every audit emitted its findings as feature.json files in the backlog. Findings became features, features became measurable improvements, and aidd worked the backlog down.
Eighteen days in, v2 had more commits than v1 accumulated in five months. But commit counts weren't the point. The loop was. In parallel, three apps got rebuilt from scratch on v2 rather than migrated, and rebuilds beat migrations every time the two were compared. The second build benefits from every lesson the first build taught. A migration drags the scar tissue along instead.
The blitz also set a habit I intend to keep: audits run as passes over the whole surface, not spot checks. A pass that reports "clean" is information. A spot check that finds nothing is noise.
Verification as a growth strategy
The rest of February was the loop applied everywhere, and the details are where the craft lives:
- Spernakit hit 110/110 with plenty of fixes: a keygen modulo bias corrected with rejection sampling, a WebSocket proxy timeout dropped from 24 hours to 5 minutes, encrypted backups with AES-256-GCM and HKDF. The template grows through verification, not just construction.
- A security audit on the new DB admin panel found a critical SQL injection through unvalidated column names. Replacing trust with a mechanical check derived from ground truth is an instinct I expect to keep leaning on.
- A 1,342-line route file became 14 domain modules. Dead-code removal at that scale is only safe when a gate re-verifies everything behind you.
- Finally, the fleet-management vocabulary started showing up. When apps diverge from the template, classify it. Identical, or intentionally different? Naming the difference is what makes drift manageable instead of scary.
Check, check, check again
The audit is the best tool. aidd made the blitz possible; the blitz made every app after it measurably better. Twenty categories of automated scrutiny catch what eyeballing a diff never will and then filing what they catch as backlog features is what turns scrutiny into throughput.
What's next is scale. Six apps on one template is past the point where syncing by hand is honest work, and the v2 apps are already drifting in small ways. The template needs lifecycle tooling: shared type contracts between frontend and backend, some way to automate upgrades, validation that the API contract matches what the frontend believes. That's next.