{"slug": "i-audited-my-own-ai-generated-refactor-and-found-46-bugs-here-s-what-that-taught", "title": "I audited my own AI-generated refactor and found 46 bugs. Here's what that taught me.", "summary": "A developer audited an AI-generated code refactor of the open-source CLI tool YouMindAG and discovered 46 undefined references across 7 files, breaking 7 of 14 commands. The refactor had reduced a 1,920-line entrypoint to 410 lines but silently dropped imports, causing bugs that ranged from loud crashes to silent failures in specific code paths. The developer fixed all bugs and added ESLint's no-undef rule to prevent similar issues.", "body_md": "*How a 1,920-line file turned into 410 lines, why \"it works\" was a lie twice, and why the fix wasn't a smarter model — it was a gate that doesn't trust anyone, including me.*\n\nI maintain [YouMindAG](https://github.com/CESARBR2025/youmindag), an open-source CLI (`npx youmindag`\n\n) that injects project context — architecture, dependencies, rules, DB schema — into AI coding tools like Claude Code, Cursor, opencode, and Copilot, so they don't have to rediscover your codebase from scratch every session.\n\nBy v2.7.0, the CLI's entrypoint, `bin/run.mjs`\n\n, had grown to **1,920 lines**. One file. Install logic, upgrade logic, seventeen subcommands, vault population, dev-server wrapping, AST-based tracing — all of it, flat.\n\nI did what you're supposed to do: I modularized it. With an AI coding agent doing the heavy lifting and me reviewing, I split it into `lib/`\n\n— one file per concern, one file per command family. By v2.9.0, `bin/run.mjs`\n\nwas down to **410 lines**, functioning only as an orchestrator.\n\nClean diff. Tests green. I shipped it.\n\nIt was broken in seven different ways.\n\nA few smoke tests in, three commands started throwing `ReferenceError: RESET is not defined`\n\nand similar. I traced it manually:\n\n`lib/graphify.mjs`\n\nused a console-color constant `RESET`\n\nin 11 places. Zero imports of it.`lib/populate.mjs`\n\nhad the same missing import, silently breaking the summary output of the vault auto-population step.`lib/commands/misc.mjs`\n\nreferenced a `VERSION`\n\nconstant that had never been passed in — it was a global in the old monolith, and extraction turned it into nothing.I fixed the three, and — this is the part I want to be honest about — I did not go looking for a fourth. I wrote eight regression tests for the three I'd found, ran the suite, saw 58/58 green, and shipped v2.9.1.\n\nEight tests, three real bugs found by reading error messages one at a time. That's not an audit. That's whack-a-mole with good intentions.\n\nA couple of releases later I asked myself an obvious question I'd skipped: if extraction can silently drop an import once, what's stopping it from doing that seven more times in files I haven't touched yet?\n\nSo I added ESLint with a single rule that matters here — `no-undef`\n\n— and pointed it at everything under `bin/`\n\nand `lib/`\n\n:\n\n```\n// eslint.config.mjs\n{\n  rules: {\n    'no-undef': 'error',\n  },\n  files: ['bin/**/*.mjs', 'lib/**/*.mjs'],\n}\n```\n\nThen I ran it.\n\n**46 undefined references. Spread across 7 files. 7 of 14 CLI commands broken or silently failing.**\n\n```\nlib/fs-helpers.mjs      +readFileSync\nlib/commands/db.mjs     +createInterface, parseEnvFile, hasPostgres  (+ a CWD→cwd typo bug)\nlib/commands/dev.mjs    +mkdirSync, openSync, closeSync, appendFileSync,\n                         dirname, execSync, spawn, writeYoumindagData\nlib/commands/misc.mjs   +rmSync, relative, extname, execSync,\n                         createInterface, findProjectFiles\nlib/commands/sync.mjs   +mkdirSync, dirname, execSync, extname\nlib/commands/trace.mjs  +join, existsSync, execSync\nlib/commands/watch.mjs  +watch, statSync, populateVaultFiles\nlib/vault.mjs           +writeYoumindagData  (lost during extraction entirely)\n```\n\nSome of these were commands that would crash loudly on first use — annoying, but at least visible. Others were worse: `youmindag dev --wrap`\n\nand `youmindag sync`\n\nwere failing in code paths that only execute on specific flags or specific project states, meaning they could sit unnoticed for weeks in a project that never happened to hit that branch.\n\nI fixed all 46, then verified every one of the 14 CLI commands manually against a real project — not just \"does the test suite pass,\" but \"does `youmindag db`\n\n, `youmindag dev --status`\n\n, `youmindag trace --client X`\n\neach actually do the thing\" — one at a time.\n\nThe bug count isn't the interesting part. Missing imports after a mechanical extraction are a known failure mode; anyone who's done a big refactor by hand has hit this. The interesting part is *why I missed 46 of them the first time and only 3 the second, and why \"read the diff carefully\" was never going to close that gap.*\n\nWhen an AI agent extracts a function from a 1,920-line file into a new module, the failure mode isn't wrong logic — the logic is usually copied verbatim. The failure mode is **forgetting what the extracted code silently depended on**. `RESET`\n\nused to be defined once, at the top of the monolith, and every function in that file could reach it without ever importing anything. Once you cut that function out into its own file, that implicit access disappears — and nothing about the extracted code *looks* wrong. It reads perfectly. It's only wrong at runtime, on the exact line that reaches for something that isn't there anymore.\n\nAnd here's the uncomfortable bit: I was reviewing that same code with the same kind of attention an LLM has when it writes it — I was reading it for whether it looked correct, not tracing every identifier back to a binding. That's a slow, mechanical, unglamorous check. It's exactly the kind of check a human reviewer skips under time pressure, and exactly the kind of check a static analysis tool never skips, because it doesn't get tired and it doesn't trust that something \"looks fine.\"\n\n`no-undef`\n\nisn't a smart rule. It doesn't understand your architecture, doesn't know what a good abstraction looks like, doesn't have opinions. That's precisely why it caught what I didn't: it isn't pattern-matching on \"does this look like working code,\" it's mechanically checking \"is every identifier bound to something.\" My eyes are good at the first question and bad at the second. A linter is the opposite, and after this I stopped assuming my eyes were enough.\n\nThe real fix in v2.9.3 wasn't \"be more careful next time.\" It was making carelessness structurally impossible to ship:\n\n```\n\"scripts\": {\n  \"test\": \"node --test\",\n  \"lint\": \"eslint bin/run.mjs lib/*.mjs lib/commands/*.mjs\",\n  \"verify\": \"npm run lint && npm test\",\n  \"prepublishOnly\": \"npm run verify\"\n}\n```\n\n`prepublishOnly`\n\nruns automatically on every `npm publish`\n\n. If lint or tests fail, the publish fails. I tested this by deliberately breaking a file and confirming the publish got blocked before it reached npm.\n\nThis means the class of bug that shipped in v2.9.0–v2.9.2 — a missing import slipping through review — cannot ship again without someone deliberately bypassing the gate. Not \"probably won't.\" Cannot, structurally, by default.\n\nYouMindAG is at v2.9.3 now, MIT-licensed, on [GitHub](https://github.com/CESARBR2025/youmindag). The commit history above is real and public if you want to check my math — `git log`\n\ndoesn't round up.", "url": "https://wpnews.pro/news/i-audited-my-own-ai-generated-refactor-and-found-46-bugs-here-s-what-that-taught", "canonical_source": "https://dev.to/cesarbr2025/i-audited-my-own-ai-generated-refactor-and-found-46-bugs-heres-what-that-taught-me-14ah", "published_at": "2026-07-15 20:21:07+00:00", "updated_at": "2026-07-15 20:40:22.543043+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "ai-tools", "ai-agents", "machine-learning"], "entities": ["YouMindAG", "Claude Code", "Cursor", "opencode", "Copilot", "ESLint"], "alternates": {"html": "https://wpnews.pro/news/i-audited-my-own-ai-generated-refactor-and-found-46-bugs-here-s-what-that-taught", "markdown": "https://wpnews.pro/news/i-audited-my-own-ai-generated-refactor-and-found-46-bugs-here-s-what-that-taught.md", "text": "https://wpnews.pro/news/i-audited-my-own-ai-generated-refactor-and-found-46-bugs-here-s-what-that-taught.txt", "jsonld": "https://wpnews.pro/news/i-audited-my-own-ai-generated-refactor-and-found-46-bugs-here-s-what-that-taught.jsonld"}}