pmacs/pmacs-gpu
Levi Neuwirth 4bd3a76618
feat(panel): replay PanelPointer --- the wiring, the seam, and the producer half
First implementation commit for parent acceptance 48. The daemon-side
replay and every producer-side rule land here; the daemon-side witness
matrices (A1-A5, B1-B6, and Q#BP-R2's document->terminal row) are the
next commit and are NOT claimed yet.

**MODIFIERS NOW CROSS THE SEAM (R-a).** The daemon destructured `mods`
into `..` and the dispatcher had no parameter for them, which inverted
two behaviours rather than degrading them: `apply_terminal_gesture`
gates child reporting on `!shift`, so Shift is the user's "select
locally instead of talking to the child" override, and the document
path reads Shift to extend the selection.

**THE REPLAY IS THE SHARED PATHS, NOT NEW ONES.** A terminal panel goes
through `apply_terminal_gesture` --- "the one terminal pointer path,
shared by both frontend kinds" --- with the side window's
`TerminalViewKey` and a viewport of `rows - 1`, never the full grid: the
frame would make the mode line a child cell and put every clamp a row
out. A document panel scrolls through the window-scoped `scroll_window`
and replays selection through new window-TARGETED writers.

Those writers exist because the selection API is active-window scoped.
`Drag` and `Up` do not activate, and another frontend can interleave
between a `Down` and its tail, so a replay reading `active_window_mut()`
would act on whatever happened to be active then. `panel_cell_byte`
converts against the SIDE window's own `view_top` and fold map without
`activate_and_position`'s `set_active_window_id`. The one place the
ambient helper is used is the double-click word selection, two
statements after the `Down` activated that window synchronously, and it
says so.

**Q#BP-R2 IS ORDERED, NOT MERELY PLACED.** A terminal panel's chrome
wheel is consumed before `focus_window`, before `active_frontend`,
before any controller claim and before the shared path --- `activates`
is `!Move` for a terminal, so a check any lower would leave the wheel
changing FOCUS while scrolling nothing.

Producer half, all target-blind because `PanelFrame` carries no
target-kind field:

  - a press on the band's MODE LINE neither sends nor arms. Arming
    would let a drag into content emit a `Drag` with no accepted
    `Down`, which no receiver-side rule can undo.
  - `gesture_last_content_cell`, a TERMINATION FALLBACK distinct from
    the dedupe baseline. `last_pointer_cell` is cleared on press
    precisely so the first drag after a press reaches the daemon
    (asserted at `main.rs:19841`); storing the press cell there would
    suppress it. The new field is written on arm and on each accepted
    content motion, cleared on release and on either identity change,
    and `panel_motion_is_new` never consults it.
  - a crossing `Drag` is normalized and then deduped; `Up` is always
    sent, always at a content coordinate.
  - the gesture latch now dies on a change of EITHER identity --- panel
    or geometry --- and survives a same-identity repaint.

Six mutations, each biting its own row:

  M-P1  arm on a chrome press          -> the producer arming row
  M-P2  release reads the dedupe field -> the chrome and no-motion rows
  M-D1  no reset on panel epoch        -> the identity row
  M-D2  no reset on geometry epoch     -> the identity row
  M-D3  reset clears `pointer_held` only -> the identity row
  M-D4  reset on every frame           -> the identity row's negative leg

M-P2 caught a defect in my own witness before it caught the code: the
no-intervening-motion row called `panel_motion_is_new` BEFORE asserting
the release, which populated the very field the mutation reads, so a
conflated implementation passed. The probe now runs after the
assertion, and the row is named for a scenario it actually performs.

One existing test moved with the contract rather than against it:
`a_held_button_makes_panel_motion_a_drag_and_a_release_lands_outside`
poked `panel_motion_is_new` and expected the release to follow it. It
now drives both fields as the production motion path does; its
assertion, and the dedupe guarantee it protects, are unchanged.

Gates: all nine green under `env -u TMPDIR`, log 20260814T151901Z.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-14 17:24:04 +02:00
..
fonts feat(math): bundle Latin Modern Math and read its MATH constants 2026-07-24 18:27:34 -04:00
src feat(panel): replay PanelPointer --- the wiring, the seam, and the producer half 2026-08-14 17:24:04 +02:00
Cargo.toml feat(release): binaries on tag — Distribution Stage 1 2026-08-01 14:40:47 -04:00