Uh oh!
There was an error while loading. Please reload this page.
fix: clear unread marker when messages are read - #294
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SessionManager.getMessages()as a pure query so thread search and the open gateway do not mark sessions read.sessions:listresponses and stale local read results while allowing newer messages to become unread again.hasUnread: truewrite.Why
Unread dots should mean there is agent output the user has not viewed yet. Opening a session is the read boundary; background reads from search or the open gateway must not mutate persisted unread state. Final refreshes must happen after runtime finalization, and older list/read responses or non-atomic persisted writes must not overwrite newer unread state.
Scope
Changed:
markSessionReadThrough(sessionId, readThroughTs)so the latest header and visible message timestamps are read and conditionally written inside one queued storage operation.SessionManager.markSessionRead(sessionId, readThroughTs)for the explicit persisted read boundary.sessions:readMessagesIPC to mark the session read after a successful message read, using the maxtsreturned by that read and without swallowing persistence failures.getMessages()pure for thread search/open gateway reads.message-appendedrefresh broadcasts in the normal stream path to after iterator drain.isFinalSessionEvent()helper and narrowed brittle renderer source-shape assertions.Not included:
Verification
apps/desktop$ npx tsx --test src/main/__tests__/permission-response-ipc-boundary.test.tsapps/desktop$ npx tsx --test src/main/__tests__/session-message-lifecycle-contract.test.tsapps/desktop$ npx tsx --test src/main/__tests__/session-read-state.test.tsnpx tsx --test apps/desktop/src/main/__tests__/session-open-routing-contract.test.tsnpx tsx --test packages/runtime/src/__tests__/session-manager.test.tsnpx tsx --test packages/runtime/src/__tests__/runtime-event-read-model.test.tsnpx tsx --test packages/storage/src/__tests__/session-store.test.tsnpm --workspace @maka/runtime run buildnpm --workspace @maka/storage run buildnpm run typecheck --workspaces --if-presentgit diff --checkUser-facing impact
Opening a session now clears its unread marker and persists that state across restarts only for messages actually read. Background search and open-gateway reads keep unread state intact. Active sessions should not show stale unread markers, and background/newer output should not be hidden by stale header timestamps, older session-list, local-read, or persisted mark-read races. No
CHANGELOG.md, docs, breaking changes, or migrations.Reviewer notes
getMessages()was clearing unread for shared read paths. Fixed by moving persisted mark-read tosessions:readMessagesIPC.message-appendedafter iterator drain/finalize.sessions.list()latest-wins ordering, added mark-read read-through protection, and replaced brittle renderer source-shape assertions with behavior tests for the list refresh race.readMessages()result could clear unread for newer output.