AI coding agents routinely omit auth wrappers, middleware guards, and SSO config because that code compiles and looks like boilerplate, so it ships unless an end-to-end test actually logs in and catches it. The result is a silent production lockout: CI is green, the deploy succeeds, and your users cannot get in.
The engineering lead opened the laptop to a support queue that had been filling for forty minutes. Every ticket said the same thing: "Cannot log in." She pulled up the CI dashboard. Green across the board. Build passed, unit tests passed, linting clean. She switched to the staging URL and tried to log in herself. Redirected to the home page. Again. And again.
The deploy had gone out two hours earlier. An AI coding agent had refactored a module to clean up some routing logic. The diff looked tidy. The review looked fine. And somewhere in that tidy diff, the auth wrapper had vanished.
This is the story of that incident, the structural reason it happened, and the only kind of test that would have caught it before it reached production.
What happened: the auth wrapper that vanished
The team was moving fast, as most lean engineering teams do in 2026. They used an AI coding agent for a significant share of their daily PRs. On this particular morning, the agent refactored a routing module to consolidate some redundant path handling. The task was straightforward: clean up the structure, keep the behavior the same.
The behavior did not stay the same.
The refactored module dropped the call to withAuth(). In the original code, every protected route was wrapped through a function that checked session validity before rendering. After the refactor, the routes rendered unconditionally. No session check. No redirect for unauthenticated users. Just the app, open to anyone, and simultaneously closed to everyone because the downstream session logic that the rest of the app depended on was no longer being initialized.
The agent did not make a judgment call to remove auth. It simply did not recognize that withAuth() was load-bearing. It looked like a wrapper. Wrappers are the kind of thing that gets cleaned up during refactors. The agent cleaned it up.
The app compiled. The deploy succeeded. Users were locked out.
Why nothing caught it: compile, review, unit tests all pass
Here is what makes this failure mode so persistent. Every layer of verification that most teams actually run passed without issue.
The compiler was happy because removing an auth wrapper is syntactically valid. withAuth() wrapping a component is optional from the TypeScript compiler's perspective. The types resolved. The module exported cleanly. No errors.
The code review approved the diff because it looked like cleanup. A leaner routing module with less nesting. The change was reasonable on its face. Whether a human reviewer or an AI reviewer looked at it, the diff communicated "we simplified the routing logic." The removed wrapper did not announce itself as a security boundary.
The unit tests stayed green because unit tests mock auth. This is correct behavior for unit tests: you isolate the component and inject the session state you need. The tests for the refactored module confirmed that the components rendered correctly when given a valid session. They did not confirm that the valid session would ever exist in the first place at runtime.
Code review and unit tests pass on code that compiles. Only a test that actually logs in catches a missing auth wrapper.
Every static check reads code, not runtime. Only a test that actually logs in exercises the missing auth wrapper.
The companion post why AI code review misses auth bugs goes deeper on the structural reason code review cannot close this gap, but the short version is this: review reads diffs, not runtime behavior. A diff that removes an auth wrapper and a diff that adds a comment share the same fundamental property from a reviewer's perspective. Both produce valid code. Only one produces a lockout.
The pattern: wrapper code AI agents silently drop
This incident is not a one-off. It is one instance of a recognizable failure mode. When AI coding agents work on modules that contain wrapper patterns, they apply the same judgment a junior developer might apply during a cleanup task: if the wrapper is not obviously load-bearing from the code structure, it is a candidate for removal.
The wrapper patterns that recur in these incidents share a few characteristics. They compile fine without the wrapper. They look like optional scaffolding. And they only fail at runtime when a real user or a real session hits the code path.
Auth wrappers are the most common because they appear in most web apps and they are structurally identical to other wrappers the agent knows it is safe to remove. But the same pattern applies to middleware guards (the function that checks a JWT before a request is processed), route protection (the redirect logic on a protected page), and SSO/session config (the initialization code that must run before any authenticated action can proceed).
In each case, the wrapper is syntactically optional, semantically mandatory, and invisible to any verification layer that does not actually exercise the code path at runtime. For the deep dive on the full taxonomy of wrapper patterns AI agents silently drop, see the wrapper patterns AI coding agents skip.
The fix: end-to-end coverage on auth that maintains itself
The honest answer is not "add better linting" or "improve your code review process." Linting cannot enforce wrapper semantics. Code review is a diff-reading process, not a runtime simulation. The only fix is a test that actually logs in.
A test that drives a real browser through the login flow on a live preview environment will hit the locked-out state immediately. When the auth wrapper is missing, the session never initializes. The login page redirects back to itself, or the app loads but the user object is null. Either way, the test fails. The PR does not merge. The incident does not happen.
The challenge most teams face is that building and maintaining E2E auth tests by hand is expensive. Auth flows change. The login UI updates. The session logic shifts when you switch providers. An E2E suite that relies on hand-written, hand-maintained scripts rots within a few sprints. Most teams let it rot.
This is the problem we built Autonoma to solve. Our agents derive auth tests from the codebase itself, run them against a live preview on every PR, and maintain them automatically when the code changes. Here is how that maps to the incident above.
The Planner reads the codebase, identifies the routes that are protected by auth wrappers, and plans the test cases that must exercise them. It also generates the endpoints needed to set up the correct database state for each test scenario: a user account in the right state, the right session flags, the right permissions. The Planner does not need a human to write test cases or configure fixtures.
The Executor drives a real browser through the login flow on the live preview environment spun up for the PR. When the auth wrapper is missing and the login flow fails, the Executor hits the lockout state. The check fails. The Executor would have flagged the incident PR before anyone approved the merge.
The Reviewer classifies what the Executor found: is this a real bug, an agent error (a misnavigation), or a test/plan mismatch (the login UI changed in a way the plan did not anticipate)? In the incident above, the Reviewer would have classified it as a real bug: the login flow does not complete, the session is not established, and the protected route is not rendered for an authenticated user.
The Diffs Agent runs on every subsequent PR. When the auth UI changes, when a new protected route is added, when the session logic is updated, the Diffs Agent re-derives and maintains the auth test suite from the code diffs. The tests never rot because they are not hand-written scripts. They are derived artifacts that stay aligned with the codebase.
Autonoma turns the missing-wrapper incident into a PR-time failure instead of a production lockout.
An Executor that actually logs in would have hit the locked-out state on that PR's preview environment and failed the check before the merge. That is the only thing that would have caught it. And that is the coverage gap that, across the teams I talk to, almost no one has closed.
The broader case for E2E regression coverage on AI-assisted changes is covered in how AI agents break existing features. Auth lockouts are one incident type within a larger pattern of AI agents shipping changes that compile and review cleanly but fail at runtime.
The incident above is not unusual. Teams shipping fast with AI coding agents encounter this class of bug regularly: code that compiles, deploys, and passes review, but fails the moment a real user tries to use the feature it was meant to protect. Auth is the highest-stakes version because it locks everyone out at once. But the underlying failure mode, an AI agent treating a load-bearing wrapper as optional cleanup, applies wherever wrapper patterns exist in your codebase.
The gap closes with end-to-end coverage that exercises the actual login path on every PR. We built our four-agent system at Autonoma specifically for teams shipping fast with AI tools who cannot afford to staff a dedicated QA function but cannot afford production lockouts either. The Planner derives the tests. The Executor logs in against a live preview. The Reviewer separates real bugs from agent errors. The Diffs Agent keeps the suite current when your auth logic changes.
If your team is shipping with AI coding agents today, the test cases for a login page is a practical starting point for the assertions your E2E auth coverage should include. Autonoma turns those assertions into a maintained PR check instead of another manual test list.
FAQ
Yes. AI coding agents regularly drop auth wrappers, middleware guards, and session initialization code during refactors because that code compiles without the wrapper and looks like optional scaffolding. The agent does not recognize the wrapper as a security boundary. The result compiles, passes review, and ships to production, where users cannot log in.
Auth wrappers are syntactically optional. A function like withAuth() wrapping a component is not enforced by the TypeScript compiler or the linter. It looks structurally similar to other wrappers that are safe to remove during a cleanup. The agent applies the same judgment a developer would apply when simplifying a module: if the wrapper is not obviously necessary from the code structure, it is a candidate for removal.
Code review reads diffs, not runtime behavior. A diff that removes an auth wrapper looks like a cleanup to a reviewer, whether that reviewer is a human or an AI. The removed wrapper does not announce itself as a security boundary in the diff view. Review confirms that the code is syntactically valid and structurally reasonable, not that the app will actually authenticate users at runtime.
With a test that actually exercises the missing code path. For a missing auth wrapper, the only test that catches it is one that drives a real browser through the login flow on a live preview environment. Compiler checks, linting, unit tests, and code review all pass on code that omits an auth wrapper. End-to-end coverage that logs in does not.
Run an end-to-end test that logs in with real credentials on a live preview environment on every PR. The test should assert that the login flow completes, the session is established, and a protected route renders correctly for an authenticated user. If the auth wrapper is missing, this test fails before the PR merges. Tools like Autonoma derive and maintain these tests automatically from the codebase, so the coverage stays current as the auth logic changes.




