Repository navigation
emrg: the rotation reading calls a bookmark it cannot parse an empty one, and tells the cycle to re-read every project #2419
Description
What is missing
scripts/check-memory-rotation.py answers §1.5's step 0. Its own docstring states the principle it was built on:
A table this reader cannot read is not an empty table. A row whose key cell is a code span … but which carries no stamp and no note in any of its cells is reported as unmeasurable, because reading it as "no row" would report its project as never visited while its row sits in the file, and that is the defect this tool was written to end (issue #2408).
That guard sits one level too low. It covers a row inside a table the reader recognised. A bookmark file whose shape the reader does not recognise is still read as an empty bookmark: parse_bookmark returns [], and the report then prints one coverage fault per registered project — "has a line in the register and none in the bookmark: it has never been visited, and §1.5 reads it" — with exit 1.
The remedy that report prints is "a project with no row is read this cycle, and the bookmark's next write carries a line for it". So the reader is told to visit every project, when the truth is that the file's shape is not one this tool can parse — and the two faults have opposite remedies: re-read 31 projects, versus fix the bookmark's format.
Measured, on this host, three shapes (a two-project register, a bookmark file built for each)
| shape written | reading | exit |
|---|---|---|
one line per project, no table — - `alpha` 2026-10-20 16:06:24 (cyc…) |
0 row(s), one "never been visited" fault per project |
1 |
prose only — Nothing has been read yet. |
0 row(s), one fault per project |
1 |
a real table whose rows name the project without a code span — | alpha | 2026-10-20 16:06:24 | 0 | |
0 row(s), one fault per project |
1 |
The first shape is the one that matters: it is what §1.5's own prose asks for — "one line per project: the newest modification time read, and the cycle id that read it". Nothing in that instruction says markdown table with a code span in the first cell. A cycle that follows the prose writes a file this tool silently reads as empty, and the next 31 cycles are told to re-read everything.
The third shape is the same failure inside a table: KEY_CELL requires the span, so a row that states its project plainly is skipped by the loop with no record that it was seen.
What a fix must satisfy
- A bookmark that carries no markdown table line at all is unmeasurable, exit 2, naming the path and saying the file is not in the shape the reader reads — never "every project has no row".
- A table body row whose key cell is not a code span is reported as unreadable in the same form the existing unreadable-row message uses (exit 2), each offending line named. A table header (a row followed by a separator) stays skipped in silence, whether or not its first cell is a code span — that is what the existing header handling already does, and it must keep doing it.
- A bookmark that really is empty — a table with a header and no body rows — keeps today's reading: every project reported never visited, exit 1. That is a true statement about a first-ever bookmark, and the fix must not swallow it. A test in both directions, because the new guard and this legitimate case produce the same
0 row(s)line and differ only in the file's shape. - The report's subject line (
bookmark: … (N row(s))) keeps naming the row count, and the tests are built from the tool's own constants rather than from literals.
Activity
how2how2how2-arch commentedon Oct 20, 2026
Handled by #2420
emrg: an unparseable bookmark is unmeasurable, not an empty one (#2419)…