Skip to content

fix(hermes): never forget on built-in memory removals; supersede only same-fact edits - #694

Merged
p-diogo merged 1 commit into
mainfrom
fix/hermes-mirror-no-evict-forget
Oct 29, 2026
Merged

p-diogo merged 1 commit into
mainfrom
fix/hermes-mirror-no-evict-forget

Conversation

@p-diogo

@p-diogo p-diogo commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Why

Hermes' built-in memory is size-capped: tools/memory_tool.py sets memory_char_limit 2200 and user_char_limit 1375. The memory tool and the background review remove or merge entries to make room. So a removal in USER.md / MEMORY.md usually means "evicted from the short profile", not "the user wants this forgotten". #690 and #692 mirrored removals as forgets, which deletes long-term facts from the durable store that nobody asked to delete.

What

The same rules apply in the foreground mirror and the reconcile pass:

  • remove → never forget. One INFO line, memory mirror: remove target=<user|memory> removed from Hermes profile; kept in TotalReclaw, with no entry text. The snapshot moves on. In the reconcile, removed entries cost no vault operation.

  • replace / patch, and reconcile "changed" pairs → always store the new text. The old fact is forgotten only when two things hold:

    • the old and new entries are clearly the same fact, i.e. normalized difflib ratio ≥ 0.8 (_same_fact). "prefers tea" → "prefers green tea" is 0.85; a merge like "likes tea" → "likes tea and coffee" is 0.73;
    • the existing confident vault match still holds: identical text, or a single fact at cosine ≥ 0.92.

    Merges and rewrites keep the old facts. When an edit keeps the old fact, the mirror log line ends in ; old entry kept (not the same fact).

  • Explicit forgetting goes through TotalReclaw's own tool. New system-prompt sentence: "To forget something, call totalreclaw_forget and also remove it from the built-in memory if it's there." The block is 565 characters.

  • Pinned facts: not checked. Telling cheaply isn't possible today: pin_status is a top-level v1 blob key that read_blob_unified and the recall-candidate passthrough drop. Exposing it touches shared read paths that open feat(core,python): pin-aware resolution + recall pin boost (PRD-04 DEP-5, Part A) #671 (pin-aware resolution) also changes. With this PR, a pinned fact can only be forgotten through a same-fact edit with a confident match.

  • Docs and tests: the guide's Compatibility and Diagnostics sections (including the log-line formats), SKILL.md (removal doesn't forget; "forget X" also removes the entry from the built-in memory), the changelog (Unreleased entries rewritten in place), and tests:

    • eviction keeps the fact;
    • a same-fact edit supersedes;
    • a merge keeps the old facts;
    • the prompt mentions totalreclaw_forget;
    • the matching rules are now tested on _find_mirrored_facts directly.

Trade-off

When an edit changes a fact too much to count as the same fact (e.g. "prefers coffee" → "prefers green tea", "works at Acme" → "works at Initech"), the old fact is kept alongside the new one. That's deliberate: no data loss in the durable store wins over a possibly stale duplicate.

Verification

  • pytest tests/ (CI flags): 2706 passed.
  • I re-ran the real Hermes 0.22.5 MemoryManager / memory_tool / MemoryStore checks:
    • Mirror: a remove kept the fact, same-fact patches superseded, and a coffee → green-tea patch kept the old fact.
    • Reconcile: changed=1 forgotten=1, the removed entry was kept in the vault, and the third pass was unchanged.

Review-fork limitation (unchanged)

Hermes 0.22.5 builds its background memory review with skip_memory=True, so those writes only reach TotalReclaw through the session-boundary reconcile (#692).

🤖 Generated with Claude Code

… same-fact edits

Hermes' built-in stores are size-capped (memory_char_limit 2200,
user_char_limit 1375) and the memory tool and background review remove
or merge entries to make room. A removal in USER.md / MEMORY.md is
usually an eviction, not a request to forget, so mirroring it as a
forget deleted long-term facts from the durable store.

- Mirror and reconcile: a removal never forgets. It logs
  "memory mirror: remove target=<t> removed from Hermes profile; kept in
  TotalReclaw" and the snapshot moves on.
- Edits (replace/patch, reconcile "changed" pairs) always store the new
  text and forget the old fact only when the two entries are clearly the
  same fact (normalized difflib ratio >= 0.8) AND the existing confident
  vault match holds. Merges and rewrites keep the old facts.
- system_prompt_block: one sentence on forgetting via totalreclaw_forget
  plus removing the entry from the built-in memory.
- Guide Compatibility/Diagnostics, SKILL.md, changelog and tests updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@p-diogo
p-diogo force-pushed the fix/hermes-mirror-no-evict-forget branch from d3189bf to 740766e Compare October 29, 2026 01:25
@p-diogo
p-diogo merged commit 5340007 into main Oct 29, 2026
12 checks passed
@p-diogo
p-diogo deleted the fix/hermes-mirror-no-evict-forget branch October 29, 2026 01:32
Sign up for free to 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