Skip to content

feat(memory): add outcome normalization to dreaming events#97705

Closed
lg320531124 wants to merge 5 commits into
openclaw:mainfrom
lg320531124:fix/dreaming-outcome-normalization
Closed

feat(memory): add outcome normalization to dreaming events#97705
lg320531124 wants to merge 5 commits into
openclaw:mainfrom
lg320531124:fix/dreaming-outcome-normalization

Conversation

@lg320531124

@lg320531124 lg320531124 commented Jun 29, 2026

Copy link
Copy Markdown

What Problem This Solves

Dreaming phase events (memory.dream.completed) currently have no structured way to indicate whether a run succeeded or failed. When a deep-dreaming workspace fails, the error is only logged to console — not recorded in the JSONL event log. Downstream consumers (monitoring, dashboards, alerting) cannot distinguish successful from failed dreaming runs without parsing log text.

Issue: #97690

Why This Change Was Made

Agent runs have normalized terminal outcomes via agent-run-terminal-outcome.ts (7 reasons: completed, hard_timeout, timed_out, cancelled, aborted, blocked, failed). Dreaming events lack an equivalent — this is a gap in observability.

The MemoryDreamOutcome type follows the same normalization pattern with 4 states relevant to dreaming: completed, partial, failed, timed_out.

User Impact

  • No behavior change for successful runs (outcome field is optional, backward compatible)
  • Failed deep-dreaming runs now emit a structured event with outcome: "failed" and an error field
  • Downstream tools can query memory.dream.completed events and filter by outcome without parsing logs

Evidence

Type-check

$ npx tsc --noEmit --skipLibCheck -p extensions/memory-core/tsconfig.json
# 0 errors on modified files (dreaming.ts, dreaming-markdown.ts, events.ts)

Unit tests (6/6 passed)

$ pnpm test extensions/memory-core/src/memory-events.test.ts

 ✓ memory host event journal integration > records recall and promotion events from short-term promotion flows
 ✓ memory host event journal integration > records skipped recall events for durable memory hits excluded from short-term promotion
 ✓ memory host event journal integration > records dreaming completion events when phase artifacts are written
 ✓ memory host event journal integration > omits outcome on successful dreaming events when no outcome is provided
 ✓ memory host event journal integration > records outcome and error on failed dreaming events
 ✓ memory host event journal integration > records partial outcome on dreaming events

 Test Files  1 passed (1)
      Tests  6 passed (6)
   Duration  643ms

Dreaming markdown tests (9/9 passed)

$ pnpm test extensions/memory-core/src/dreaming-markdown.test.ts

 Test Files  1 passed (1)
      Tests  9 passed (9)
   Duration  284ms

Backward compatibility

The outcome field is optional on MemoryHostDreamCompletedEvent. Existing event consumers that don't check for it continue to work unchanged. The JSDoc comment documents the backward-compatible default: "treat missing as completed".

ClawSweeper P2 fix

The failure-event append in the catch block (dreaming.ts:705) is wrapped in its own try/catch so diagnostic event-log writes cannot turn a caught workspace failure into a rejected trigger that skips later workspaces.

Files changed

  • src/memory-host-sdk/events.ts — Added MemoryDreamOutcome type and outcome/error fields to event type
  • extensions/memory-core/src/dreaming-markdown.ts — Pass through outcome/error params to event emissions
  • extensions/memory-core/src/dreaming.ts — Emit memory.dream.completed with outcome: "failed" in the deep-dreaming catch block (guarded)
  • extensions/memory-core/src/memory-events.test.ts — Added 3 tests for outcome normalization (implicit success, failed with error, partial)

Add MemoryDreamOutcome type (completed|partial|failed|timed_out) and
optional outcome/error fields to MemoryHostDreamCompletedEvent so
downstream consumers can distinguish failed from successful dreaming
runs without parsing log text.

- src/memory-host-sdk/events.ts: add type + event fields
- extensions/memory-core/src/dreaming-markdown.ts: pass through
  outcome/error to event emissions
- extensions/memory-core/src/dreaming.ts: emit failed event in
  deep-dreaming catch block

Backward compatible: outcome is optional; missing treated as completed.

Closes openclaw#97690
@clawsweeper

clawsweeper Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 29, 2026, 4:09 AM ET / 08:09 UTC.

Summary
The PR adds optional outcome/error fields to memory dream completion events, forwards them through memory-core dream writers, emits a failed deep-dream event from the promotion catch path, and adds event-log tests.

PR surface: Source +40, Tests +68. Total +108 across 4 files.

Reproducibility: yes. at source level: current main and v2026.6.10 lack outcome/error fields on dream completion events, and the deep failure path only logs. I did not run a live dreaming timeout or failed-run scenario in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Public event contract expansion: 1 union added, 2 optional fields added. The changed type is exported through a public plugin SDK subpath, so the additive shape and outcome names need maintainer compatibility review.
  • Outcome implementation coverage: 4 states exported, 1 runtime failure state emitted. The public taxonomy includes partial and timed_out even though the runtime catch currently emits only failed, which is the main pre-merge semantic risk.

Stored data model
Persistent data-model change detected: unknown-data-model-change: extensions/memory-core/src/dreaming-markdown.ts, unknown-data-model-change: extensions/memory-core/src/dreaming.ts, unknown-data-model-change: extensions/memory-core/src/memory-events.test.ts, vector/embedding metadata: extensions/memory-core/src/dreaming-markdown.ts, vector/embedding metadata: extensions/memory-core/src/dreaming.ts, vector/embedding metadata: extensions/memory-core/src/memory-events.test.ts, and 1 more. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #97690
Summary: This PR is the direct candidate fix for the open dreaming outcome-normalization issue; the crash-recovery issue is related but broader, and the older task-outcome PR is adjacent rather than canonical.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted terminal output, logs, or event-log contents from a real failed dreaming run showing memory.dream.completed with outcome and error.
  • Clarify and test when a caught deep-dreaming failure should be partial versus failed.
  • Update the PR body after adding proof so ClawSweeper can re-review automatically, or ask a maintainer to comment @clawsweeper re-review if it does not.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body and comments provide typecheck and unit-test output only; contributor action is needed to add redacted terminal output, logs, or JSONL event contents from a real failed dreaming run and update the PR body for re-review.

Risk before merge

  • [P1] The PR expands a public plugin SDK event taxonomy; once released, downstream readers may depend on the exact outcome names and semantics.
  • [P1] The broad deep-dreaming catch can record outcome failed with lineCount 0 after MEMORY.md, recall-store, or promotion-event side effects already occurred, hiding a partial run behind a full failure label.
  • [P1] Real behavior proof is still absent; typecheck and unit tests do not show a real failed dreaming run writing the structured JSONL event.

Maintainer options:

  1. Settle Dream Outcome Semantics (recommended)
    Define when deep dreaming emits completed, partial, failed, and timed_out, update the catch behavior and tests accordingly, and require redacted failed-run event-log proof before merge.
  2. Accept Failed-Only Runtime Risk
    Maintainers can intentionally accept the current failed-only runtime path now, but should own follow-up taxonomy and downstream reader adjustments after release.
  3. Fold Into Crash-Recovery Design
    Pause or close this branch if the broader dreaming lifecycle contract in [Feature]: Dreaming phase crash recovery — detect and record interrupted runs #97692 should define started, partial, failed, timed_out, and interrupted semantics together.

Next step before merge

  • [P1] Manual review is needed because the remaining blockers combine public event taxonomy/product semantics with contributor real behavior proof rather than one narrow automation repair.

Security
Cleared: No workflow, dependency, permission, credential, package-resolution, or executable supply-chain surface is changed; the diff uses the existing memory host event writer.

Review findings

  • [P2] Classify partial deep-dream failures separately — extensions/memory-core/src/dreaming.ts:710-713
Review details

Best possible solution:

Land an additive, maintainer-approved dreaming outcome contract that preserves existing readers, classifies completed/partial/failed/timed_out correctly, and includes redacted real failed-run event-log proof.

Do we have a high-confidence way to reproduce the issue?

Yes, at source level: current main and v2026.6.10 lack outcome/error fields on dream completion events, and the deep failure path only logs. I did not run a live dreaming timeout or failed-run scenario in this read-only review.

Is this the best way to solve the issue?

No, not yet: the additive event direction is plausible, but the latest head still conflates partial side effects with failed completion and needs maintainer-approved taxonomy plus real behavior proof.

Full review comments:

  • [P2] Classify partial deep-dream failures separately — extensions/memory-core/src/dreaming.ts:710-713
    This broad catch can run after promotion has already written MEMORY.md, updated the recall store, or appended memory.promotion.applied, but the new event always reports outcome: "failed" and lineCount: 0. That leaves downstream readers unable to distinguish a partial run even though this PR publishes partial as a supported outcome.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 96c8338d5bfa.

Label changes

Label justifications:

  • P2: This is a normal-priority memory-core observability and public event-contract improvement with limited blast radius.
  • merge-risk: 🚨 compatibility: The diff changes an exported memory-host event type on a public plugin SDK subpath and publishes new outcome names.
  • merge-risk: 🚨 session-state: The diff persists new dreaming run outcome state and can currently misrepresent partial memory writes as a full failure.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body and comments provide typecheck and unit-test output only; contributor action is needed to add redacted terminal output, logs, or JSONL event contents from a real failed dreaming run and update the PR body for re-review.
Evidence reviewed

PR surface:

Source +40, Tests +68. Total +108 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 3 41 1 +40
Tests 1 69 1 +68
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 110 2 +108

What I checked:

  • Root and scoped policy read: Root AGENTS.md, extensions/AGENTS.md, and src/plugin-sdk/AGENTS.md were read; the review applied the plugin boundary and public SDK compatibility guidance. (AGENTS.md:29, 96c8338d5bfa)
  • Current main event shape lacks outcome fields: Current main's MemoryHostDreamCompletedEvent contains type, timestamp, phase, paths, lineCount, and storageMode only; it has no outcome or error field. (src/memory-host-sdk/events.ts:58, 96c8338d5bfa)
  • Public plugin SDK subpath: The memory-host-events facade is exported as openclaw/plugin-sdk/memory-host-events, so changing its event type is public plugin SDK contract surface. (package.json:1200, 96c8338d5bfa)
  • Current main failure path is log-only: The deep dreaming promotion catch increments failedWorkspaces and logs the error, but does not append a structured memory.dream.completed failure event. (extensions/memory-core/src/dreaming.ts:692, 96c8338d5bfa)
  • PR head publishes new outcome taxonomy: The PR head adds MemoryDreamOutcome with completed, partial, failed, and timed_out plus optional outcome and error fields on MemoryHostDreamCompletedEvent. (src/memory-host-sdk/events.ts:57, 7f9f18056724)
  • PR head broad catch emits failed with zero lines: The PR head appends outcome failed and lineCount 0 from the broad deep-dreaming catch, regardless of whether earlier promotion side effects already happened. (extensions/memory-core/src/dreaming.ts:706, 7f9f18056724)

Likely related people:

  • vincentkoc: Authored the memory event journal bridge and multiple memory-core dreaming/event changes that shape the public event contract this PR extends. (role: feature-history contributor; confidence: high; commits: d1c7d9af800d, 0609bf858175, a9dbaa112465; files: src/memory-host-sdk/events.ts, src/plugin-sdk/memory-host-events.ts, extensions/memory-core/src/dreaming-markdown.ts)
  • vignesh07: Authored and merged the PR that added the managed dreaming promotion flow whose failures this PR records. (role: introduced dreaming promotion behavior; confidence: high; commits: 4c1022c73b39; files: extensions/memory-core/src/dreaming.ts, extensions/memory-core/src/short-term-promotion.ts)
  • steipete: Recent history shows several memory-core dreaming cleanup, alignment, verbose logging, and normalizer commits adjacent to the changed runtime path. (role: adjacent area contributor; confidence: medium; commits: eb9ce9482cac, 1cec37184c19, f7670bde7efa; files: extensions/memory-core/src/dreaming.ts, extensions/memory-core/src/dreaming-markdown.ts)
  • hugenshen: The latest current-line blame for the event type and dreaming writers maps to a merged PR by this author, though the commit appears to be broad current-main carry-forward rather than the original feature introduction. (role: recent current-line contributor; confidence: medium; commits: 245257238bbb; files: src/memory-host-sdk/events.ts, extensions/memory-core/src/dreaming.ts, extensions/memory-core/src/dreaming-markdown.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 29, 2026
sweepNowMs is declared inside the try block, so the catch block cannot
reference it. Use Date.now() instead — precise timestamp alignment is
not important for failure events.
ClawSweeper P2: appendMemoryHostEvent in the catch block can itself
throw (mkdir/appendRegularFile), which would reject the whole dreaming
trigger and skip later workspaces. Wrap in try/catch so diagnostic
logging is best-effort.
@lg320531124

Copy link
Copy Markdown
Author

Addressed the P2 finding in 367fbea.

The appendMemoryHostEvent call in the catch block at extensions/memory-core/src/dreaming.ts:703 is now wrapped in its own try/catch. If the diagnostic event-log write fails (e.g. mkdir/appendRegularFile rejection), we log a warning via params.logger.warn instead of letting the exception escape and reject the dreaming trigger.

This follows the codebase's existing best-effort convention for diagnostic writes — a failed event append should never turn a caught workspace failure into a trigger rejection that skips later workspaces.

@clawsweeper clawsweeper Bot added status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. labels Jun 29, 2026
Tests for:
- Successful dream events omit outcome (backward compatible)
- Failed dream events record outcome and error fields
- Partial outcome on deep dreaming events
@lg320531124

Copy link
Copy Markdown
Author

@steipete Hi! This PR adds outcome normalization to dreaming events (issue #97690). ClawSweeper P2 finding (unguarded diagnostic append) has been fixed. Added 3 focused tests for outcome fields. Could you take a look when you get a chance?

@lg320531124

Copy link
Copy Markdown
Author

@vincentkoc 👋 This PR adds outcome normalization (MemoryDreamOutcome) to dreaming events and guards diagnostic event-log writes in catch blocks. Since you merged the related #97701, would appreciate your take on whether this approach aligns with the event schema direction. Tests pass (6/6). Thanks!

@lg320531124

Copy link
Copy Markdown
Author

Closing in favor of #97723, which was merged and covers the same ground — MemoryDreamOutcome (completed/failed), the catch-block best-effort failed-event write (the P2 ClawSweeper finding I had patched locally in 367fbea), and the dreaming tests. The merged version's "best-effort and guarded" approach to failed-outcome writes is the right call and subsumes my catch-block guard.

Thanks @vincentkoc / @steipete — happy to see this land. Keeping an eye on #97692 (crash-recovery design) for the partial/timed_out/interrupted semantics that were intentionally deferred here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: memory-core Extension: memory-core merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant