openclaw / openclaw/openclaw

[Bug]: Codex harness assistant replies do not mark Control UI sessions unread

Open
#142,002 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:session-state impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P2
Dominant language
TypeScript
Stars
390k
Forks
82k
PR merge metrics
PR metrics pending

Description

Bug type

Behavior bug (incorrect session state without a crash)

Summary

Completed assistant replies from Codex agent-harness sessions do not make the session unread in the Control UI. The reply is durably present after the user's last read acknowledgement, but the session row remains unread: false.

Steps to reproduce

  1. Configure a session to use the Codex agent runtime.
  2. Open the session in the Control UI and send a message.
  3. Navigate away before the assistant reply completes.
  4. Wait for the completed reply.
  5. Inspect the session list.

Expected behavior

A completed user-facing assistant reply after lastReadAt advances unread-worthy activity and the session shows an unread badge.

Actual behavior

The assistant message is committed and the session updatedAt advances, but lastActivityAt remains absent. Since deriveSessionUnread() intentionally ignores updatedAt, the row stays read.

Environment

  • OpenClaw 2026.9.2 (base release behavior; deployed build 83c63dc has no changes in the relevant unread/session-store files)
  • Fedora Linux, Node 26
  • Control UI in browser
  • Agent runtime: Codex
  • Models observed: openai/gpt-6-astra

Redacted evidence from two independent sessions

Session A (Telegram-backed Codex session)
  • lastReadAt: 2026-09-08 09:37:03 +02:00
  • durable assistant message: 2026-09-08 09:37:14 +02:00
  • updatedAt: after the assistant message
  • lastActivityAt: NULL
  • derived unread: false
Session B (dashboard Codex session)
  • lastReadAt: 2026-09-07 14:28:52 +02:00
  • durable assistant message: 2026-09-07 14:29:15 +02:00
  • updatedAt: after the assistant message
  • lastActivityAt: NULL
  • derived unread: false

No transcript text or private identifiers are included.

Source analysis

deriveSessionUnread() in src/gateway/session-utils-core.ts derives unread state only from:

  • an explicit markedUnreadAt, or
  • max(lastInteractionAt, lastActivityAt) > (lastReadAt ?? createdAt)

This is consistent with the documented contract: lastActivityAt is the timestamp of the last completed unread-worthy agent run, while updatedAt is not an activity signal.

The canonical completion writer in src/agents/command/session-store.ts normally computes lastActivityAt, but its preserved-user-facing-state metadata patch explicitly omits it. The observed Codex harness completions advance updatedAt and commit the assistant transcript while leaving lastActivityAt NULL, so the unread derivation has no completion signal.

The same relevant logic is present on current origin/main at 8ac88a1a335aa5f6ec467e539f6bbce3df478d84.

Existing issues / PRs checked

  • #100739 introduced the unread contract and states that completed activity should drive unread state.
  • #128986 covers never-opened modern sessions.
  • #129373 / #129386 cover preserving explicit manual unread markers.
  • #134158 / #134160 cover optimistic clearing when a session opens.
  • #126837 reported widespread NULL last_activity_at for retention tooling, but was closed as not planned because qualifying ordinary completions are expected to populate it. This report demonstrates a current qualifying Codex completion path where they do not.

Suggested repair

Ensure every completed, user-facing Codex/CLI harness turn persists lastActivityAt, even when model/accounting fields are intentionally preserved. Keep heartbeat, internal-event, and metadata-only paths excluded. Add an end-to-end regression that:

  1. records lastReadAt,
  2. completes a Codex harness assistant turn later,
  3. asserts lastActivityAt advances and sessions.list returns unread: true.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/gateway/session-utils-core.ts and src/agents/command/session-store.ts, then trace the Codex harness completion path and existing session unread tests. Verify that a completed user-facing Codex turn advances lastActivityAt without changing excluded heartbeat or metadata-only paths. Done means an end-to-end regression shows a later completed turn makes sessions.list return unread: true after lastReadAt.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend-api-design, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.