Skip to content

The lenses

Each lens answers one question. They are independent (run whichever you need), but they share a vocabulary (source units, tiers, layer awareness) and a shape: a pure analysis pass, then a text or --json rendering of the same data.

Lens Question Runs your tests? Cost
shape How much test code is there, and in what shape? no instant
gaps Does the test tree structurally parallel the source tree? no instant
cover Which tier actually executes each unit? yes ~one suite run
reach Do unit-tier tests stay inside the unit under test? no instant
report All the static checks, with the why and the how no instant

Why more than one

Each lens has a blind spot the others cover.

shape measures mass, and mass is a proxy. A 200-line test file can be shallow; a 20-line parametrized test can be deep. A test's tier is decided by the directory it sits in, not by what it actually exercises: a "unit test" that opens a database connection still counts as a unit test.

cover closes exactly that gap by running the suite: it measures which lines each tier really executes. It is the only lens that can answer "are these unit tests real?", and also the slowest.

gaps catches what neither sees: a package with no test file at all shows up as an absence, and absences are easy to miss.

reach catches the other direction: tests that exist, run fast, and sit in the unit tier while importing half the codebase.

report runs the static three and turns them into ranked, explained findings.

Shared flags

Flag Available on Meaning
-C/--root DIR all Analyse the named project. Defaults to the current directory.
--json shape, gaps, reach, cover Machine-readable output in place of the table.
--exclude NAME shape, gaps, reach, cover, report Skip this unit, on top of config exclusions. Repeatable.
--min-src N shape, cover, report Skip units below this size (default 20).

Every lens exits 0 even with findings. None of them is a gate; tepyd check is.