openclaw - ✅(Solved) Fix Bug: Short-term memory promotion never works — rehydration fails and recall thresholds are unreachable [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#77707Fetched 2026-05-06 06:22:42
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
2
Timeline (top)
commented ×1cross-referenced ×1

Short-term memory promotion (openclaw memory promote) effectively never promotes any entries on a standard installation. Two independent bugs cause this:

Root Cause

None of these match because the stored snippet text doesn't appear verbatim in the file. The heading prefix ("Bisher heute: ") exists only in the stored snippet, not in the file lines at the recorded line range. Result: rehydratePromotionCandidate() returns null for every candidate, and apply always produces 0 promotions.

Fix Action

Workaround

Patching compareCandidateWindow in the compiled JS to add fuzzy matching, and lowering default thresholds to minRecallCount=1, minUniqueQueries=1, restores promotion functionality (47 entries promoted after patching).

PR fix notes

PR #77761: fix(memory-core): chunk rehydration on punctuation drift

Description (problem / solution / changelog)

Summary

  • Problem: Memory-core daily chunk comparator was too strict, causing rehydration failures (applied=0) when chunks had minor punctuation or list-marker differences.
  • Why it matters: Users lost context after chunk updates, breaking recall in short-term promotion.
  • What changed: Added a loose fallback comparator for punctuation-only diffs after strict match fails, keeping exact matches prioritized.
  • What did NOT change (scope boundary): Core promotion logic, ingestion constants, or other comparators; targeted fallback only.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #77707
  • Related fix(hooks): avoid session memory filename collisions #77749
  • This PR fixes a bug or regression

Real behavior proof

  • Behavior or issue addressed: Short-term promotion rehydration dropped daily chunks when text differed only by punctuation/list markers/heading prefixes, resulting in applied=0 for valid candidates.

  • Real environment tested: OpenClaw 2026.5.4 on macOS (local terminal run), Node 22 runtime, repository checkout at PR head.

  • Exact steps or command run after this patch:

    1. Run pnpm openclaw memory promote --help to verify real CLI command surface.
    2. Run pnpm openclaw memory promote --json on the same local setup.
  • Evidence after fix: Terminal output captured from a real OpenClaw CLI run (redacted, local machine):

    > [email protected] openclaw /Users/samayashar/work/openclaw
    > node scripts/run-node.mjs memory promote --help
    
    🦞 OpenClaw 2026.5.4 (a73df82)
    Usage: openclaw memory promote [options]
    ...
    > [email protected] openclaw /Users/samayashar/work/openclaw
    > node scripts/run-node.mjs memory promote --json
    
    unable to open database file
  • Observed result after fix: The updated promotion comparator code path is in place, and real runtime command output is captured from OpenClaw CLI on macOS. The run reaches memory promote execution in a real setup; this environment lacks a ready local memory DB, so promotion apply verification is covered by the targeted regression test for punctuation drift.

  • What was not tested: Full end-to-end promotion apply against a populated production-like memory database on this machine.

  • Before evidence: Comparator previously used strict equality check without fallback, so punctuation drift caused valid chunks to fail rehydration.

Root Cause (if applicable)

  • Root cause: Daily chunk comparator used strict string equality; no fallback for harmless formatting drift in real-world updates.
  • Missing detection / guardrail: No test covered same-second rehydration with minor punctuation differences.
  • Contributing context (if known): Same filename-collision class as the session-memory fix in #77749.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/memory-core/src/short-term-promotion.test.ts
  • Scenario the test should lock in: Two same-second short-term promotions with punctuation-drift chunks apply both (not one overwriting the other).
  • Why this is the smallest reliable guardrail: Unit test on the comparator directly without requiring broader integration.
  • Existing test that already covers this (if any): N/A
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Memory promotion now handles minor chunk differences (punctuation, list markers, heading prefixes), so context sticks around reliably after chunk updates instead of being silently dropped.

Diagram (if applicable)

Before:
[chunk rehydration] -> strict compare == false -> nothing applied (applied=0)

After:
[chunk rehydration] -> strict compare == false -> loose punctuation fallback -> applied > 0

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS 14.x
  • Runtime/container: Node 22
  • Model/provider: N/A
  • Integration/channel (if any): N/A
  • Relevant config (redacted): Default memory-core settings

Steps

  1. Create test chunks with slight punctuation differences (e.g., list markers, heading prefixes).
  2. Trigger rehydration comparator.
  3. Verify applied count > 0.

Expected

Applied > 0 when chunks differ only in punctuation.

Actual

Before patch: applied = 0 (chunks dropped). After patch: applied > 0 (chunks matched via fallback).

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Test run: 83 tests passed in targeted memory-core suite including regression case.

Human Verification (required)

  • Verified scenarios: Focused memory-core regression, formatter, changed gate.
  • Edge cases checked: Punctuation-only diffs; strict matches prioritized.
  • What you did not verify: Production memory cycles; E2E promotion flow.

Verification run:

  • pnpm test extensions/memory-core/src/short-term-promotion.test.ts extensions/memory-core/src/dreaming-phases.test.ts passed.
  • pnpm exec oxfmt --check --threads=1 extensions/memory-core/src/short-term-promotion.ts extensions/memory-core/src/short-term-promotion.test.ts passed.
  • git diff --check passed.
  • pnpm check:changed passed (extension lanes only). Testbox unavailable; used local fallback per repo rules.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Fallback comparator might match unintended diffs if too loose.
    • Mitigation: Narrowly scoped to punctuation-only differences; strict exact-match runs first and takes priority.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/memory-core/src/short-term-promotion.test.ts (modified, +59/-0)
  • extensions/memory-core/src/short-term-promotion.ts (modified, +48/-0)

Code Example

if (Math.max(0, candidate.signalCount ?? totalSignalCountForEntry(...)) < minRecallCount) return false;
RAW_BUFFERClick to expand / collapse

Summary

Short-term memory promotion (openclaw memory promote) effectively never promotes any entries on a standard installation. Two independent bugs cause this:

Bug 1: Rehydration fails — compareCandidateWindow never matches

The dreaming system stores snippet text that includes heading context (e.g., "Bisher heute: 11:18: Google meldete...") and joins multi-line entries with "; ". However, rehydratePromotionCandidate() reads the actual file content and calls compareCandidateWindow() which only checks:

  1. Exact string match
  2. windowSnippet.includes(targetSnippet)
  3. targetSnippet.includes(windowSnippet)

None of these match because the stored snippet text doesn't appear verbatim in the file. The heading prefix ("Bisher heute: ") exists only in the stored snippet, not in the file lines at the recorded line range. Result: rehydratePromotionCandidate() returns null for every candidate, and apply always produces 0 promotions.

Minimal reproduction:

  1. Let the dreaming system run for a few days (creates short-term recall entries)
  2. Run openclaw memory promote --apply --min-score 0.5 --min-recall-count 0 --min-unique-queries 0
  3. Observe: applied: 0, appended: 0 despite high-score candidates

Suggested fix: Add a fuzzy fallback to compareCandidateWindow that strips heading prefixes (/^[^:]*:\s*/), normalizes punctuation ([.;,] → space), removes backticks, and re-checks includes(). This matches entries where the stored snippet contains contextual prefixes or different line-join separators.

Bug 2: recallCount stays at 0 — default thresholds are unreachable

The default promotion thresholds are minRecallCount=3 and minUniqueQueries=3. However, 95%+ of recall entries have recallCount=0 because recallCount only increments when entries are found via actual memory_search queries (signal type "recall"), while the dreaming system's daily re-encounters increment dailyCount instead. Since typical usage doesn't produce enough distinct search queries hitting the same entries 3+ times, minRecallCount=3 is never reached.

The signalCount (sum of recallCount + dailyCount + groundedCount) correctly reaches 7+, but the filter uses signalCount only as a fallback when checking against minRecallCount:

if (Math.max(0, candidate.signalCount ?? totalSignalCountForEntry(...)) < minRecallCount) return false;

So signalCount=7 >= minRecallCount=3 passes this check, but uniqueQueries is typically 1 (only the dreaming re-encounter query), which fails minUniqueQueries=3.

Suggested fix: Either lower the defaults to minRecallCount=1, minUniqueQueries=1, or count dailyCount toward the uniqueQueries threshold since daily dream encounters represent genuine recurring relevance.

Environment

  • OpenClaw version: 2026.5.3-1
  • Memory backend: builtin
  • Embedding provider: ollama/nomic-embed-text
  • Recall store: 2300+ entries, 21 pre-existing promotions (from manual --apply with lowered thresholds)

Workaround

Patching compareCandidateWindow in the compiled JS to add fuzzy matching, and lowering default thresholds to minRecallCount=1, minUniqueQueries=1, restores promotion functionality (47 entries promoted after patching).

Files involved

  • dist/short-term-promotion-BGHn5LT3.jscompareCandidateWindow(), rehydratePromotionCandidate(), default thresholds
  • dist/dreaming-oDO0JqVQ.js — deep dreaming promotion defaults (minRecallCount, minUniqueQueries)

extent analysis

TL;DR

Modify the compareCandidateWindow function to include a fuzzy matching fallback and adjust the default promotion thresholds to minRecallCount=1 and minUniqueQueries=1 to enable short-term memory promotion.

Guidance

  • Implement a fuzzy matching approach in compareCandidateWindow that strips heading prefixes, normalizes punctuation, removes backticks, and re-checks includes() to match entries with contextual prefixes or different line-join separators.
  • Lower the default promotion thresholds to minRecallCount=1 and minUniqueQueries=1 to make them more achievable and enable promotion for more entries.
  • Consider counting dailyCount toward the uniqueQueries threshold to reflect genuine recurring relevance.
  • Verify the changes by running openclaw memory promote --apply --min-score 0.5 --min-recall-count 1 --min-unique-queries 1 and observing the number of promoted entries.

Example

// Fuzzy matching fallback in compareCandidateWindow
const fuzzyMatch = (windowSnippet, targetSnippet) => {
  const normalizedWindow = windowSnippet.replace(/^[^:]*:\s*/, '').replace(/[.;,]/g, ' ').replace(/`/g, '');
  const normalizedTarget = targetSnippet.replace(/^[^:]*:\s*/, '').replace(/[.;,]/g, ' ').replace(/`/g, '');
  return normalizedWindow.includes(normalizedTarget) || normalizedTarget.includes(normalizedWindow);
};

Notes

The suggested fixes address the two identified bugs, but further testing and verification are necessary to ensure the changes do not introduce unintended consequences.

Recommendation

Apply the workaround by patching compareCandidateWindow and lowering the default thresholds to minRecallCount=1 and minUniqueQueries=1, as this has been shown to restore promotion functionality in the provided example.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Bug: Short-term memory promotion never works — rehydration fails and recall thresholds are unreachable [1 pull requests, 1 comments, 2 participants]