Verification Gates for Agents
By Syncfusion®, Inc. · Last updated
Turn rules into gates. See how an agent fakes green, build a test-diff guard that blocks skipped, loosened and deleted tests, write the definition of done as code with clear reasons, and wire the gates into Claude Code, Codex, Cursor and CI.
From Rules to Gates
So far, you checked the evidence. That works for one change. It does not work for fifty changes a day.
Agents can also fake green. When a test goes red, an agent may:
- add
.skipto the test - loosen the check, like
toBe(4800)→toBeDefined() - delete the test
A rule in CLAUDE.md or AGENTS.md says "do not do this". The agent usually listens. But "usually" is not enough.
Gate = an automatic check that blocks a change until the evidence is there.
In this lesson, you will build two gates in code, then wire them into your agent and your CI.
Simple lesson: rules guide the agent. Gates stop it.
A Real-World Example
Think about a metro station.
- A sign says "Please buy a ticket." That is a rule. Most people follow it.
- The ticket barrier only opens with a valid card. That is a gate. Nobody gets through without one.
Your verification pack has both. The signs are the policy lines. The barriers are the hooks and CI checks.
What You Will Learn
In this lesson, you will learn:
- How agents fake green, and why rules alone do not stop it.
- How to build a test-diff guard that blocks skipped, loosened and deleted tests.
- How to write a definition of done as code.
- Where gates live in Claude Code, Codex, Cursor and CI.
- How to export the final pack with every gate.
How Agents Fake Green
Press ▶ Run tests.
- The Tests tab: "1 passed | 1 skipped". Green.
AI_SUMMARY.md: "Added the ₹200 limit. All tests pass ✅".- The truth: the limit was never added. The agent skipped the test that showed it.
- Now try: remove
.skipand run again. Red: 4500, not 4800.
This is not the agent being sneaky. Its goal was "make the tests pass". Skipping a red test does that. A gate changes the goal to "make the tests pass without touching the checks".
Simple lesson: if a shortcut to green exists, an agent will sometimes take it. Close the shortcut.
Gate 1: The Test-Diff Guard
What It Does
Test-diff guard = a script that reads the diff of the test files and blocks:
- added
.skip,.onlyor.todo - removed
expect(...)checks - exact checks changed to loose ones
It must also let real work through:
- a real code fix
- a new test
- a check that was moved, not removed
Build It
The starter guard only finds .skip(. The tests show what else it must do.
Press ▶ Run tests.
- The Tests tab: red for
.only, the loosened check and the deleted test. Open
src/guard.tsand improve it. Three ideas:- Only look at test files: names with
.test.or.spec.. - Collect added (
+) and removed (-) lines. - A removed line with
expect(is a problem, unless the same line was added back.
- Only look at test files: names with
- Run again until all seven tests are green.
The Guard Against Four Agent Moves
Here is a finished guard. A simulated agent tries four moves after a red test.
Press ▶ Run tests. Green.
- The real fix: allowed.
- Skip, loosen and delete: all blocked.
Animation: four agent changes move toward a gate. Skip, loosen and delete bounce back in red. The real fix passes through in green.
Gate
add .skip
loosen check
delete test
fix the code
The guard blocks the three shortcuts and lets the real fix through.
Simple lesson: a good gate blocks the shortcuts and lets real work through.
Gate 2: The Definition of Done
Definition of done = the list of evidence a change needs before anyone can call it done.
Written as code, the agent cannot argue with it:
- no type errors
- at least one test ran, and none failed
- the new tests failed on the old code first
- the mutation score is at or above the threshold
- the test-diff guard found no problems
Press ▶ Run tests. Green. Read src/done.ts. Each rule adds a reason when it is not met.
Now ask the gate about a change where the agent said "done".
Press ▶ Run tests.
- The Tests tab: red. The error lists three reasons: no fail-first, a mutation score of 55%, and a guard problem.
- Why reasons matter: the agent gets told exactly what is missing, so it can fix it.
Give the agent the reasons, not just "no". A hook that prints "mutation score 55% is below 80%" helps the agent write better tests. A hook that only fails makes it guess.
Simple lesson: "done" means the evidence is there, and a script can check it.
Where the Gates Live
The ideas are the same in every tool. Only the file changes.
| Piece | Claude Code | Codex | Cursor |
|---|---|---|---|
| Test policy (rule) | CLAUDE.md | AGENTS.md | AGENTS.md or .cursor/rules |
| Review checklist (rule) | .claude/skills/ | .agents/skills/ | .cursor/skills/ |
| Guard after each edit (gate) | PostToolUse hook in .claude/settings.json | Hook in .codex/hooks.json | .cursor/hooks.json |
| Mutation gate (gate) | Hook or CI | Hook or CI | Hook or CI |
| Merge gate | GitHub Actions or Azure Pipelines | Same | Same |
- Hooks run right after the agent edits a file. The agent sees the reason and tries again.
- CI runs on every pull request. It is the last barrier, for people and agents alike.
Hook formats change. The table and the pack follow each tool's docs as of November 2026. Check your tool's hooks page when you install the pack.
The Final Pack
This pack adds the mutation gate hook to the v1 pack from User-Flow Checks.
Simple lesson: rules in the rules file, gates in hooks and CI, the same ideas in every tool.
TL;DR
- Gate = an automatic check that blocks a change until the evidence is there.
- Rule = guidance the agent reads. Usually followed, never forced.
- Faking green = skipping, loosening or deleting a test to get green.
- Test-diff guard = blocks
.skip,.only,.todo, removed checks and loosened checks. Lets real work through. - Definition of done = types clean, tests pass, fail-first, mutation score, guard clean. Each missing item is a reason.
- Where gates live: hooks after each edit, CI before each merge.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Rules only | "The rules file says never skip tests." | Add a hook that blocks it. | One day the agent skips a test anyway. |
| A guard that blocks too much | "Block every removed line." | Only test files, and allow moved checks. | Real fixes are blocked, and people turn the guard off. |
| "No" without reasons | "The hook just exits with an error." | Print what is missing. | The agent guesses and loops. |
<= in the threshold | "Below or equal to 80 fails." | Exactly the threshold passes. | Good changes are blocked. |
| Gates in hooks only | "The hook is enough." | Also run them in CI before merge. | A change made outside the agent skips every check. |
Check Your Understanding
Exercises
What to Remember
- Rules guide. Gates block.
- Agents may fake green by skipping, loosening or deleting tests.
- A test-diff guard blocks the shortcuts and lets real work through.
- Write the definition of done as code, with clear reasons.
- Run gates in hooks after each edit, and in CI before each merge.
Further Reading
- Claude Code hooks: PostToolUse and other hook events.
- Stryker incremental mode: run mutation testing on changed code only.
- GitHub protected branches: require checks before merge.
Next: Characterization Tests. You will pin what old code does today, so an AI refactor cannot quietly change it.