Something's been bugging me about how most teams are handling AI-generated UI code right now.
The pattern goes: Cursor, Copilot, v0, or Claude Code writes the component. It looks right. It compiles. It probably even matches the Figma file at a glance. Then six sprints later someone notices the button padding doesn't match the design tokens anymore, or the loading state was never implemented, or there's a hardcoded hex value sitting in a component that's supposed to pull from the theme. Nobody did that on purpose. It just... drifted.
The numbers back this up if you don't already feel it in your own codebase. Faros AI's 2026 engineering report found code churn is up 861% against pre-AI baselines, and 31.3% more PRs are now merging without any human review at all. Humans didn't get worse at reviewing. There's just more to review than any team can keep up with, and a lot of what's slipping through isn't broken code — it's code that's quietly disagreeing with the design system it's supposed to be implementing.
So teams reach for the obvious fix: point another AI model at the diff and ask it to catch what the first one missed.
I think that's the wrong architecture, and it's worth explaining why.
The problem with "AI checking AI"
Using an LLM to catch drift introduced by another LLM has three structural problems that don't show up until you're relying on it in production:
It's non-deterministic. Ask the same model to review the same diff twice and you can get two different answers. That's fine for a suggestion. It's not fine for something you want to gate a merge on, because "sometimes it catches this class of bug" isn't a policy, it's a coin flip.
It's expensive in a way that compounds. Every scan is more tokens on top of the tokens that generated the code in the first place. At CI scale, across every PR, that adds up fast — and it's a cost that scales with your team's AI usage instead of shrinking it.
It's a black box checking a black box. If a model flags something, can you explain why to a teammate, in a way that's the same explanation every time? If not, you've just added a second layer of "trust me" on top of the first one.
None of this means detection should be AI-powered. It means the checker needs a different design than the thing it's checking.
What deterministic checking actually buys you
A deterministic engine — same input, same output, every single time — isn't just a nice property. It's what makes a check trustworthy enough to gate a merge on in the first place. If a rule flags something, it flags it because a specific, inspectable condition was true, not because a model's confidence crossed some threshold on a given run. That means:
- You can explain exactly why something was flagged, every time, to anyone.
- It's safe to run in CI as an actual gate, not just an advisory comment.
- It doesn't get more expensive as your team ships more AI-generated code — there's no additional model call per scan.
- Two people running it on the same code get the same answer, which is the whole point of having a shared standard at all.
This is the architecture we went with for ReWeaver: a versioned rule engine that runs the same checks over your design source and your code, surfaces drift as a diff, and never asks you to trust a probability score.
Drift isn't one thing — it's at least nine
"Design-code drift" gets used loosely, so it's worth being specific about what it actually covers. We ended up mapping it across nine dimensions, because "does the code still match the design" turns out to be a much bigger question than color and spacing:
- Design Consistency — hardcoded hex values and inline styles that bypass your design tokens.
- Accessibility — missing roles, broken keyboard patterns, the stuff that's functionally fine but unusable for real users.
- User Experience — the happy path is complete but the loading, empty, error, and undo states around it never got built.
- Reliability — stale closures, missing cleanup, absent error boundaries — the edge cases that don't show up until production.
- Maintainability — the defensive fallbacks and copy-paste noise that accumulate every sprint until the codebase is mostly scar tissue.
- Architecture — business logic that quietly collects in UI components instead of where it belongs.
- Testability — tests that pass on write and don't actually protect anything once the code changes.
- Security & Privacy — vulnerabilities reproduced from training data that look identical to safe code.
- AI Code Governance — no audit trail of what was accepted, overridden, or suppressed, and by whom.
A hardcoded color and a missing error boundary are both "drift" in the sense that matters here: the code no longer agrees with the intent it was supposed to implement, and nothing forced a human to make that decision on purpose.
Finding it isn't the hard part — deciding what to do about it is
A checker that only flags issues just moves the bottleneck. You still need someone to triage every finding, which doesn't scale any better than manual review did.
So, findings come with a proposed fix, not just a flag. And when something genuinely should be suppressed — a false positive, a deliberate exception — that suppression has to be an explicit, git-visible decision (a //reweaver-ignore with a reason), not a silently ignored warning. Given that nearly a third of PRs are merging without review at all, a decision gate only does anything if someone is actually the one making the decision. The goal isn't to add another layer of noise on top of an already-overwhelmed review process — it's to make sure the decisions that do get made are visible and on the record.
It's also model-agnostic by design. It doesn't matter whether the code came from Cursor, Copilot, Claude Code, or v0 — the same rule engine runs regardless, and it doesn't need extra API tokens to do it. It runs inline in VS Code, does a round-trip sync with Figma (not just one-way detection), and runs as a GitHub Action on every PR — no new dashboard, no workflow change.
Where this stands right now
We're in private beta and looking for a small number of teams actually shipping AI-generated frontend code to run this against a real repo and tell us what you find. Even if it's just one small workflow, your feedback is valuable.
The beta is developer-led, not a sales process — install it, point it at something real, see what surfaces. You get direct access to the founder and engineering team for bugs, questions, and feedback while we build this out.
(Current caveat, in the interest of not overselling: it runs primarily on Mac today. Windows support exists in beta but has some rough edges we're still smoothing out.)
If you want to see the detection engine before committing to anything, there's a no-signup Playground where you can paste a snippet of real AI-generated code and get a live drift score. If you're interested in the full beta — running across your actual codebase, Figma files, and PRs, that's here.
Either way, if you're dealing with this problem, I'd genuinely like to hear how you're handling it today, even if it's not with us.
Top comments (0)