emrg: bound memory index growth — 50-row hygiene protocol + 50KB embed cap (rant 2026-08-23T11:00:31) - #944
Conversation
argszero
commented
Aug 23, 2026
CI note: the first run's test-windows job failed on the 3 new memory-cap tests — my tests wrote the index via Path.write_text without an explicit encoding, so on Windows (cp1252 locale) the —/… characters were stored as 0x95/0x97 bytes that failed the utf-8 read-back. Fixed by passing encoding="utf-8" (def340a); the daemon code itself always reads utf-8 and was unaffected. New run pending. |
argszero
commented
Aug 23, 2026
✅ LGTM — cycle 1290. Fresh-eyes review of head def340a (CI run 32615364066: test + test-windows both SUCCESS): the two-layer fix addresses rant 2026-08-23T11:00:31 exactly — (1) evolution_prompt §6 hard index-hygiene protocol (title-only ≤512-char rows, ≤50 cycle rows cap with append-only cycle-archive-YYYYMMDD.md handoff, detail files never deleted, archive excluded from prompt) and (2) daemon render-time 50KB cap on the embedded index that fires regardless of write path (line-boundary truncation + pointer to cycle-archive-*.md). The first CI run's Windows failure was my test writing non-ASCII chars with locale-default encoding — fixed with explicit utf-8 (def340a); production code always reads utf-8. Local pytest 1012 passed + 1 skipped. |
argszero
commented
Aug 23, 2026
✅ LGTM — cycle 1291. Second consecutive fresh-eyes review (head def340a unchanged since cycle 1290; CI run 32615364066 re-verified: test + test-windows both PASS; MERGEABLE/CLEAN). Re-checked the final diff: the 50-row hygiene protocol in evolution_prompt §6 is self-enforcing for all three MEMORY.md indexes (evolution-level, project-level, session-level), and the daemon _cap_memory_index render cap is write-path-independent — even a protocol violation can never re-inflate the embedded prompt past 50KB per index. The 4 tests cover the pass-through, truncation-at-line-boundary, embedded-capped-index, and no-index paths. Local pytest 1012 passed + 1 skipped. No ❌ since the first LGTM. |
argszero
commented
Aug 23, 2026
✅ LGTM — cycle 1292. Third consecutive fresh-eyes review (head def340a unchanged; CI run 32615364066: test + test-windows both PASS; MERGEABLE/CLEAN). Final code check: _cap_memory_index reads utf-8 explicitly, caps at 50KB (matching memory.INDEX_SIZE_WARN), truncates at a line boundary via rfind so no index row is ever half-cut, and appends a notice pointing at cycle-archive-*.md; it is applied to both the project and session index embeds in _collect_memory_data. evolution_prompt §6 protocol makes the write path self-enforcing. No ❌ since the first LGTM — merge condition (3 consecutive ✅ from cycles 1290/1291/1292) satisfied. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Fix unbounded growth of evolution-task MEMORY.md indexes (rant 2026-08-23T11:00:31): the #941 memory index governance guards only fire on
memory_storeAPI writes, but the evolution loop appendscycle-<ts>.md+ MEMORY.md index rows directly via file tools — bypassing the guards entirely. The index grew to 787KB/2931 lines (evolution level), which made up 77% of a 452,972-char system prompt (~250K all-miss tokens per evolution request, full-price burn). A one-time local cleanup at 10:59 was palliative only; this PR makes the bound permanent.Changes
emrg/server/evolution_prompt.md§6 Record — index hygiene protocol (replaces the advisory "index-line norm"):cycle-<ts>.mddetail files only (no inline text in index rows).cycle-archive-YYYYMMDD.md(same dir, append-only) and remove them from MEMORY.md. Detail files are never deleted.MEMORY.md): never reference/re-add/paste archive content into the index.emrg/server/daemon.py— render-time embed cap (defense in depth):_collect_memory_datanow runs each MEMORY.md through_cap_memory_index(50KB cap, truncated at a line boundary with a notice pointing atcycle-archive-*.md). This guard fires regardless of write path — even a future agent that forgets the protocol can never bloat the embedded prompt again.tests/test_daemon.py— 4 new tests: small index passes through unchanged; >50KB index truncated at line boundary with notice;_collect_memory_dataembeds the capped index; no-index →has_memoriesFalse.Verification