volt: path_claim_check learns --rev WORKTREE (index inventory, disk bytes; cells 27->31); verify gains leg 2 path-claims (8 legs, cells 55->59)

This commit is contained in:
volt committed 2026-10-24 02:06:26 +00:00
1 parent df46ca7b5a
commit 9732094dfd
3 files changed
+182 -20

No files matched your search

+112 -6
View File
@@ -96,6 +96,30 @@ THE BASELINE, AND WHY THE FIRST CENSUS IS ITS LEDGER
check rather than a word that closes a red. A claim that something EXISTS is
still MISSING until the file does.
REVISIONS -- AND WHY `WORKTREE` IS NOT ONE OF THEM
`--rev` selects the tree the corpus is read from AND the tree existence is
judged against, so the claim and its oracle come from the same revision. The
default is `HEAD`.
`--rev WORKTREE` reads the files on disk and lists them from the INDEX, so it
grades the tree you are about to commit. It is not a revision and has no tree
object: `git rev-parse --verify WORKTREE^{commit}` fails, which is why this
flag could not be spelled until now. The two modes were measured apart in the
selftest before this paragraph existed, on one fixture document: a path claim
that lives only in the staged tree is invisible at `HEAD` (rc 0, no MISSING
row) and is a graded MISSING row under `WORKTREE` (rc 1 under
--fail-on-missing). That window -- the tick between writing prose and
committing it -- is exactly where the archive writes every claim it makes, so
a grader that could only read HEAD could not grade a lane's own tick. The
convention is `doc_command_check.py`'s and `tool_map.py`'s, and the reason is
the same in all three: grade the tree you are about to commit, not the last
one.
A path that exists on disk but is in neither the index nor HEAD is still
MISSING under `WORKTREE`: the inventory is the index, so `git add` before the
gate is the discipline, not a workaround. Untracked debris under a scratch
tree therefore cannot make a claim read EXISTS.
EXIT CODES
0 the census ran. Without --fail-on-missing a MISSING path is not a fault.
1 --fail-on-missing and at least one MISSING path is not in the baseline, or
@@ -108,13 +132,14 @@ EXIT CODES
that file is graded with no ledger after one note on stderr.
USAGE
python3 path_claim_check.py [--repo DIR] [--rev HEAD] [--corpus PATH...]
python3 path_claim_check.py [--repo DIR] [--rev HEAD|WORKTREE] [--corpus PATH...]
[--json OUT] [--only missing|exists|docrel|external|template|all]
[--context] [--fail-on-missing] [--baseline PATH]
--baseline defaults to tools/path_claim_baseline.tsv, resolved against
--repo, so the bare form already grades against this archive's ledger.
python3 path_claim_check.py --selftest # 27 cells
python3 path_claim_check.py --selftest # 31 cells
python3 path_claim_check.py --repo . --fail-on-missing
python3 path_claim_check.py --repo . --rev WORKTREE --fail-on-missing
python3 path_claim_check.py --repo . --only docrel --context
"""
import argparse
@@ -138,6 +163,11 @@ DEFAULT_REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# direction of a defect.
DEFAULT_BASELINE = "tools/path_claim_baseline.tsv"
# The pseudo-revision `doc_command_check.py` and `tool_map.py` already carry.
# Spelled once, here, so a reader greps one name and finds every branch that
# treats it as a state rather than as a commit.
WORKTREE = "WORKTREE"
# The extensions this archive actually names. A closed list, for the reason
# citation_resolve_check.py gives: an open `\\.[a-z]+` swallows clock times,
# decimals and domain names.
@@ -199,6 +229,11 @@ def precondition(repo, rev):
p = git(repo, "rev-parse", "--is-inside-work-tree")
if p.returncode != 0 or p.stdout.strip() != b"true":
return "cannot read repo %s: not a git work tree" % repo
if rev == WORKTREE:
# WORKTREE is a state, not a revision: it has no commit to resolve to.
# Everything below reads the index (inventory) and the disk (bytes), so
# the work-tree test just made is the whole precondition.
return None
q = git(repo, "rev-parse", "--verify", rev + "^{commit}")
if q.returncode != 0:
why = q.stderr.decode("utf-8", "replace").strip().splitlines()
@@ -325,13 +360,38 @@ def scan(repo, rev, corpus, store):
class Store:
"""The inventory and the bytes, at one revision or at the staged work tree.
WORKTREE is two reads, not one: the INVENTORY is the index (`ls-files`), so
only what will actually be committed can make a claim read EXISTS, and the
BYTES are the disk, so an edit that is not staged yet is still graded as the
text a reader will see. A path the index lists but the disk has lost falls
back to the index blob -- that is byte-for-byte what the commit would carry,
and it is the only honest answer to "does this exist in the tree I am about
to commit".
"""
def __init__(self, repo, rev):
self.repo, self.rev = repo, rev
self.tree = set(git(repo, "ls-tree", "-r", "--name-only", rev)
.stdout.decode("utf-8", "replace").splitlines())
if rev == WORKTREE:
raw = git(repo, "ls-files", "-z").stdout.decode("utf-8", "replace")
names = [p for p in raw.split("\0") if p]
else:
names = git(repo, "ls-tree", "-r", "--name-only", rev) \
.stdout.decode("utf-8", "replace").splitlines()
self.tree = set(names)
self.tops = {p.split("/")[0] for p in self.tree}
def read(self, path):
if self.rev == WORKTREE:
try:
with open(os.path.join(self.repo, path), "rb") as fh:
return fh.read()
except OSError:
p = git(self.repo, "show", ":" + path)
if p.returncode != 0:
raise CannotGrade("cannot read %s at WORKTREE" % path)
return p.stdout
p = git(self.repo, "show", "%s:%s" % (self.rev, path))
if p.returncode != 0:
raise CannotGrade("cannot read %s at %s" % (path, self.rev))
@@ -394,7 +454,10 @@ def apply_baseline(rows, ledger):
def report(rows, stats, rev, sha, corpus, ledger, path, only, context):
counts = collections.Counter(r["verdict"] for r in rows.values())
print("path_claim_check: %s at %s (%s)" % ("repo", rev, sha[:7]))
# WORKTREE has no commit of its own, so the sha printed is the HEAD it sits
# on, labelled as such: a reader must not mistake it for the graded tree.
where = ("HEAD " + sha[:7] + ", worktree graded") if rev == WORKTREE else sha[:7]
print("path_claim_check: %s at %s (%s)" % ("repo", rev, where))
print("matcher: /?(?:[A-Za-z0-9_.@+-]+/)+[A-Za-z0-9_.@+-]+\\.(closed ext list), "
"at least one '/' required")
print(" graded only when the first component is a tracked top-level entry; "
@@ -494,7 +557,8 @@ def main():
return 2
try:
store = Store(a.repo, a.rev)
sha = git(a.repo, "rev-parse", a.rev).stdout.decode().strip()
sha = git(a.repo, "rev-parse",
"HEAD" if a.rev == WORKTREE else a.rev).stdout.decode().strip()
corpus = a.corpus if a.corpus is not None else \
sorted(p for p in store.tree if p.endswith((".md", ".markdown")))
if not corpus:
@@ -657,6 +721,48 @@ def selftest():
cell("c17 a corpus with no markdown is rc 2, never an empty clean census",
rc == 2 and "no markdown corpus" in out, "rc=%d %s" % (rc, out[-200:]))
# --- WORKTREE: the tree you are about to commit, not the last commit ----
# One fixture document in three states: the committed claim (HEAD), an
# unstaged edit on disk, and a claim that lives only in the index. Each cell
# names which of the two reads it measures -- the inventory or the bytes.
q = os.path.join(repo, "WORK-QUEUE.md")
with open(q) as fh:
committed_txt = fh.read()
with open(q, "w") as fh:
fh.write("the real docs/real.md, with the committed claim gone\n")
_, out_h = run("--repo", repo)
_, out_w = run("--repo", repo, "--rev", "WORKTREE")
cell("c17a WORKTREE reads the bytes on disk; HEAD reads the blob",
"1 missing" in out_h and "0 missing" in out_w,
"HEAD %r | WORKTREE %r" % (out_h[-140:], out_w[-140:]))
with open(os.path.join(repo, "docs", "new.md"), "w") as fh:
fh.write("new\n")
with open(q, "w") as fh:
fh.write("the record now cites docs/new.md\n")
subprocess.run(["git", "-C", repo, "add", "-A"], capture_output=True)
_, out_h = run("--repo", repo, "--only", "exists")
_, out_w = run("--repo", repo, "--rev", "WORKTREE", "--only", "exists")
cell("c17b a path staged but never committed is invisible at HEAD, EXISTS under WORKTREE",
"docs/new.md" not in out_h and "docs/new.md" in out_w,
"HEAD %r | WORKTREE %r" % (out_h[-200:], out_w[-200:]))
with open(q, "w") as fh:
fh.write("the record cites docs/ghost.md\n")
subprocess.run(["git", "-C", repo, "add", "-A"], capture_output=True)
rc_h, out_h = run("--repo", repo, "--fail-on-missing", "--baseline", bl)
rc_w, out_w = run("--repo", repo, "--rev", "WORKTREE",
"--fail-on-missing", "--baseline", bl)
cell("c17c a claim only the staged tree makes: rc 0 at HEAD, rc 1 under WORKTREE",
rc_h == 0 and rc_w == 1 and "FAIL: 1 missing path" in out_w,
"HEAD rc=%d | WORKTREE rc=%d %s" % (rc_h, rc_w, out_w[-200:]))
rc, out = run("--repo", td, "--rev", "WORKTREE")
cell("c17d WORKTREE outside a git work tree is rc 2, not a crash",
rc == 2 and "not a git work tree" in out, "rc=%d %s" % (rc, out[-200:]))
# Put the fixture back the way the committed cells below expect it.
with open(q, "w") as fh:
fh.write(committed_txt)
os.remove(os.path.join(repo, "docs", "new.md"))
subprocess.run(["git", "-C", repo, "add", "-A"], capture_output=True)
# --- the ledger's closed set is enforced, not decorative ----------------
badcls = os.path.join(td, "badclass.tsv")
with open(badcls, "w") as fh:
+2 -2
View File
@@ -20,7 +20,7 @@ doc_census_check.py 104 cells
doc_command_check.py 18 cells
gate_blame.py 21 cells
landing_check.py 26 cells
path_claim_check.py 27 cells
path_claim_check.py 31 cells
queue_append_audit.py 25 cells
queue_claim_check.py 24 fixtures
queue_index.py 58 cells
@@ -28,5 +28,5 @@ reply_check.py 49 cells
selftest_sweep.py 39 cells
served_drift_check.py 25 cells
tool_map.py 20 cells
verify.py 55 cells
verify.py 59 cells
write_probe.py 15 cells
1 # selftest_baseline.tsv -- the cell count each tool's selftest prints, pinned.
20 doc_command_check.py
21 gate_blame.py
22 landing_check.py
23 path_claim_check.py
24 queue_append_audit.py
25 queue_claim_check.py
26 queue_index.py
28 selftest_sweep.py
29 served_drift_check.py
30 tool_map.py
31 verify.py
32 write_probe.py
+68 -12
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""verify.py -- the HOME the index gate did not have: one command, seven legs,
"""verify.py -- the HOME the index gate did not have: one command, eight legs,
one exit code, and a row per leg so a partial run cannot look like a clean one.
WHY THIS EXISTS
@@ -45,6 +45,18 @@ WHAT IT RUNS -- one row per leg, cheapest first, never in parallel
unknown handles, dates, emptiness), where the ledger states the
faults the archive already carried; only a class it does not
name is a fault. `--checkin-day DATE` adds a `--since` floor
path-claims tools/path_claim_check.py --rev WORKTREE --fail-on-missing
every path this archive's prose names, at the tree about to be
committed: the INVENTORY is the index, the BYTES are the disk,
so a claim written this tick and not yet committed is graded
rather than invisible. `tools/path_claim_baseline.tsv` states
the readings already reviewed; only a MISSING path the ledger
does not name is a fault, and every tolerated row is still
printed. WORKTREE, not HEAD, for the reason doc-commands gives
below -- HEAD cannot see the tick a lane is writing in -- and
the reason the leg exists at all: the instrument shipped
2026-10-20 could only read a commit, so it could not grade the
only tree that matters before the commit was made
reply-headings tools/reply_check.py --baseline tools/reply_baseline.tsv
every reply's heading against its own filename (addressee and
number), on the same ledger rule: `replies/` is the second
@@ -146,7 +158,7 @@ TOOLS ARE RESOLVED FROM --repo, NOT FROM THIS FILE'S DIRECTORY
The path must still be the ROOT: a subdirectory is rc 2 naming the root,
because widening `--repo` silently would grade a tree nobody named.
`--selftest` fixture corpus, 55 cells
`--selftest` fixture corpus, 59 cells
"""
import argparse
@@ -170,6 +182,10 @@ LEGS = (
{"key": "checkin", "tool": "checkin_check.py", "slow": False,
"what": "grade the newest day's check-ins against the naming and "
"duplicate rules"},
{"key": "path-claims", "tool": "path_claim_check.py", "slow": False,
"what": "every path the archive's prose names, graded at the tree about to "
"be committed (index inventory, disk bytes), against the ledger "
"that states the readings already reviewed"},
{"key": "reply-headings", "tool": "reply_check.py", "slow": False,
"what": "grade every reply's heading against its own filename"},
{"key": "index-current", "tool": "queue_index.py", "slow": False,
@@ -345,6 +361,17 @@ def leg_argv(key, repo, queue, index, checkin_day=None):
if checkin_day:
argv += ["--since", checkin_day]
return argv
if key == "path-claims":
# WORKTREE, and the ledger from the tree being graded: a revision is
# graded against the tolerance it committed, and a lane is graded
# against the tree it is about to commit. HEAD would grade the last
# commit while the tick's own prose went unread -- the blind spot this
# leg exists to close.
return [sys.executable, os.path.join(repo, "tools",
"path_claim_check.py"),
"--repo", repo, "--rev", "WORKTREE", "--fail-on-missing",
"--baseline", os.path.join(repo, "tools",
"path_claim_baseline.tsv")]
if key == "reply-headings":
# The ledger comes from the tree being graded, for the same reason the
# check-in ledger does: a revision is graded with the tolerance it
@@ -624,7 +651,8 @@ def _verify(*argv):
return proc.returncode, (proc.stdout or "") + (proc.stderr or "")
GREEN_ALL = {"checkin_check.py": 0, "reply_check.py": 0, "queue_index.py": 0,
GREEN_ALL = {"checkin_check.py": 0, "path_claim_check.py": 0,
"reply_check.py": 0, "queue_index.py": 0,
"queue_append_audit.py": 0, "doc_command_check.py": 0,
"selftest_sweep.py": 0, "write_probe.py": 0}
@@ -643,11 +671,11 @@ def selftest():
failures.append("%s\n got: %r\n want: %r" % (label, got, want))
with tempfile.TemporaryDirectory(prefix="verify-selftest-") as td:
# 1. seven green stubs -> rc 0
# 1. eight green stubs -> rc 0
repo = _fixture(os.path.join(td, "c1"), GREEN_ALL)
rc, out = _verify("--repo", repo)
check("1 all seven legs green -> rc 0", rc, 0)
check("1b summary counts the seven legs", "verify: 7 legs, 7 pass, 0 fault, "
check("1 all eight legs green -> rc 0", rc, 0)
check("1b summary counts the eight legs", "verify: 8 legs, 8 pass, 0 fault, "
"0 ungradable, 0 skipped" in out, True)
# 2. a stale index is a FAULT, and its own line reaches the row
@@ -702,8 +730,8 @@ def selftest():
rc, out = _verify("--repo", repo, "--json", jpath)
obj = json.load(open(jpath)) if os.path.exists(jpath) else {}
check("7 --json writes the rows", [r["key"] for r in obj.get("rows", [])],
["checkin", "reply-headings", "index-current", "append-audit",
"doc-commands", "selftest-sweep", "write-axis"])
["checkin", "path-claims", "reply-headings", "index-current",
"append-audit", "doc-commands", "selftest-sweep", "write-axis"])
check("7b --json carries the same rc the process returned",
obj.get("rc"), rc)
@@ -732,9 +760,10 @@ def selftest():
dict(GREEN_ALL, **{"queue_index.py": 1}),
outs={"queue_index.py": "STALE: line 1\n"})
rc, out = _verify("--repo", repo)
order = [out.find(k) for k in ("checkin", "reply-headings", "index-current",
"append-audit", "doc-commands",
"selftest-sweep", "write-axis")]
order = [out.find(k) for k in ("checkin", "path-claims", "reply-headings",
"index-current", "append-audit",
"doc-commands", "selftest-sweep",
"write-axis")]
check("11 legs print in fixed order", order == sorted(order)
and -1 not in order, True)
@@ -746,7 +775,7 @@ def selftest():
check("12 skipped leg is its own count in --json",
obj.get("counts", {}).get("SKIP"), 1)
check("12b and the skipped leg is not counted as a pass",
obj.get("counts", {}).get(PASS), 6)
obj.get("counts", {}).get(PASS), 7)
# 13. the detail line must not contradict the verdict: a row graded
# FAULT beside "0 fatal" is the SILENT failure this gate exists to catch.
@@ -945,6 +974,33 @@ def selftest():
check("29b the fault row is named doc-commands and carries its reason",
"fault: doc-commands" in out and "FLAG_NOT_ACCEPTED" in out, True)
# 30. THE PATH-CLAIMS LEG, and the tree it must read. The tool is called
# with `--rev WORKTREE --fail-on-missing` and the ledger taken from the
# tree being graded. HEAD cannot see the tick a lane writes in, so a leg
# reading HEAD would grade the last commit while this tick's new prose
# went unread -- measured apart from the mode itself in
# path_claim_check.py's c17a-c17c.
av = os.path.join(td, "c30-argv")
repo = _fixture(os.path.join(td, "c30"), GREEN_ALL,
argv_markers={"path_claim_check.py": av})
rc, out = _verify("--repo", repo)
seen = open(av).read() if os.path.exists(av) else ""
check("30 the path-claims leg runs --rev WORKTREE --fail-on-missing",
"--rev WORKTREE" in seen and "--fail-on-missing" in seen, True)
check("30b and it grades against the ledger inside the tree it grades",
os.path.join(repo, "tools", "path_claim_baseline.tsv") in seen, True)
# 31. a path claim the ledger does not name is a FAULT on the gate, named
# on the row -- the class that was a report nobody ran until this leg.
repo = _fixture(os.path.join(td, "c31"),
dict(GREEN_ALL, **{"path_claim_check.py": 1}),
outs={"path_claim_check.py":
"FAIL: 1 missing path(s) the baseline does not name\n"})
rc, out = _verify("--repo", repo)
check("31 an unledgered missing path -> rc 1", rc, 1)
check("31b the fault row is named path-claims and carries its reason",
"fault: path-claims" in out and "does not name" in out, True)
# 27. the count in this file's own docstring is a CLAIM, so it is graded
# against the count that actually ran. On 2026-10-19 the docstring and
# the run said 50 while the argparse help string still said 42 and