fix(desktop): preserve concurrent session pin intent - #74444
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for covering the stale-page race and the superseded-promise cleanup path. The premise is confirmed on current main: pullRemotePins() runs before the local push pass in apps/desktop/src/store/session-pin-sync.ts:102, so a stale row can reverse a click before writePin() sets unconfirmed.
Problems
apps/desktop/src/store/session-pin-sync.ts:43-45still dispatches every PATCH immediately. The generation only prevents an older promise from clearing the newer local guard; it does not order backend mutations. The server applies each PATCH directly (hermes_cli/web_routers/sessions.py:675-678) with no generation precondition, so two toggles can be applied out of order and leave the durable pin value opposite to the latest click.
Suggested changes
- Serialize or coalesce writes per session id, retaining the latest desired value until the previous PATCH settles.
- Add a test asserting that a second toggle does not send its PATCH until the first request settles, covering durable-write order rather than only response/guard order.
Automated hermes-sweeper review.
|
|
||
| function profileFor(pinId: string): null | string | undefined { | ||
| return $sessions.get().find(row => sessionMatchesStoredId(row, pinId))?.profile | ||
| } |
There was a problem hiding this comment.
This generation only orders local cleanup. setSessionPinnedRemote() is still invoked immediately for each toggle, while the backend applies each PATCH as it arrives (hermes_cli/web_routers/sessions.py:675-678), so rapid toggles can persist in reverse order. Please serialize or coalesce writes per id and retain the stale-read guard through the final queued write.
Summary
Root cause
Both Desktop entry points update the same local pin store. The session watcher could then adopt an explicit but stale backend value before the PATCH was observed, or after an older PATCH resolved out of order. A failed latest unpin was also discarded, allowing the next backend refresh to re-pin the row.
Test plan
npm run test:ui --workspace apps/desktop -- src/store/session-pin-sync.test.ts(18 tests)npm run test:ui --workspace apps/desktop(2,983 tests)npm run typecheck --workspace apps/desktopnpm run lint --workspace apps/desktop(0 errors; existing warnings only)npm run build --workspace apps/desktopgit diff --checkNotes
The change is limited to the session pin synchronizer and its behavior tests. It does not alter Gateway lifecycle or restart behavior.