An agentic SDLC shifts the bottleneck from writing code to verifying it. Review worked as a proxy for verification when writing was the slow part, because if a person wrote a change, a person could read it. Agents broke that ratio, and adding reviewers doesn't close the gap.
Agent-written code doesn't need a separate review process. Agent-authored and human-authored pull requests clear the same tests, the same two approvals, and the same deployment path. Neither approval asks who wrote the change.
Testing AI-generated code means generating coverage per change, not maintaining a fixed suite. An agent reads each PR, assembles a suite from what actually changed, and writes the Playwright and Appium tests new coverage requires. Every release candidate then clears roughly 400 end-to-end flows.
Not every test failure should block a release. A failing test re-runs twice under different conditions before it counts as a bug, and each bug's priority feeds a readiness status that can programmatically stop a deployment.
Ship fast and you find out what's broken from your customers. Ship safe and you find out you're too slow to keep up with your competitors.
Before coding agents came and changed everything, most companies chose a balance they could live with. Then, agents started writing a meaningful share of the code and that balance shifted.
The speed with which coding agents can generate PRs often justifies shipping faster than the team can validate the work. Review processes that used to catch problems can't keep up with the volume of AI-driven development, and teams are quietly sliding toward speed over quality.
Given how fast you can ship now, the question becomes how fast should you ship? And what is your company willing to risk in order to ship faster? More concretely: what does an agentic SDLC look like that balances speed and quality?
At QA Wolf, we understand these challenges because we work with companies like DoorDash that need to move fast – but have large user bases that count on their apps to work. Downtime on DoorDash would disrupt drivers’ workdays worldwide, and you don’t want to interfere with someone’s ability to get their takeout order. We also work with some of the largest dev tools and AI-native companies like Drata, Grafana, Lovable, and CodeRabbit, who are redefining what an agentic SDLC looks like and doing so with verification and E2E testing at its center.
In this piece, we’ll share the balance our engineering team came to: how we validate, ship, and recover daily, with agent-written and human-written code going through identical processes.
We ship to production once every day. That gives us enough runway to run our end-to-end suite and clear blocking bugs before a release goes out, with room to cut more than one PR from the release when we need to. The PRs that make up those releases come from agents, humans, or a mix of both, and each one passes through the same validation and deployment path before it goes live.
Agentic E2E testing is the foundation
As a QA testing company, it won’t surprise you to learn that we rely heavily on automated end-to-end tests. We also get to use our own agentic platform to test itself.
We first check every pull request against our codebase during the PR stage. We then work on outlining any additional or missing coverage for the new release. We built an agent that autonomously explores an app, while parallel background triggers continuously draft and clean a test outline (via *.flow.ts files) and build a world model of the app's pages and how they connect.
The agent tracks what's already tested, so it isn't proposing new flows for paths we already cover in existing tests. Another agent then generates Playwright and Appium tests and updates existing tests if the release requires changes.
After it generates or updates tests, it then runs all the new flows it builds to make sure they work. If any of the new flows fail, the agent updates them with a relevant change and keeps trying until the flow passes or it runs out of ideas. Once all those tests have passed, we can start validating the PR.
Teams can also pin specific tests to run on every PR regardless of what changed, but most of the suite is still assembled dynamically: our agent reads the PR's title and description and pulls in whichever flows relate to what changed, potentially including any new coverage added in the previous step. That saves us time and confusion. Engineers aren't waiting on a suite that has nothing to do with their change and we're not burning cycles running hundreds of irrelevant flows just to be thorough. By the time we cut a release candidate, it's already cleared PR-level testing.
The release validation suite that runs next is the full ~400-flow pass across web, AI, Android, and iOS, checking 100% of front-end workflows before anything ships.
All of that is on top of the unit, integration, and linting checks already built into our PR process. Whenever we attempt a release, our release automation creates a temporary pre-production preview environment for the RC, and ArgoCD syncs the deployment into it. We poll each service's /health endpoint until everything comes back healthy, then hit deploy_success, which notifies the QA Wolf platform and kicks off the release validation suite.

Failures are automatically classified
When agents write a meaningful share of the code, the number of PRs goes up, and so does the number of test failures. Every test failure needs a judgment: does it stop the release? If you judge by hand, the judgment process becomes the new bottleneck. Skip the oversight, and you risk blocking the release for cosmetic bugs or pushing real bugs to production.
A failing test isn't the same thing as a bug, and at volume that gap widens fast. More PRs means more runs, and more runs means more flakes. So before making a go/no-go decision, we run any failing test two more times under different conditions. If it passes on either retry, we ignore the failure for now. If it fails all three attempts, we file a bug.
Only then does gating come into it. Our own releases run on the same release-gating capability we ship to customers: Every bug the platform finds is assigned a priority, and the platform uses it to calculate a readiness status that can programmatically prevent a deployment when necessary. Blocking bugs stop the release.
But not all bugs should prevent a release. That’s the part some teams get backward. When volume goes up, the instinct is to tighten everything: block on more, require more sign-off. It feels safer, and it stops releases that had nothing wrong with them.
In our process, the release owner already knows which bugs blocked a release and where to look. So the release owner spends their time figuring out what actually went wrong instead of figuring out what's worth looking at. They work through each flagged bug: whether it's real, whether this release caused it or it was already in production, and who will fix it. It's a short list, so one person can own an active release without drowning in it.
Release coordination and safeguards
A release used to be something the people who built it could explain. When agents write a meaningful share of it, teams lose most of the context a human used to provide. So release coordination can't depend on someone holding that context. It has to run off the signals the release produces itself
In our process, release coordination happens in two places: inside the release PR itself, and in a thread in our release-specific Slack channel, which serves as a live checklist as the release progresses:
- Pre-release checks: Basic checks, Docker images built, PR approved, release owner assigned, branch up to date
- Release validation: E2E status and Linear release blockers
- Deployment: PR merged, deploy job approved, changes pushed to
deploy-production - Post-release checks: ArgoCD synced and healthy for the relevant systems
The underlying signals come from GitHub, QA Wolf, Linear, and ArgoCD. The release thread pulls them into one place.
Sometimes production changes while an RC is open — most commonly due to a hotfix. In that case, the release automation marks the branch as stale and notifies the release thread. Those changes have to be merged back into the RC before the release can proceed, so it doesn't ship from a branch that's fallen behind production.
We don’t stack releases
When agents started contributing a real share of PRs, more work piled into every release, and we still allowed multiple concurrent in-flight releases. Releases stacked up because the ones already out weren't merging on time, and each one that stayed open drifted further from production. More upstream throughput turned into a bigger downstream bottleneck. So we capped it at one active release at a time. We may loosen that constraint over time, but the important lesson was that parallelism only helps after validation and ownership are under control.
Every release is a batch of whatever's been merged into main since the last release shipped. Every hour, a GitHub Action, rolling-releases.yaml, checks releases-config.yaml to see whether a release is already in progress and whether we've already created a release today (the daily limit is set to 1, and it's used up the moment a release is created — not when it merges).
When those checks are clear, we automatically cut a new branch — rc/YYYY-MM-DD — from whatever's in main at that moment, and open a PR from that branch into production. That PR is the RC: what we validate before anything goes live.

Because the cut happens early (as soon as the day's first eligible check clears) and only one release can be created per day, anything that merges into main for the rest of that day doesn't get included — it just waits. In practice, that means most of what's in a given day's release is the previous day's work.
While the RC is open, PRs can also be merged directly into it — most commonly to fix a release blocker found during validation. Everything else waits for the next cut.

Each release needs persistent ownership
We didn't start with a rotation — a couple of teams ended up owning most releases, and as agents pushed more PRs into every release, the job got heavier without anyone deciding it should. Spreading ownership across teams by weekday fixed the issue so that no one team carries it every time; everyone takes a turn. Adding Friday fixed a related problem: without it, nothing shipped from Thursday through the weekend, so Monday's release absorbed four days of accumulated changes. At agent volume, four days of accumulation is a much bigger release than it used to be.
Each weekday is assigned to one product team. That team lead designates a release owner for the day.
That person owns the release and all pre- and post-release checks, from monitoring the release thread through validation and deployment to confirming everything's healthy after the release merges. Ownership doesn't reset with the calendar — if a release spans multiple days, the same person sees it through until it ships.

Release notes are generated automatically
Since the release owner rotates by weekday, whoever draws a given release within the assigned team didn't write most of what's in it. With agents contributing much of the development, there often isn't a person who did. Before we automated our release notes, they lived wherever a PR author happened to put them, which made customer-facing notes nearly impossible and occasionally blocked releases outright. To support agent velocity, we needed to standardize on where notes go and what they look like for agents and humans alike.
When the release PR is created, automation parses every PR body, regex-matches ##<SystemName> headers — for example, ##Backend, ##Frontend, or ##Infra — and compiles the matching text into that system's release notes. It does this again every time the release PR is updated, so the notes stay current as more changes land before the release merges. Those notes give the release owner the operational context they need, including pre- and post-release tasks and anything that requires extra attention during rollout, and they double as cleaner source material for customer-facing changelog updates.


We roll out in two steps, both requiring approval
Once no blockers remain and a product engineer has approved the release PR, the release owner merges it into production. That triggers push-production.yaml. The workflow reconciles production back into the main branch, so release fixes and hotfixes do not diverge from the normal development branch. It then tags the release images with the commit SHA and release tag and requests approval from an infrastructure admin via GitHub's production environment.
Once approved, the workflow marks the GitHub Release as the latest release and pushes the changes directly to deploy-production's main branch, which ArgoCD picks up and syncs automatically.
The two approvals protect different things. The PR approval checks the code itself. The GitHub environment approval checks whether it's safe to touch production infrastructure right now.

A hotfix skips the queue, not the checks
The base-branch check used to just evaluate a PR's current base, so someone could open a PR against the wrong base and retarget it to production later to slip past the check. The fix was to make the check remember the PR's original base and fail permanently if that was wrong, closing that loophole.
Hotfixes skip the daily RC queue, but they do not skip production controls: they still target production, run required checks, require deploy-admin approval, and follow the same deploy-production/ArgoCD path. Merging still requires approval from @eng-deploy-admins, the same gate used for regular releases.
We manage risk, we don’t eliminate it
We can't eradicate the risk of a daily release, and agent-written code doesn't change that. What it changes is how often you're exposed. Holding a daily cadence at that volume only works if catching and recovering are cheap enough that neither depends on luck or heroics.
Agentic development increases the need for release discipline. Agents can produce more code, faster, but that only helps if the release system can validate candidates, surface real blockers, coordinate ownership, and recover quickly when something goes wrong.
That's the balancing point we found: fast enough to keep pace with how much code agents can now produce, safe enough that a release doesn't depend on nobody making a mistake. Teams that ship fast and let bugs slip through have always had that problem; agents didn't create it, they just raised the volume and the stakes.
We're not claiming to have solved that at every scale: we merge a few hundred pull requests a quarter on our own platform, modest compared with teams pushing that many in a single day. But the validation and recovery process is what lets us hold our pace without the damage, and it's built to scale with volume rather than break under it. Teams that ship safe and slow usually have a review process that can't scale: no persistent ownership, no fast way to recover when something breaks, so every release gets the same manual scrutiny regardless of actual risk.
Agents didn't create the tradeoff between shipping fast and shipping safe. They just made it a lot more expensive to get wrong.
What is an agentic SDLC?
An agentic SDLC is a software development lifecycle where AI agents write, test, and validate a meaningful share of the code alongside human engineers. In practice it means the same pipeline handles agent-authored and human-authored changes, and the verification layer has to scale with how fast agents produce work.
How does the QA Wolf platform support an agentic SDLC?
By handling verification at the speed agents produce code. An agent generates and maintains test coverage as the application changes, assembles a per-PR suite from what actually changed, filters flakes by re-running failures under different conditions, and turns the results into a readiness status that can programmatically block a deployment. QA Wolf runs its own daily releases on it.
Does agent-written code need a separate review process?
No. At QA Wolf, agent-written and human-written pull requests clear the same tests, the same two approvals, and the same deployment path. Neither approval asks who wrote the change. Adding a separate lane for agent code creates a second process to maintain without making either one safer.
Can code review keep up with AI-generated code?
Not as a verification mechanism. Review worked as a proxy for verification when writing code was the slow part, because if a person wrote a change, a person could read it. Once agents write a significant share of the code, the volume outpaces review, and adding reviewers doesn't close the gap.
How do you test AI-generated code?
The same way you test any code, but with test coverage that keeps pace. An agent explores the application, models how its pages connect, writes the Playwright and Appium tests each change requires, and validates each new test before it joins the suite. Every release candidate then clears roughly 400 end-to-end flows.
How do you decide which tests to run on a pull request?
Assemble the suite per pull request instead of running a fixed one. An agent reads the PR's title and description and pulls in the flows that relate to what actually changed. Teams can also pin specific tests to run on every PR regardless of the change.
How do you tell a flaky test from a real bug?
Programattically re-run the failure. Every failing test runs two more times under different conditions. If it passes on either retry, the failure is treated as a flake and ignored in the short term. If it fails all three attempts, a bug is filed. At agent volume this filter is what keeps flakes from blocking releases.
Should every test failure block a release?
No, and treating every failure as blocking is what makes a daily release cadence impossible. Each failure needs a severity judgment. Blocking bugs stop the release; everything else is surfaced without stopping it. Getting the second half right is what lets a team ship daily.
How often should you release when agents are writing your code?
QA Wolf ships to production once a day, with one active release at a time. Daily gives enough runway to run the full end-to-end suite and clear blocking bugs before shipping. Allowing multiple concurrent releases caused them to stack up and drift from production.