Repository navigation
emrg: the rotation bookmark can be written into a shape nothing refuses #2513
Description
The rotation bookmark can be written into a shape nothing refuses
What was observed
scripts/check-memory-rotation.py is the reader of
.emrg/memory/project-memory-rotation-bookmark.md — the per-project table that answers
"which projects' memory moved since I last read them". It is thorough about the table's
rows and says nothing about the file's structure above them. Three shapes were
written into temp copies of the real bookmark and read back (2026-10-23, on this checkout):
| shape written | what the reader answered |
|---|---|
| the real file, unchanged | exit 0, every project has a row and every row names a project (32 of 32) |
a row's disambiguating qualifier dropped (aitokenpool for aitokenpool (github)) |
exit 1 — the bookmark's row 'aitokenpool' names 2 projects — already caught |
| the cycle section rewritten to end of file, taking the project table with it | exit 2 — carries no markdown table ... a bookmark in another shape is not an empty bookmark |
a second ## Cycle section appended below the table |
exit 0 — every project has a row and every row names a project (32 of 32) |
Why the two bad answers matter
The appended section is invisible. The file's own text states the rule — "Update this
file in place every cycle — never append a second entry" — and records why: measured
2026-10-21, this file had grown to 359 lines carrying eight per-cycle sections, one of
them duplicated. Every row still parsed, so the reader reports a clean file. The growth is
what the rule exists to prevent, and nothing measures it today. This file is embedded in a
cycle's prompt, so the growth is paid for on every round that reads it.
The truncated write is refused for the wrong reason. The section rewrite that runs
past the table header is the shape that once deleted all 32 rows. The reader does refuse
it, which is the good half — but the sentence it refuses with says the file is "a bookmark
in another shape", whose remedy is to re-shape a file the writer never mis-shaped. The
actual cause is one mechanism, named in the same file: "A cycle section is replaced from
its ## heading to the next ## heading or the table header — never to end of file."
A reader who meets that refusal needs to be told which boundary was overrun, not that their
file is in an unfamiliar format.
What the fix must satisfy
- A second
## Cyclesection is a fault, and the reading survives it. It is reported
with the row count it read, exit 1, in the same list the coverage faults are printed in —
not asnot measurable, because the rows are measurable and a refusal would throw away
a valid reading of the rotation. - The message names the rule, not the symptom: one cycle section, replaced in place,
with the measured consequence of appending. - A file that carries a cycle section and no table row anywhere is refused as the
section-rewrite shape, in those words, and distinguished from a bookmark written in
another format — that second message stays for the file that carries no section either. - A bookmark with no cycle section at all is not a fault. A minimal or first-ever
bookmark has only the table, and the existing tests' fixtures are that shape. - Both directions are measured: a one-section file is clean, a two-section file is a
fault, and the arm that removes the check reddens the test that names it. - The host-side counterpart is the existing command —
check-memory-rotation.py --bookmark <path>— because the bookmark lives under the host's home and no CI leg can
see it. The CI side is fixture tests over files written intmp_path.
Activity
argszero commentedon Oct 23, 2026
Handled by #2514