Repository navigation
emrg: the cycle id names a run, not a file - #2538
Conversation
A cycle was minting one cycle-<id>.md per run into .emrg/memory/ — 45 files, 380 KB, 37 of them written in a single day — and nothing reads them: the readers went in #2476, no MEMORY.md row links one, and the same deletion removed the only instrument that noticed the files. So the loop kept believing it owed one, and grew one more, every cycle, invisibly. Section 4 gave it the belief: it told the cycle to write where "a later cycle can find the record by cycle id" and handed it "The record's `id`: `cyc{{ timestamp }}`". The id is real and load-bearing — vote bodies are attributed by it — but it names a run, not a file. Section 4 now says so, and still tells the cycle to write what it found, what it changed, how it was verified and what it expects. Section 1.3's meta-review read "the last 3-5 cycle records in memory", a corpus that stops existing once the loop stops writing it. It now reads the memory index already embedded in the prompt, which section 1.5 already rules out re-reading as a file. The guard that pulls the cycle id out of the rendered prompt to check the instructed vote examples against it anchored on the old wording. It is re-anchored on the new declaration and renamed to what it reads — CYCLE_ID, _declared_cycle_id — because there is no record's id to name. It is anchored on the declaration rather than on a bare `cyc…` token on purpose: the vote examples are cycle ids too and precede it, so a token scan would check the examples against themselves.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261023-180740
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261023-182314
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261023-183251
Read the diff, not the page. §1.3 no longer sends a cycle to re-read a memory file the prompt already embeds, which is what §1.5 already ruled out — the two sections now say one thing. §4 stops calling the cycle id a record's id and says plainly what it is for: naming this run in a vote body and a report, never a file name.
The test change is the part I checked twice. CYCLE_ID anchors on the declaration (The cycle id — cyc… —) rather than on a bare cyc… token, and the comment says why: the three vote examples come earlier in the file, so a token scan would have read an example as the declaration and then checked the examples against themselves — green forever, measuring nothing. That is the failure mode this whole file exists to prevent, so pinning it is worth the diff.
check-merge-freshness.py reads FRESH — merge base f30d7c36 is master's tip, status ahead, no drift — so the green CI is about the tree this merge produces, not one it no longer can.
Closes #2537
A cycle was minting one
cycle-<id>.mdper run into.emrg/memory/— 45files, 380 KB, 37 of them written in a single day — and nothing reads them.
The readers went in #2476, no
MEMORY.mdrow links one, and that same deletionremoved the only instrument that would have noticed the files still appearing.
One day after the corpus was declared gone, it was 45 files again.
What changed
§4 Record is where the belief came from. It told a cycle to write its
conclusions "so a later cycle can find the record by cycle id" and handed it
"The record's
id:cyc{{ timestamp }}". The id is real and load-bearing —a vote body is attributed by it — but it names a run, not a file. Section 4
now says so, and keeps the obligation intact: the cycle still writes what it
found, what it changed, how it was verified and what it expects. Where memory
keeps it stays the memory system's business, which is the rule an earlier
ruling established and this change does not touch.
§1.3 — the meta-review that looks for the same trivial change made
repeatedly, the same feature fixed over and over, a change with no lasting
effect, and consecutive "nothing to evolve" cycles — read "the last 3–5 cycle
records in memory", a corpus that stops existing once the loop stops writing
it. It now reads the memory index already embedded in the prompt, which §1.5
already rules out re-reading as a file. Same four signals, an instrument that
exists.
tests/test_evolution_prompt_vote_body.py— the guard that pulls the cycleid out of the rendered prompt to check the three instructed vote examples
against it anchored on the old wording, so it failed the moment the wording
went. It is re-anchored on the new declaration and renamed to what it reads
(
CYCLE_ID,_declared_cycle_id) — there is no record's id to name. It isanchored on the declaration, not on a bare
cyc…token, deliberately: theinstructed vote examples are cycle ids too and they precede the declaration in
the file, so a token scan would read an example as the declaration and check
the examples against themselves.
Verification
uv run pytest tests/— 5777 passed, 35 skipped (260.65 s)declaration to the old "The record's
id: …" wording reddenstest_the_instructed_vote_examples_name_exactly_one_cycle_id(
assert match is not None), and restoring it greens the file (3 passed).The arm was verified to apply, not assumed: the rewrite asserted its own
replacement took.
uv run python -c "from emrg.client.app import run_client"— importsuv run python -m emrg --help— exits 0uv run --no-sync python3 scripts/check-memory-index.py .emrg/memory/MEMORY.md— OK: 100 of 100 lines, 39,127 of 52,224 chars, longest row 512, 97 row links
with none resolving to a missing file
CI on this head is pending.
The 44 files this removes from one checkout
They are untracked and unindexed, so this PR cannot carry their deletion: the
work here is that no cycle creates another one. A local cleanup of an existing
installation is
rm .emrg/memory/cycle-cyc*.md, keeping any dated statearchive the index still links.