openclaw - 💡(How to fix) Fix Dreaming pipeline promotes empty-result placeholder "No strong candidate truths surfaced" into MEMORY.md

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…

On days where the REM dreaming phase finds zero candidate truths, the pipeline still writes a placeholder bullet into the REM dream file. That placeholder is subsequently ingested by light sleep, emitted as a - Candidate: line into the daily memory file, and then promoted by applyShortTermPromotions into the long-term workspace/MEMORY.md. Each empty-REM day permanently bloats MEMORY.md with a meaningless entry.

Root Cause

In dist/dreaming-phases-*.js, previewRemDreaming:

const bodyLines = [
    "### Reflections",
    ...reflections,
    "",
    "### Possible Lasting Truths",
    ...candidateTruths.length > 0
        ? candidateTruths.map((entry) => `- ${entry.snippet} [confidence=${entry.confidence.toFixed(2)} evidence=${entry.evidence}]`)
        : ["- No strong candidate truths surfaced."]
];

The else branch unconditionally emits a human-readable placeholder line into the REM file even when there is nothing to promote. Downstream the placeholder becomes indistinguishable from a real candidate.

Fix Action

Workaround

Patching the two dist/ files in /usr/lib/node_modules/openclaw/ as above and stripping the existing placeholder entries from workspace/MEMORY.md. The patch is lost on npm install -g openclaw upgrade.

Code Example

### Possible Lasting Truths
   - No strong candidate truths surfaced.

---

- Candidate: Possible Lasting Truths: No strong candidate truths surfaced.
     - confidence: 0.00
     - evidence: memory/YYYY-MM-DD.md:443-443
     - recalls: 0
     - status: staged

---

<!-- openclaw-memory-promotion:memory:memory/YYYY-MM-DD.md:443:443 -->
   - - Candidate: Possible Lasting Truths: No strong candidate truths surfaced. [score=0.832 recalls=0 avg=0.620 source=memory/YYYY-MM-DD.md:13-13]

---

const bodyLines = [
    "### Reflections",
    ...reflections,
    "",
    "### Possible Lasting Truths",
    ...candidateTruths.length > 0
        ? candidateTruths.map((entry) => `- ${entry.snippet} [confidence=${entry.confidence.toFixed(2)} evidence=${entry.evidence}]`)
        : ["- No strong candidate truths surfaced."]
];

---

const bodyLines = [
    "### Reflections",
    ...reflections,
    ...(candidateTruths.length > 0 ? [
        "",
        "### Possible Lasting Truths",
        ...candidateTruths.map((entry) => `- ${entry.snippet} [confidence=${entry.confidence.toFixed(2)} evidence=${entry.evidence}]`)
    ] : [])
];

---

const selected = options.candidates.filter((candidate) => {
    if (isContaminatedDreamingSnippet(candidate.snippet)) return false;
    if (/no strong candidate truths surfaced/i.test(candidate.snippet || "")) return false;
    if (candidate.promotedAt) return false;
    // …
});
RAW_BUFFERClick to expand / collapse

Summary

On days where the REM dreaming phase finds zero candidate truths, the pipeline still writes a placeholder bullet into the REM dream file. That placeholder is subsequently ingested by light sleep, emitted as a - Candidate: line into the daily memory file, and then promoted by applyShortTermPromotions into the long-term workspace/MEMORY.md. Each empty-REM day permanently bloats MEMORY.md with a meaningless entry.

Version

[email protected] (npm global install).

Reproduction

Run the dreaming pipeline on a day where REM produces no candidate truths above the 0.45 confidence threshold (e.g. a low-activity day).

  1. workspace/memory/dreaming/rem/YYYY-MM-DD.md ends up containing:

    ### Possible Lasting Truths
    - No strong candidate truths surfaced.
  2. The next light sleep pass ingests that placeholder bullet as a memory entry. buildLightDreamingBody emits it as a Candidate line into the daily memory file workspace/memory/YYYY-MM-DD.md:

    - Candidate: Possible Lasting Truths: No strong candidate truths surfaced.
      - confidence: 0.00
      - evidence: memory/YYYY-MM-DD.md:443-443
      - recalls: 0
      - status: staged
  3. applyShortTermPromotions (in dist/short-term-promotion-*.js) treats it as a valid candidate. It passes isContaminatedDreamingSnippet (no confidence/evidence/status/recalls keys in the snippet itself) and accumulates enough score to be promoted. workspace/MEMORY.md gains:

    <!-- openclaw-memory-promotion:memory:memory/YYYY-MM-DD.md:443:443 -->
    - - Candidate: Possible Lasting Truths: No strong candidate truths surfaced. [score=0.832 recalls=0 avg=0.620 source=memory/YYYY-MM-DD.md:13-13]

In my workspace this produced three identical noise entries (2026-04-19, 2026-04-20, 2026-04-21) under three separate ## Promoted From Short-Term Memory (YYYY-MM-DD) headers.

Expected behavior

Days with zero candidate truths should add nothing to long-term MEMORY.md. Empty results are not findings.

Actual behavior

Every empty-REM day produces three pieces of bloat — a placeholder bullet in the REM dream file, a Candidate line in the daily memory file, and a promoted entry in MEMORY.md.

Root cause

In dist/dreaming-phases-*.js, previewRemDreaming:

const bodyLines = [
    "### Reflections",
    ...reflections,
    "",
    "### Possible Lasting Truths",
    ...candidateTruths.length > 0
        ? candidateTruths.map((entry) => `- ${entry.snippet} [confidence=${entry.confidence.toFixed(2)} evidence=${entry.evidence}]`)
        : ["- No strong candidate truths surfaced."]
];

The else branch unconditionally emits a human-readable placeholder line into the REM file even when there is nothing to promote. Downstream the placeholder becomes indistinguishable from a real candidate.

Proposed fix

1. dist/dreaming-phases-*.js — skip the entire ### Possible Lasting Truths section when candidateTruths.length === 0:

const bodyLines = [
    "### Reflections",
    ...reflections,
    ...(candidateTruths.length > 0 ? [
        "",
        "### Possible Lasting Truths",
        ...candidateTruths.map((entry) => `- ${entry.snippet} [confidence=${entry.confidence.toFixed(2)} evidence=${entry.evidence}]`)
    ] : [])
];

2. dist/short-term-promotion-*.js — defensive filter in applyShortTermPromotions so historical placeholders in already-written daily memory files don't get promoted on future runs:

const selected = options.candidates.filter((candidate) => {
    if (isContaminatedDreamingSnippet(candidate.snippet)) return false;
    if (/no strong candidate truths surfaced/i.test(candidate.snippet || "")) return false;
    if (candidate.promotedAt) return false;
    // …
});

Both edits applied locally; node -e "require('…dreaming-phases….js'); require('…short-term-promotion….js')" loads both modules cleanly.

Workaround

Patching the two dist/ files in /usr/lib/node_modules/openclaw/ as above and stripping the existing placeholder entries from workspace/MEMORY.md. The patch is lost on npm install -g openclaw upgrade.

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…

FAQ

Expected behavior

Days with zero candidate truths should add nothing to long-term MEMORY.md. Empty results are not findings.

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 - 💡(How to fix) Fix Dreaming pipeline promotes empty-result placeholder "No strong candidate truths surfaced" into MEMORY.md