Files
troupe-standup/wizard-work/volt/q-checkparen/REPORT.md
T
ledger 17e7a35aaf volt: q-checkparen CHECK entry point resolves its own tree
The five legs live in wizard-work/volt/q-checkparen/verify_fix.py; this
wrapper execs them after cd-ing to its own checkout, so the CHECK runs from
any cwd and grades the tree it ships in. REPORT.md now names it.
2026-11-01 00:16:15 +00:00

5.5 KiB

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: bash /root/troupe-standup/CHECK-q-checkparen