volt: check_lint catches a trailing prose aside after sentence punctuation

`bash CHECK-quill-draft-compliance (the artifact gate).` is prose, and bash
refuses it before the command runs: syntax error near unexpected token `(`,
rc 2. tools/check_lint.py graded that exact line SOUND because its
"trailing parenthetical" marker required `)` to be end-of-line; the sentence's
full stop after the aside defeated it. The marker now allows `[.!?,;:]?`
between the closing paren and EOL, and five selftest cells pin it: the two
measured prose shapes as PROSE_TAIL, and three controls that must stay SOUND
(process substitution, an opening subshell, a quoted aside).

The pin moves 37 -> 42 in tools/selftest_baseline.tsv, in this diff.

Evidence: selftest 42/42 rc 0; the repro line PROSE_TAIL rc 1 and the bare
command SOUND rc 0; a one-line mutant (old regex only) fails exactly cells 29
and 30, 40 passed / 2 failed rc 1; selftest_sweep 23 pinned / 23 agree / 0
drift rc 0; tools/verify.py --fast 12 legs, 11 pass, 0 fault, 1 skipped, rc 0.
Artifact and leg-graded CHECK: wizard-work/volt/q-checkparen/.
This commit is contained in:
ledger committed 2026-11-01 00:13:35 +00:00
1 parent fcd5d6b0f9
commit aba1621812
4 files changed
+241 -3

No files matched your search

+17 -2
View File
@@ -61,7 +61,7 @@ WHAT IT DOES NOT DO
USAGE
python3 check_lint.py --check "$CHECK"
python3 check_lint.py --ralph-dir /root/.hermes/wizard-outputs/ralph
python3 check_lint.py --selftest # 37 cells, one per class and edge
python3 check_lint.py --selftest # 42 cells, one per class and edge
"""
from __future__ import annotations
@@ -115,7 +115,12 @@ CATCH_ALL_RE = re.compile(
PROSE_MARKERS = [
(re.compile(r"\s+[\u2014\u2013]\s+"), "em dash"),
(re.compile(r"\s--\s+"), "spaced --"),
(re.compile(r"\s\([^()]*\)\s*$"), "trailing parenthetical"),
# The parenthetical may carry sentence punctuation: `bash CHECK-x (the
# artifact gate).` is prose with a full stop after the aside, and every
# unquoted `(` there is a bash syntax error, not an argument. Measured on
# the 2026-11-01 ralph run: the runner REDs with "syntax error near
# unexpected token `('" while the old `\)\s*$` read the line SOUND.
(re.compile(r"\s\([^()]*\)[.!?,;:]?\s*$"), "trailing parenthetical"),
(re.compile(r"\.\s+[A-Z]"), "sentence break"),
]
@@ -366,6 +371,16 @@ FIXTURES = [
("CHECK: sha256sum a.tar.gz | grep -q 4844c5fc\n", "SOUND"),
("CHECK: python3 tools/x.py --selftest | tail -1 | grep -q 'cells, 0 failed'\n", "SOUND"),
("CHECK: python3 -c \"print(1)\"\n", "SOUND"), # paren not preceded by space
# A trailing prose aside with sentence punctuation after the closing paren.
# This is the exact line the 2026-11-01 ralph run RED'd on: bash reads the
# unquoted `(` as a subshell opener and exits 2 before the command runs.
("CHECK: bash CHECK-quill-draft-compliance (the artifact gate).\n", "PROSE_TAIL"),
("CHECK: python3 v.py (re-derives the table),\n", "PROSE_TAIL"),
# Controls that must stay SOUND: the paren is not preceded by whitespace
# (process substitution), opens the command (a real subshell), or is quoted.
("CHECK: diff -u <(a) <(b)\n", "SOUND"),
("CHECK: (cd sub && python3 t.py)\n", "SOUND"),
("CHECK: python3 x.py \"note (a).\"\n", "SOUND"),
("CHECK: python3 x.py --json /tmp/o.json\n", "SOUND"), # -- flag, not " -- "
("CHECK: python3 v.py && echo CHECK_OK", "SOUND"),
# last-wins extraction, and a prose mention AFTER the real line. The second
+1 -1
View File
@@ -12,7 +12,7 @@
append_only_audit.py 18 cells
append_only_owners.py 15 cells
census_row_delta.py 37 cells
check_lint.py 37 cells
check_lint.py 42 cells
checkin_check.py 36 cells
citation_hash_class.py 19 fixtures
citation_resolve_check.py 14 fixtures
1 # selftest_baseline.tsv -- the cell count each tool's selftest prints, pinned.
12 append_only_audit.py
13 append_only_owners.py
14 census_row_delta.py
15 check_lint.py
16 checkin_check.py
17 citation_hash_class.py
18 citation_resolve_check.py
+125
View File
@@ -0,0 +1,125 @@
# check_lint: a trailing prose parenthetical with sentence punctuation read SOUND
Artifact: `tools/check_lint.py` (PROSE_TAIL marker) + `tools/selftest_baseline.tsv` (pin 37 -> 42).
HEAD when measured: `626e272` (`volt: Q142 record -- ...`). Author: volt, 2026-11-01.
Repro is not hypothetical: the 2026-11-01 ralph run RED'd on exactly this line.
## 1. The defect, measured
The runner extracts the last `^\s*CHECK:` line and hands it to `bash -c`. This
line -- my own previous CHECK -- is prose with a gloss:
bash CHECK-quill-draft-compliance (the artifact gate).
`bash` reads the unquoted `(` as a subshell opener and refuses before running
anything:
$ printf '%s\n' 'bash CHECK-quill-draft-compliance (the artifact gate).' > parenthetical-probe.sh
$ bash -n parenthetical-probe.sh
parenthetical-probe.sh: line 1: syntax error near unexpected token `('
parenthetical-probe.sh: line 1: `bash CHECK-quill-draft-compliance (the artifact gate).'
rc 2
`tools/check_lint.py` exists to catch this class before the runner does (§9 of
STANDING-AGREEMENT.md: a CHECK that is prose is a fault, not a verification).
Before the fix it graded the line **SOUND**, rc 0:
$ python3 tools/check_lint.py --check 'bash CHECK-quill-draft-compliance (the artifact gate).'
SOUND: 'bash CHECK-quill-draft-compliance (the artifact gate).'
rc 0
Cause: the marker was `\s\([^()]*\)\s*$`. The parenthetical is there, but the
sentence's full stop after the closing paren means `\)` is followed by `.`, not
end of line, so the match failed. The two sibling markers (`em dash`, `spaced --`)
were not affected; the trailing-aside shape was.
## 2. The fix, one character class
- (re.compile(r"\s\([^()]*\)\s*$"), "trailing parenthetical"),
+ (re.compile(r"\s\([^()]*\)[.!?,;:]?\s*$"), "trailing parenthetical"),
The paren still has to follow whitespace, so the three legitimate shapes are
untouched: process substitution (`<(a)` -- no space before `(`), an opening
subshell (`(cd x && y)` -- no character before `(`), and quoted text. The
optional punctuation covers `. , ; : ! ?`, the sentence marks that appear after
an aside.
After:
$ python3 tools/check_lint.py --check 'bash CHECK-quill-draft-compliance (the artifact gate).' --fail-on-fault
PROSE_TAIL: 'bash CHECK-quill-draft-compliance (the artifact gate).'
faults: PROSE_TAIL
detail: {"prose_marker": "trailing parenthetical", "command_prefix": "bash CHECK-quill-draft-compliance"}
rc 1
$ python3 tools/check_lint.py --check 'bash CHECK-quill-draft-compliance' --fail-on-fault
SOUND: 'bash CHECK-quill-draft-compliance'
rc 0
## 3. Tests
Five selftest cells added (37 -> 42):
- PROSE_TAIL: the exact failing line, full stop after `)`.
- PROSE_TAIL: `python3 v.py (re-derives the table),` -- comma after `)`.
- SOUND control: `diff -u <(a) <(b)` -- process substitution.
- SOUND control: `(cd sub && python3 t.py)` -- a real subshell.
- SOUND control: `python3 x.py "note (a)."` -- quoted, punctuation inside quotes.
Measured:
$ python3 tools/check_lint.py --selftest
selftest: 42 cells, 42 passed, 0 failed
rc 0
Non-vacuity, one-line mutant (`q-checkparen/mutant.py`, the old regex restored,
nothing else changed):
$ python3 mutant.py --selftest
cell 29: want PROSE_TAIL got SOUND <- 'CHECK: bash CHECK-quill-draft-compliance (the artifact gate).\n'
cell 30: want PROSE_TAIL got SOUND <- 'CHECK: python3 v.py (re-derives the table),\n'
selftest: 42 cells, 40 passed, 2 failed
rc 1
Exactly the two new cells fail; the 40 other cells are indifferent to the fix.
## 4. The pin, and the repo gate
`tools/selftest_baseline.tsv` carried `check_lint.py 37 cells`; re-pinned to
42 in the same diff, as the file's own header asks ("Re-pin on purpose, in the
diff").
$ python3 tools/selftest_sweep.py --repo .
...
pin: 23 pinned, 23 agree, 0 drift
verdict: rc 0 -- clean: tools 0 fatal, read-refusal 0 fault, malformed-input 0 fault, pin 0 drift
$ python3 tools/verify.py --fast
...
verify: 12 legs, 11 pass, 0 fault, 0 ungradable, 1 skipped
gate: OK -- 11 of 11 graded leg(s) passed (1 skipped: not a pass, not a fault)
rc 0
## 5. Not claimed
- That this makes `check_lint` complete. It is a text rubric; the new cell is
one measured prose shape, and a gloss that bash happens to parse (a bare word
after the command, say) is still SOUND. Only unquoted `(` is now caught.
- That every `CHECK:` line in `WORK-QUEUE.md` passes under the widened rule.
The queue's 64 CHECK lines were not graded by this item, before or after.
- That the fix would have failed the run differently. The runner already
RED'd; the tool now names the same line PROSE_TAIL instead of SOUND.
- That the parenthetical case is one class. The optional punctuation also
matches `cmd (x);` and `cmd (x):`; both are bash syntax errors at the `(`
for the same reason, and no selftest cell pins those two separately.
- That a queue record exists for this change. None was appended: the fix is
two tool files, the report is this directory, and no `WORK-QUEUE.md` byte
moved, so no index re-render was due.
Files changed: `tools/check_lint.py` (regex + 5 selftest cells + docstring count),
`tools/selftest_baseline.tsv` (pin 37 -> 42), and this artifact
(`wizard-work/volt/q-checkparen/`: `REPORT.md`, `verify_fix.py`). Nothing else
was edited. The report's own CHECK is leg-graded by `verify_fix.py`, and the
five legs were read rc 0 before the commit.
CHECK: python3 wizard-work/volt/q-checkparen/verify_fix.py
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""CHECK for the q-checkparen artifact: check_lint catches a trailing prose aside.
Legs (each prints PASS/FAULT; exit 0 only if all pass, 2 if it cannot grade):
1 selftest tools/check_lint.py --selftest prints 42 cells, 0 failed, rc 0
2 repro the measured ralph line classifies PROSE_TAIL, rc 1, and the
command prefix printed is exactly the command
3 clean the bare command classifies SOUND, rc 0 (no over-fire)
4 pin tools/selftest_baseline.tsv pins check_lint.py at 42 cells
5 falsifier a copy with only the regex reverted fails selftest on exactly
the two added PROSE_TAIL cells (40 passed / 2 failed), rc 1
Read-only over the repo: leg 5 writes only inside a TemporaryDirectory. The
repo root defaults to this file's own tree (four levels up), never a pinned
host path, so the check travels with a clone.
"""
import argparse
import os
import re
import subprocess
import sys
import tempfile
HERE = os.path.dirname(os.path.abspath(__file__))
DEFAULT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
REPRO = "bash CHECK-quill-draft-compliance (the artifact gate)."
CLEAN = "bash CHECK-quill-draft-compliance"
OLD = r'(re.compile(r"\s\([^()]*\)[.!?,;:]?\s*$"), "trailing parenthetical"),'
NEW = r'(re.compile(r"\s\([^()]*\)\s*$"), "trailing parenthetical"),'
def run(args, cwd=None):
p = subprocess.run(args, capture_output=True, text=True, timeout=120, cwd=cwd)
return p.returncode, (p.stdout or "") + (p.stderr or "")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--repo", default=DEFAULT_REPO)
a = ap.parse_args()
tool = os.path.join(a.repo, "tools", "check_lint.py")
pin = os.path.join(a.repo, "tools", "selftest_baseline.tsv")
for path in (tool, pin):
if not os.path.isfile(path):
print("cannot grade: missing " + path)
return 2
failed = 0
rc, out = run([sys.executable, tool, "--selftest"])
ok = rc == 0 and "42 cells, 42 passed, 0 failed" in out
print(("PASS" if ok else "FAULT") + " selftest rc=%d %s" % (rc, out.strip().splitlines()[-1]))
failed += 0 if ok else 1
rc, out = run([sys.executable, tool, "--check", REPRO, "--fail-on-fault"])
ok = rc == 1 and out.startswith("PROSE_TAIL:") and "command_prefix" in out
print(("PASS" if ok else "FAULT") + " repro rc=%d %s" % (rc, out.strip().splitlines()[0]))
failed += 0 if ok else 1
rc, out = run([sys.executable, tool, "--check", CLEAN, "--fail-on-fault"])
ok = rc == 0 and out.startswith("SOUND:")
print(("PASS" if ok else "FAULT") + " clean rc=%d %s" % (rc, out.strip().splitlines()[0]))
failed += 0 if ok else 1
with open(pin, encoding="utf-8") as fh:
rows = [ln for ln in fh.read().splitlines()
if ln and not ln.startswith("#") and ln.split("\t")[0] == "check_lint.py"]
ok = rows == ["check_lint.py\t42\tcells"]
print(("PASS" if ok else "FAULT") + " pin %s" % (rows or "no row"))
failed += 0 if ok else 1
with open(tool, encoding="utf-8") as fh:
src = fh.read()
if src.count(OLD) != 1:
print("FAULT falsifier fixed regex not found exactly once")
failed += 1
else:
with tempfile.TemporaryDirectory(prefix="checkparen.") as tmp:
mut = os.path.join(tmp, "mutant.py")
with open(mut, "w", encoding="utf-8") as fh:
fh.write(src.replace(OLD, NEW))
rc, out = run([sys.executable, mut, "--selftest"])
tail = out.strip().splitlines()[-1]
cells = re.findall(r"cell (\d+): want PROSE_TAIL got SOUND", out)
ok = (rc == 1 and "42 cells, 40 passed, 2 failed" in out
and cells == ["29", "30"])
print(("PASS" if ok else "FAULT") + " falsifier rc=%d %s" % (rc, tail))
failed += 0 if ok else 1
print("verify_fix: %d leg(s) faulted" % failed)
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())