Own branch, own slice, protocol-bearing, runs alone. Framing only; no
implementation. Blocks `panel-pointer-replay`, which blocks GUI arc 1b.
Answers review of revision 13. Every item below reverses or completes
something 13 got wrong.
**GATING IS REFUSAL, NOT FALLBACK.** Revision 13 said a bare
`PanelPointer` from a new peer would be "handled under the old
semantics". That is a BYPASS: it leaves the exact hole this slice
exists to close, reachable by omitting a field. A >= v25 session
sending the legacy event is REFUSED before mutation, and a >= v25
frontend REJECTS a legacy `Present` rather than painting a band it
cannot safely hit-test. Only negotiated <= v24 keeps legacy semantics;
`Absent` stays common to both families.
**ONE AUTHORITATIVE PER-FRONTEND KEY**, used by projection AND inbound
validation, advanced after any mapping mutation and BEFORE the next
inbound pointer is handled --- whether or not anything has rendered.
Comparing against the last EMITTED frame recreates the hole, because a
mutation not yet painted has still changed the inverse mapping.
**STALE TAILS TERMINATE; THEY DO NOT VANISH.** A blanket drop breaks
liveness: a refused `Up` leaves an empty document selection armed with
a stale anchor, and leaves a reporting terminal child HOLDING A BUTTON
FOREVER. Cancellation is now a ruled outcome --- producer latch reset,
daemon selection and click-chain cleanup, and the child's release
delivered at the last coordinate known good. A cancelled gesture is
explicitly not a replayed one: the release is for liveness, and no
selection or scroll effect is applied from the stale event. Stale
BEGINNINGS may still simply drop.
**THE DOMAIN WAS INCOMPLETE.** `view_left` is added, because 1b makes
horizontal scrolling real. "Cursor movement is stable" is now
CONDITIONAL: a cursor move that triggers vertical or horizontal follow
changes `view_top` or `view_left` and therefore does change the
mapping. Terminal panels are ruled explicitly --- their coordinates are
decided by the SCREEN, so output and scrollback movement change the
generation while their buffer revision does not.
**SS5b HAD NO ACCEPTANCE MATRIX.** G1-G11 now cover the foreign edit
before render, every changing and stable domain entry ROW BY ROW, a
selection repaint that must preserve the generation and let a drag
continue, mid-gesture cancellation, v24 and v25 positive controls with
both wrong-family refusals, identical cells across a generation change
still emitting, atomic retention of frame and generation on an invalid
frame, and fail-closed exhaustion. The per-entry enumeration is
deliberate: one aggregate row cannot show WHICH input moved the key,
and a key ignoring `view_left` passes every vertical-only row.
**MAPPED MOTION KEEPS ITS COALESCING TAGS.** A new variant falling
through to the lossless default would put pixel-rate `Move`/`Drag` on a
bounded queue.
**PINS ACCUMULATE.** Revision 13 said the pin "moves", which would
delete coverage of the shape it protects. `PanelPointer` is retained;
exact `TextInput` bytes are added as the previous-final
`FrontendEvent`; the complete nested `PanelFrame(Absent)` bytes are
added as the previous-final `PanelFramePayload`. Recorded honestly: I
could find NO exact-bytes pin for `PanelPointer` anywhere in the tree,
though `pmacs-protocol/src/message.rs:524` says one is in the tests.
Either my search missed it or the doc overclaims; this slice resolves
it either way, since it must add exact pins regardless.
**AND THIS SLICE OWNS THE VERSION CORRECTION.**
`docs/gui-stage1-input-framing.md` now says 1e's `OpenTarget` is
**v26**, with the reason stated at the top. An expected rebase conflict
on `gui-stage1b-pointer-scroll` is not grounds for leaving the
canonical document false --- which is what I argued last round, and it
was wrong. `ADVERTISED_PROTOCOL_VERSION` stays pinned at 20.
Gates: all ELEVEN green under `env -u TMPDIR`, with `--protocol`
(`build-crdt`, `sweep-crdt`), log 20260814T162843Z.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Adds the approved framing for the bottom-panel arc: a buffer displayed
in a fixed-height window pinned to the bottom of the frame, targeted by
policy rather than by stealing the selected window, plus the missing
display-buffer/window-parameter concept underneath it.
Revision 4 follows three review rounds, an integration review, and a
landed-state audit against GPU initial target (#148, protocol v20) and
folding Stage 2 (#149).
Amended before branching by the pre-implementation dependency
verification recorded in section 0.6:
- the folding dependency is cleared and re-verified against canonical
main at ddaa80d (nothing in flight, folding Stage 2 acceptance 48/48
green, every borrowed anchor reproducing, and folding's only window.rs
edit confined to one 22-line hunk that leaves the layout functions
pre-folding code);
- R5-B1: Layout::compute has TWO production callers, not one. The
second, the peer-presence overlay pass in src/overlay_paint.rs, builds
its own text-area rect from active_layout() and never routes through
window_placements, so the planned compute(area, fixed) signature change
would otherwise leave every peer cursor painted at its no-panel row.
Corrected in section 1.1 and Q#BP2, pinned by acceptance 1, and the
fixed map is now specified to come from one shared helper rather than
being assembled per call site.
Stage 1 (window placement + TUI side windows) changes no wire shape.