tools (volt): the check-in leg grades the whole archive against a ledger, not one day -- a backdated fault was rc 0 before, rc 1 now

The 09:49Z leg ran checkin_check --since <newest day>, on the reasoning that the
newest day is the only day a new fault can appear. Measured false on a clone of
e98a34b: one added checkins/2026-10-02-volt-b.md (BAD_NAME) is invisible to that
floor -- verify --fast rc 0 'checkin_check: 1 files, 0 with a fault', while the
whole-archive run on the same tree is rc 1 with 74 files / 36 faults.

tools/checkin_baseline.tsv (35 data rows, sha256 0f599c5e...) is the faults the
archive already carried; checkin_check --baseline splits each row's classes into
known/new, only a new class makes rc 1, per class not per path; --emit-baseline
prints it to stdout (no new write path); an unreadable ledger is rc 2; stale
entries are advisory. Refreshed leg: same clone, same file -> rc 1 naming exactly
that file; live tree -> 73 files, 0 new, 35 known, rc 0.

Cells: checkin_check 29 -> 35 (35/35), verify 35 -> 37 (37/37), sweep 19/19 +
17/17 rc 0, ruff F,E9 clean. One docstring count removed after
doc_census_check graded it STALE -- the ledger is now the artifact that carries it.
This commit is contained in:
volt committed 2026-10-19 10:00:55 +00:00
1 parent e98a34b0c1
commit 92f8934e15
5 files changed
+402 -58

No files matched your search

+13
View File
@@ -10092,3 +10092,16 @@ Artifact: `/root/.hermes/wizard-outputs/volt/2026-10-18-index-stale/` (`REPORT.m
- **Nothing operational.** No queue item opened or closed; open set unchanged at `Q37:5278` (pipe) and career-lane `Q53:7303` (held for Alexander); no issue/PR/release/deploy surface; no another-party file edited (the only file changed is this lane's own `tools/verify.py`); no counterparty messaged; no secret printed. Reply 33's ask is done: `git config user.name Volt` / `user.email volt@agents.invalid` are set in the shell that ran this commit, so the author line no longer lands as the pipe. Artifact: `/root/.hermes/wizard-outputs/volt/2026-10-19-checkin-leg/` (`REPORT.md`, `check.sh`, `before/verify-3legs.py`, `before/verify.txt`, `before/checkin_check.txt`, `after/verify.txt`, `clone-path.txt`). - **Nothing operational.** No queue item opened or closed; open set unchanged at `Q37:5278` (pipe) and career-lane `Q53:7303` (held for Alexander); no issue/PR/release/deploy surface; no another-party file edited (the only file changed is this lane's own `tools/verify.py`); no counterparty messaged; no secret printed. Reply 33's ask is done: `git config user.name Volt` / `user.email volt@agents.invalid` are set in the shell that ran this commit, so the author line no longer lands as the pipe. Artifact: `/root/.hermes/wizard-outputs/volt/2026-10-19-checkin-leg/` (`REPORT.md`, `check.sh`, `before/verify-3legs.py`, `before/verify.txt`, `before/checkin_check.txt`, `after/verify.txt`, `clone-path.txt`).
— Volt — Volt
**Volt tick 2026-10-19 10:00Z — the fourth leg graded one day, and a check-in added under a backdated name walked past it: the check-in leg now grades the whole archive against a committed ledger.** (Pure suffix append; clock read immediately before this edit at 10:00:19Z; the file's true last line at `e98a34b` was `— Volt` closing the 09:49Z block, so nothing above this anchor was touched. This block opens and closes no item; the index is re-rendered in this same commit and `--check` reads rc 0 at the commit this block lands in.)
- **The hole, measured before anything was changed.** The `checkin` leg added at 09:49Z ran `checkin_check.py --since <newest day present>` on the reasoning that the newest day is the only day on which a new fault can appear. That reasoning is false in one direction, and a clone of `e98a34b` showed it: one file added at `checkins/2026-10-02-volt-b.md` — a badly-named file whose date half is a typo, i.e. the ordinary way this arrives — is not on the newest day, so the `--since` floor excluded it. Same tree, two instruments, opposite verdicts: `checkin_check.py --repo . --fail` → **74 files, 36 with a fault (BAD_NAME 26; DUPLICATE groups 10), rc 1**; `verify.py --fast` → **rc 0**, `gate: OK -- 3 of 3 graded leg(s) passed`, its checkin row reading `checkin_check: 1 files, 0 with a fault, 0 advisory`. Captured in the artifact's `before/verify-fast.txt` and `before/checkin-whole-archive.txt`.
- **The fix is a ledger, not a wider window.** `tools/checkin_baseline.tsv` (5 header lines + 35 data rows, 1,857 B, sha256 `0f599c5e7955a124d92e1fd41d5087598af19e69f00de4cd1f610f0f4851022e`) names the faults this archive already carried, one `<filename>\t<CLASS[,CLASS]>` row each — `DUPLICATE` included as a class, because 10 of the 35 rows are that. `checkin_check.py --baseline PATH` splits every row's classes into **known** (in the ledger) and **new**; only a new class makes rc 1. So the archive is graded end to end on every run and a fault landing on *any* date is red the moment it lands. The split is per **class**, not per path: a listed file that gains a class it did not have (truncated to empty) is new. `--emit-baseline` prints the ledger to stdout and exits 0, so refreshing it is a redirect and the tool keeps no new write path; an unreadable or malformed ledger is **rc 2** (could not grade), never a silent pass; entries that no longer match (file gone, class cleared) print as `STALE BASELINE` and never make rc 1.
- **Proof after, same clone and same one file.** `verify.py --fast` on the fixed tree → **rc 1**, `checkin FAULT rc=1 FAIL: 1 file(s) carry a class the baseline does not tolerate`, `verify: 4 legs, 2 pass, 1 fault, 0 ungradable, 1 skipped`. The 35 pre-rule rows stayed green in that same run — the file was the *only* new fault named. Live tree: **73 files, 0 new fault(s), 35 known-faulting in the baseline (BAD_NAME 25; DUPLICATE groups 10), 0 stale, 0 cleared, rc 0**. Artifact `after/verify-fast.txt`.
- **The cells, and the second defect this exposed.** `checkin_check.py --selftest` **29 → 35 cells, 35 passed** (c30 a ledger naming every class grades rc 0; c31 a fault on an older date the ledger does not name is rc 1; c32 a gained class on a listed path is new; c33 emit → load round-trips and silences exactly the current archive; c34 an entry for a file that is gone is stale, never a fault; c35 an unreadable, malformed or absent ledger refuses at rc 2). `verify.py --selftest` **35 → 37 cells, 37 passed** — cell 16b now pins that the leg is run with the ledger resolved **from `--repo`** and *no* `--since` by default, cell 19/19b that a missing ledger reaches the row as UNGRADABLE with the tool's own reason. `selftest_sweep.py` **19/19 read-refusal, 17/17 malformed, rc 0**; `ruff check --select F,E9 tools/` **All checks passed**.
- **A count in this lane's own docstring, corrected by the census rather than by argument.** `verify.py`'s new prose first asserted the archive's unbaselined figure as a bare `35 faults` counted at HEAD, and `doc_census_check.py` graded it **STALE** (`printed 1 [no-rev]`): the number was true at `e98a34b` and is *not a census the current tool prints*, because the tool now prints new faults and known-faulting separately. The assertion was removed and replaced by a pointer at the ledger, which is the artifact that carries the 35 rows — a number that lives in a file cannot drift from the file. Same rule applied in `checkin_check.py`'s docstring (`the 35 pre-rule faults` → `the faults the archive already carried`).
- **What this does not do.** The ledger is a maintenance surface: a *legitimate* new fault-tolerant state (a wizard renaming a bad file, a section of history republished) needs `--emit-baseline` re-run and committed, and until it is, the gate reads that repair as a stale entry (advisory, never rc 1) — a repair is visible, not silent, which is the direction worth paying for. It does not grade check-in *content* (A1 stays advisory inside `checkin_check.py` and this leg inherits that), does not repair the pre-rule rows (renaming them would edit the record to make a report green), and does not add the ruff leg, which is still a dependency decision: `ruff 0.16.4` is on this host and not a repo dependency, so the leg would make a ruff-less host rc 2 for the whole gate.
- **Nothing operational.** No queue item opened or closed; open set unchanged at `Q37:5278` (pipe) and career-lane `Q53:7303` (held for Alexander); no issue/PR/release/deploy surface; no another-party file edited (the two files changed and the one file added are this lane's own `tools/`); no counterparty messaged; no secret printed. No second check-in file was written for 2026-10-19 — the contract this leg enforces counts a same-day suffix as a DUPLICATE, and the 09:37Z file is the day's one. Artifact: `/root/.hermes/wizard-outputs/volt/2026-10-19-baseline-ledger/` (`REPORT.md`, `check.sh`, `probe.sh`, `before/`, `after/`, `post-verify.txt`).
— Volt
+9 -9
View File
@@ -56,7 +56,7 @@
| 46 | Q44 | 6162-6705 | 88496 | opening | The pin class: redirect every constant composed from the live data root, not only `SNAPSHOT_PATH` *(Helm lane; opened 2026-10-12 by the pipe, per Q43's own closing sentence — "extend the redirect … | DONE 2026-10-12 — `recoveries/helm-root-redirect.md` (Merlin, Helm lane); the closure block is at the foot | | 46 | Q44 | 6162-6705 | 88496 | opening | The pin class: redirect every constant composed from the live data root, not only `SNAPSHOT_PATH` *(Helm lane; opened 2026-10-12 by the pipe, per Q43's own closing sentence — "extend the redirect … | DONE 2026-10-12 — `recoveries/helm-root-redirect.md` (Merlin, Helm lane); the closure block is at the foot |
| 47 | Q48 | 6706-6825 | 15123 | opening | The runtime-resolution redirect: close the class Q45's literals cannot see | DONE 2026-10-13 — `recoveries/helm-runtime-redirect.md` (Merlin, Helm lane), scratch tree | | 47 | Q48 | 6706-6825 | 15123 | opening | The runtime-resolution redirect: close the class Q45's literals cannot see | DONE 2026-10-13 — `recoveries/helm-runtime-redirect.md` (Merlin, Helm lane), scratch tree |
| 48 | Q49 | 6826-7593 | 92050 | opening | The runtime-resolved root's live write path: name it, reproduce it, then close it | open and unclaimed. Opened by the pipe 2026-10-13 | | 48 | Q49 | 6826-7593 | 92050 | opening | The runtime-resolved root's live write path: name it, reproduce it, then close it | open and unclaimed. Opened by the pipe 2026-10-13 |
| 49 | Q45 | 7594-10094 | 384209 | opening | §9 follow-on — the home-directory channel *(Helm lane; Merlin)* | -- | | 49 | Q45 | 7594-10107 | 390226 | opening | §9 follow-on — the home-directory channel *(Helm lane; Merlin)* | -- |
## Ids with no `## ` heading ## Ids with no `## ` heading
@@ -71,7 +71,7 @@ Opened as records inside another section. `line` is the record's own opening lin
| Q50 | 6990 | 6990 | 46 | Q49 | BULLET+BOLD | BOLD-LEAD | | Q50 | 6990 | 6990 | 46 | Q49 | BULLET+BOLD | BOLD-LEAD |
| Q51 | 7106 | 7106 | 37 | Q49 | BULLET+BOLD | BOLD-LEAD | | Q51 | 7106 | 7106 | 37 | Q49 | BULLET+BOLD | BOLD-LEAD |
| Q52 | 7167 | 7167 | 90 | Q49 | BULLET+BOLD | BOLD-LEAD | | Q52 | 7167 | 7167 | 90 | Q49 | BULLET+BOLD | BOLD-LEAD |
| Q53 | 7292 | 7246 | 123 | Q49 | BULLET+BOLD | BOLD-LEAD | | Q53 | 7292 | 7246 | 124 | Q49 | BULLET+BOLD | BOLD-LEAD |
| Q63 | 9918 | 9909 | 17 | Q45 | BULLET+BOLD | BOLD-LEAD | | Q63 | 9918 | 9909 | 17 | Q45 | BULLET+BOLD | BOLD-LEAD |
**Not in this document.** Ids the prose corpus names that the queue has never mentioned (`checkins/`, `replies/`, `recoveries/`, `audits/`, `docs/`, the top-level documents; `tools/` excluded). That set moves with the prose, not with the queue, so embedding it here would make `--check` go RED for a reason that has nothing to do with the queue being current. It is reported on demand: `python3 tools/queue_index.py --outside`. **Not in this document.** Ids the prose corpus names that the queue has never mentioned (`checkins/`, `replies/`, `recoveries/`, `audits/`, `docs/`, the top-level documents; `tools/` excluded). That set moves with the prose, not with the queue, so embedding it here would make `--check` go RED for a reason that has nothing to do with the queue being current. It is reported on demand: `python3 tools/queue_index.py --outside`.
@@ -217,7 +217,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD", "form": "BOLD-LEAD",
"id": "Q53", "id": "Q53",
"line": 7292, "line": 7292,
"refs": 123, "refs": 124,
"section": "Q49", "section": "Q49",
"shape": "BULLET+BOLD" "shape": "BULLET+BOLD"
}, },
@@ -236,9 +236,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
"end_line": 8, "end_line": 8,
"line": 1 "line": 1
}, },
"queue_bytes": 1276470, "queue_bytes": 1282487,
"queue_lines": 10094, "queue_lines": 10107,
"queue_sha256": "a145bebb1b0c70738c3d284d4ac638feec7f97833f4800db483dc7a8464efe27", "queue_sha256": "0f8829c1114a19f23a29e75f0c93faf3ade6e98bda35199c3b74aebae1896eeb",
"sections": [ "sections": [
{ {
"bytes": 3139, "bytes": 3139,
@@ -817,11 +817,11 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "The runtime-resolved root's live write path: name it, reproduce it, then close it" "title": "The runtime-resolved root's live write path: name it, reproduce it, then close it"
}, },
{ {
"bytes": 384209, "bytes": 390226,
"end_line": 10094, "end_line": 10107,
"id": "Q45", "id": "Q45",
"line": 7594, "line": 7594,
"lines": 2501, "lines": 2514,
"role": "opening", "role": "opening",
"role_detail": "", "role_detail": "",
"status": null, "status": null,
+40
View File
@@ -0,0 +1,40 @@
# check-in baseline -- the faults this archive already carried when the
# naming rule was written. One row per file: <filename>\t<CLASS[,CLASS]>.
# Regenerate: checkin_check.py --repo . --emit-baseline > tools/checkin_baseline.tsv
# A row is a stated tolerance, not an exemption: a file that gains a class,
# and a file that is not listed, both make rc 1 under --fail --baseline.
2026-09-24-zephyrus-02.md BAD_NAME,DUPLICATE
2026-09-24-zephyrus.md DUPLICATE
2026-09-26-zephyrus-02.md BAD_NAME,DUPLICATE
2026-09-26-zephyrus.md DUPLICATE
2026-09-28-zephyrus-02.md BAD_NAME,DUPLICATE
2026-09-28-zephyrus.md DUPLICATE
2026-10-01-zephyrus-03.md BAD_NAME,DUPLICATE
2026-10-01-zephyrus-04.md BAD_NAME,DUPLICATE
2026-10-01-zephyrus-05.md BAD_NAME,DUPLICATE
2026-10-01-zephyrus-06.md BAD_NAME,DUPLICATE
2026-10-01-zephyrus-07.md BAD_NAME,DUPLICATE
2026-10-01-zephyrus.md DUPLICATE
2026-10-02-zephyrus-01.md BAD_NAME
2026-10-03-zephyrus-02.md BAD_NAME,DUPLICATE
2026-10-03-zephyrus-03.md BAD_NAME,DUPLICATE
2026-10-03-zephyrus.md DUPLICATE
2026-10-04-zephyrus-02.md BAD_NAME,DUPLICATE
2026-10-04-zephyrus.md DUPLICATE
2026-10-05-zephyrus-02.md BAD_NAME,DUPLICATE
2026-10-05-zephyrus-03.md BAD_NAME,DUPLICATE
2026-10-05-zephyrus.md DUPLICATE
2026-10-06-zephyrus-02.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus-04.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus-05.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus-06.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus-wizards-02.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus-wizards-03.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus-wizards.md BAD_NAME,DUPLICATE
2026-10-06-zephyrus.md DUPLICATE
2026-10-07-cassian-02.md BAD_NAME,DUPLICATE
2026-10-07-cassian-q5-census.md BAD_NAME,DUPLICATE
2026-10-07-cassian-q5-recount.md BAD_NAME,DUPLICATE
2026-10-07-cassian.md DUPLICATE
2026-10-07-zephyrus-02.md BAD_NAME,DUPLICATE
2026-10-07-zephyrus.md DUPLICATE
1 # check-in baseline -- the faults this archive already carried when the
2 # naming rule was written. One row per file: <filename>\t<CLASS[,CLASS]>.
3 # Regenerate: checkin_check.py --repo . --emit-baseline > tools/checkin_baseline.tsv
4 # A row is a stated tolerance, not an exemption: a file that gains a class,
5 # and a file that is not listed, both make rc 1 under --fail --baseline.
6 2026-09-24-zephyrus-02.md BAD_NAME,DUPLICATE
7 2026-09-24-zephyrus.md DUPLICATE
8 2026-09-26-zephyrus-02.md BAD_NAME,DUPLICATE
9 2026-09-26-zephyrus.md DUPLICATE
10 2026-09-28-zephyrus-02.md BAD_NAME,DUPLICATE
11 2026-09-28-zephyrus.md DUPLICATE
12 2026-10-01-zephyrus-03.md BAD_NAME,DUPLICATE
13 2026-10-01-zephyrus-04.md BAD_NAME,DUPLICATE
14 2026-10-01-zephyrus-05.md BAD_NAME,DUPLICATE
15 2026-10-01-zephyrus-06.md BAD_NAME,DUPLICATE
16 2026-10-01-zephyrus-07.md BAD_NAME,DUPLICATE
17 2026-10-01-zephyrus.md DUPLICATE
18 2026-10-02-zephyrus-01.md BAD_NAME
19 2026-10-03-zephyrus-02.md BAD_NAME,DUPLICATE
20 2026-10-03-zephyrus-03.md BAD_NAME,DUPLICATE
21 2026-10-03-zephyrus.md DUPLICATE
22 2026-10-04-zephyrus-02.md BAD_NAME,DUPLICATE
23 2026-10-04-zephyrus.md DUPLICATE
24 2026-10-05-zephyrus-02.md BAD_NAME,DUPLICATE
25 2026-10-05-zephyrus-03.md BAD_NAME,DUPLICATE
26 2026-10-05-zephyrus.md DUPLICATE
27 2026-10-06-zephyrus-02.md BAD_NAME,DUPLICATE
28 2026-10-06-zephyrus-04.md BAD_NAME,DUPLICATE
29 2026-10-06-zephyrus-05.md BAD_NAME,DUPLICATE
30 2026-10-06-zephyrus-06.md BAD_NAME,DUPLICATE
31 2026-10-06-zephyrus-wizards-02.md BAD_NAME,DUPLICATE
32 2026-10-06-zephyrus-wizards-03.md BAD_NAME,DUPLICATE
33 2026-10-06-zephyrus-wizards.md BAD_NAME,DUPLICATE
34 2026-10-06-zephyrus.md DUPLICATE
35 2026-10-07-cassian-02.md BAD_NAME,DUPLICATE
36 2026-10-07-cassian-q5-census.md BAD_NAME,DUPLICATE
37 2026-10-07-cassian-q5-recount.md BAD_NAME,DUPLICATE
38 2026-10-07-cassian.md DUPLICATE
39 2026-10-07-zephyrus-02.md BAD_NAME,DUPLICATE
40 2026-10-07-zephyrus.md DUPLICATE
+265 -13
View File
@@ -57,18 +57,49 @@ RULES IMPLEMENTED (stated, not implied)
EXIT CODES (the repo's contract, `tools/selftest_sweep.py`) EXIT CODES (the repo's contract, `tools/selftest_sweep.py`)
0 ran; nothing to report, or faults reported without --fail 0 ran; nothing to report, or faults reported without --fail
1 ran, and graded at least one F-fault, under --fail 1 ran, and graded at least one F-fault, under --fail
2 could not grade: no checkins dir, no roster, or a file this host cannot 2 could not grade: no checkins dir, no roster, a baseline ledger this host
read as UTF-8. Never 1, never a traceback. cannot read or parse, or a file this host cannot read as UTF-8. Never 1,
never a traceback.
READ-ONLY: the only write path is `--json PATH`. It renames nothing -- the BASELINE: GRADING THE WHOLE ARCHIVE WITHOUT KEEPING IT RED
badly named files are the principals' history, and a tool that renamed them A `--since` floor is how this tool stayed adoptable: the faults the archive
would be editing the record to make its own report green. already carried are the record and are not re-litigated every run. But a floor grades *one
side of the archive*, and a floor chosen from the archive's own newest date
grades **nothing that is added before that date**. Measured on a clone of
`e98a34b` on 2026-10-19: a new `checkins/2026-10-02-volt-b.md` (BAD_NAME)
added today is invisible to `--since 2026-10-19` -- `verify.py --fast` printed
`checkin_check: 1 files, 0 with a fault` and exited **0** -- while the same
tree's whole-archive run exited **1** with that file in the table. A backdated
filename is not a hypothetical: it is what a typo in the date half makes.
`--baseline PATH` replaces the floor with a ledger. The ledger is one row per
*known-faulting file*: `<filename>\t<CLASS[,CLASS]>`, with `DUPLICATE` as a
class like any other. A file's classes are then split into **known** (in the
ledger) and **new**; only a new class makes rc 1, so the archive can be
graded end to end every run and a fault that lands *anywhere*, on any date, is
red the moment it lands. The split is per **class**, not per path: an existing
file that gains a class it did not have (a check-in truncated to empty) is
new, because the ledger states what was tolerated, not that the path is
exempt. Entries that no longer match -- file gone, or class cleared -- are
reported as stale and never make rc 1: that is someone repairing the record,
which is the point.
`--emit-baseline` prints that ledger to stdout and exits 0, so refreshing it
is a redirect and the tool keeps no write path of its own. An unreadable or
malformed ledger is rc 2, never a silent pass: a baseline that cannot be read
cannot certify anything.
READ-ONLY: the only write paths are `--json PATH` and stdout. It renames
nothing -- the badly named files are the principals' history, and a tool that
renamed them would be editing the record to make its own report green.
USAGE: USAGE:
python3 checkin_check.py --repo /root/troupe-standup python3 checkin_check.py --repo /root/troupe-standup
python3 checkin_check.py --repo . --gaps --json /tmp/checkins.json python3 checkin_check.py --repo . --gaps --json /tmp/checkins.json
python3 checkin_check.py --repo . --fail --baseline tools/checkin_baseline.tsv
python3 checkin_check.py --repo . --emit-baseline > tools/checkin_baseline.tsv
python3 checkin_check.py --dir /tmp/fake/checkins --roster volt,zephyrus --today 2026-10-18 python3 checkin_check.py --dir /tmp/fake/checkins --roster volt,zephyrus --today 2026-10-18
python3 checkin_check.py --selftest # 29 cells, names, dates, roster, refusals python3 checkin_check.py --selftest # 34 cells, names, dates, roster, baseline, refusals
""" """
from __future__ import annotations from __future__ import annotations
@@ -89,6 +120,10 @@ FENCE_RE = re.compile(r"^\s*(```|~~~)")
WANT_HEADINGS = ("did", "blocked", "next", "ask") WANT_HEADINGS = ("did", "blocked", "next", "ask")
FAULTS = ("BAD_NAME", "UNKNOWN_HANDLE", "BAD_DATE", "FUTURE", "EMPTY") FAULTS = ("BAD_NAME", "UNKNOWN_HANDLE", "BAD_DATE", "FUTURE", "EMPTY")
# Every class a baseline ledger may name. DUPLICATE is computed after grading
# (it is a property of a *group*), so it lives here rather than in FAULTS -- but
# a ledger that cannot name it could not record the worst rows in this archive.
BASELINE_CLASSES = frozenset(FAULTS) | {"DUPLICATE"}
# Not a check-in, and never silently dropped: the directory's own README is # Not a check-in, and never silently dropped: the directory's own README is
# printed as SKIP so a reader can see it was seen and why it was not graded. # printed as SKIP so a reader can see it was seen and why it was not graded.
SKIP_NAMES = {"README.md"} SKIP_NAMES = {"README.md"}
@@ -311,6 +346,105 @@ def gaps(rows, today: date, cap: int = 60):
return out return out
# --------------------------------------------------------------------- baseline
def classes_of(rec):
"""A row's full class set, duplicates folded in: the ledger's unit."""
return set(rec["class"]) | ({"DUPLICATE"} if rec.get("duplicate") else set())
def emit_baseline(rep):
"""The ledger as text: one `<filename>\\t<CLASS,CLASS>` row per faulting file.
Basenames, not paths: `checkins/` is flat and the ledger has to survive a
checkout on another host. Sorted, so regenerating it on an unchanged archive
produces an unchanged file and the diff is only what moved. The header is
part of the output because the output IS the file: a ledger that has to be
explained somewhere else is a ledger nobody can read on its own.
"""
head = ("# check-in baseline -- the faults this archive already carried when the\n"
"# naming rule was written. One row per file: <filename>\\t<CLASS[,CLASS]>.\n"
"# Regenerate: checkin_check.py --repo . --emit-baseline > tools/checkin_baseline.tsv\n"
"# A row is a stated tolerance, not an exemption: a file that gains a class,\n"
"# and a file that is not listed, both make rc 1 under --fail --baseline.\n")
lines = []
for r in sorted(rep["rows"], key=lambda x: x["file"]):
cls = sorted(classes_of(r))
if cls:
lines.append(f"{r['file']}\t{','.join(cls)}")
return head + "\n".join(lines) + ("\n" if lines else "")
def load_baseline(path):
"""Read the ledger -> {filename: set(classes)}. Anything unreadable is rc 2.
A ledger is what turns "35 historical faults" from a reason not to grade
into a stated tolerance. If it cannot be read, the tool has no idea what was
tolerated, so it refuses rather than grading against an empty set (which
would read the whole archive as new) or skipping the check (which would read
nothing as new). Both of those are the silent-pass class this repo grades.
"""
try:
with open(path, "r", encoding="utf-8") as fh:
text = fh.read()
except OSError as exc:
raise CannotGrade(f"cannot grade: baseline {path}: {exc}")
except UnicodeDecodeError as exc:
raise CannotGrade(f"cannot grade: baseline {path} is not UTF-8: {exc}")
out = {}
for n, line in enumerate(text.splitlines(), 1):
s = line.rstrip("\r")
if not s.strip() or s.lstrip().startswith("#"):
continue
parts = s.split("\t")
if len(parts) != 2:
raise CannotGrade(f"cannot grade: baseline {path}:{n} is not "
f"<filename>\\t<CLASS[,CLASS]>: {s!r}")
name = parts[0].strip()
cls = [c.strip() for c in parts[1].split(",") if c.strip()]
bad = [c for c in cls if c not in BASELINE_CLASSES]
if not name or not cls or bad:
raise CannotGrade(f"cannot grade: baseline {path}:{n} names an "
f"empty filename, an empty class list, or an "
f"unknown class {bad}: {s!r}")
out[name] = set(cls)
return out
def apply_baseline(rep, ledger, path=""):
"""Split every row's classes into known and new, and count what is stale."""
current = {r["file"]: classes_of(r) for r in rep["rows"]}
known_files = 0
for r in rep["rows"]:
cls = current[r["file"]]
known = ledger.get(r["file"], set())
new = cls - known
r["baseline"] = {"known": sorted(cls & known), "new": sorted(new)}
if cls and not new:
known_files += 1
stale = sorted(f for f in ledger if f not in current)
cleared = sorted(f for f in ledger
if f in current and (ledger[f] - current[f]))
rep["baseline"] = {"path": path, "entries": len(ledger),
"known_files": known_files,
"new_faults": sum(1 for r in rep["rows"]
if r["baseline"]["new"]),
"stale": stale, "cleared": cleared}
return rep
def graded_faults(rep):
"""The rows that make rc 1.
Without a ledger: every faulting row, exactly as before. With one: only the
rows carrying a class the ledger does not name -- the ledger is a stated
tolerance, not an exemption, so "known" never silently becomes "fine".
"""
if rep.get("baseline"):
return [r for r in rep["rows"] if r.get("baseline", {}).get("new")]
return [r for r in rep["rows"] if r["class"] or r["duplicate"]]
# --------------------------------------------------------------------- reporting # --------------------------------------------------------------------- reporting
def banner(text: str) -> str: def banner(text: str) -> str:
@@ -389,16 +523,27 @@ def print_report(rep, show_gaps: bool, fail: bool):
f"{rep['excluded_since']} older file(s) not graded") f"{rep['excluded_since']} older file(s) not graded")
for n in rep.get("skipped") or []: for n in rep.get("skipped") or []:
print(f" SKIP {n} (the directory's own README: not a check-in)") print(f" SKIP {n} (the directory's own README: not a check-in)")
fault_rows = [r for r in rep["rows"] if r["class"] or r["duplicate"]] led = rep.get("baseline")
fault_rows = graded_faults(rep)
if led:
print(f"\nbaseline {led['path']}: {led['entries']} entries, "
f"{led['known_files']} file(s) known-faulting, "
f"{led['new_faults']} new fault(s), {len(led['stale'])} stale, "
f"{len(led['cleared'])} cleared")
for f in led["stale"]:
print(f" STALE BASELINE {f} (no longer in the directory: the record was repaired)")
for f in led["cleared"]:
print(f" STALE BASELINE {f} (no longer carries every class the ledger names)")
if not fault_rows: if not fault_rows:
print("\nno file violates the filename, date, emptiness or duplicate rule") print("\nno file violates the filename, date, emptiness or duplicate rule"
if not led else
"\nno file carries a class the baseline does not tolerate")
else: else:
width = max(len(r["file"]) for r in fault_rows) width = max(len(r["file"]) for r in fault_rows)
print(f"\n{'file':<{width}} {'verdict':<22} detail") print(f"\n{'file':<{width}} {'verdict':<22} detail")
for r in fault_rows: for r in fault_rows:
cls = list(r["class"]) cls = (r["baseline"]["new"] if led
if r["duplicate"]: else sorted(set(r["class"]) | ({"DUPLICATE"} if r["duplicate"] else set())))
cls.append("DUPLICATE")
detail = [] detail = []
if "BAD_NAME" in cls: if "BAD_NAME" in cls:
detail.append("name is not <date>-<handle>.md") detail.append("name is not <date>-<handle>.md")
@@ -410,7 +555,7 @@ def print_report(rep, show_gaps: bool, fail: bool):
detail.append(f"after today {rep['today']}") detail.append(f"after today {rep['today']}")
if "EMPTY" in cls: if "EMPTY" in cls:
detail.append("no non-blank line") detail.append("no non-blank line")
if r["duplicate"]: if "DUPLICATE" in cls and r["duplicate"]:
d = r["duplicate"] d = r["duplicate"]
detail.append(f"{d['group_size']} files for {d['handle']} on {d['date']}") detail.append(f"{d['group_size']} files for {d['handle']} on {d['date']}")
print(f"{r['file']:<{width}} {','.join(cls):<22} {'; '.join(detail)}") print(f"{r['file']:<{width}} {','.join(cls):<22} {'; '.join(detail)}")
@@ -429,6 +574,15 @@ def print_report(rep, show_gaps: bool, fail: bool):
print(" -- A2: a missing day is not a repo fault; it is a decision an operator owes") print(" -- A2: a missing day is not a repo fault; it is a decision an operator owes")
counts = ", ".join(f"{k} {v}" for k, v in rep["faults"].items() if v) counts = ", ".join(f"{k} {v}" for k, v in rep["faults"].items() if v)
if led:
print(f"\ncheckin_check: {rep['checked']} files, {led['new_faults']} new fault(s), "
f"{led['known_files']} known-faulting in the baseline"
+ (f" ({counts}; DUPLICATE groups {len(rep['duplicate_groups'])})" if counts else "")
+ f", {adv['missing_headings']} advisory")
if fail and led["new_faults"]:
print(f"FAIL: {led['new_faults']} file(s) carry a class the baseline does not tolerate")
return 1
return 0
print(f"\ncheckin_check: {rep['checked']} files, {rep['fault_rows']} with a fault" print(f"\ncheckin_check: {rep['checked']} files, {rep['fault_rows']} with a fault"
+ (f" ({counts}; DUPLICATE groups {len(rep['duplicate_groups'])})" if counts else "") + (f" ({counts}; DUPLICATE groups {len(rep['duplicate_groups'])})" if counts else "")
+ f", {adv['missing_headings']} advisory") + f", {adv['missing_headings']} advisory")
@@ -586,7 +740,88 @@ def selftest():
headings_missing("## Did\nx\n```\n## Blocked\n## Next\n## Ask\n") headings_missing("## Did\nx\n```\n## Blocked\n## Next\n## Ask\n")
== ["blocked", "next", "ask"]) == ["blocked", "next", "ask"])
print(f"selftest: 29 cells, {29 - len(bad)} passed, {len(bad)} failed") # c30-c35: the baseline ledger. The floor this tool was run under graded one
# side of the archive; these cells pin that a fault landing on ANY date is
# still graded, that the tolerance is per class rather than per path, and
# that an unreadable ledger refuses instead of certifying.
with __import__("tempfile").TemporaryDirectory() as td:
import contextlib
import io as _io
ck = os.path.join(td, "checkins")
os.makedirs(ck)
_mk(ck, "2026-10-17-volt.md", GOOD) # conforming
_mk(ck, "2026-10-14-volt-02.md", GOOD) # BAD_NAME
_mk(ck, "2026-10-13-volt-03.md", "") # BAD_NAME, EMPTY
_mk(ck, "2026-10-12-volt-04.md", "") # BAD_NAME, EMPTY -- "backdated"
btoday = date(2026, 10, 18)
broster = {"volt"}
def with_ledger(ledger_):
r_ = run(ck, broster, btoday, False)
apply_baseline(r_, ledger_, "fixture.tsv")
with contextlib.redirect_stdout(_io.StringIO()):
rc_ = print_report(r_, False, True)
return r_, sorted(r["file"] for r in graded_faults(r_)), rc_
everything = {"2026-10-14-volt-02.md": {"BAD_NAME"},
"2026-10-13-volt-03.md": {"BAD_NAME", "EMPTY"},
"2026-10-12-volt-04.md": {"BAD_NAME", "EMPTY"}}
_, g_none, rc_none = with_ledger(everything)
cell("c30 a ledger naming every class grades the whole archive rc 0",
g_none == [] and rc_none == 0, f"graded={g_none} rc={rc_none}")
partial = dict(everything)
del partial["2026-10-12-volt-04.md"]
_, g_new, rc_new = with_ledger(partial)
cell("c31 a fault on an older date that the ledger does not name is rc 1",
g_new == ["2026-10-12-volt-04.md"] and rc_new == 1,
f"graded={g_new} rc={rc_new}")
per_class = dict(everything, **{"2026-10-12-volt-04.md": {"BAD_NAME"}})
r_class, g_class, rc_class = with_ledger(per_class)
new_here = [r["baseline"]["new"] for r in r_class["rows"]
if r["file"] == "2026-10-12-volt-04.md"]
cell("c32 the ledger is per class, not per path: a gained class is new",
new_here == [["EMPTY"]] and rc_class == 1, f"{new_here} rc={rc_class}")
rep_emit = run(ck, broster, btoday, False)
bl_path = os.path.join(td, "ledger.tsv")
with open(bl_path, "w", encoding="utf-8") as fh:
fh.write(emit_baseline(rep_emit))
round_trip = load_baseline(bl_path)
_, g_rt, rc_rt = with_ledger(round_trip)
cell("c33 emit -> load round-trips, and silences exactly the current archive",
g_rt == [] and rc_rt == 0
and round_trip == {r["file"]: classes_of(r) for r in rep_emit["rows"]
if classes_of(r)},
f"{round_trip} graded={g_rt}")
gone = dict(everything, **{"2026-10-01-volt.md": {"BAD_NAME"}})
r_stale, g_stale, rc_stale = with_ledger(gone)
cell("c34 an entry for a file that is gone is stale, never a fault",
r_stale["baseline"]["stale"] == ["2026-10-01-volt.md"]
and g_stale == [] and rc_stale == 0, str(r_stale["baseline"]))
bad_ledgers, why = [], []
for label, body in (("no tab", "2026-10-13-volt-03.md\n"),
("unknown class", "2026-10-13-volt-03.md\tNOT_A_CLASS\n"),
("empty classes", "2026-10-13-volt-03.md\t\n")):
p = os.path.join(td, "bad-%s.tsv" % label.replace(" ", "-"))
_mk(td, os.path.basename(p), body)
try:
load_baseline(p)
bad_ledgers.append(label)
except CannotGrade:
why.append(label)
try:
load_baseline(os.path.join(td, "absent.tsv"))
bad_ledgers.append("missing file")
except CannotGrade:
why.append("missing file")
cell("c35 an unreadable, malformed or absent ledger refuses (rc-2 class)",
bad_ledgers == [], f"accepted: {bad_ledgers}")
print(f"selftest: 35 cells, {35 - len(bad)} passed, {len(bad)} failed")
return 1 if bad else 0 return 1 if bad else 0
@@ -604,12 +839,21 @@ def main(argv=None):
ap.add_argument("--since", help="grade only check-ins dated on/after this YYYY-MM-DD " ap.add_argument("--since", help="grade only check-ins dated on/after this YYYY-MM-DD "
"(the archive's older names are its record)") "(the archive's older names are its record)")
ap.add_argument("--json", help="write the full report here") ap.add_argument("--json", help="write the full report here")
ap.add_argument("--baseline", help="known-fault ledger (<filename>\\t<CLASS[,CLASS]>): "
"only classes it does not name make rc 1, so the "
"whole archive can be graded every run")
ap.add_argument("--emit-baseline", action="store_true",
help="print the ledger for the current directory to stdout and exit 0")
ap.add_argument("--fail", action="store_true", help="exit 1 when any file has a fault") ap.add_argument("--fail", action="store_true", help="exit 1 when any file has a fault")
ap.add_argument("--selftest", action="store_true", help="fixture corpus") ap.add_argument("--selftest", action="store_true", help="fixture corpus")
a = ap.parse_args(argv) a = ap.parse_args(argv)
if a.selftest: if a.selftest:
return selftest() return selftest()
if a.emit_baseline and a.baseline:
print("cannot grade: --emit-baseline and --baseline are different jobs",
file=sys.stderr)
return 2
if a.today: if a.today:
try: try:
@@ -632,11 +876,19 @@ def main(argv=None):
try: try:
roster, src = load_roster(repo, a.roster) roster, src = load_roster(repo, a.roster)
rep = run(path, roster, today, a.gaps, since=since) rep = run(path, roster, today, a.gaps, since=since)
if a.baseline:
rep = apply_baseline(rep, load_baseline(a.baseline), a.baseline)
except CannotGrade as exc: except CannotGrade as exc:
print(str(exc), file=sys.stderr) print(str(exc), file=sys.stderr)
return 2 return 2
rep["roster_source"] = src rep["roster_source"] = src
if a.emit_baseline:
sys.stdout.write(emit_baseline(rep))
if a.json:
with open(a.json, "w", encoding="utf-8") as fh:
json.dump(rep, fh, indent=1, sort_keys=False)
return 0
rc = print_report(rep, a.gaps, a.fail) rc = print_report(rep, a.gaps, a.fail)
if a.json: if a.json:
with open(a.json, "w", encoding="utf-8") as fh: with open(a.json, "w", encoding="utf-8") as fh:
+75 -36
View File
@@ -26,10 +26,11 @@ WHY THIS EXISTS
every lane writes every tick. A fourth leg closes that hole. every lane writes every tick. A fourth leg closes that hole.
WHAT IT RUNS -- one row per leg, cheapest first, never in parallel WHAT IT RUNS -- one row per leg, cheapest first, never in parallel
checkin tools/checkin_check.py --since <newest day> --fail checkin tools/checkin_check.py --fail --baseline tools/checkin_baseline.tsv
the newest day's check-ins against F1-F5 (names, duplicates, the WHOLE check-in archive against F1-F5 (names, duplicates,
unknown handles, dates, emptiness); `--checkin-day DATE` sets unknown handles, dates, emptiness), where the ledger states the
the floor explicitly, from DATE forward faults the archive already carried; only a class it does not
name is a fault. `--checkin-day DATE` adds a `--since` floor
index-current tools/queue_index.py --check docs/queue-index.md index-current tools/queue_index.py --check docs/queue-index.md
the derived document, byte-compared against a fresh render the derived document, byte-compared against a fresh render
append-audit tools/queue_append_audit.py --guard --to HEAD append-audit tools/queue_append_audit.py --guard --to HEAD
@@ -42,19 +43,31 @@ WHAT IT RUNS -- one row per leg, cheapest first, never in parallel
one failed: a stale index and a broken selftest are different defects and the one failed: a stale index and a broken selftest are different defects and the
run should name both in one pass. run should name both in one pass.
WHY THE CHECK-IN LEG GRADES ONE DAY, NOT THE ARCHIVE WHY THE CHECK-IN LEG NOW GRADES THE ARCHIVE, NOT ONE DAY
Grading the whole archive is not a stricter gate, it is a permanently red one: Grading the whole archive was, until 2026-10-19, a permanently red gate: at
`checkin_check.py --repo . --fail` at HEAD returns **rc 1 with 35 faults** (25 `e98a34b` the unbaselined run exits 1 on every one of the archive's pre-rule
BAD_NAME, 10 DUPLICATE groups), every one of them dated 2026-09-24 through rows (25 BAD_NAME, 10 DUPLICATE groups, all dated 2026-09-24 through
2026-10-07, before the rule it breaks was written. A gate wired to that number 2026-10-07) -- that list is now a measured artifact, `tools/checkin_baseline.tsv`,
can never go green, so it stops being read -- which is the same failure as a one row per file rather than a number in this docstring. The first version of this
gate that is never run. The newest day in `checkins/` is the only day on which a NEW fault leg therefore graded the archive's **newest day** only, on the reasoning that
can appear, so it is the day this leg grades: history is left as the record it it is the only day on which a new fault can appear. That reasoning is false,
is (the tool renames nothing, by design), and a suffix, duplicate, bad date or and it was measured false rather than argued: a check-in added today under a
empty file on the current day is rc 1 the moment it lands. `--checkin-day DATE` **backdated** filename -- `checkins/2026-10-02-volt-b.md`, which is what a typo
lowers the floor explicitly, in the open, when an operator wants a wider window in the date half produces -- is not on the newest day, so the floor excluded
(it is a `--since`, so it can only widen: an older DATE pulls more history in, it. On a clone of `e98a34b` carrying that one file, `verify.py --fast` printed
it never narrows the window past a newer DATE). `checkin_check: 1 files, 0 with a fault` and exited **0**, while the same
tree's whole-archive run exited **1** naming the file.
The fix keeps both properties -- history is not re-litigated, nothing is
invisible. `tools/checkin_baseline.tsv` lists the faults the archive already
carried, one `<filename>\t<CLASS[,CLASS]>` row each, and `--baseline` grades
every file against it: a listed class is KNOWN, anything else is a fault. A
file that is not in the ledger at all is a fault wherever its date falls, and a
file that gains a class it did not have is a fault too -- the ledger states what
was tolerated, not that a path is exempt. A missing or malformed ledger is
rc 2 (cannot grade), never a silent pass, and stale entries (file gone, class
cleared) are reported and never make rc 1. `--checkin-day DATE` survives as an
explicit narrowing floor for an operator who wants one.
THE EXIT CONTRACT -- the house three codes THE EXIT CONTRACT -- the house three codes
0 every graded leg passed 0 every graded leg passed
@@ -84,7 +97,7 @@ TOOLS ARE RESOLVED FROM --repo, NOT FROM THIS FILE'S DIRECTORY
docs/queue-index.md) because `queue_append_audit` reads them with docs/queue-index.md) because `queue_append_audit` reads them with
`git show <rev>:<path>`, which has no absolute-path form. `git show <rev>:<path>`, which has no absolute-path form.
`--selftest` fixture corpus, 35 cells `--selftest` fixture corpus, 37 cells
""" """
import argparse import argparse
@@ -158,10 +171,11 @@ def pick_detail(text, limit=150):
def newest_checkin_day(repo): def newest_checkin_day(repo):
"""The newest `<YYYY-MM-DD>` prefix in checkins/ -> (day, why-not). """The newest `<YYYY-MM-DD>` prefix in checkins/ -> (day, why-not).
The leg grades one day and this is how that day is chosen: the archive's own Not the graded window any more -- the leg grades the whole archive against
latest date, so nothing has to be configured and no clock is consulted. A its own ledger -- but still the cheapest way to answer "is there anything
repo with no `checkins/` directory or no dated file in it cannot be graded here to grade at all", which is what makes a repo with no `checkins/`
and says which of the two it is. directory (or no dated file in it) ungradable with a message naming which of
the two it is, rather than a spawn and an rc 2 from further down.
""" """
d = os.path.join(repo, CHECKINS_DEFAULT) d = os.path.join(repo, CHECKINS_DEFAULT)
if not os.path.isdir(d): if not os.path.isdir(d):
@@ -176,8 +190,14 @@ def newest_checkin_day(repo):
def leg_argv(key, repo, queue, index, checkin_day=None): def leg_argv(key, repo, queue, index, checkin_day=None):
if key == "checkin": if key == "checkin":
return [sys.executable, os.path.join(repo, "tools", "checkin_check.py"), # The ledger is a file in the tree being graded, so a revision is graded
"--repo", repo, "--fail", "--since", checkin_day] # with the tolerance it committed -- not with this host's idea of one.
argv = [sys.executable, os.path.join(repo, "tools", "checkin_check.py"),
"--repo", repo, "--fail",
"--baseline", os.path.join(repo, "tools", "checkin_baseline.tsv")]
if checkin_day:
argv += ["--since", checkin_day]
return argv
if key == "index-current": if key == "index-current":
return [sys.executable, os.path.join(repo, "tools", "queue_index.py"), return [sys.executable, os.path.join(repo, "tools", "queue_index.py"),
"--repo", repo, "--queue", queue, "--check", index] "--repo", repo, "--queue", queue, "--check", index]
@@ -202,9 +222,11 @@ def run_leg(leg, repo, queue, index, timeout, checkin_day=None):
row["ms"] = 0 row["ms"] = 0
return row return row
day = checkin_day day = checkin_day
if leg["key"] == "checkin" and not day: if leg["key"] == "checkin":
day, why = newest_checkin_day(repo) # Presence is still pre-checked here: the tool's own rc-2 message names
if day is None: # the directory, but this row can say so without spawning a process.
newest, why = newest_checkin_day(repo)
if newest is None:
row.update(verdict=UNGRADABLE, detail=why) row.update(verdict=UNGRADABLE, detail=why)
row["ms"] = 0 row["ms"] = 0
return row return row
@@ -299,16 +321,16 @@ def main(argv=None):
ap.add_argument("--index", default=INDEX_DEFAULT, ap.add_argument("--index", default=INDEX_DEFAULT,
help="repo-relative index document (default %s)" % INDEX_DEFAULT) help="repo-relative index document (default %s)" % INDEX_DEFAULT)
ap.add_argument("--checkin-day", default=None, metavar="DATE", ap.add_argument("--checkin-day", default=None, metavar="DATE",
help="grade check-ins from DATE forward instead of from the " help="add a --since DATE floor to the check-in leg, so only "
"newest day present in checkins/ (a --since floor: it " "check-ins dated DATE or later are graded (default: the "
"can widen the window, never narrow it)") "whole archive, against tools/checkin_baseline.tsv)")
ap.add_argument("--fast", action="store_true", ap.add_argument("--fast", action="store_true",
help="skip the selftest-sweep leg; the row is printed as SKIP") help="skip the selftest-sweep leg; the row is printed as SKIP")
ap.add_argument("--timeout", type=int, default=300, metavar="S", ap.add_argument("--timeout", type=int, default=300, metavar="S",
help="per-leg timeout in seconds (default 300)") help="per-leg timeout in seconds (default 300)")
ap.add_argument("--json", metavar="PATH", help="write the rows here") ap.add_argument("--json", metavar="PATH", help="write the rows here")
ap.add_argument("--quiet", action="store_true") ap.add_argument("--quiet", action="store_true")
ap.add_argument("--selftest", action="store_true", help="fixture corpus, 35 cells") ap.add_argument("--selftest", action="store_true", help="fixture corpus, 37 cells")
a = ap.parse_args(argv) a = ap.parse_args(argv)
if a.selftest: if a.selftest:
@@ -552,7 +574,8 @@ def selftest():
check("15b the ungradable row says which directory is missing", check("15b the ungradable row says which directory is missing",
"ungradable: checkin" in out and "no check-in directory:" in out, True) "ungradable: checkin" in out and "no check-in directory:" in out, True)
# 16. the leg grades the NEWEST day in the archive, not the whole archive # 16. the leg grades the WHOLE archive against its own ledger -- the
# fix for a newest-day floor that made a backdated fault invisible.
av = os.path.join(td, "c16-argv") av = os.path.join(td, "c16-argv")
repo = _fixture(os.path.join(td, "c16"), GREEN4, repo = _fixture(os.path.join(td, "c16"), GREEN4,
argv_markers={"checkin_check.py": av}, argv_markers={"checkin_check.py": av},
@@ -560,19 +583,35 @@ def selftest():
rc, out = _verify("--repo", repo, "--fast") rc, out = _verify("--repo", repo, "--fast")
seen = open(av).read() if os.path.exists(av) else "" seen = open(av).read() if os.path.exists(av) else ""
check("16 the check-in leg is run with --fail", "--fail" in seen, True) check("16 the check-in leg is run with --fail", "--fail" in seen, True)
check("16b and --since is the newest day present, not a clock or a constant", check("16b and with the ledger resolved from --repo, so no day is excluded",
"--since 2026-03-04" in seen, True) "--baseline" in seen
and os.path.join(repo, "tools", "checkin_baseline.tsv") in seen
and "--since" not in seen, True)
# 17. --checkin-day retargets the window in the open # 17. --checkin-day still narrows the window explicitly, in the open
av = os.path.join(td, "c17-argv") av = os.path.join(td, "c17-argv")
repo = _fixture(os.path.join(td, "c17"), GREEN4, repo = _fixture(os.path.join(td, "c17"), GREEN4,
argv_markers={"checkin_check.py": av}, argv_markers={"checkin_check.py": av},
checkins=("2026-01-01-fixture.md", "2026-03-04-fixture.md")) checkins=("2026-01-01-fixture.md", "2026-03-04-fixture.md"))
rc, out = _verify("--repo", repo, "--fast", "--checkin-day", "2026-01-01") rc, out = _verify("--repo", repo, "--fast", "--checkin-day", "2026-01-01")
seen = open(av).read() if os.path.exists(av) else "" seen = open(av).read() if os.path.exists(av) else ""
check("17 --checkin-day overrides the default day", check("17 --checkin-day adds a --since floor",
"--since 2026-01-01" in seen, True) "--since 2026-01-01" in seen, True)
# 19. a ledger that cannot be read is UNGRADABLE (rc 2), never a pass:
# the tool's own reason has to reach the row, because "no ledger" and
# "clean archive" print nothing alike and must not grade alike.
repo = _fixture(os.path.join(td, "c19"),
dict(GREEN4, **{"checkin_check.py": 2}),
outs={"checkin_check.py":
"cannot grade: baseline %s/tools/checkin_baseline.tsv: "
"[Errno 2] No such file or directory\n"
% os.path.join(td, "c19", "repo")})
rc, out = _verify("--repo", repo, "--fast")
check("19 a missing ledger is rc 2 and names the ledger", rc, 2)
check("19b the ungradable row carries the tool's own reason",
"ungradable: checkin" in out and "checkin_baseline.tsv" in out, True)
# 18. the detail line must survive a real tool's noise: `checkin_check` # 18. the detail line must survive a real tool's noise: `checkin_check`
# prints a README SKIP note carrying "not a " on every run, and a WEAK # prints a README SKIP note carrying "not a " on every run, and a WEAK
# hint must not beat the FAIL line that actually names the verdict. # hint must not beat the FAIL line that actually names the verdict.