Repository navigation
Description
User impact
An active mouse drag can continue on a replacement Browser page. A related ordering check can report success after the input channel disconnects, allowing a later Runtime input to proceed without proof that the earlier selection arrived.
Found in the latest local 0.8.0 train input changes during #93's audit. Proposed priority: P1 for page ownership, P2 for the lost-channel ordering case; triage before freezing the Browser candidate under #87.
Exact candidate and evidence
Candidate 460b1888d344f52cebd1c25866be88ff4085f035, tree 17aeaf23c640e2dec8f653fd16f3771f95a55b9c. It is local and unpublished. Two reviewers independently repeated deterministic in-memory fixtures against its actual JavaScript. These are source-level reproductions, not installed media proof.
Active drag changes owner
capsules/browser/browser/browser-input-surface.js:335-460 stores pointer and drag state without the originating page/generation. A queued animation-frame move and direct release use the page current when the callback runs. browser.js:1609 captures ownership at that later invocation.
Fixture: pointerdown at x=100 on old page; queue pointermove x=120; replace current page before the animation frame; flush frame; pointerup x=140.
Both runs produced:
[
{"page":"old","type":"mouse","x":100,"y":100,"buttons":1},
{"page":"replacement","type":"mouse","x":120,"y":100,"buttons":1},
{"page":"replacement","type":"mouse","x":140,"y":100,"buttons":0}
]Expected: later input stays bound to the original gesture owner or is retired. It cannot become a new page's gesture.
Disconnect is treated as completed drain
browser.js:1670 waits on buffer amount and elapsed time without binding the channel identity/open state. The real display getter returns zero when the channel is removed (browser-remote-display.js:1384, close at :281). The caller continues after its page check (browser.js:1735-1741); channel reconnect can occur without changing page identity.
Fixture: bufferedAmount=64; disconnect after 20 ms and return buffer=0. The helper resolved with the channel closed:
{"settled":true,"channelOpen":false,"elapsedMs":175}The separate reviewer observed 180 ms. Elapsed time is incidental; successful settlement on a closed channel is the finding.
Acceptance
- Capture gesture page/session/generation at pointerdown; retire queued callbacks when ownership ends.
- Release the old gesture through its own valid owner, or terminate it without sending to a replacement.
- Cover page replacement, close, navigation, blur, pointer capture loss and a fresh gesture after retirement.
- Bind the input ordering barrier to the actual channel/generation and distinguish confirmed drain from disconnect/unknown delivery.
- Cover pending bytes then disconnect/reconnect with the same page ID; later input must receive a clear refusal/recovery outcome.
- Add regression cases using the real source callback boundaries, then run the installed Mac selection/paste/close/reconnect journey on the signed candidate.
Existing input/order tests and the overall 1,819-test behaviour suite pass; these transitions are absent from that evidence. Coordinate with draft PR #421 (deferred wheel/touch ownership), #439 (adapter uncertainty) and #87. This issue owns the new mouse-drag and datachannel-barrier slice; it does not duplicate those broader tasks. The exact no-file reproduction commands are retained in the audit's local evidence packet and can become the regression fixtures.
Activity
andersalm commentedon Oct 22, 2026
Triage (22 Oct, OMP security lane): known gap for 0.8.0, fixed after the release, or earlier if a new candidate is cut for another reason.
Both mechanisms are confirmed in source on
460b1888d. Both came with the new drag-select code:26f7c7589has no drag state and no drain barrier. Severity is Low:Fix shape: keep the page owner in the drag state at pointerdown and end the drag silently when the owner changes (about 20 lines and 2 tests); remember the channel of the last send and refuse instead of settling when that channel has closed (about 10 lines and 1 test). The same change adds a test for a release sent while Runtime text waits at the barrier, and checks what the guest receives when a release finds the channel closed.
andersalm commentedon Oct 22, 2026
Disposition update (22 Oct, OMP). Main's Browser lane now has a fix for both mechanisms in this issue:
22e40f1f2on local branchfix/080-browser-copy-protocol, after the Browser Copy fix787d1b44d, both on460b1888d. It is not on the train yet; Main integrates it after its gate. Codex reviewed22e40f1f2(treecfef92b9db42): PASS WITH CHANGES, with no blocking finding. That review did not run builds or tests.The review left two notes. Both are recoverable, and both stay open here as follow-ups after 0.8.0:
The review's smoke supplies the clipboard text and stands in for the approval, so the real guest-to-Mac Copy journey still needs Anders's recheck on a rebuilt test Home (#87).
andersalm commentedon Oct 22, 2026
Status (22 Oct): fixed on the 0.8.0 train in
22e40f1f2(Codex copyproto1 PASS WITH CHANGES; remote gate PASS).787d1b44d). The window now accepts the guest'sclipboardreply.Follow-ups after 0.8.0 (non-blocking review notes):
Still open for acceptance: the installed Mac select, copy, paste, close and reconnect journey on the signed candidate.