tool_map: the drift guard graded a revision, so the pre-commit tree was ungraded; --rev WORKTREE derives the map from the files git would commit

Measured before: 4602bd5's message says "TOOLS.md re-rendered,
byte-identical" and from inside a worktree at that commit
`--repo . --check docs/TOOLS.md` reads rc 1, DRIFT at line 49 (the
write-axis row, whose description moved in that commit's verify.py),
and `--repo . --selftest` reads 15/16. Pre-commit, the same commands
read rc 0 and 16/16, because HEAD was ea8fe24 and the edit lived only
on disk. The guard was working; it was guarding the last commit.

Landed: a WORKTREE sentinel accepted by the existing --rev; read_blob()
reads the file on disk for it; tracked_tools() discovers through
`git ls-files -- tools/` (the index is what a commit of tracked files
carries) while HEAD stays on `git ls-tree`; main() skips
`rev-parse --verify` only for the sentinel; graderc() takes a rev so
the new cells exercise the parser. Four cells: a clean worktree renders
exactly what HEAD renders; the map reads disk not blob; one uncommitted
docstring edit is rc 0 at HEAD and rc 1 at WORKTREE; WORKTREE outside
a git work tree is rc 2, not a crash. Selftest 16 -> 20, 20/20 rc 0.

Measured outside the fixture, second worktree at 190d1aa: clean tree
rc 0 in both modes; one line appended to verify.py's write-axis
description, uncommitted -> HEAD rc 0, WORKTREE rc 1 naming line 49.
Transcript: wizard-outputs/volt/2026-10-21-worktree-mode/measure.txt

Found and NOT fixed, recorded in the docstring and the queue record:
selftest_sweep.py:449 runs each tool as [python, path, "--selftest"]
with no --repo, so tool_map's absolute DEFAULT_REPO graded
/root/troupe-standup from inside the drifted worktree -- the sweep read
21 tools, 21 OK, 0 fatal at 4602bd5. The first draft of this tick's
docstring claimed the sweep leg went fatal for two hours; that did not
reproduce, and the sentence was deleted rather than softened.

Gate: verify --fast 5/5 (pre-commit); verify --repo . 6/6 at this
commit, doc_command 65/65, doc_census 0 STALE.
This commit is contained in:
volt committed 2026-10-21 20:11:58 +00:00
1 parent 190d1aae05
commit 214c200bb2
3 files changed
+132 -28

No files matched your search

+105 -17
View File
@@ -2,12 +2,12 @@
"""tool_map.py -- the instruments get a map, and the map is generated from the tree.
WHY THIS EXISTS
`tools/` holds sixteen scripts and there is no document that says what they
are. A reader meets them one at a time -- in a `verify.py` leg, in a queue
block, in a reply -- and nothing states the whole set: which tool grades what,
which flags each one actually accepts, which of them the two probe axes cover,
and which leg of the operator's gate a failure shows up in. The closest thing
is `verify.py`'s `LEGS` table, which names five of the sixteen.
`tools/` holds one script per instrument and there is no document that says
what they are. A reader meets them one at a time -- in a `verify.py` leg, in a
queue block, in a reply -- and nothing states the whole set: which tool grades
what, which flags each one actually accepts, which of them the two probe axes
cover, and which leg of the operator's gate a failure shows up in. The closest
thing is `verify.py`'s `LEGS` table, which names six of them.
A hand-written map would be a fourth notation of the defect this suite keeps
grading: prose about the tree, one step from the thing it describes, with no
@@ -39,6 +39,42 @@ WHAT IT MEASURES -- one verdict per invocation
docstring, flags or probe rows without re-rendering the map turns the sweep
RED instead of leaving a stale document that reads as current.
THE PRE-COMMIT BLIND SPOT, AND THE MODE THAT CLOSES IT
Every cell above is derived from a REVISION, not from the working tree:
`collect()` reads blobs with `git show <rev>:<path>` and runs `--help` from a
copy of that blob. That is right for a document that makes a claim about a
commit, and wrong for the ten minutes before a commit exists.
Measured on this repository, 2026-10-21. `4602bd5` is drifted: its commit
message states "TOOLS.md re-rendered, byte-identical" and the map it ships is
not the render of its own tree. Two runs, both from inside a worktree checked
out at that commit: `--repo . --check docs/TOOLS.md` reads **rc 1, DRIFT at
line 49** (the `write-axis` cell, whose description moved in `verify.py`),
and `--repo . --selftest` reads **15/16, rc 1**, the one failure being the
currency cell below. Before the commit existed both commands read rc 0 and
16/16, because the document on disk and the tools at `HEAD` (`ea8fe24`) were
still the pre-edit pair -- the edit lived only in the worktree.
The gate did not catch it either. `selftest_sweep.py --repo .` at `4602bd5`
reads **21 tools, 21 OK, 0 fatal**, because the sweep runs each tool as
`[python, path, "--selftest"]` with no `--repo` (`selftest_sweep.py:449`) and
this tool's `DEFAULT_REPO` is an absolute path, so its selftest graded
/root/troupe-standup -- a different, clean tree. That is a second defect, and
it is NOT fixed here: the sweep's selftest axis can grade the wrong tree. It
is recorded because it is why the pre-commit runs stayed green.
`--rev WORKTREE` derives the map from the files on disk, discovered through
`git ls-files -- tools/` -- the index, which is what a commit of tracked
files will carry. Measured on a clean worktree at `190d1aa`: rc 0, and
byte-identical to what HEAD renders; with one uncommitted line appended to
`verify.py`'s `write-axis` description, `--rev HEAD` still reads rc 0 and
`--rev WORKTREE` reads **rc 1, DRIFT at line 49**. The currency cell stays
HEAD-scoped by design: a worktree mid-edit is not a fault, and a sweep that
fails while a docstring is being typed teaches nothing. The pre-commit guard
is that `--check` is run in WORKTREE mode before the commit; four cells below
measure that it separates the two trees and that a clean worktree renders
byte-for-byte what HEAD renders, so the mode cannot invent a drift of its own.
READ-ONLY except for the one path it is told to write. The only process it
starts is `<tool> --help`, which does no work by construction; it never runs a
documented command, so it cannot write, post, or deploy anything.
@@ -52,8 +88,9 @@ EXIT CODES (the tools/ contract)
USAGE
python3 tool_map.py --repo . --write docs/TOOLS.md # render
python3 tool_map.py --repo . --check docs/TOOLS.md # grade drift, rc 1 on drift
python3 tool_map.py --repo . --rev WORKTREE --check docs/TOOLS.md # ...as it will be committed
python3 tool_map.py --repo . --json out.json
python3 tool_map.py --selftest # 16 cells
python3 tool_map.py --selftest # 20 cells
"""
from __future__ import annotations
@@ -70,6 +107,10 @@ DEFAULT_REPO = "/root/troupe-standup"
DEFAULT_DOC = "docs/TOOLS.md"
HELP_TIMEOUT = 30
# The one value of `--rev` that does not name a revision: the files git would
# commit from this worktree (the index lists them, the disk supplies them).
WORKTREE = "WORKTREE"
# A long option, or a short one, as argparse prints them in the usage block.
# `-h`/`--help` are dropped: every tool has them, and a column of sixteen
# identical pairs is noise, not information.
@@ -84,13 +125,29 @@ def git(repo, *args, inp=None):
def read_blob(repo, rev, path):
"""The file's text at `rev`; from disk when `rev` is WORKTREE."""
if rev == WORKTREE:
try:
with open(os.path.join(repo, path), encoding="utf-8") as fh:
return fh.read()
except OSError:
return None
rc, out, err = git(repo, "show", f"{rev}:{path}")
return out if rc == 0 else None
def tracked_tools(repo, rev):
"""Sorted `tools/*.py` basenames tracked at `rev`."""
rc, out, _ = git(repo, "ls-tree", "-r", "--name-only", rev, "--", "tools/")
"""Sorted `tools/*.py` basenames tracked at `rev`.
WORKTREE is not a revision and has no tree object: the set is the INDEX
(`git ls-files`), which is what a commit of tracked files will carry, and
the contents come from disk. Reading the index rather than a reflog of the
worktree keeps one rule -- "the file git would commit" -- for both halves.
"""
if rev == WORKTREE:
rc, out, _ = git(repo, "ls-files", "--", "tools/")
else:
rc, out, _ = git(repo, "ls-tree", "-r", "--name-only", rev, "--", "tools/")
if rc != 0:
return None
names = [p.split("/")[-1] for p in out.split("\n")
@@ -417,6 +474,34 @@ def selftest(repo):
cell("--repo a directory that is not a git work tree: rc 2",
rc_norepo == 2, f"rc {rc_norepo}")
# -- WORKTREE: the tree you are about to commit, not the last commit --
# The map is derived from a revision by construction, so a docstring
# edited after the last commit is invisible to both `--check` and the
# currency cell below. That is measured here, not described: the same
# document is current against HEAD and drifted against the worktree.
cell("WORKTREE: a clean worktree renders exactly what HEAD renders",
render(collect(fixture, WORKTREE)) == text)
fake = os.path.join(fixture, "tools", "fake_tool.py")
with open(fake, encoding="utf-8") as fh:
src = fh.read()
with open(fake, "w", encoding="utf-8") as fh:
fh.write(src.replace("which nothing measured",
"which nothing has measured yet"))
wt = collect(fixture, WORKTREE)
hd = collect(fixture, "HEAD")
purpose_wt = {r["tool"]: r["purpose"] for r in wt["rows"]}["fake_tool.py"]
purpose_hd = {r["tool"]: r["purpose"] for r in hd["rows"]}["fake_tool.py"]
cell("WORKTREE: reads the file on disk, not the blob at HEAD",
purpose_wt != purpose_hd and "has measured yet" in purpose_wt,
f"worktree={purpose_wt!r} head={purpose_hd!r}")
rc_head = compare(doc, render(hd), quiet=True)
rc_wt = compare(doc, render(wt), quiet=True)
cell("blind spot: an uncommitted docstring edit is rc 0 at HEAD and rc 1 at WORKTREE",
rc_head == 0 and rc_wt == 1, f"HEAD rc {rc_head}, WORKTREE rc {rc_wt}")
rc_wt_norepo = graderc(td, rev=WORKTREE)
cell("WORKTREE outside a git work tree: rc 2, not a crash",
rc_wt_norepo == 2, f"rc {rc_wt_norepo}")
# -- the currency cell: the reason this document stays true ----------
here = os.path.join(repo, "docs", "TOOLS.md")
try:
@@ -436,11 +521,13 @@ def selftest(repo):
return 0 if passed == len(cells) else 1
def graderc(td):
def graderc(td, rev=None):
"""rc of a full `--check` run against a directory that is not a repo."""
proc = subprocess.run([sys.executable, os.path.abspath(__file__),
"--repo", td, "--check", os.path.join(td, "x.md")],
capture_output=True, text=True)
cmd = [sys.executable, os.path.abspath(__file__), "--repo", td]
if rev:
cmd += ["--rev", rev]
cmd += ["--check", os.path.join(td, "x.md")]
proc = subprocess.run(cmd, capture_output=True, text=True)
return proc.returncode
@@ -488,10 +575,11 @@ def main():
if rc != 0:
print(f"tool_map: cannot read repo: {args.repo} is not a git work tree")
return 2
rc, _, err = git(args.repo, "rev-parse", "--verify", f"{args.rev}^{{commit}}")
if rc != 0:
print(f"tool_map: cannot read rev {args.rev}: {err.strip().splitlines()[0] if err.strip() else 'no such object'}")
return 2
if args.rev != WORKTREE:
rc, _, err = git(args.repo, "rev-parse", "--verify", f"{args.rev}^{{commit}}")
if rc != 0:
print(f"tool_map: cannot read rev {args.rev}: {err.strip().splitlines()[0] if err.strip() else 'no such object'}")
return 2
data = collect(args.repo, args.rev)
text = render(data)