Files

4.4 KiB

checklint -- lint the CHECK line of a standup entry

Stdlib-only (Python 3, no deps). The troupe's lane contract ends with

CHECK: <single bare shell command>

whose own exit code IS the verdict. Two defects keep recurring in the ralph loop and both are statically detectable before anything runs:

  • a fallback arm (cmd || true, cmd; exit 0, cmd || echo ...) or a constant-success builtin (true, exit 0) -- the exit code is forced, so the gate cannot fail;
  • a CHECK line that is not one bare command (a && b, a | b, a redirect, a line continuation) -- the harness cannot run it as written, and the multi-command line resolves to whichever arm last ran.

--run adds the only non-static leg: it executes the extracted command with a timeout and folds its real exit code into the verdict.

Usage

python3 checklint.py entry.md                 # static lint
python3 checklint.py --run entry.md           # + execute the command
python3 checklint.py --run --timeout 5 entry.md
python3 checklint.py --json entry.md
python3 checklint.py --scan /root/troupe-standup

Exit code IS the verdict

code meaning
0 the CHECK line is clean (and with --run, the command exited 0)
1 a graded fault: one or more findings
2 COULD NOT GRADE -- entry unreadable, command could not execute, or timed out; every 2 names its cause, and a 2 is never reported as a fault

Findings

code kind meaning
MISSING error no top-level CHECK: line
MULTIPLE error more than one top-level CHECK: line
EMPTY error CHECK: with no command
FALLBACK_ARM error || true, || exit 0, || echo/printf, ; exit 0, ; true, ; echo/printf -- exit code forced
METACHAR error `` ` $ < > &
TAUTOLOGY error the command is a constant-success builtin (true, :, exit 0, `echo [ok
RUN_FAILURE error --run: the command exited nonzero (its code is in the message)
TIMEOUT cng --run: the command exceeded --timeout
UNREADABLE cng the entry is missing or binary

A CHECK: line inside a fenced code block is a replay transcript, not the contract, and is not read. --scan DIR gates a corpus: 0 when every CHECK line in the tree is clean, 1 when any is faulty, 2 when the tree could not be read; it skips .git, __pycache__ and files with a NUL byte in the first 8 KiB.

What it deliberately does NOT check

Whether the command's assertions are strong enough. A CHECK line can be one bare command and assert nothing (test -f f). A static linter cannot see that, and a reader who assumes checklint grades gate quality would be wrong. It grades the shape of the verdict, not its content; --run grades that the command actually exits 0.

Evidence (measured 2026-10-25)

claim status proof
the linter's own suite passes measured python3 test_checklint.py -> Ran 37 tests ... OK, exit 0
--run really executes the command measured test test_cli_run_leg_executes_the_command: a touch sentinel appears only because the command ran
--run refuses a fallback arm measured test test_cli_run_leg_does_not_execute_a_fallback_arm: exit 1, sentinel absent
a timeout is could-not-grade, not a fault measured test test_cli_timeout_exits_2_and_names_its_cause
static linting executes nothing measured test test_lint_text_is_pure_and_never_executes: same findings twice, sentinel absent
the linter finds real defects in the live repo measured checklint.py --scan /root/troupe-standup -> exit 1, 16 file(s) with a CHECK line, 8 clean, 8 faulty, 814 unreadable/binary skipped; full output in scan-troupe.txt
defects found are the two documented classes measured scan: &/`
this lane's own entry passes the linter measured python3 checklint.py --run ../checklint-entry.md -> exit 0

Replay

python3 test_checklint.py
python3 checklint.py --scan /root/troupe-standup
python3 checklint.py --run ../checklint-entry.md