Expand description
Shared recursive contract directory walker.
Multiple pv subcommands need to load every YAML contract under
a directory tree (including subdirectories like contracts/aprender/,
contracts/trueno/, contracts/patterns/). This module provides the
canonical walker so commands agree on what counts as a contract and
which sidecar files to skip.
PVL-1 (PMAT-1099): a corpus with ZERO contracts is REFUSED, never
reported. Measured before this change (PV-LEAN-AUDIT-001, 2026-09-10):
pv lint /nonexistent-path exited 0 with Result: PASS over 0 contracts,
and pv proof-status <empty dir> printed Proof Status (0 contracts) at
exit 0 — a gate that measures nothing and reports PASS. collect_corpus
is the entry point every reporting subcommand uses: it returns
ZeroContracts (exit ZERO_CONTRACTS_EXIT) for an empty or missing
directory, and treats a single .yaml file as a one-contract corpus so
pv <cmd> <file> reports that file instead of walking nothing.
ONE definition of “empty”. The set of contract files is the one pv lint
walks — provable_contracts::lint::collect_yaml_files (the
is_contract_yaml rule plus the skipped sidecar directories) — so no two
commands can disagree on what is there. A contract file that fails to
parse is NOT “no contract”: it was measured, and it failed
(ParseErrors, exit 1, every file named). The second review quorum on
#3093 measured proof-status and lint --diff refusing an
unparsable-only directory as “0 contracts” (exit 2) while lint failed
the same directory with contracts: 1, errors: 1 (exit 1); this walker’s
old private rule also skipped every *playbook* stem, and the corpus holds
real contracts named that way.
Structs§
- Parse
Errors - Contract files under
paththat failed to parse: measured, and failed (exit 1) — never a silent skip, never “0 contracts”. - Zero
Contracts - The corpus under
pathholds no contract (afterfilter, when set).
Constants§
- ZERO_
CONTRACTS_ EXIT - Exit status of a refused empty corpus.
Functions§
- collect_
contracts - Walk
dirand collect every PARSEABLE contract, dropping the rest. - collect_
corpus - Load the corpus at
pathand refuse an empty one. - exit_
code_ for - Exit status for a
dispatcherror:ZERO_CONTRACTS_EXITfor a refused empty corpus, 1 for everything else (a parse failure included). - has_
contract_ files - Is there at least one contract file under
path? The one definition of a non-empty corpus, answered WITHOUT parsing (diff mode asks this before it says “nothing changed”). A file path is a one-contract corpus. - require_
contracts - Refuse an empty corpus:
Err(ZeroContracts)whencorpusis empty. - verdict_
for - The verdict class
pvprints before an error, in PVL-001 §0’s vocabulary:decline(exit 2, nothing measured),reject(exit 1, measured and failed),error(anything else). One definition, so the word and the exit code cannot drift apart — ONT-001 §5 ONT-1 asserts both halves of the line. - walk_
contracts - Walk
dirrecursively withpv lint’s file rule: every contract file is parsed intooutas(stem, contract), or recorded inerrorsas(file, error). Nothing is dropped.