All posts

The Quality Gate AI Agents Can't Game

Published Mar 26, 2026 · Iván Etchart

About a week ago Uncle Bob dropped his morning bath robe rant video on X. It hit home because it lines up exactly with what we've been running into ourselves over the last ten months. He basically said unit tests by themselves fall short. You still need that extra layer of acceptance tests running on top to confirm the entire system delivers what a real user actually expects.

The idea itself has been around for ages. But it feels especially relevant now that we're leaning on AI agents for so much of the coding.

We Started with Gherkin Ten Months Ago

Ten months ago we kicked off a new project and decided right away that every requirement would start life as a Gherkin scenario in a .feature file. We didn't treat them as something to add later or as plain documentation. They were part of the process from the very beginning, right as we were bootstrapping the project.

The idea was straightforward: take a PRD, translate it into Gherkin feature scenarios, then turn those into code. A natural language that both AI and humans could work with equally well, sitting right between the requirements and the implementation. AI wasn't nearly as capable back then as it is now — but even at that stage, having specs in plain language made it way easier to feed context into the models and get useful code out.

Gherkin as the Human Interface

Here's what we've learned after ten months: Gherkin's real value isn't that it gives you acceptance tests. It's that it closes the gap between what a human wants and what the code does. It's a human interface for requirements — and it turns out that same interface works just as well for AI agents. An agent can read a .feature file and understand what needs to happen just like a developer can.

But Gherkin by itself is just a language. You could write perfectly clear scenarios and back them with mocks and stubs, and you'd end up with tests that pass while the real system is broken. The scenarios describe the what. The quality gate is in how you implement the steps behind them.

These are two independent decisions. You can have Gherkin without real integrations — mocked steps, fast feedback, shallow confidence. And you can have real integration tests without Gherkin — coded directly, technically sound, but opaque to anyone who isn't reading TypeScript. The power is in the combination: a human-readable interface on top, a quality gate underneath that exercises real infrastructure. Either one alone leaves a gap. Together they close it.

The Quality Gate: Real Integrations

This is the part that actually matters. When we implement our Gherkin steps, they hit real databases, seed real data, call real services. The scenarios exercise the system the same way a user would. That's where the confidence comes from — not from the fact that we have acceptance tests, but from the fact that those tests run real processes end to end.

If you've worked with AI agents you already know the pattern: they're fast, they're confident, and they'll happily produce code that makes every unit test green while quietly breaking the thing the user actually cares about. Unit tests with mocks can't catch that. But a scenario that spins up real infrastructure and walks through the actual flow — that catches it immediately. Not because some mock drifted out of sync. Because the real behavior broke.

Stretching It into Every New Project

Since that first project we've been pulling this into everything new we start, including Dap where we pushed it further. We added headless UI tests so the same Gherkin workflow covers the full user-facing experience, not just backend logic. Same idea: plain language scenarios on top, real integrations underneath. That part deserves its own entry — there's a lot to unpack in how Gherkin and headless browsers fit together in practice.

It lets us move fast without crossing our fingers. When an agent finishes a task and the scenarios go green, we trust that change in a way unit tests alone never gave us. The feature files double as documentation anyone on the team can read — and as a contract the AI can't sweet-talk its way around.

What This Looks Like Inside Dap

Dap is where we've pushed this the furthest. The numbers today: 76 feature files, 332 scenarios, roughly 3,800 lines of Gherkin backed by over 12,000 lines of step definitions. Every scenario spins up a real NestJS API server, a real PostgreSQL database with real migrations, real RabbitMQ queues, real OAuth flows — plus Playwright for the UI tests. The mock boundary is only at external services we don't control (GitHub API, Jira API, the identity provider).

That suite is both the product's safety net and the thing that slows us down.

The Trade-offs

This isn't free. Ten months in, here's what we're dealing with:

Bloat. Scenarios pile up. Some end up testing overlapping things, others could be merged or written more tightly. When you're cranking out Gherkin under pressure to cover every edge case, the feature files get messy. Keeping them lean takes real discipline and we're still figuring that part out.

Cost. Running real integrations is cheap when the project is small. As the codebase grows, every scenario that spins up a database and seeds real data adds to the bill. You don't notice the scaling problem until you're staring at the invoice.

Time. Slow suites hurt more when AI agents are in the loop. The agent runs the tests, waits for results, reads the output, adjusts. When that cycle takes minutes instead of seconds, you burn more tokens on context and back-and-forth. A slow feedback loop is expensive in ways that sneak up on you.

Where We're Headed

None of this makes us want to stop. It makes us want to get sharper about how we write and organize scenarios. Which is exactly where scheduled agents come in.

Dap has a trigger system that connects GitHub Actions cron schedules to autonomous agent sessions. A cron schedule fires a GitHub event. The Dap API receives it, matches it against a registered trigger — which pairs a name with an agent and a prompt — validates it against the repository's policy, and spins up an autonomous session. The agent gets a workspace, the full codebase, and a task. It can commit, push, open PRs, and monitor CI results. When checks pass, the loop closes.

We're already using this for dependency maintenance — agents that run weekly to check for updates and open PRs automatically. The same machinery works for suite maintenance: an agent that reads the feature files, identifies overlapping scenarios, proposes merges, and uses CI feedback to verify nothing broke. Adding a new scheduled task is a workflow file and a database entry. Instead of a human spending Friday afternoon cleaning up redundant scenarios, an agent does it on Monday morning and the team reviews a PR.

The meta-loop is the part we find most interesting: the agents that depend on the quality gate also maintain it. The same Gherkin scenarios that catch an agent's mistakes are themselves maintained by agents running on a schedule. The feature files are the contract, and the contract is self-maintaining — as long as the real integrations underneath keep catching real breaks.

The core bet has two parts: Gherkin as the human interface that bridges requirements to code — for people and AI alike — and real integrations underneath as the quality gate that actually catches breaks. Both parts have held up. Ten months later we're more sure than ever it was the right call.