pmacs/pmacs-protocol
Levi Neuwirth 34f7913f9d
feat(protocol): one scroll classifier, so the frontends cannot disagree
First implementation commit for QoL Stage 3 (framing section 5d.6,
COHERENCE section 16).

ScrollPosition and a pure classify() land in pmacs-protocol. Not a wire
type, and deliberately not presentation either. The split: each
frontend computes its own local layout facts --- whether the buffer's
first or last row is on screen is a question only the frontend that
laid the text out can answer --- while the shared crate owns the
semantic decision those facts feed. Rendering to a string stays in each
frontend.

No wire message and no protocol-version bump. classify is a pure
function over values each side already holds.

Why it cannot take the existing four counts. format_scroll_indicator
derives EVERY branch from total_lines, and line wrapping leaves no row
total to give it: the GPU shapes only its viewport slice, so it cannot
count rows it never laid out, and computing a total arithmetically
would disagree with the break points cosmic-text actually chose.
Handing that signature byte counts instead would make

  view_top + visible >= total_lines

compare rows against bytes --- plausible strings, meaningless
arithmetic. So the mixing is not avoided here, it is unrepresentable:
two decided predicates and a byte pair, and no count of rows enters the
module at all.

The bug this forecloses is not hypothetical. pmacs-gpu depends on
pmacs-protocol and never on the pmacs lib, so the readout was
duplicated STRUCTURALLY --- once in src/editor.rs, once in
pmacs-gpu/src/main.rs, each with its own tests. During this lane's
review a fix landed in one copy while the other kept reporting "All"
for a wrapped one-line buffer. The GPU's own test pins the premise
today: format_scroll_indicator(0, 10, 1, 0) == "All", and a wrapped
single line still has total_lines == 1.

a_wrapped_single_line_is_top_not_all is that case, and it passes here
for a structural reason rather than a careful one: the classifier is
never told how many lines there are.

Five tests including degenerate totality --- empty buffer, cursor past
the end, u64::MAX offsets --- and a range sweep asserting Percent never
leaves 0..=100.

Gates: fmt, workspace clippy -D warnings, diff --check,
pmacs-protocol --lib 24/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-06 23:04:38 +02:00
..
src feat(protocol): one scroll classifier, so the frontends cannot disagree 2026-08-06 23:04:38 +02:00
Cargo.toml feat(vterm): protocol v19 terminal frames and a native GPU terminal 2026-07-22 13:28:35 -04:00