Blog
Thirty-four conformance vector files, 512 cases, zero ever executed — and when counted, 412 of those cases carried no inputs and no expected values at all. This is how a corpus becomes decorative, why the first classifier reported 147 where an independent pass said 100, and the three-verdict registry (executed / numbered debt / aspirational) that lets a small true number replace a large false one.
A repository had thirty-four conformance vector files. Five hundred and twelve test cases. Zero of them had ever been executed against the hardware they described — and when we finally counted what was inside, four hundred and twelve of those cases carried no data at all: an identifier, a sentence, and nothing else. No inputs. No expected values. Documentation wearing the shape of a test.
Nothing dramatic happened. A file landed in the conformance directory. A CI job read its stored 'verdict' field — a string someone typed once — and printed it into the run summary. Another file landed. The count grew. 'Thirty-four vector files' became a sentence people said about the project, and every part of it was true except the part that mattered: no runner ever opened them.
The gap is easy to miss because both halves look like work. Writing a vector file IS work. Reading a summary that says CLEAN is reassuring. The missing step — actually applying the vectors to the RTL — leaves no trace when it is absent, because absence has no output.
The first classifier we wrote reported 147 data-carrying cases. An independent pass in another language reported 100. Two instruments disagreeing is not a rounding difference to average away: one of them is wrong, and until you know which, neither number can be written down.
Ours was wrong. It split each JSON object on commas to find fields — and descriptions contain commas. 'Sync FIFO reports is_sync=true, is_async=false' splits into two fragments, the second of which looks exactly like an unrecognised field. Every prose case with a comma in its sentence was promoted to data-carrying. The rewrite tracks string state and collects only real keys; it now reproduces the independent count on all thirty-four files.
$ tri vectors debt # 2026-08-22, as first measured
1 executed, 9 debt, 24 prose-only (34 files);
512 cases, 100 carrying data (19%).
$ tri vectors debt # after spi joined the executed set
2 executed, 8 debt, 24 prose-only (34 files);
The instinct on discovering this is to say 'run them all'. That instinct is the same one that produced the problem: it treats every artifact as a test that merely hasn't been run yet. Most of these cannot be run at all — not because of a bug, but because they describe behaviour that no interface in the design exposes. One module's vectors check LED output patterns; the specification contains no LED function of any kind.
So the registry sorts every file into exactly one of three verdicts, and the third one is the important one:
Two verdicts force every unexecutable artifact to masquerade as one of them, and 'not yet' is where they all end up. The third category is what lets you state a real number: the honest ceiling for execution here is ten files, not thirty-four.
Fixing twenty-four files is a decision someone else owns. Stopping the twenty-fifth is not. A gate now freezes the existing prose-only files as named debt and fails when a new one lands — the same baseline-as-debt pattern the repository already uses elsewhere. A planted prose-only file is caught with its case count; a planted file with a single input field passes. The class cannot grow again without someone deliberately recording that they want it to.
Two modules now execute for real: eighteen cases across seven groups in one, three in another, each with a planted-fault control proving the check reacts. That is a small number and it is the true one, which is the only property that makes it worth having. (This sentence first said nineteen. The runner prints eighteen; the correction is recorded here rather than made silently, because a post about counting things honestly has no business rounding its own.)
Any artifact whose presence is counted but whose execution is not — fixtures, golden files, property sets, benchmark suites — drifts toward decoration at exactly the rate nobody checks. The check is cheap and specific: for each artifact, name the code path that consumes it. If you cannot, you have documentation, and calling it something else is the only real defect.
Every figure above is measured, and the limits are named with it.