tools (volt): doc_census_check -- a cached vocabulary gives the fast mode its teeth back

Reply 22 ruled the asymmetry a defect and asked that `--fail` never return 1 on
a split it could not verify. 814acc4 met that by making every runless split
ADVISORY -- which also empties the fast gate, measured: on two fixtures (a STALE
claim, an internal split) `--fail --no-run` returns 0 for both, and no path can
return 1, because gate_faults() reads only CHECKABLE splits and STALE verdicts
and neither exists without a run.

So the fast mode gets the oracle it can have. `--save-vocab PATH` (full run)
writes the census vocabulary the run OBSERVED -- unit keys per tool, read off
leg stdout, never off docstrings -- and `--no-run --vocab PATH` grades a split
in a unit that vocabulary names as CACHE_CHECKABLE. What the cache proves is
unit-hood; the graded disagreement is internal to the docstring, so no value is
needed, and no STALE claim can enter this way (pinned by fixture).

Measured at fca3f2e, tools/citation_resolve_check.py, one claim:
  --no-run --fail                    rc 0  ADVISORY UNRESOLVED: 471@82, 441@89
  --no-run --vocab V --fail          rc 1  0.205s, SPLIT ... (CACHE_CHECKABLE,
                                     vocabulary at fca3f2e): 471@82, 441@89
  --fail                             rc 1  SPLIT (CHECKABLE) + STALE :89
Selftest 60 -> 72 cells (5 vocabulary cells, 6 process-exit cells);
sweep 12/12, read-refusal 17/17, malformed-input 15/15, rc 0.
rc 2 covers an unreadable --vocab and --save-vocab without a run.
This commit is contained in:
volt authored and Volt committed 2026-10-18 12:40:19 +00:00
1 parent fcfb323180
commit ecdaecd7cb
1 file changed
+179 -23
+179 -23
View File
@@ -152,9 +152,12 @@ FAILING ON THE CLASS IT CATCHES (`--fail`)
The code means: The code means:
0 ran, and graded no fault (every claim adjudicated agrees) 0 ran, and graded no fault (every claim adjudicated agrees)
1 ran, and graded a fault (a VERIFIED INTERNAL SPLIT, or STALE) 1 ran, and graded a fault (an INTERNAL SPLIT whose unit a leg --
or a cached vocabulary -- verified,
or a STALE claim)
2 could not grade (usage, a --tools filter that matches 2 could not grade (usage, a --tools filter that matches
nothing tracked, unreadable input) nothing tracked, an unreadable
--vocab, --save-vocab without a run)
THE TWO MODES GRADE THE SAME CLASS. `--no-run` runs nothing, so it has no THE TWO MODES GRADE THE SAME CLASS. `--no-run` runs nothing, so it has no
oracle and cannot prove any split is a census unit: it prints every split as oracle and cannot prove any split is a census unit: it prints every split as
@@ -167,6 +170,23 @@ FAILING ON THE CLASS IT CATCHES (`--fail`)
run prints `UNRESOLVED 471` -- plus the STALE claim at :89. The teeth are run prints `UNRESOLVED 471` -- plus the STALE claim at :89. The teeth are
kept where they can be verified, which is the only place they mean anything. kept where they can be verified, which is the only place they mean anything.
A CACHED VOCABULARY PUTS THE TEETH BACK IN THE FAST MODE, without asking it
to invent an oracle. `--save-vocab PATH` (full run) writes the census
vocabulary the run OBSERVED -- every unit key some leg printed, per tool --
and `--no-run --vocab PATH` grades a split in a unit that vocabulary names as
CACHE_CHECKABLE. What the cache proves is narrow and enough: the unit is a
census unit for that tool (a leg printed it at `<vocab rev>`), and the
disagreement being graded is INTERNAL to the docstring, so the leg never has
to supply the value. What it cannot prove is a value, so a STALE claim is
still impossible without a run, and a unit the vocabulary does not name stays
ADVISORY -- the 39/12/1 `ACS-only` class is still never spent. Measured
2026-10-18 at 814acc4 on a stub whose docstring splits 471/441 over a census
printing 471: `--no-run --fail` rc 0, `--no-run --vocab V --fail` rc 1,
`--fail` rc 1. The vocabulary's rev is printed with every CACHE_CHECKABLE
row, because a reader is entitled to know how old the census behind the
label is; it is NOT required to equal the revision being checked (unit-hood
is a property of the unit word, and the graded disagreement is internal).
rc 2 keeps its meaning from the tools/ contract (6ee8fce) and is decided rc 2 keeps its meaning from the tools/ contract (6ee8fce) and is decided
before the gate runs, so "could not grade" never reads as "graded clean" or before the gate runs, so "could not grade" never reads as "graded clean" or
as "graded a fault". A LEG FAILURE (RUN_FAILED) is reported in its own column as "graded a fault". A LEG FAILURE (RUN_FAILED) is reported in its own column
@@ -176,7 +196,8 @@ FAILING ON THE CLASS IT CATCHES (`--fail`)
USAGE USAGE
python3 doc_census_check.py [--repo DIR] [--rev HEAD] [--tools NAME...] python3 doc_census_check.py [--repo DIR] [--rev HEAD] [--tools NAME...]
[--json OUT] [--no-run] [--fail] [--selftest] # selftest: 60 cells, one per claim class [--json OUT] [--fail] [--no-run] [--vocab PATH] [--save-vocab PATH]
[--selftest] # selftest: 72 cells, one per claim class
""" """
import argparse import argparse
import ast import ast
@@ -806,6 +827,24 @@ def _fixture_checks():
check("mode: --fail cannot fail on a split it could not verify", check("mode: --fail cannot fail on a split it could not verify",
gate_rc([rep_norun], True), 0) gate_rc([rep_norun], True), 0)
check("mode: and still fails on the verified one", gate_rc([rep_run], True), 1) check("mode: and still fails on the verified one", gate_rc([rep_run], True), 1)
# a cached vocabulary grades unit-hood without a run -- and only when it
# names the unit, which is the whole difference between a proof and a
# guess (reply 22, option 2)
check("vocab: a cached census unit is recognised",
vocab_has("UNRESOLVED", {"unresolved", "citations"}), True)
check("vocab: a unit the vocabulary does not name is not",
vocab_has("WOMBATS", {"unresolved"}), False)
rep_cached = check_tool(td, split_stub, "stub_split.py", {}, run=False,
tmpdir=td, vocab={"unresolved"}, vocab_rev="abc1234")
check("vocab: the same runless split grades as CACHE_CHECKABLE",
[(s["unit"], s["how"], s["oracle_rev"]) for s in rep_cached["splits"]],
[("UNRESOLVED", "CACHE_CHECKABLE", "abc1234")])
check("vocab: and the gate spends it", gate_rc([rep_cached], True), 1)
rep_other = check_tool(td, split_stub, "stub_split.py", {}, run=False,
tmpdir=td, vocab={"wombats"}, vocab_rev="abc1234")
check("vocab: a vocabulary naming another unit leaves it advisory",
([s["unit"] for s in rep_other["splits"]], gate_rc([rep_other], True)),
([], 0))
with tempfile.TemporaryDirectory(prefix="doccensus-gate-") as td: with tempfile.TemporaryDirectory(prefix="doccensus-gate-") as td:
os.makedirs(os.path.join(td, "tools")) os.makedirs(os.path.join(td, "tools"))
@@ -841,6 +880,41 @@ def _fixture_checks():
run_gate("--tools", "tools/stub_split.py", "--no-run", "--fail"), 0) run_gate("--tools", "tools/stub_split.py", "--no-run", "--fail"), 0)
check("gate e2e: --fail with the run grades that same split (rc 1)", check("gate e2e: --fail with the run grades that same split (rc 1)",
run_gate("--tools", "tools/stub_split.py", "--fail"), 1) run_gate("--tools", "tools/stub_split.py", "--fail"), 1)
# the process exit code through the vocabulary, both directions, plus
# the two ways a vocabulary can fail to be usable at all
vpath = os.path.join(td, "vocab-names-unit.json")
with open(vpath, "w") as fh:
json.dump({"rev": "abc1234",
"tools": {"tools/stub_split.py": ["unresolved"]}}, fh)
check("gate e2e: --no-run --vocab grades a split the vocabulary names (rc 1)",
run_gate("--tools", "tools/stub_split.py", "--no-run",
"--vocab", vpath, "--fail"), 1)
vother = os.path.join(td, "vocab-other-unit.json")
with open(vother, "w") as fh:
json.dump({"rev": "abc1234",
"tools": {"tools/stub_split.py": ["wombats"]}}, fh)
check("gate e2e: a vocabulary that does not name the unit leaves rc 0",
run_gate("--tools", "tools/stub_split.py", "--no-run",
"--vocab", vother, "--fail"), 0)
check("gate e2e: an unreadable --vocab is rc 2, not 0 and not 1",
run_gate("--tools", "tools/stub_split.py", "--no-run",
"--vocab", os.path.join(td, "nope.json"), "--fail"), 2)
check("gate e2e: --save-vocab without a run is rc 2",
run_gate("--tools", "tools/stub_split.py", "--no-run",
"--save-vocab", os.path.join(td, "v0.json"), "--fail"), 2)
# the round trip a gate runner would actually run: a full run writes the
# vocabulary it observed, the fast mode reads it back and still fails
vrt = os.path.join(td, "vocab-roundtrip.json")
check("gate e2e: a full run writes the vocabulary it observed (rc 1)",
run_gate("--tools", "tools/stub_split.py", "--save-vocab", vrt,
"--fail"), 1)
with open(vrt) as fh:
check("gate e2e: the written vocabulary names the unit the leg printed",
sorted(json.load(fh)["tools"].get("tools/stub_split.py", [])),
["unresolved"])
check("gate e2e: the round trip fails the fast mode on the same split",
run_gate("--tools", "tools/stub_split.py", "--no-run",
"--vocab", vrt, "--fail"), 1)
print(f"selftest: {cells[0]} cells, {cells[0] - bad[0]} passed, {bad[0]} failed") print(f"selftest: {cells[0]} cells, {cells[0] - bad[0]} passed, {bad[0]} failed")
return 0 if ok else 1 return 0 if ok else 1
@@ -920,7 +994,9 @@ def unit_scope(unit, legs, no_run):
DESIGN (`citations` prints once under EXPLICIT and once under BARE), so a DESIGN (`citations` prints once under EXPLICIT and once under BARE), so a
docstring that mirrors both is correct and is reported as such, not flagged. docstring that mirrors both is correct and is reported as such, not flagged.
A unit no leg prints is not a census unit here. Without a run, only A unit no leg prints is not a census unit here. Without a run, only
uppercase census labels are checked. uppercase census labels are checked -- and a cached vocabulary (see
vocab_has) can widen that, which is why the cache decision is taken in
check_tool, not here: this function answers about the legs it was given.
""" """
if no_run or not legs: if no_run or not legs:
return ("LABEL_ONLY" if is_label(unit) else "UNCHECKED_NO_ORACLE") return ("LABEL_ONLY" if is_label(unit) else "UNCHECKED_NO_ORACLE")
@@ -940,7 +1016,19 @@ def unit_scope(unit, legs, no_run):
return "NOT_A_CENSUS_UNIT" return "NOT_A_CENSUS_UNIT"
def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240): def vocab_has(unit, vocab):
"""True when a cached census vocabulary names this unit word.
The vocabulary is a set of the unit KEYS a full run observed (`unresolved`,
`citations`, `acs_only` ...), and `keys_for` is the same matcher the oracle
uses -- so a cache hit means exactly "a leg printed this unit under this
key", no letter of the rule re-invented for the cache.
"""
return bool(keys_for(unit, {u: [0] for u in (vocab or ())}))
def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240,
vocab=None, vocab_rev=None):
text = open(script, encoding="utf-8", errors="replace").read() text = open(script, encoding="utf-8", errors="replace").read()
span = docstring_span(script, text) span = docstring_span(script, text)
if span is None: if span is None:
@@ -1015,21 +1103,35 @@ def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240):
rev_for_oracle = (items[0][0], scope[0] if len(scope) == 1 else "HEAD") rev_for_oracle = (items[0][0], scope[0] if len(scope) == 1 else "HEAD")
why = ("SELF_NOT_RUN" if is_self and run why = ("SELF_NOT_RUN" if is_self and run
else unit_scope(unit, legs_for(*rev_for_oracle), not run)) else unit_scope(unit, legs_for(*rev_for_oracle), not run))
oracle_rev = None
# A CACHED VOCABULARY WIDENS WHAT A RUNLESS MODE MAY GRADE, and only in
# the one direction it can prove: a unit some leg printed at the
# vocabulary's rev is a census unit, and the disagreement here is
# internal to this docstring, so the leg's VALUE is never needed. It is
# consulted only when nothing ran -- with a run, a unit the live leg
# does not print is evidence AGAINST census-hood and the cache must not
# overrule it. A STALE claim never enters through here: `why` only
# decides splits.
if why in ("LABEL_ONLY", "UNCHECKED_NO_ORACLE") and not run \
and vocab_has(unit, vocab):
why, oracle_rev = "CACHE_CHECKABLE", vocab_rev
row = {"unit": unit, "revs": list(scope), "values": sorted(vals), row = {"unit": unit, "revs": list(scope), "values": sorted(vals),
"how": why, "rows": [{"line": ln, "value": v, "block": b} "how": why, "oracle_rev": oracle_rev,
for b, ln, v, _ in items]} "rows": [{"line": ln, "value": v, "block": b}
for b, ln, v, _ in items]}
# THE ONLY DOOR INTO `splits`. A split is graded only when a leg ran and # THE ONLY DOOR INTO `splits`. A split is graded only when a leg ran and
# printed its unit with exactly one value (CHECKABLE): then the docstring # printed its unit with exactly one value (CHECKABLE), or when a cached
# and the output are talking about one number and a disagreement is a # vocabulary proves the unit is a census unit and no run happened
# defect the gate can verify. Every other reason -- no oracle at all # (CACHE_CHECKABLE): then the docstring and the census are talking about
# (LABEL_ONLY, --no-run), a unit no leg prints (NOT_A_CENSUS_UNIT), a # one number and a disagreement is a defect the gate can verify. Every
# unit the tool itself prints per section (SECTION_SPLIT_BY_TOOL), this # other reason -- no oracle at all (LABEL_ONLY, --no-run), a unit no leg
# tool reading itself (SELF_NOT_RUN) -- is reported with its values and # prints (NOT_A_CENSUS_UNIT), a unit the tool itself prints per section
# never reaches the gate. Decided 2026-10-18 (reply 22) after # (SECTION_SPLIT_BY_TOOL), this tool reading itself (SELF_NOT_RUN) -- is
# `--fail --no-run` returned 1 on the 471/441 split at fca3f2e while the # reported with its values and never reaches the gate. Decided 2026-10-18
# full run returned 0 for the same units it could not see: rc 1 must # (reply 22) after `--fail --no-run` returned 1 on the 471/441 split at
# never mean "I could not check this". # fca3f2e while the full run returned 0 for the same units it could not
if why != "CHECKABLE": # see: rc 1 must never mean "I could not check this".
if why not in ("CHECKABLE", "CACHE_CHECKABLE"):
unchecked[why] += 1 unchecked[why] += 1
advisory.append(row) advisory.append(row)
continue continue
@@ -1157,12 +1259,40 @@ def main():
"VERIFIED (CHECKABLE) or a STALE claim; unverified " "VERIFIED (CHECKABLE) or a STALE claim; unverified "
"splits and leg failures are reported, never spent as " "splits and leg failures are reported, never spent as "
"defects (rc 2 stays 'could not grade')") "defects (rc 2 stays 'could not grade')")
ap.add_argument("--vocab", metavar="PATH",
help="a census vocabulary written by --save-vocab: under "
"--no-run, a split in a unit the vocabulary names is "
"GRADED (CACHE_CHECKABLE) instead of labelled. The "
"vocabulary proves unit-hood, never a value, so no "
"STALE claim can enter this way")
ap.add_argument("--save-vocab", metavar="PATH",
help="write the census vocabulary THIS RUN observed (unit "
"keys per tool) for a later --no-run --vocab; needs "
"the run, so it is refused with --no-run (rc 2)")
ap.add_argument("--selftest", action="store_true") ap.add_argument("--selftest", action="store_true")
a = ap.parse_args() a = ap.parse_args()
if a.selftest: if a.selftest:
return _fixture_checks() return _fixture_checks()
if a.save_vocab and a.no_run:
print("cannot save a vocabulary: --save-vocab needs the census a run "
"prints, and --no-run runs nothing", file=sys.stderr)
return 2
vocab, vocab_rev = {}, None
if a.vocab:
try:
with open(a.vocab, encoding="utf-8") as fh:
vdoc = json.load(fh)
vocab = {t: set(u) for t, u in (vdoc.get("tools") or {}).items()}
vocab_rev = vdoc.get("rev")
except (OSError, ValueError, AttributeError, TypeError) as exc:
print(f"cannot grade: --vocab {a.vocab}: {exc}", file=sys.stderr)
return 2
if not a.no_run:
print("note: --vocab is read only by the runless mode; a live leg is "
"the oracle when the tool runs", file=sys.stderr)
store = git(a.repo, "ls-tree", "-r", "--name-only", a.rev) store = git(a.repo, "ls-tree", "-r", "--name-only", a.rev)
tree = {p for p in store.decode("utf-8", "replace").split("\n") if p} tree = {p for p in store.decode("utf-8", "replace").split("\n") if p}
tools, missing = resolve_tools(a.tools, tree) tools, missing = resolve_tools(a.tools, tree)
@@ -1186,7 +1316,8 @@ def main():
fh.write(src) fh.write(src)
try: try:
rep = check_tool(a.repo, local, t, cache, run=not a.no_run, rep = check_tool(a.repo, local, t, cache, run=not a.no_run,
tmpdir=tmpdir) tmpdir=tmpdir, vocab=vocab.get(t),
vocab_rev=vocab_rev)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
rep = {"tool": t, "splits": [], "blocks_with_claims": 0, rep = {"tool": t, "splits": [], "blocks_with_claims": 0,
"verdicts": [{"file": t, "verdict": "TIMEOUT", "rev": "-", "verdicts": [{"file": t, "verdict": "TIMEOUT", "rev": "-",
@@ -1196,6 +1327,10 @@ def main():
print(f"tools scanned at {a.rev}: {len(reports)} " print(f"tools scanned at {a.rev}: {len(reports)} "
f"({'internal-split only, label vocabulary' if a.no_run else 'docstring vs printed census'})") f"({'internal-split only, label vocabulary' if a.no_run else 'docstring vs printed census'})")
if a.vocab:
print(f"vocabulary: {a.vocab} -- census at {vocab_rev}, "
f"{len(vocab)} tool(s), {sum(len(v) for v in vocab.values())} unit(s)"
+ ("" if a.no_run else " (not read: a live leg is the oracle)"))
tot = collections.Counter() tot = collections.Counter()
for rep in reports: for rep in reports:
bad = rep["failures"] + [v for v in rep["verdicts"] if v["verdict"] == "STALE"] bad = rep["failures"] + [v for v in rep["verdicts"] if v["verdict"] == "STALE"]
@@ -1207,7 +1342,9 @@ def main():
for s in rep["splits"]: for s in rep["splits"]:
vals = ", ".join(f"{r['value']}@{r['line']}" for r in s["rows"]) vals = ", ".join(f"{r['value']}@{r['line']}" for r in s["rows"])
scope = ",".join(s["revs"]) or "no rev named" scope = ",".join(s["revs"]) or "no rev named"
print(f" SPLIT {s['unit']} [{scope}] ({s['how']}): {vals}") prov = (f", vocabulary at {s['oracle_rev']}"
if s.get("oracle_rev") else "")
print(f" SPLIT {s['unit']} [{scope}] ({s['how']}{prov}): {vals}")
for k, c in sorted(rep["unchecked"].items()): for k, c in sorted(rep["unchecked"].items()):
print(f" (not flagged: {c} split(s) in units {k})") print(f" (not flagged: {c} split(s) in units {k})")
# A --no-run split is the one advisory class a reader of the fast mode # A --no-run split is the one advisory class a reader of the fast mode
@@ -1235,17 +1372,36 @@ def main():
with open(a.json, "w") as fh: with open(a.json, "w") as fh:
json.dump({"rev": a.rev, "repo": a.repo, "reports": reports}, fh, indent=1) json.dump({"rev": a.rev, "repo": a.repo, "reports": reports}, fh, indent=1)
print(f"wrote {a.json}") print(f"wrote {a.json}")
if a.save_vocab:
# The vocabulary is READ OFF THE RUN, not off the docstrings: only the
# keys `parse_printed` saw in a leg's stdout count as census units, so a
# tool whose leg failed contributes nothing and cannot hand the fast
# mode a vocabulary it never printed.
units = collections.defaultdict(set)
for (name, rev), entry in cache.items():
if rev == "<selftest>" or not entry[0]:
continue
units[name].update(entry[0][0].keys())
with open(a.save_vocab, "w", encoding="utf-8") as fh:
json.dump({"rev": a.rev, "repo": a.repo,
"tools": {k: sorted(v) for k, v in units.items()}},
fh, indent=1, sort_keys=True)
print(f"wrote vocabulary {a.save_vocab}: {len(units)} tool(s), "
f"{sum(len(v) for v in units.values())} unit(s) at {a.rev}")
if a.fail: if a.fail:
nsplit, nstale = gate_faults(reports) nsplit, nstale = gate_faults(reports)
if nsplit or nstale: if nsplit or nstale:
print(f"\nFAIL: {nsplit} INTERNAL SPLIT + {nstale} STALE claim(s) " print(f"\nFAIL: {nsplit} INTERNAL SPLIT + {nstale} STALE claim(s) "
f"at {a.rev}" f"at {a.rev}"
+ (" (internal-split only: --no-run)" if a.no_run else "")) + (" (graded on a cached census vocabulary: --no-run --vocab)"
if a.no_run else ""))
return 1 return 1
print(f"\nOK: 0 INTERNAL SPLIT, 0 STALE claim(s) at {a.rev}" print(f"\nOK: 0 INTERNAL SPLIT, 0 STALE claim(s) at {a.rev}"
+ (" (no oracle in this mode: nothing was verified, so nothing is " + (" (no oracle in this mode: nothing was verified, so nothing is "
"graded -- ADVISORY rows above are labels, not faults)" "graded -- ADVISORY rows above are labels, not faults"
if a.no_run else "")) + ("; the vocabulary graded any split in a unit it names)"
if a.vocab else ")")
if a.no_run else ""))
return gate_rc(reports, a.fail) return gate_rc(reports, a.fail)