One of my review subagents caught an IDOR in code the model had just written: any user could write to any chat by changing a UUID in the request. It never reached production. What caught it was another instance of the same model that introduced the bug.
Over a single session the agent also pushed to the remote twice without asking, shipped react-icons where the design specified a custom SVG, and painted a button #FFFFFF where Figma said #0F1A20. Seventeen PRs, two repositories, fifty-odd files, thirty-two post-implementation corrections in all. None of them became a production bug.
Nine months ago I published 212 Sessions, my last piece on supervising this workflow. In it I measured 89% success rate, 4x faster median delivery, two production incidents against eleven on standard prompting. Since then the tooling changed and the method sharpened. What used to be “write specs, then ultrathink” now looks more like a DevOps pipeline than a conversation, and the reason is the thing 212 got half-right.
The Design Gets Read Before the Code
The agent starts by reading the task itself. I paste a monday.com task URL and it pulls the title, assignee, status, the full description with its acceptance-criteria checklist, linked Figma URLs, and attached screenshots over MCP. Nothing gets copy-pasted or summarized; it sees exactly what the PM wrote.
Then it reads the design, because the most expensive iterations come from an agent that builds from memory. The first time I let it work that way, it produced react-icons instead of the custom Figma SVG, the wrong border color, button text at #FFFFFF instead of #0F1A20, a 1px separator where the design called for 0.5px, and a 24px border-radius instead of 8px. Ten piecemeal fixes later, this went into project memory:
Before implementing ANY UI component, call
get_design_context+get_screenshotfor the specific Figma node. Check every detail: colors, borders, icons, padding, hover states, tooltips. Do NOT implement from memory.
Now, for every component, the agent pulls the exact CSS from the Figma node, captures the visual reference, and checks every property against the plan before writing anything. That one rule cut about 80% of UI fix iterations.
The Plan Gets Torn Apart First
The agent plans in read-only mode, unable to edit anything but the plan document. Two or three explorer subagents map the terrain first: current component structure, the theme system and design tokens, similar features already built. The plan they feed covers context, a file-by-file change summary, execution order with a dependency graph, and how to verify the result end to end.
Then two subagents tear that plan apart before a single line of code exists, one on architecture and security, one on TypeScript patterns and conventions. On the chat redesign the first pass flagged eight problems, most of them structural: a content-width change that hit every user, UnauthSidebar dropped into the wrong architectural layer, a ConfirmModal duplicated instead of reused, SVG icons that needed forwardRef to work with Chakra. A second pass, fresh from zero, caught four more, down to semantic-token keys that had to be nested objects instead of flat strings.
Twelve issues found and killed before implementation started. A spec tells the agent what to build; it does not tell you the font change is global and will break your auth pages. After agents approve the plan, it is time for me to step in, and in most cases, something will still be missing.
Implementation Is the Boring Part
Once the plan survives review, building is mechanical. All styling goes into the Chakra v3 theme system: a custom _unauth condition via a data-unauth attribute, semantic tokens that auto-resolve on auth state, button recipe variants (brandSolid, brandOutline), and text styles for every pattern in the design. Zero conditional styling in components. One data-unauth="true" on the container and everything downstream resolves.
A subagent pulls the SVGs from Figma, converts them to React components with forwardRef + SVGProps<SVGSVGElement>, and barrel-exports ten typed icons in one parallel task.
Each component gets written and immediately verified: npx tsc --noEmit, then yarn lint, then yarn build, then a Playwright screenshot against Figma. TypeScript runs after every single file edit, not once at the end. On the backend, the sequence is the same: code, lint, format, tests, and API-level E2E, all without me. After several rounds of agent review, I step in.
Where the Bugs Actually Die
The failures that matter surface in code review, where the same two subagents read the full diff in parallel: one hunting architecture drift and security holes, the other enforcing zero any, real discriminated unions, and pattern compliance. On the chat redesign this took four rounds. The first found seven problems, including a <Button> nested inside a <Link> and a batch of semantic tokens created but never used. The next two rounds cleared five more between them, down to a bottom-margin change that leaked onto every mobile user instead of just the unauthenticated ones. The fourth was clean.
Nested interactive HTML and a leaked margin are not the bugs that make headlines. The IDOR from the opening is.
When Both Reviewers Are Wrong
The tech lead noticed that the copy button was hidden for unauthenticated users: readOnly gated both copy and the like/dislike reactions. “Correct behavior,” he wrote. “Unauth is read-only, no interactions.” The fullstack enforcer agreed the readOnly guard was clean code: one boolean, one gate, no special cases.
They were both wrong. Copy is a read action. The user copies text to their own clipboard, nothing touches the server. Like/dislike is a write action: it persists feedback to the database and requires a user ID. Gating both behind readOnly conflated a security boundary (write operations) with a UX convenience (clipboard). I told the agent to split the gate:
const showCopy = message.message != null && message.message.length > 0;
const showReactions = isSaved && !readOnly;
Two lines. Neither reviewer suggested this: they were debating whether the existing gate was correct, not whether the gate itself was the wrong abstraction. That’s the tie-break: not picking a side, but seeing that both sides are answering the wrong question.
The same model implemented that split in two lines once I saw it, and had defended the broken gate twice when it reviewed itself. Genius and idiot in the same weights, and I have never found the line between them.
The Browser Gets a Vote
After review, the agent drives the running app in a headless browser and checks the states a diff cannot prove:
Empty state: sidebar, logo, starters, input, disclaimer, Log In button
Send message: user bubble color, streaming indicator, bot avatar
Response: markdown rendering, copy button, no like/dislike for unauth
Auto-resize: multi-line input expands up to 4 rows
Sidebar collapse: toggle shows icons-only view with tooltips
Mobile: at 375px, drawer opens and closes, header layout holds
Clear Chat modal: title, body, buttons match Figma
DB persistence: query PostgreSQL to confirm messages saved
Each check saves a screenshot to disk for comparison against Figma.
Thirty-Two Corrections Across Seventeen PRs
Plan-review findings are not included. This count begins after implementation and covers code, UI, process, CI, and merge failures.
The merged PRs hide this history. Without structured review, some of these corrections would have shipped as bugs, some as broken process, and the rest would have waited for the next developer to trip over them.
Every Mistake Becomes a Rule
Each correction turns into a rule, and the rules persist across sessions as markdown files:
feedback_figma_first.md : Verify each component against Figma BEFORE implementing
feedback_no_commit_without_review.md : STRICTLY FORBIDDEN to commit without explicit user approval
feedback_simplifier_danger.md : Simplifier can revert uncommitted work, commit/stash first
feedback_dco_signoff.md : Always use git commit -s for DCO Signed-off-by
feedback_full_review_report.md : Report ALL review findings verbatim, never filter
The agent reads these at session start. They are non-negotiable. The one that changed the most:
Never commit, push, or create PRs without the user’s EXPLICIT instruction. Even if the plan says “commit and push” as a step, STILL ask.
That came from the agent committing and pushing without my review, twice. If an error reflects a general failure mode, the rule goes into global memory; otherwise, it stays with the project.
One Feature, End to End
The ML integration ran the whole pipeline on a single task: replace the mock chat handler with real LLM streaming from an external service. Plan created, two review rounds, eighteen issues found and fixed, then approved. The implementation:
ML client with AsyncGenerator SSE streaming
withRetryfor connection resilience (HTTP status check inside the callback, caught in review)isMlConfiguredguard (no default QA URL, caught in review)is_processingflag management (caught in review)Empty response guard (caught in review)
Business logic extracted from controller to service (suggested post-implementation)
Type-safe SSE events via
StreamEventEmitter(caught in the third review)
The reviewers caught six things that were production bugs waiting to happen:
IDOR vulnerability (any user could write to any chat via UUID)
Client disconnect doesn’t save the response (fixed: let ML finish, save to DB)
SSE parser stripped all whitespace instead of the single leading space the spec allows (broke markdown formatting)
Empty
data:lines filtered out (broke paragraph breaks in markdown)doneevent not sent on error paths (frontend hung)Type assertions instead of proper discriminated unions
That IDOR got the same treatment as the whitespace bug and the hung frontend beside it: reported verbatim, fixed, verified.
The Stack Behind It
The agent is Claude Code, running as a CLI process that sits inside the repo all day, rather than a chat window I paste into. It reads tasks from monday.com and designs from Figma Dev Mode over MCP, drives a headless Playwright browser for the E2E checks, and controls my actual Chrome for debugging.
The review layer is subagents with fixed jobs: a tech-lead-architect for architecture, security, and breaking changes; a fullstack-typescript-enforcer for types, patterns, and coverage; a code-simplifier for dead code and naming; a verify-app agent that runs the browser checks.
Every commit clears a Lefthook chain before it lands: TypeScript, license check, ESLint, Prettier, JSDoc, and unit tests. Every PR clears two of those reviewers. Then it clears me. I read every diff by hand. I never opened an IDE to write code. I opened it to read files and point at Figma elements. Across seventeen PRs, the test suite stayed green.
The Update to 212 Sessions
Nine months ago I wrote: “Most engineering failures aren’t about complexity, they’re about vague specifications we code around instead of fixing.”
After thousands more sessions, that is half the story. A perfect spec still ships with wrong icon imports, CSS shorthand that overrides explicit values, type assertions where discriminated unions belong, missing finally blocks on async operations, and mobile edge cases that only surface at 375px. The spec caught most of it. The review pipeline caught most of what the spec missed. The browser caught what neither a plan nor a diff could prove. Across these seventeen PRs, the gates produced thirty-two corrections. None reached production.
Every gate that matters ends in a human decision. The agent writes, reviews, and tests, but a person decides which finding is real, which of its decisions to overrule, and whether the feature is actually done. Without someone at the gates, the pipeline emits findings and calls it governance. The difference between producing those findings and preventing the problems from shipping was me.
None of the implementation work was unusually difficult. These were junior-level tasks, and I chose them on purpose, so the piece would not reduce to “the model is stupid.” Even at that level, it needs supervision. The problems that actually leave scars, the ones with no clean spec and a dozen systems touching each other, are where it degrades fastest.
This run is not why I believe this. It is the one I counted. Across thousands of sessions, the details changed and the pattern did not.
The quality collapse I wrote about last year reads to me less like AI writing worse code and more like teams shipping its first draft with the review layer torn out. I cannot prove that is the cause. I can tell you what this pipeline refused to skip.
The model earns its place. I am faster than I was, and throughput went up, though the work is less fun than it used to be. AI can take a feature end to end. Without the gates, quality degrades dramatically, and across the industry it has already fallen off a cliff. Automation alone cannot pull it back. The human is the switch between poor quality and good.
The AI wrote the code. The gates shipped it.




For your Claude agent, are you using Opus? I find Opus got dumber over time.
Interesting. It is the most formidable attempt to fix the problems that using agents create 😁 And I respect it for that. The EXPERT in the loop is unavoidable as you state in the article. And the false negatives as hard to detect as before. Not sure if being faster, not sure if better, worth all what people is doing. And not sure if any dev has improved his quality of life after this. Anyway, I'm pretty sure your work flow is the exception, not the norm. I appreciated your honesty and professionalty for sharing it, as usual. Thanks.