Skip to content

[Bug]: WebChat session transcript overwritten on every turn (5.2 regression — SessionManager removal) #77012

@dertbv

Description

@dertbv

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

In OpenClaw v2026.5.2, the webchat session JSONL transcript is overwritten on every turn — only the latest message exchange survives. On page refresh, all previous messages are gone. This worked correctly on v2026.4.29.

Root cause

mirrorCodexAppServerTranscript (in run-attempt-*.js) receives the full conversation history via messagesSnapshot (built from readMirroredSessionHistoryMessages at line 3264) and rewrites ALL messages to the JSONL every turn. Each message is written via appendCodexAppServerTranscriptMessage, which calls migrateLinearTranscriptToParentLinked — a function that reads the entire file and rewrites it via fs.writeFile (not append).

The per-turn idempotencyScope (codex-app-server:${threadId}:${turnId}) changes every turn, so old messages get new keys and bypass the idempotency check. The rewrite creates new entries with different parentId chains, causing selectBoundedActiveTailRecords (the tree walk) to follow the newest branch and orphan previous entries.

In v4.29, SessionManager.open().appendMessage() truly appended to the file. The SessionManager was removed in 5.2 and replaced with this read-migrate-rewrite cycle.

Steps to reproduce

  1. Open webchat on v2026.5.2
  2. Send message 1, receive response
  3. Send message 2, receive response
  4. Check the session JSONL — message 1's assistant response is gone
  5. Refresh page — only message 2 and its response are visible

Evidence

Controlled test on macOS arm64, v2026.5.2 (8b2a6e5), stock dist (no patches except prewarm skip):

  • Took a JSONL snapshot between turns
  • Diffed after the next turn
  • The previous assistant response (id 44b4ec62, parentId d3471f25) was replaced by the new user message (id 9f4b19a1, parentId d3471f25) — same parent, sibling branch
  • The tree walk follows the new branch, orphaning the old assistant entry
  • 9 minutes between turns — no race condition, purely the mirror rewrite logic

Contributing factors

  1. migrateLinearTranscriptToParentLinked rewrites via writeFile — any concurrent access or stale read loses data
  2. Per-turn turnId in idempotency scope — old messages get new keys, bypassing dedup
  3. Write lock race (fix: session write lock race — async release can delete newly-acquired lock #57019)releaseHeldLock deletes HELD_LOCKS before async cleanup, allowing concurrent acquirers on macOS
  4. appendCodexAppServerTranscriptMessage calls migration inside the lock but mirrorCodexAppServerTranscript takes a separate lock per batch — interleaving between the webchat write path and the mirror write path can race

Code references (v2026.5.2 dist)

  • run-attempt-CektiLYp.js:3264finalMessages = readMirroredSessionHistoryMessages(sessionFile) (full history)
  • run-attempt-CektiLYp.js:3598idempotencyScope: codex-app-server:${threadId}:${turnId} (per-turn keys)
  • run-attempt-CektiLYp.js:2082appendCodexAppServerTranscriptMessage triggers migration
  • transcript-C_uDP9Gl.js:121migrateLinearTranscriptToParentLinked rewrites file via writeFile
  • transcript-C_uDP9Gl.js:156fs.writeFile(transcriptPath, ...) — destructive overwrite
  • session-utils.fs-W0CAUUsv.js:564selectBoundedActiveTailRecords tree walk follows one branch

What changed (4.29 → 5.2)

4.29 5.2
Write method SessionManager.open().appendMessage() — true append appendCodexAppServerTranscriptMessagemigrateLinearTranscriptToParentLinkedwriteFile — full rewrite
Session read readSessionMessages — sync, reads all readRecentSessionMessagesAsync — async, tail window + tree walk
Branch resolution SessionManager.open().getBranch() selectBoundedActiveTailRecords — drops orphaned branches
Mirror scope Current turn only Full messagesSnapshot (entire history)
Idempotency N/A (true append) Per-turn scope — changes every turn, old messages get new keys

Environment

  • OpenClaw: v2026.5.2 (8b2a6e5), npm global install
  • OS: macOS 26.4.0 arm64 (Mac Mini M4 Pro)
  • Node: 22
  • Channels affected: WebChat (Telegram and BlueBubbles unaffected — different write path)

Related issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions