-
-
Notifications
You must be signed in to change notification settings - Fork 80.7k
Role-ordering-conflict auto-reset hard-deletes the previous session transcript with no archive (fs.unlinkSync), keeping only the replayed tail #97529
Copy link
Copy link
Closed
Labels
P1High-priority user-facing bug, regression, or broken workflow.High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.ClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.ClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:data-lossCan lose, corrupt, or silently drop user/session/config data.Can lose, corrupt, or silently drop user/session/config data.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.Session, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.Issue affects a taxonomy feature currently scored M4/M5.no-staleExclude from stale automationExclude from stale automation
Description
Metadata
Metadata
Assignees
Labels
P1High-priority user-facing bug, regression, or broken workflow.High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.ClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.ClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:data-lossCan lose, corrupt, or silently drop user/session/config data.Can lose, corrupt, or silently drop user/session/config data.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.Session, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.Issue affects a taxonomy feature currently scored M4/M5.no-staleExclude from stale automationExclude from stale automation
Type
Fields
Priority
None yet
Summary
When the agent runner performs the automatic session reset triggered by a provider role-ordering conflict, the previous conversation transcript is hard-deleted from disk with
fs.unlinkSyncand no archive is written. Only the last few user/assistant messages are replayed into the new session (cap of 6), so the rest of the conversation is gone with no recoverable.reset/.deleted/archive copy and nothing for memory-core to re-index. Every other reset/rollover path archives the previous transcript; only this path unlinks it.Environment
891096926e272e5e3c24fae66133876b8dbe7060(origin/main at time of filing)resetSessionAfterRoleOrderingConflict) -> file session storage lifecycleSteps to reproduce
embedded-agent-runner/run/attempt.tscannot reshape the transcript.resetSessionAfterRoleOrderingConflict, which routes topersistSessionResetLifecyclewithcleanupPreviousTranscript: true.Expected
The previous transcript should be preserved the same way
/resetand/newpreserve it: rotated to a recoverable archive (a.jsonl.reset.<ts>file) so memory-core can re-index it and the conversation remains recoverable.Actual
The previous transcript file is unlinked from disk. No
.reset/.deleted/archive copy is written. Only the replayed tail (at most 6 user/assistant messages; 0 when the tail is assistant-only) is carried into the new session. The loss is silent (no user-facing notice).Root cause
src/config/sessions/session-accessor.ts.persistSessionResetLifecyclereplays only the recent tail, then on the cleanup flag callscleanupPreviousResetTranscripts, which hard-deletes:The asymmetry: the normal
/resetand/newrotation goes througharchivePreviousSessionTranscript, which calls the archive runtime withreason: "reset"and produces a recoverable, memory-indexed.jsonl.reset.<ts>:Only the role-ordering-conflict path uses the unlink branch.
The replay cap is
DEFAULT_REPLAY_MAX_MESSAGES = 6(src/config/sessions/transcript-replay.ts).replayRecentUserAssistantMessagescarries at most that many user/assistant messages, and an assistant-only tail replays 0, so the new session can start empty.Trigger path:
resetSessionAfterRoleOrderingConflict(src/auto-reply/reply/agent-runner.ts) is the sole caller passingcleanupTranscripts: true. It is threaded ascleanupPreviousTranscriptthroughagent-runner-session-reset.tsintopersistSessionResetLifecycle. The original role-ordering auto-reset (#998) deleted the transcript on purpose to clear a corrupt session; that delete-without-archive predates the.resetarchive convention now used by every other rotation, which is the divergence.Related issues (distinct, not duplicates)
rma session file in any OC codepath". That proposal assumes the rename-only behavior. This report is the concrete, source-located proof that a real codepath actuallyfs.unlinkSyncs a transcript with no archive, with a runnable repro driving the real runtime function. It is a specific reset-path deletion defect, distinct from the broad naming request..reset.but no new file was created. Here the file is unlinked (never renamed) and a new file is created carrying only the replayed tail.cleanupPreviousResetTranscriptsor the delete-versus-archive behavior ofpersistSessionResetLifecycle. fix(reply): retry stalled compacted direct sessions after reset #97099 (open) touches the reset path but only adjusts store null-guards and retry of stalled compacted sessions; the unlink remains.Real behavior proof
Behavior addressed: role-ordering-conflict auto-reset hard-deletes the previous transcript with no archive, keeping only the replayed tail.
Real environment tested: drove the real exported
persistSessionResetLifecyclefromsrc/config/sessions/session-accessor.tswithcleanupPreviousTranscript: trueagainst a 25-turn transcript laid out in the realagents/<id>/sessions/shape, at commit891096926e272e5e3c24fae66133876b8dbe7060.Exact steps or command run after this patch:
node --import tsx /tmp/openclaw-bug-repros/reset-role-ordering-unlink/repro.mjsEvidence after fix:
Observed result after fix: on current origin/main the previous transcript is removed with zero recoverable archive copies; replacing the unlink with a preserving rename leaves one recoverable archive on the same inputs.
What was not tested: I did not drive a live provider to emit the role-ordering error end to end, and did not exercise the database-backed session store (the repro covers the file session storage lifecycle only). The EXPECTED run used a preserving rename to demonstrate recoverability; it does not assert the full memory-core re-index step.