fix(memory): keep loop rules resident and trim whole entries (#1443) - #1446
Conversation
Work-in-progress snapshot committed by the operator after the agent's session was interrupted by a gateway 429. Not reviewed, not test-run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The resident block is selected by matching label text in memory/index.md -- an artifact the INSTANCE owns and can rename. A rename returns that rule to the droppable remainder, which is precisely the failure this policy exists to prevent, and it would happen silently: an unmatched label reads exactly like a matched one. last_index_fit now carries resident_matched, resident_expected and resident_missing, and a mismatch logs a warning naming the missing labels. Reported, never asserted -- the memory reader must not fail a cycle over index text it does not own. Tests pin both directions: a renamed "[DO NOT touch]" entry reports 4 of 5 with the missing label named, and an intact index reports 5 of 5 so the counter cannot pass vacuously. Verified against the live 8,680-byte index: 5/5 matched, kept_chars 3985, 28 entries dropped -- agreeing with the PR's accounting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Reviewed and accepted; one commit added on top (86f937c). The byte accounting is the right deliverable and it holds — I re-ran the policy against the live 8,680-byte index independently: What I added, and why. The resident block is selected by matching label text in
One edge left open deliberately. Focused suites after my commit: |
Summary
Resolves #1443 by replacing positional tail slicing of
memory/index.mdwith a structural resident/remainder policy:## Factsheading, and the five operational rules entries remain resident: Identity, Write target, DO NOT touch, Rules, and Key paths.ContextBuilder.last_fit["memory_index"], so dropped-entry count and byte counts are visible alongside the fix(context): degrade the prompt visibly instead of failing the cycle (#1438) #1440 prompt-fit ladder.max_charsis unchanged at 4000.memory/index.mdis not modified.Live-size accounting (addendum)
Measured read-only on the live host against the 8,680-byte
memory/index.md, withmax_chars=4000:Thus the resident rules are restored without increasing the memory section; the new result is 15 bytes smaller than the broken tail result. This is compatible with the measured 461-character prompt slack (23,539 / 24,000, 98.08%) and does not invoke the #1440 degradation ladder merely because the rules are restored.
Interaction with #1440
#1440 continues to operate on the assembled sections after
get_memory_context. This change makes the memory section structurally safe before that ladder runs and addsmemory_indexaccounting to the existing fit record. The ladder remains responsible for total prompt overflow; the memory reader no longer silently loses the front of the index or reports its post-truncation size as if no content had been dropped.Tests
last_fit["memory_index"].31 passed(test_memory_v2.py,test_context_prompt_fit.py,test_system_prompt_sections.py,test_log_format_style.py).3582 passed, 18 skipped, 4 failed; the four failures are exactly the required Windows baseline intest_bridge_cycle_tags.pyandtest_bridge_locking.py.origin/mainbaseline check:tests/test_memory_v2.pypassed before the new regression was applied.Files changed
nanobot/agent/memory.pynanobot/agent/context.pytests/test_memory_v2.pyAn unrelated upstream #1441 log-format guard was restored in the branch after the milestone WIP history; no #1441 production/test behavior is part of this PR diff against current
origin/main.