# Can your verify gate actually fail?

> Source: <https://dev.to/arti0/can-your-verify-gate-actually-fail-3ib4>
> Published: 2026-08-15 14:20:43+00:00

I let Claude Code commit directly to my repositories. I don't review the diffs. I didn't think I needed to, because I built a deterministic verify gate — a script that lints, typechecks, builds, and runs tests. If the gate goes green, the PR merges automatically.

I trusted that gate implicitly. Until I actually sat down and asked the one question that matters: **If an agent pushes completely broken code right now, will this gate actually go red?**

Not "is the script configured?" Not "does the file exist?"

*Will it actually fail?*

Turns out, for three out of my four repos, the answer was an emphatic **no**. The gate was returning `GREEN`

without running a single line of code.

My gate script is repo-agnostic. It looks up the repository name in a policy JSON file (`gates.<repoName>`

) and falls back to a default if it doesn't find one.

Here is the PowerShell logic driving the whole operation:

``` php
$steps = $policy.gates.$RepoName
if ($null -eq $steps) { $steps = $policy.gates.default }
if (-not $steps -or $steps.Count -eq 0) {
    Write-Log "GREEN (no gate steps configured for '$RepoName')"
    exit 0                       # <-- Unconditional green
}
```

And here is my config file:

```
"gates": {
  "app": [
    "npm run lint",
    "npm run test",
    "<design-gate script>"
  ],
  "default": []
}
```

Look at that exit code. If a repo doesn't have an explicit entry in the JSON file, it falls through to `default: []`

. The script sees zero steps, prints `GREEN`

, and exits with `0`

.

The runner sees exit code `0`

and instantly merges the code. I built a system where **having no tests configured is structurally identical to passing all tests.**

When I audited all four repos the runner is allowed to touch, the reality was pretty grim:

`app`

(The Runner itself):`npm run lint`

runs, but `tsconfig`

explicitly excludes the `runner/`

directory — meaning `build`

isn't in the gate at all, so client/server boundary breaks ship freely. Vitest runs 28 test files, but the glob pattern completely misses `*.test.tsx`

files.`product`

(Next.js app):`tsc --noEmit`

, `vitest`

(10 suites), and `next build`

ready to go in `package.json`

. None of them were wired into the gate config. It had 0% coverage purely because of lazy config debt.`notes`

(Markdown vault):`portfolio`

(Vite site):The real bug here isn't missing npm scripts. The structural flaw is that **an empty gate defaults to success**.

To fix this properly:

`$steps.Count -eq 0`

, the script must exit non-zero or return an explicit `UNGATED`

status. A missing key should break the build, not bypass it.`product`

repo was fixed with a single line in `policy.json`

. `npm run build`

to the gate costs execution time, but it's the only way to catch real deployment breakers.`tsconfig`

and fix the Vitest globs before someone writes a `.tsx`

test that never actually gets executed.If you run AI agents against your codebase without reading the diffs, go break a file on purpose and run your gate. If it doesn't yell at you, you don't have a safety gate — you just have a script that automatically approves bad code.

*I'm Andréas — full-stack dev, CTO at a B2B SaaS, building my own agent tooling. Portfolio: https://andreas-bodin.vercel.app*
