Documentation
¶
Overview ¶
Package vacuousguard is the repository-wide proof that a green test actually ran something.
A failing test is loud. A test that quietly declines to test is silent, and silence reads as success on every dashboard forge has. Two shapes produce it, and both have already cost this codebase real time:
TestProjectWorkflows_* (sibling repo, reliant) skipped itself when a fixture DIRECTORY was missing. A checkout leaves that directory present but EMPTY, so the skip never fired, the loop over its contents ran zero times, and six tests sat hard-red and unwatched. Both halves of that bug are guarded here: a guard that skips instead of failing, and a loop that passes because it never executed.
forge's own tree still carries skips conditioned on the presence of files that are tracked in this repository. Those skips cannot fire today, which sounds harmless — it means they are unfalsifiable. Rename the file they stat and the tests do not fail, they evaporate.
THE RULES
vacuous-loop A test discovers a set from the filesystem (os.ReadDir,
filepath.Glob, …), ranges over it, and nothing in the test
proves the set was non-empty. Such a test passes when the
discovery returns nothing, which is precisely when something
is wrong.
dead-skip A t.Skip that is unconditional (a test that can never run),
or one conditioned on the presence of a REPO-RELATIVE path.
A file tracked in this repository is present on every
checkout, so a skip guarding it either never fires — an
assertion nobody can falsify — or fires because the repo
layout moved, which must be a failure, not a shrug.
unwritten-gate An audit category or lint check gates on a generated Go
file in the user's project, and nothing in forge writes that
file. The check then returns its PASSING verdict every time,
on every project, forever. `forge project audit` shipped a
wire_coverage category and two lint flags reading
pkg/app/wire_gen.go for months after the DI rewrite stopped
emitting it; all three were green, and green is what people
read. Every one of them had passing unit tests — the tests
fed the scanner synthetic strings, and none asked whether a
real project could produce the input. The discriminator is
not "is it tested" but "does anything write the file", so the
ledger in gates_test.go answers that per path, with the
emitter named.
WHAT IS DELIBERATELY NOT A RULE ¶
A skip on a missing TOOLCHAIN (kcl, node, dlv, golangci-lint), on testing.Short(), on runtime.GOOS, on an environment opt-in, or on os.UserHomeDir() is legitimate: the thing it guards is genuinely absent on some machines and no checkout can supply it. Those are left alone, on purpose. A rule broad enough to catch them is a rule that gets switched off.
The analysis is a package library rather than a bare test so its rules can be unit-tested against planted defects in testdata/. Nothing in forge's production path imports it.
Index ¶
Constants ¶
const ( RuleVacuousLoop = "vacuous-loop" RuleDeadSkip = "dead-skip" )
Rule names. They double as the stable first half of a ledger key.
const RuleSilentCapability = "silent-capability"
RuleSilentCapability names the third rule. See checkCapabilityGuards.
const RuleUnwrittenGate = "unwritten-gate"
RuleUnwrittenGate names the third rule. See ScanGates.
Variables ¶
This section is empty.
Functions ¶
func LookPathProbeFuncs ¶
LookPathProbeFuncs returns the name of every function under root that is a capability probe by CONSTRUCTION: it takes a name, consults exec.LookPath, and answers a bool. Its caller (TestCapabilityProbeSetIsComplete) asserts that every one of them appears in capabilityProbeNames, so the rule cannot go blind because someone spelled the helper differently.
Both test and non-test files are walked: a probe helper that migrates into production code and gets re-used from a test is the same blind spot.
Types ¶
type Finding ¶
Finding is one violation, keyed by "<repo-relative file>::<TestFunc>" so a ledger entry survives reformatting and line moves.
func ScanGateSource ¶
ScanGateSource applies the unwritten-gate rule to one file's source. ScanGates is this over the judging trees; the guard's own tests are this over planted defects, so the rule under test is the rule that ships.
func ScanGates ¶
ScanGates reports every existence-gate, in the judging trees, on a generated-project Go file.
WHY THIS RULE EXISTS. `forge project audit` shipped a `wire_coverage` category that stat'd pkg/app/wire_gen.go and, finding nothing, returned StatusOK with the summary "n/a". Two `forge lint` flags scanned the same ghost. No code path had emitted pkg/app/wire_gen.go since the DI rewrite — forge's own generator test asserts the file is never written — so the category was permanently green, the flags permanently silent, and every dashboard read that as a clean bill of health. The checks had unit tests, and those tests passed: they fed the scanner synthetic strings. What no test asserted was that a real project could ever produce the input.
The discriminator is not "does a test exist" but "does anything WRITE the file". So the rule reports the gates and the ledger in the test answers that question per path, one entry at a time, with the emitter named.
Scoped to paths ending in `.go`: a gate on proto/, db/migrations/ or forge.yaml is reading the USER's tree, which is legitimately absent in projects that have none. A generated Go file is forge's own output, and forge either writes it or is lying about it.
func ScanSource ¶
ScanSource applies both rules to a single test file's source. Scan is this over the repository; the guard's own tests are this over a file of planted defects, so the rules under test are the rules that ship.