a73x

14ffe9c4

docs: record the selection lane's totality and history watermark

a73x   2026-08-18 12:27

Commit message
docs: record the selection lane's totality and history watermark

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

docs/decisions.md
Old New
@@ -3752,3 +3752,81 @@ while its native CLI copy-mode scope remains open and separate. `7c777ec6`
3752 maps to the OSC 52 browser clipboard path, and `ee062dd9` to the shared mode 3752 maps to the OSC 52 browser clipboard path, and `ee062dd9` to the shared mode
3753 semantics and DEC 2004 browser paste path; the mouse-mirroring half of the 3753 semantics and DEC 2004 browser paste path; the mouse-mirroring half of the
3754 latter remains separate. No issue is closed by this record. 3754 latter remains separate. No issue is closed by this record.
3755
3756 ## 2026-08-18 (selection review: totality, the history watermark, intent)
3757
3758 **A request the daemon could decode leaves with an answer.** The selection
3759 lane is request/reply, and the only thing a requester can do with silence is
3760 wait out its timeout. So the decode now happens BEFORE the session lookup,
3761 and the two orderings mean different things: a malformed payload carries no
3762 id to correlate, and silence is the only honest response to it — but a
3763 well-formed request from a slot with no session (promoted by a QUIC
3764 handshake, never attached) does carry one, and answering `unavailable` costs
3765 a frame where dropping it cost the client five seconds. The same rule
3766 governs the encode: `unavailable` with no text is the one reply that cannot
3767 fail validation, so a failed encode of anything else falls back to it, and
3768 the capacity that fallback needs is reserved before the attempt that can
3769 fail. Totality is a property of the lane, not a property of the happy path.
3770
3771 **Absolute screen rows are not a name for a line, so the reply carries the
3772 watermark that says so.** Row zero is the OLDEST RETAINED row, not the
3773 oldest row the session ever had. When the page list evicts a page every
3774 absolute row shifts underneath a request already in flight, and the reply
3775 that comes back is `ok`, valid UTF-8, and text the user never highlighted —
3776 the worst shape a bug can take, because nothing about it looks wrong.
3777 `selection_reply` therefore carries the daemon's `history_rows` sampled at
3778 extraction time, and the requester compares it with the reading it took when
3779 its own request became authoritative.
3780
3781 The comparison is deliberately `lower means discard`, not `different means
3782 discard`, and that is the whole subtlety. Ordinary output RAISES the retained
3783 count without renaming a single row, because new rows are appended below the
3784 ones already there; demanding equality would make every selection taken
3785 during output unusable, which is most of the selections anyone wants. Only
3786 eviction lowers it. Measured on a five-column grid: the count climbed to
3787 10000, dropped to 5214 in one step, and absolute row zero changed identity at
3788 exactly that drop — page-sized jumps, never a slow drift.
3789
3790 What this buys is a watermark, not a lease, and the difference is the point:
3791 the daemon holds no per-client selection state and gains none here. The
3792 residual hole is that an eviction followed by a whole page of fresh output
3793 INSIDE one round trip would read as a rise. That needs thousands of rows
3794 between the client's last applied frame and the extraction, and closing it
3795 would mean the daemon remembering who asked for what — a trade this feature
3796 has refused from the start.
3797
3798 **User intent beats arrival order on the clipboard.** An explicit copy is the
3799 newest statement of what the human wants, so it retires the automatic OSC 52
3800 lane rather than racing it. A write already handed to the browser genuinely
3801 cannot be cancelled and that limit still stands — but the re-dispatch such a
3802 write performs when it settles is ours to start, and starting it put terminal
3803 text on the system clipboard after the gesture that asked for something else,
3804 with the UI still reading "Copied" for the selection. Retiring the version and
3805 the queued value together is what suppresses it. The rule is about which
3806 writes we choose to begin, and it does not pretend to own the ones already
3807 in the browser's hands.
3808
3809 **The browser honours one OSC 52 target.** The protocol still accepts every
3810 Pc xterm defines, because the native client can route them: `p` is PRIMARY,
3811 `s` the selection, `0`-`7` the cut buffers. A browser tile has one
3812 destination and no way to reach the others, and writing them all to the
3813 system clipboard meant that an ordinary mouse drag inside the session — which
3814 is exactly what emits `ESC]52;p;…` in many X11 applications — silently
3815 clobbered whatever the human last copied on their own machine. Narrowing the
3816 web path to `c` is a loss of nothing anybody asked for. Non-`c` targets
3817 remain valid on the wire and are simply not this tile's business.
3818
3819 **Validation run for this round.** `make build` and `make test` both exit 0,
3820 and `web/verify.js` reports 704/704 against `zig-out/bin/mux_core.wasm`, run
3821 directly as well as through the build graph. Every new assertion was watched
3822 failing first, against the mutation or the bug it exists for.
3823
3824 The cross-version gate ran too, containerised, with this tree against
3825 v0.0.1-5 in both directions: 9 passed, 0 failed, 1 skipped, the skip being
3826 the agent surface the old ref predates. What it measures about the wire
3827 change is the general property and not the specific frame — an old client
3828 ignores daemon-to-client frames it has no arm for and keeps parsing past
3829 them, because they are length-prefixed and its dispatch ends in
3830 `else => {}`. It could not be made to measure `selection_reply` itself,
3831 and that is a fact about the protocol rather than a gap in the rig: nothing
3832 can make a daemon send one to a client that never asks.