Repository navigation
fix(cursor-native): follow the TUI onto its new chat after /clear - #7295
omni-resolve-agent[bot] wants to merge 4 commits into
Conversation
A cursor-agent TUI /clear (or /new, /new-chat) starts a brand-new chat store while the old one stays on disk, so the forwarder — which only re-discovers when its bound store disappears — stayed pinned to the cleared-away chat: composer replies landed in the TUI's new chat but never reached the web transcript (from the browser the session looked dead), and the one-shot external_session_id patch left a later cold resume targeting the pre-/clear chat. The forwarder now detects a newer sibling chat store (created after the bound chat and at/after this launch) once each poll's backlog is drained, re-binds the mirror to it (fresh rowid cursor and model dedupe), and re-points the cold-resume target. A candidate claimed by any live sibling session is never taken, so a concurrent same-cwd session's first chat cannot be stolen. external_session_id is write-once by contract (a divergent wrapper write signals a bug worth surfacing loudly), so the re-point rides a new wrapper event, external_session_rotated, which the server maps to the one sanctioned overwrite (set_external_session_id with allow_rotation=True); the plain PATCH keeps its loud-failure contract for every other caller.
|
UI Preview for this PR has been removed. |
|
Benchmark results (SQLite, PR #7295)Commit: Benchmark comparisonRegression threshold: 100% on run-median P50 or P95.
PASS — no regressions detected. |
Signed-off-by: Pat Sukprasert <pattara.sk127@gmail.com>
…on runner authority Address review of the /clear cold-resume rotation: - _post_external_session_rotated now retries on transient rejections (429/5xx) instead of settling. Settling advanced patched_chat_id and stranded the cold-resume target against the write-once PATCH; only a 2xx ack or a deterministic 4xx (an old server without this event) settles now. - external_session_rotated is the one sanctioned overwrite of the write-once external_session_id, so restrict it to the session's runner bridge via _has_runner_created_by_authority (403 otherwise). The cursor forwarder now presents the runner tunnel binding token so its legitimate rotation post is authorized on both tunnel- and bearer-auth hosts. Adds transient-retry and negative-authority regression tests, notes the sibling-claim and old-store-drain race windows, and drops a redundant import flagged by CodeQL.
|
Resolve-agent reviewed this contributor PR as the candidate fix. Future actionable maintainer review feedback may be remediated automatically. |
There was a problem hiding this comment.
Resolve-agent review outcome: fixed.
Summary
PR #7295 makes the forwarder discover an eligible new chat store after /clear, drain the backlog, rebind with a fresh cursor, and POST a sanctioned external_session_rotated event so the server re-points external_session_id via set_external_session_id(allow_rotation=True), while plain PATCH writes stay write-once. On top of that PR head I committed 89779a9 to address Polly's two blockers: (1) forwarder.py _post_external_session_rotated now returns False (retry next poll) on 429/5xx and settles only on 2xx or a deterministic 4xx, so a transient server hiccup can no longer permanently strand the cold-resume target; (2) routes_events.py gates external_session_rotated on runner-tunnel authority (_has_runner_created_by_authority), returning 403 to any non-runner caller, and orchestration.py sends the runner tunnel binding token (X-Omnigent-Runner-Tunnel-Token) with the cursor forwarder's requests so the real bridge is authorized. I also added the sibling-claim TOCTOU and old-store drain-race notes Polly flagged as non-blocking.
Root cause
cursor-native's forwarder resolved the chat store once and only re-discovered it when the file disappeared; /clear creates a new sibling ~/.cursor/chats/<md5(cwd)>//store.db while the old file remains, so the forwarder stayed pinned to the pre-/clear chat and external_session_id (the --resume target), patched write-once behind chat_id_patched, was never re-pointed. No rotation logic existed for cursor-native (grep -ci rotat over the package returned 0).
CI
not run in this session — CI is implementation-only for the agent; the publisher owns the CI loop after it pushes 89779a9 to fix/34731956277.
Automated review
not clean/not re-run: the prior Polly review (issue comment 5650987543, against old head a094a3b) raised two blocking findings — (1) transient 5xx/429 permanently strands the cold-resume target, and (2) the rotated overwrite is not restricted to runner origin — both addressed in commit 89779a9, plus the non-blocking sibling-claim TOCTOU and old-store drain-race notes. No fresh comment exists for the current head; the agent does not dispatch Polly in CI, so a fresh Polly review on the new head is still required (publisher/CI owns it). Not claiming clean.
Reviewed and tested commit: 89779a90068ae5d31b0934df5163cc3f0ef9116e.
Related issue
Closes #7289
Resolves OMNI-7409
Summary
After
/clearin Cursor's terminal, web chat and later resume could remain attached to the old conversation.ELI5: The forwarder now discovers eligible new chat stores, resets its cursor, and signals a sanctioned external-session rotation to the server. It will not take a store claimed by another live session, and ordinary ID updates remain write-once.
Test Plan
Regression coverage in this PR targets the reported behavior. The original description did not record a test-run result; the linked resolve update contains the historical verification context.
Changed regression coverage:
tests/e2e_ui/messages/test_cursor_native_clear_rotation.pytests/server/integration/test_sessions_endpoints.pySuggested check from the PR checkout, with the repository test dependencies installed (not rerun for this edit):
Source reports and verification runs
Original resolve workflow
Latest resolve-agent update
Demo
Recordings from the resolve-agent update; Linear sign-in required. Captions describe the recorded environment, not a new test run.
before-web-strand.mp4
after-web-rotation.mp4
Type of change
Test coverage
Coverage notes
Test results above are attributed to the original resolve runs. No product tests were rerun for this description-only update.