Fix #2370: [Bug] meta.rewardDirty is re-set on episode reopen and never cleared when the ep - #2371
Memtensor-AI wants to merge 2 commits into
Conversation
…MemTensor#2370) When an episode is terminal-skipped (meta.reward.skipped=true) and then reopened, episode-manager.ts correctly sets rewardDirty but leaves reward.skipped untouched. episodeRewardIsDirty() in memory-core.ts calls rewardWasSkipped() before hasRewardDirtyMarker(), short-circuiting to false and making the episode permanently invisible to every rescore scan. Fix: in reopen(), when setting rewardDirty, also clear reward.skipped so the marker is evaluated and the episode is queued for rescoring. The collectDirtyClosedEpisodes bounded-page cleanup already handles existing persisted rows with the contradictory marker pair; this fix closes the write-path gap so new reopens don't produce the stale state in the first place. Regression test: reopen clears reward.skipped when setting rewardDirty (MemTensor#2370)
🤖 Open Code ReviewTarget: PR #2371 🔍 OpenCodeReview found 1 issue(s) in this PR. 1.
|
🔧 Open Code Review requested Agent fixOpen Code Review found 1 issue(s). I have resumed the development Agent to fix them.
The Agent will push a new commit to this PR branch. OCR will recheck after the commit is pushed. |
…emTensor#2370) reopen() re-sets meta.rewardDirty, but EpisodeManager.finalize() and abandon() passed snap.meta through to the repo without clearing it. Any terminal path that did not happen to run the reward write — e.g. the episode resumed with rTask != null, so the reward fallback was skipped — left the marker on a fully resolved episode. episodeRewardIsDirty() and consistency checks built on json_type(meta_json,'$.rewardDirty') then reported the row as dirty indefinitely (reporter saw 17 days), which is the durable half of MemTensor#2370 that clearing reward.skipped on reopen does not address on its own. Overwrite the key with `undefined` rather than dropping it or setting `null`: the repo merges the patch into the existing meta_json (so an omitted key would leave the stale value), and toJsonText uses JSON.stringify, which omits undefined-valued keys — leaving the key absent instead of present-and-null, which would still satisfy `IS NOT NULL`. Regression tests cover both terminal paths and assert on the JSON-round-tripped meta, i.e. the shape the reporter's watchdog reads.
Description
Fixed a permanent
meta.rewardDirtymarker on episodes that were terminal-skipped and then reopened (issue #2370).Root cause:
episode-manager.ts reopen()correctly setsrewardDirty: {reason:"episode_reopened",...}on the episode meta, but leftmeta.reward.skipped: trueuntouched from the earlier heuristic-skip scoring pass.episodeRewardIsDirty()inmemory-core.tsevaluatesrewardWasSkipped()beforehasRewardDirtyMarker(), so the skip flag permanently short-circuited the function tofalse, making the episode invisible to every rescore scan path (init recovery loop, periodic dirty-closed scan, backoff filter). The marker was therefore never cleared.Fix: In
episode-manager.ts reopen(), when settingrewardDirty, also spreadreward.skipped: undefinedinto the reward object if the episode had previously been terminal-skipped. This is a targeted one-shot patch to the object written tometa; it does not change any other reward fields. The existingcollectDirtyClosedEpisodesbounded-page cleanup already handles any persisted rows that have the contradictory marker pair from before this fix.Tests: Added two regression tests to
tests/unit/session/episode-manager.test.ts: one asserting thatreward.skippedis cleared andrewardDirtyis set correctly after reopen on a previously-skipped episode, and one asserting thatrewardDirtyis not set when the episode was never scored. All 176 tests across 13 files pass.Related Issue (Required): Fixes #2370
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Not run; documentation-only change.
Checklist
@whipser030, @hijzy please review this PR.
Reviewer Checklist