From 7260a7807441adad877c19d33294af9ef6edfe5b Mon Sep 17 00:00:00 2001 From: AutoDev Bot Date: Wed, 3 Jun 2026 22:48:13 +0800 Subject: [PATCH] fix: include abandoned episodes in reward pipeline and add periodic rescore - Add closeReason === 'abandoned' to episodeRewardIsDirty() check - Add 10-minute periodic timer in init() to rescore dirty episodes - Timer uses unref() to prevent blocking shutdown - Fixes #1782: 98% of closed episodes were skipped (219 of 224 had closeReason: 'abandoned') Before: Only 7 episodes scored on bootstrap (stale open episodes) After: All 219 abandoned episodes eligible for scoring --- .../core/pipeline/memory-core.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/memos-local-plugin/core/pipeline/memory-core.ts b/apps/memos-local-plugin/core/pipeline/memory-core.ts index cfb37f64e..ece2058b6 100644 --- a/apps/memos-local-plugin/core/pipeline/memory-core.ts +++ b/apps/memos-local-plugin/core/pipeline/memory-core.ts @@ -924,6 +924,19 @@ export function createMemoryCore( }); } + // Periodic rescore timer for episodes that miss the startup scan or + // retry of failed reward runs. 10-minute interval is safe because + // autoRescoreDirtyClosedEpisodes has its own 30-second dedup guard. + const rescoreInterval = setInterval(() => { + void autoRescoreDirtyClosedEpisodes().catch((err) => { + log.debug("periodic_rescore.error", { + err: err instanceof Error ? err.message : String(err), + }); + }); + }, 10 * 60 * 1000); + // Mark as unref so the timer doesn't block shutdown + (rescoreInterval as unknown as { unref?: () => void }).unref?.(); + // Wire `memory_add` into the api_logs table on EVERY turn so the // Logs viewer shows per-turn capture activity. `capture.lite.done` // fires once per `onTurnEnd` (the per-turn lite capture path); @@ -1272,7 +1285,9 @@ export function createMemoryCore( if ( ep.rTask == null && (ep.traceIds?.length ?? 0) > 0 && - (meta.closeReason === "finalized" || meta.recoveryReason === "missed_session_end") + (meta.closeReason === "finalized" || + meta.closeReason === "abandoned" || + meta.recoveryReason === "missed_session_end") ) { return true; }