87 lines
4.4 KiB
Markdown
87 lines
4.4 KiB
Markdown
# 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 | `` ` $ < > & | ; ( ) { } `` or a trailing `\` -- not one bare command |
|
|
| `TAUTOLOGY` | error | the command is a constant-success builtin (`true`, `:`, `exit 0`, `echo [ok|pass|PASS|0]`, `printf ok`, `test 1 -eq 1`, `test -f /dev/null`, `test -e /`) |
|
|
| `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: `&`/`|`/redirect METACHAR in `quill/rfc-draft-agent-outputs.md`, `quill/draft-sprint-template*.md`, `forge/CHECKIN_CHECK_DRY_REFACTOR_VERIFICATION.md`; MULTIPLE in `sphinx/.../EVIDENCE-runs.txt`, `checkins/2026-10-17-volt.md`, `null/q62_scan.py` |
|
|
| 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
|
|
```
|