# I measured whether AI writes hollower tests than humans. It doesn't

> Source: <https://driivai.github.io/voidguard/>
> Published: 2026-07-17 04:48:44+00:00

# Does your green actually check anything?

`voidguard`

is a static scanner for *void guards* —
checks that are present, plausible, and verify nothing. It asks one question per
guard: *could this, as configured, ever be observed to fail?* — and shows its
evidence for every answer.

```
pip install voidguard
voidguard scan .
name: voidguard
on: [pull_request]
permissions:
  contents: read
  pull-requests: write
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: driivai/voidguard@v0
```

Report-only by default — it comments findings on the PR and never fails
your build unless you opt in with `fail-on`

. Requires Python 3.11+
for the CLI; the Action brings its own.

A guard that **fails** is doing its job.

A guard that's **absent** is at least honest.

The dangerous one runs, reports **green**, and verifies nothing.

## What it catches

**1 · Tests that never run** Skips gated on an environment flag that is set nowhere your repo actually runs; markers every CI invocation deselects; go, rust and js best-effort.

**2 · Type gates that check nothing** A mypy that cannot see your own types and passes vacuously; imports skipped; check targets matching no files; a weak tsconfig behind an advertised typecheck.

**3 · Settings silently discarded** PYTHON* variables handed to

`python -I`

/`-E`

, which
drop them; workflow env set and never read; a Docker ARG consumed after FROM
without re-declaration.**4 · CI conditions that cannot fire** An

`if:`

requiring an event the workflow's triggers never
deliver; schedules with no run on the record; golden-file assertions whose path
matches nothing.Every verdict — VOID, WARN, or an honest UNKNOWN — carries its enumerated search set: what was searched, what was found, absent conventional locations named as absent. A tool about unverified claims does not get to make any.

## What it cannot catch

The taxonomy this tool comes from has **seven** instance-types. voidguard v0
detects the shapes of **four**. It would not have caught the other three:

**Semantic voids**— a verdict typed nullable so “nothing” can be mistaken for a value, or a field the code carries but nothing ever persists. These need type-flow and data-flow analysis, not file-shape analysis.**Process voids**— a human approval gate that a merge routed around while every check was green. No scanner catches a decision that nobody waited for.**Anything requiring execution**— voidguard never runs your code. A guard that runs and is*wrong*is outside its question; it only asks whether a guard could ever be observed to fail at all.

Where static analysis cannot decide, the verdict is UNKNOWN with the reason — because a scanner that overclaims void guards is itself a void guard.

## Where it comes from

In one week, one repository turned up **seven guards that were present,
plausible, and void** — a core integrity test that had silently skipped in CI
since inception, a type gate that passed while checking nothing, an approval step
a merge walked straight past. Every one of them was green. voidguard is the
generalization of the sweep that found them.
