fix(re): the capture checker counted its own selftest fixture as a citation
`check-capture-citations` exits 1 on a clean checkout of this branch, and would
have kept doing so for ever:
🔴 cited but NOT committed: 1
docs/re/captures/no-such-file-anywhere.png
`SEARCH` includes `tools`, so the scan reads this file -- and `selftest()`'s
planted fixture is a literal capture path. The checker cited its own test data,
to a file that will never exist by construction. A gate that is red before
anyone changes anything teaches people to ignore it, which is the opposite of
what Phase 4 built it for.
Excluding only this one file (`SELF`) keeps every other tool in scope. A real
citation belongs in a page, or in a tool that opens the capture -- never in the
checker itself.
Added a selftest case for it, because this is exactly the class of bug the rest
of this file already documents surviving: the ERE that matched nothing while
five ticks stayed green. Verified the guard can fail, rather than assuming it:
exclusion neutralised -> "own fixtures not counted 🔴 FAILED",
selftest rc=2, real check rc=1 reproducing the bug
exclusion restored -> selftest ok (7 cases), check rc=0
After the fix, on this branch:
captures committed : 212
cited by a page or a tool : 212
cited by nothing : 0
🔴 cited but NOT committed: 0 rc=0
which is also the first independent confirmation of Phase 4's "212 captures,
all cited" -- the checker now agrees with the page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,14 @@ CITE = re.compile(r"(?:docs/re/)?captures/[A-Za-z0-9._/-]+")
|
|||||||
CITE_ERE = r"(docs/re/)?captures/[A-Za-z0-9._/-]+"
|
CITE_ERE = r"(docs/re/)?captures/[A-Za-z0-9._/-]+"
|
||||||
# Where a citation may live. Prose AND code: tests and tools open these files.
|
# Where a citation may live. Prose AND code: tests and tools open these files.
|
||||||
SEARCH = ["docs", "crates", "tools", "port", "authored"]
|
SEARCH = ["docs", "crates", "tools", "port", "authored"]
|
||||||
|
# 🔴 AND NOT THIS FILE. `SEARCH` includes `tools`, so the scan read *itself* --
|
||||||
|
# and `selftest()`'s planted fixture below is a literal capture path. The check
|
||||||
|
# therefore reported a dangling citation to a file that will never exist, and
|
||||||
|
# exited 1 on a clean checkout, for ever. A gate that is red before anyone
|
||||||
|
# changes anything teaches people to ignore it.
|
||||||
|
# Excluding only this one file keeps every other tool in scope; a real citation
|
||||||
|
# belongs in a page or a tool that opens the capture, never in the checker.
|
||||||
|
SELF = ":!tools/re/check-capture-citations"
|
||||||
|
|
||||||
|
|
||||||
def git(*args: str) -> str:
|
def git(*args: str) -> str:
|
||||||
@@ -67,7 +75,7 @@ def committed() -> tuple[set[str], set[str]]:
|
|||||||
|
|
||||||
|
|
||||||
def cited() -> set[str]:
|
def cited() -> set[str]:
|
||||||
raw = git("grep", "-rhoE", CITE_ERE, "--", *SEARCH).splitlines()
|
raw = git("grep", "-rhoE", CITE_ERE, "--", *SEARCH, SELF).splitlines()
|
||||||
out = set()
|
out = set()
|
||||||
for line in raw:
|
for line in raw:
|
||||||
c = line.split(":")[-1]
|
c = line.split(":")[-1]
|
||||||
@@ -98,7 +106,7 @@ def named_bare() -> set[str]:
|
|||||||
out = set()
|
out = set()
|
||||||
for line in git("grep", "-rhoE",
|
for line in git("grep", "-rhoE",
|
||||||
r"[A-Za-z0-9._-]+\.(png|jpg|csv|log|txt|json|jsonl|bin|tsv)",
|
r"[A-Za-z0-9._-]+\.(png|jpg|csv|log|txt|json|jsonl|bin|tsv)",
|
||||||
"--", *SEARCH).splitlines():
|
"--", *SEARCH, SELF).splitlines():
|
||||||
out.add(line.split(":")[-1].strip())
|
out.add(line.split(":")[-1].strip())
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -151,7 +159,16 @@ def selftest() -> int:
|
|||||||
print(" %-34s %s (%d citations found)"
|
print(" %-34s %s (%d citations found)"
|
||||||
% ("citation gathering works", "ok" if gathering_ok else "🔴 FAILED", len(refs)))
|
% ("citation gathering works", "ok" if gathering_ok else "🔴 FAILED", len(refs)))
|
||||||
|
|
||||||
ok = gathering_ok
|
# 🔴 REGRESSION GUARD FOR `SELF`. The planted fixture above is a literal
|
||||||
|
# capture path living in a file `SEARCH` covers. Before the exclusion
|
||||||
|
# existed the scan counted it as a real citation, so the check reported a
|
||||||
|
# dangling capture and exited 1 on a clean tree — permanently. If anyone
|
||||||
|
# drops `SELF`, this goes red here instead of in everybody else's run.
|
||||||
|
fixture_counted = cases[0][1] in refs
|
||||||
|
print(" %-34s %s"
|
||||||
|
% ("own fixtures not counted", "🔴 FAILED" if fixture_counted else "ok"))
|
||||||
|
|
||||||
|
ok = gathering_ok and not fixture_counted
|
||||||
for name, path, want in cases:
|
for name, path, want in cases:
|
||||||
got = resolves(path.rstrip(".,;:)`"), files, dirs)
|
got = resolves(path.rstrip(".,;:)`"), files, dirs)
|
||||||
mark = "ok" if got == want else "🔴 FAILED"
|
mark = "ok" if got == want else "🔴 FAILED"
|
||||||
|
|||||||
Reference in New Issue
Block a user