Skip to content

emrg: bound memory index growth — 50-row hygiene protocol + 50KB embed cap (rant 2026-08-23T11:00:31) - #944

Merged
argszero merged 2 commits into
masterfrom
feature/index-hygiene-protocol
Aug 23, 2026
Merged

emrg: bound memory index growth — 50-row hygiene protocol + 50KB embed cap (rant 2026-08-23T11:00:31)#944
argszero merged 2 commits into
masterfrom
feature/index-hygiene-protocol

Conversation

@argszero

Copy link
Copy Markdown
Owner

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_store API writes, but the evolution loop appends cycle-<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

  1. emrg/server/evolution_prompt.md §6 Record — index hygiene protocol (replaces the advisory "index-line norm"):

    • Title-only rows: each MEMORY.md row is a one-line summary ≤512 chars; cycle summaries live in the cycle-<ts>.md detail files only (no inline text in index rows).
    • Hard cap: keep at most the 50 most recent cycle rows per MEMORY.md. Before exceeding 50, append the oldest rows to cycle-archive-YYYYMMDD.md (same dir, append-only) and remove them from MEMORY.md. Detail files are never deleted.
    • Archive files excluded from the system prompt (the daemon embeds only MEMORY.md): never reference/re-add/paste archive content into the index.
    • Applies to every MEMORY.md the cycle maintains (evolution-level, source-project-level, session-level).
  2. emrg/server/daemon.py — render-time embed cap (defense in depth): _collect_memory_data now runs each MEMORY.md through _cap_memory_index (50KB cap, truncated at a line boundary with a notice pointing at cycle-archive-*.md). This guard fires regardless of write path — even a future agent that forgets the protocol can never bloat the embedded prompt again.

  3. tests/test_daemon.py — 4 new tests: small index passes through unchanged; >50KB index truncated at line boundary with notice; _collect_memory_data embeds the capped index; no-index → has_memories False.

Verification

  • Local pytest: 1012 passed + 1 skipped (1008 before + 4 new; Agent.md documented count synced 1009 → 1013)
  • Import check + CLI OK

@argszero

Copy link
Copy Markdown
OwnerAuthor

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

Copy link
Copy Markdown
OwnerAuthor

✅ 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

Copy link
Copy Markdown
OwnerAuthor

✅ 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

Copy link
Copy Markdown
OwnerAuthor

✅ 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.

@argszero
argszero merged commit 19b4d93 into masterAug 23, 2026
2 checks passed
@argszero
argszero deleted the feature/index-hygiene-protocol branch August 23, 2026 04:28
argszero added a commit that referenced this pull request Aug 23, 2026
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero