Repository navigation
fix(desktop): close cross-session leak windows in composer + session refs - #70986
Merged
Merged
Conversation
…refs (#59305) Two React passive-effect timing bugs let a session switch land in the wrong chat: activeSessionIdRef/selectedStoredSessionIdRef (use-session-state-cache) and the composer's attachment-scope swap (use-composer-draft) both mirrored their source props via useEffect, which fires one commit AFTER the new session's view has already painted — a synchronous read/submit in that window observed the outgoing session's ids/attachments. - use-session-state-cache.ts: mirror the session refs synchronously during render instead of a useEffect, guarded to fire only when the prop itself changed (not unconditionally) so an imperative pin from submit.ts / use-session-actions (e.g. a freshly resumed runtime id, intentionally not synced to the source atom) survives an unrelated re-render. - use-composer-draft.ts: the per-thread attachment-scope-swap effect is now a useLayoutEffect, closing the window before paint. - submit.ts / session-context-drift.ts: add a 3rd drift prong comparing the composer's loaded scope (SubmitTextOptions.composerScope) against the submit target, resolved into the same lineage-root domain (resolveComposerSessionKey) the composer itself uses — comparing against the raw tip id would false-positive-abort every submit into any session that has ever auto-compressed. - routes.ts / chat/index.tsx: the primary composer's durable scope key now prefers the route over a possibly-stale store selection (primaryRouteSelectedSessionId). - use-composer-draft.ts: redacted [composer-rehydrate] diagnostic log (counts/kinds/scope only, never raw refs) for future reports in this class. - chat-runtime.ts: normalize attachment id values (url/path) before hashing so a re-attach with a trailing slash or backslash path dedupes correctly. 16 files, 286 tests across the touched/dependent suites (17 files) green, including new regression coverage for each fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
….test.tsx CI's check:lint failed on two perfectionist rule violations introduced by the new test file: type import ordering and missing blank line between the parent-relative and same-directory import groups. No behavior change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
૮ >ﻌ< ა ci reviewran on 80c21cc all good! |
This was referenced Jul 24, 2026
teknium1
pushed a commit
that referenced
this pull request
Jul 25, 2026
…e submit pipeline (#64327) From PR #64327 (@Kenmege), whose target-aware drift predicate (compare route tokens by their routed chat target; ignore selection null-resets, search/hash churn, and background active-ref retargets; never count a move onto the submit's own target) already reached main via the #69578 salvage (1bdd478, Co-authored-by Kennedy Umege) and gained the #70986 composerScope prong. What main covered only at the unit level (session-context-drift.test.ts) is here pinned at the pipeline level, both directions: - a send from a second chat rides out simultaneous programmatic churn (selection null-reset from a gateway/profile reconnect, active-ref retarget from a background event, search/hash-only route change from an overlay) mid-session.resume and still reaches prompt.submit; - a genuine user switch (selection AND route moving to another real chat) mid-submit still aborts before prompt.submit. Part of the #63078 fix branch.
1 task
1 task done
12 of 19 tasks
This was referenced Aug 1, 2026
Closed
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…e submit pipeline (NousResearch#64327) From PR NousResearch#64327 (@Kenmege), whose target-aware drift predicate (compare route tokens by their routed chat target; ignore selection null-resets, search/hash churn, and background active-ref retargets; never count a move onto the submit's own target) already reached main via the NousResearch#69578 salvage (b21b39f, Co-authored-by Kennedy Umege) and gained the NousResearch#70986 composerScope prong. What main covered only at the unit level (session-context-drift.test.ts) is here pinned at the pipeline level, both directions: - a send from a second chat rides out simultaneous programmatic churn (selection null-reset from a gateway/profile reconnect, active-ref retarget from a background event, search/hash-only route change from an overlay) mid-session.resume and still reaches prompt.submit; - a genuine user switch (selection AND route moving to another real chat) mid-submit still aborts before prompt.submit. Part of the NousResearch#63078 fix branch.
prmartinow
pushed a commit
to prmartinow/hermes-agent
that referenced
this pull request
Aug 26, 2026
…e submit pipeline (NousResearch#64327) From PR NousResearch#64327 (@Kenmege), whose target-aware drift predicate (compare route tokens by their routed chat target; ignore selection null-resets, search/hash churn, and background active-ref retargets; never count a move onto the submit's own target) already reached main via the NousResearch#69578 salvage (80145d0, Co-authored-by Kennedy Umege) and gained the NousResearch#70986 composerScope prong. What main covered only at the unit level (session-context-drift.test.ts) is here pinned at the pipeline level, both directions: - a send from a second chat rides out simultaneous programmatic churn (selection null-reset from a gateway/profile reconnect, active-ref retarget from a background event, search/hash-only route change from an overlay) mid-session.resume and still reaches prompt.submit; - a genuine user switch (selection AND route moving to another real chat) mid-submit still aborts before prompt.submit. Part of the NousResearch#63078 fix branch.
melon-xf
added a commit
to melon-xf/hermes-agent
that referenced
this pull request
Sep 3, 2026
…e submit pipeline (NousResearch#64327) From PR NousResearch#64327 (@Kenmege), whose target-aware drift predicate (compare route tokens by their routed chat target; ignore selection null-resets, search/hash churn, and background active-ref retargets; never count a move onto the submit's own target) already reached main via the NousResearch#69578 salvage (1bdd478, Co-authored-by Kennedy Umege) and gained the NousResearch#70986 composerScope prong. What main covered only at the unit level (session-context-drift.test.ts) is here pinned at the pipeline level, both directions: - a send from a second chat rides out simultaneous programmatic churn (selection null-reset from a gateway/profile reconnect, active-ref retarget from a background event, search/hash-only route change from an overlay) mid-session.resume and still reaches prompt.submit; - a genuine user switch (selection AND route moving to another real chat) mid-submit still aborts before prompt.submit. Part of the NousResearch#63078 fix branch.
austinpickett
added a commit
to austinpickett/hermes-agent
that referenced
this pull request
Sep 25, 2026
…arch#62823 zombie slot) When a compute-host turn has not settled by session close, the session's real active-session lease is parked in _deferred_active_session_leases and the turn's completion callback is supposed to release it. If that callback is lost (supervisor restart/reload, child killed without failing its pending turns, dropped completion), the lease sat in the registry forever: _own_live_lease_ids vouches for it so the orphan sweep never reclaims it, and the concurrent-session cap treats the dead session as active - new sessions could not send until a backend restart. Track when each lease was deferred and have the reaper tick force-release deferred leases past a generous 30-minute ceiling (the longest legitimate isolated turn is the compression ceiling, minutes). Normal settlement still releases immediately and clears the age entry. Fixes NousResearch#62823 (zombie-concurrency-slot half; cross-window queue-sync was fixed by NousResearch#122953 and visual-merge by NousResearch#70986 - not touched here)
austinpickett
added a commit
that referenced
this pull request
Sep 25, 2026
…ombie slot) When a compute-host turn has not settled by session close, the session's real active-session lease is parked in _deferred_active_session_leases and the turn's completion callback is supposed to release it. If that callback is lost (supervisor restart/reload, child killed without failing its pending turns, dropped completion), the lease sat in the registry forever: _own_live_lease_ids vouches for it so the orphan sweep never reclaims it, and the concurrent-session cap treats the dead session as active - new sessions could not send until a backend restart. Track when each lease was deferred and have the reaper tick force-release deferred leases past a generous 30-minute ceiling (the longest legitimate isolated turn is the compression ceiling, minutes). Normal settlement still releases immediately and clears the age entry. Fixes #62823 (zombie-concurrency-slot half; cross-window queue-sync was fixed by #122953 and visual-merge by #70986 - not touched here)
dzianisv
pushed a commit
to dzianisv/hermes-agent
that referenced
this pull request
Sep 26, 2026
…arch#62823 zombie slot) When a compute-host turn has not settled by session close, the session's real active-session lease is parked in _deferred_active_session_leases and the turn's completion callback is supposed to release it. If that callback is lost (supervisor restart/reload, child killed without failing its pending turns, dropped completion), the lease sat in the registry forever: _own_live_lease_ids vouches for it so the orphan sweep never reclaims it, and the concurrent-session cap treats the dead session as active - new sessions could not send until a backend restart. Track when each lease was deferred and have the reaper tick force-release deferred leases past a generous 30-minute ceiling (the longest legitimate isolated turn is the compression ceiling, minutes). Normal settlement still releases immediately and clears the age entry. Fixes NousResearch#62823 (zombie-concurrency-slot half; cross-window queue-sync was fixed by NousResearch#122953 and visual-merge by NousResearch#70986 - not touched here)
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 free
to 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
Desktop chat tabs no longer mix messages across sessions — the two passive-effect race windows are closed and submit now enforces composer/session coherence.
Changes
Validation
141 tests green across touched suites;
npm run typecheckclean; eslint 0 errors.Fixes #59305
Fixes #70609
Infographic