v0.9.0: a finding has to say why it applies
A protocol release. Two verdicts that could previously be published as defects in someone's repository without ever making the claim that would justify them now have to make it.
Upgrading: re-run your install command with @v0.9.0. Schema version 5. Run-states from every earlier release remain readable and re-renderable by this build; a v0.9.0 run-state cannot be read by an earlier build.
Both changes came out of an external tester's Codex run and the repository owner's review of it, which rejected 20 of 32 findings. Most of those rejections were correct, and correct in a way that made them the tool's defects rather than a disagreement.
A finding must state its precondition (#178)
not-applicable names the precondition that fails. could-not-evaluate says why a verdict could not be reached. pass is a specific claim that you looked. finding asked for nothing, so nothing in the protocol ever put the question "does this rule's precondition hold here at all?" to the auditor.
That run filed 11 findings in the requirements domain and 7 in threat modelling with no not-applicable verdict in either, while setting aside 147 rules elsewhere. Among them: no release SBOM, against a project with no release pipeline. No CVSS-scored vulnerability register, against a project with one dependency. No assistive-technology evaluation, against a personal tool whose only user is its author. Every rule real, every citation correct, every precondition absent.
Finding.precondition is now required, and names where the precondition holds in this repository. Being unable to write it is the signal, not an obstacle: the rejection message names not-applicable as the verdict that was actually correct.
AUDIT.md's not-applicable criteria gain the limb they were missing. A precondition can be a context, not only an artefact: external users, a release pipeline, a distribution channel, an organisation, a compliance regime. The old worked example only covered the artefact case.
A completed domain must record its evidence boundary (#179)
In the same run, the requirements domain returned could-not-evaluate on one rule with the note "the README points to external issue records that were not inspected", then filed 11 findings in that same domain asserting those requirements did not exist, each citing README.md. The requirements were in the project's issue tracker throughout. One rule knew. Nothing carried it to the other eleven, because there was nowhere to record it once for the domain.
DomainResult.uninspected_evidence is now required on a completed domain: the evidence stores the repository points at that the audit did not open. An explicit empty list is the common answer and a claim in its own right; never recording it is refused.
The report prints the list beside every finding in that domain, and the Tool performance summary gains an Evidence boundary block that separates three outcomes it used to collapse into one: domains that read everything the repository pointed at, domains that read less and said so, and domains that never answered.
The tool does not guess which findings are absence claims. That judgement needs evidence the tool does not have, and making it here would be the tool pre-writing the verdict. It shows the boundary and the finding together and lets the reader decide.
Also
- AUDIT.md now says to cite the line a finding is actually about. A reviewer of that run reconstructed four findings from their cited locations alone, guessed the claim from the code at that line, and refuted claims the audit had never made.
- The demo report carries both evidence-boundary states, so the new block is visible in
docs/demo/report.htmlrather than only its all-clear message.
Verification
791 tests passing (774 before, 17 new). ruff check, ruff format --check and mypy all clean. domains/pack.toml's requires_tool is deliberately unchanged: it pins the pack format, which this release does not touch, so existing rules packs work as they are.