I measured whether AI writes hollower tests than humans. It doesn't
This article introduces voidguard, a new tool that detects hollow tests, type gates, and CI conditions that exist but verify nothing. Inspired by a sweep that found seven such void guards in one repository, the tool identifies four types of voids and explicitly acknowledges three it cannot catch. It emphasizes the importance of verifying our verification systems rather than trusting green CI statuses blindly.
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.
→ The story: the skip-sweep that found seven
→ voidguard on PyPI
→ Source on GitHub