docs(vterm): carry approved stage 3 framing onto the implementation branch

Revision 8 of docs/vterm-framing.md was reviewed and approved on the
documentation branch vterm-stage3-framing. Stage 3 is implemented on this
branch, cut from canonical main, rather than stacked on that branch.

The framing locks additive protocol v19 (TerminalFrame, TerminalResize,
TerminalPointer), an 8 MiB aggregate glyph-byte bound under the unchanged
16 MiB transport cap, dual viewport declaration after every semantic
snapshot, authenticated per-view routing, and a fixed-cell native GPU
renderer. Criteria 28-37 are the scope of this branch.
This commit is contained in:
Levi Neuwirth 2026-07-22 11:46:45 -04:00
parent 1dd47fcad1
commit 3adac8c4cb
4 changed files with 526 additions and 208 deletions

View File

@ -14,7 +14,8 @@ backlog.
machine-local: `origin` may name this canonical URL, a release mirror,
or something else, and therefore has no authority by name alone.
- Canonical base at this snapshot:
`githubsucks/main` @ `86fc1bc` (Vterm Stage 2 #130 merged; protocol v18).
`githubsucks/main` @ `1dd47fc` (modeline detection #132 merged atop Vterm
Stage 2 #130; protocol v18).
- On the transfer source, `origin/main` named a release mirror at
`d3fa632` and lagged badly. On the current destination, `origin` names
the canonical URL. This difference is why all recovery begins by
@ -48,44 +49,43 @@ git worktree list
git status --short --branch
```
The first command must expose `86fc1bc` or a newer intentional main.
The first command must expose `1dd47fc` or a newer intentional main.
If it does not, stop and repair the remote/fetch configuration.
## Modeline detection implementation lane
## Vterm Stage 3 framing lane
- Portable branch: `githubsucks/modeline-detection`
- Approved framing head: `6b4f3c3`
- Implementation head: `f8d05d2`
- Base: originally canonical `main` @ `d5d9b9c`; current canonical `main`
@ `86fc1bc` (Vterm Stage 2 #130) is integrated before merge.
- PR: #132, <https://github.com/levineuwirth/pmacs/pull/132>, open against
canonical `main` and explicitly authorized for merge.
- State: Revision 2's bounded Emacs/Vim parser, explicit-over-inferred
precedence, alias normalization, shared fresh-load language pin, LSP path
guard, and all thirteen acceptance criteria are implemented. Protocol
remains v18.
- Verification:
- focused modeline + shebang-pin acceptance before integration: 7 passed on
default LuaJIT and 7 passed on non-default Lua 5.4;
- post-integration `cargo fmt --check`;
- post-integration `cargo clippy --workspace --all-targets -- -D warnings`;
- post-integration `cargo test --lib`: 1,753 passed;
- post-integration `cargo test --lib --features crdt`: 1,929 passed;
- post-integration `cargo test --test m4_acceptance -- --skip basedpyright`:
120 passed, 3 ignored, 1 filtered;
- post-integration `PMACS_REQUIRE_GPU=1 cargo test -p pmacs-gpu`: 109 passed;
- post-integration `cargo test --workspace -- --skip basedpyright`: 2,888
passed across 82 suites, 19 ignored, 1 filtered;
- `git diff --check`.
- Next: push the current-main integration and merge PR #132 as authorized.
- Portable branch: `githubsucks/vterm-stage3-framing`
- Framing contract commit: `d7bb831`; Revision 8 review fixes: `c72dfea`;
both follow canonical-main integration.
- Base: canonical `main` @ `1dd47fc` (modeline detection #132 atop Vterm
Stage 2 #130), protocol v18.
- PR: none. This is framing only; no Stage 3 implementation branch exists.
- State: `docs/vterm-framing.md` Revision 8 maps criteria 2837, has passed
one external review, and awaits explicit user approval. It locks additive
protocol v19 `TerminalFrame`, `TerminalResize`, and `TerminalPointer`; an
8 MiB aggregate glyph-byte bound under the unchanged 16 MiB transport cap;
dual viewport declaration for the first terminal frame; authenticated
per-view semantic routing; and a fixed-cell native GPU renderer/input/cache
contract.
- Stage 2 is landed as PR #130 at merge `86fc1bc`. Stage 3 starts from that
integrated substrate and does not reopen its TUI/Lua/controller contracts.
- Review: no architectural defect. `c72dfea` makes the measured-size fixture
maximize style and cluster-prefix overhead, names the GPU clipboard signal
path without implying child OSC 52 support, and aligns Arc 5/internal-stage
naming.
- Verification: documentation-only `git diff --check`; framing consistency
search. No runtime gates apply before implementation.
- Next: explicit user approval. After approval, create `vterm-gpu` from the
then-current canonical main and implement criteria 2837; do not stack the
feature on this documentation branch.
Recovery worktree on a machine that does not already own the branch:
```sh
git worktree add --track \
-b modeline-detection \
../pmacs-modeline-detection \
githubsucks/modeline-detection
-b vterm-stage3-framing \
../pmacs-vterm-stage3-framing \
githubsucks/vterm-stage3-framing
```
## Parked lane: kill-ring browser + persistence

View File

@ -1,10 +1,10 @@
# Agent handoff — cross-machine continuity
**Last updated: 2026-07-22, after Vterm Stage 2 PR #130 review round 2
was addressed and approved for merge; mode system wiring (#129) and its
handoff (#131), config registry (#127), Vterm Stage 1 terminal core (#126),
and completed Themes Arc 4 (#120/#124/#125) are landed on `main`. Vterm
Stage 3 is not implemented.**
**Last updated: 2026-07-22, after Vterm Stage 2 landed as PR #130 and
modeline detection landed as #132. Mode system wiring (#129), config registry
(#127), Vterm Stage 1 terminal core (#126), and completed Themes Arc 4
(#120/#124/#125) are also on `main`. Vterm Stage 3 framing Revision 8 has
passed one external review and is not implemented.**
This file is the
bridge between development machines. If you are an agent reading
this on a fresh clone: this document plus the `docs/*-framing.md`
@ -18,9 +18,9 @@ commands, read `docs/active-work.md` immediately after this file.
## 1. Where the project stands (2026-07-22)
- `main` @ `d5d9b9c` (mode system handoff #131), protocol **v18**
(`SUPPORTED=[6..18]`; v16 = `ThemeFacts`, v17 = `FontFacts`, v18 =
`StatuslineSegments`).
- `main` @ `1dd47fc` (modeline detection #132 atop Vterm Stage 2 #130),
protocol **v18** (`SUPPORTED=[6..18]`; v16 = `ThemeFacts`, v17 =
`FontFacts`, v18 = `StatuslineSegments`).
- **Config registry LANDED — #127** (`docs/config-registry-framing.md`
rev 3; merge `2e37c04`; two review rounds). `pmacs.config` is the
typed, introspectable options registry the backlog ranked first, and
@ -246,10 +246,11 @@ commands, read `docs/active-work.md` immediately after this file.
behavioral bite; the original `main`/crate-root bite remains explicitly
weaker compile-time API evidence.
- Stage 3 owns `pmacs-gpu/src/attach.rs`, authenticated source routing,
protocol-owned wire types/limits, and a deliberate complete-frame limit
decision: 16 MiB is insufficient; use a measured legal-worst cap or
aggregate bound, never silent chunking.
- **Stage 2 TUI is implemented on `vterm-tui`** (`docs/vterm-framing.md`
protocol-owned wire types/limits, and complete-frame semantic projection.
Revision 8 chooses a shared 8 MiB aggregate glyph-byte bound whose measured
legal maximum stays below the unchanged 16 MiB transport cap; over-bound
snapshots are rejected, never truncated or silently chunked.
- **Stage 2 TUI LANDED ON `main` — #130** (`docs/vterm-framing.md`
Revision 7, criteria 1527). `TerminalViewKey` keys per-frontend/window
projection state over one shared process/screen; logical row anchors retain
scroll/selection through reflow. One authenticated frontend controls at
@ -286,16 +287,26 @@ commands, read `docs/active-work.md` immediately after this file.
removes owned cell snapshots from terminal mouse routing. The framing now
records the transient v18 semantic-controller boundary and bracketed-paste
injection deferral.
- Current-main integration (`3f0252f`) preserves per-frontend terminal
dispatch while applying the landed mode-scoped keymap, and exposes the
`mode`, `terminal`, and `lsp` statusline providers together.
- Post-integration gate: `cargo fmt --check`; strict workspace Clippy;
- Current-main integration (`3f0252f`) preserved per-frontend terminal
dispatch while applying the landed mode-scoped keymap, and exposed the
`mode`, `terminal`, and `lsp` statusline providers together. PR #130 merged
at `86fc1bc`.
- Final integrated gate: `cargo fmt --check`; strict workspace Clippy;
1,753 default + 1,929 CRDT library tests (3 ignored each); mode-system
acceptance 1 default + 1 CRDT; Stage 1 acceptance 9 default + 10 CRDT;
Stage 2 acceptance 4 default + 4 CRDT; statusline acceptance 7 default +
8 CRDT; M4 114 passed (3 ignored, 1 filtered); required GPU 109;
workspace 2,882 passed across 82 suites (19 ignored, 1 filtered);
`git diff --check` clean.
- **Stage 3 framing is Revision 8 on `vterm-stage3-framing`**: additive
protocol v19 complete frames/events, dual viewport bootstrap, common
validation/aggregate limits, authenticated semantic view adapters, and
fixed-cell GPU rendering/input/cache behavior. Criteria 2837 are mapped.
First review found no architectural defect; `c72dfea` pins maximal style
and cluster-prefix overhead in the measured frame fixture, corrects the
GPU clipboard criterion, and distinguishes Arc 5 stage 2 from its internal
Stages 13. No implementation branch or PR exists pending explicit user
approval.
- **PARKED: kill-ring browser + persistence.** Revision 2 framing is
preserved on branch `kill-ring-browser`, but its `0efb5cd` scout is stale
and must be repeated before implementation. No PR or implementation is
@ -312,8 +323,9 @@ commands, read `docs/active-work.md` immediately after this file.
fix (#101).
- **Arc 4 (themes + extensibility) COMPLETE** — named UI faces (#120),
live GPU font preferences (#124), statusline providers (#125).
- **Arc 5 terminal stage ACTIVE** — compile mode (#113) and Vterm terminal
core (#126) landed; Vterm TUI is the next formal stage.
- **Arc 5 terminal stage ACTIVE** — compile mode (#113), Vterm terminal
core (#126), and Vterm TUI (#130) landed; protocol/GPU Stage 3 is framed
and awaiting approval.
- **Config registry COMPLETE (#127)** — not a numbered arc; it was the
cross-cutting substrate ranked first on
`docs/side-quest-backlog.md`'s north star, and it unblocks the
@ -551,8 +563,12 @@ currently accepted for `autosave.interval-ms`, where a per-buffer
value is meaningless.
**Tab width is NOT a config gap** — see §5.
Mode system (SHIPPED #129): minor modes, `buffer.after-mode-change`,
mode-scoped settings, modeline detection, `describe-mode`, and persistence of
explicit major-mode overrides/clears across sessions.
mode-scoped settings, `describe-mode`, and persistence of explicit major-mode
overrides/clears across sessions.
Modeline detection (SHIPPED #132): bounded first/last-line Emacs `-*-`
and Vim `ft=`/`filetype=` parsing, explicit-over-inferred precedence,
alias normalization, and shared fresh-load language pinning for
syntax/highlight/LSP startup.
Highlight/detection (from the #114#118 side-quest + injections #122):
locals-query processing (run each grammar's LOCALS_QUERY so
`#is?`/`#is-not? local` is honored instead of the current fail-closed
@ -564,8 +580,7 @@ comment schemes), child-tree incrementality + range-scoped layer rebuild
runtime/Lua-registered languages (v1 resolves only against
`BUILTIN_LANGUAGES`), and the next injection *consumers* gated on new
grammars — HTML/CSS/GraphQL/SQL (`<script>`/`<style>`, JS/TS template
literals, doc-comment code); modeline detection as a 5th layer
(`-*- mode: … -*-` / `# vim: ft=…`);
literals, doc-comment code);
byte-accurate multibyte cursor placement in `move_active_cursor_to`
(still steps one codepoint per LSP byte column). A full Jupyter `.ipynb`
setup (reader → editable → kernel execution) now has its JSON grammar

View File

@ -80,7 +80,7 @@ preference at protocol v17; and composable per-window
`pmacs.statusline` providers transported to semantic/GPU frontends by
protocol-v18 `StatuslineSegments`.
### Arc 5 — Terminal, staged — VTERM STAGE 2 ON FEATURE BRANCH
### Arc 5 — Terminal, staged — VTERM STAGE 3 FRAMED
- **Compile mode landed in #113**: line-oriented PTY/ANSI output,
error-regex navigation, and `M-x compile`.
@ -89,13 +89,14 @@ protocol-v18 `StatuslineSegments`.
encoders, internal `TerminalManager`, read-only identity buffers, process
lifecycle, control-free renderer-boundary cells, and headless real-PTY
acceptance.
- **Vterm Stage 2 TUI is implemented on `vterm-tui`**: terminal-window
composition, input/resize, per-context scroll/selection/copy, authenticated
frontend ownership, BEL/clipboard drainage, and the strict Lua surface.
- **Vterm Stage 3 protocol/GPU follows Stage 2**: additive protocol v19
complete frames, authenticated daemon routing, and native GPU terminal
rendering. Its framing must resolve the 16 MiB transport cap's incompatibility
with the legal worst complete terminal frame; never silently chunk.
- **Vterm Stage 2 TUI landed in #130**: terminal-window composition,
input/resize, per-context scroll/selection/copy, authenticated frontend
ownership, BEL/clipboard drainage, and the strict Lua surface.
- **Vterm Stage 3 protocol/GPU is framed at Revision 8**: additive protocol
v19 complete frames/events, an aggregate glyph-byte bound under the
unchanged transport cap, dual viewport bootstrap, authenticated semantic
routing, and native fixed-cell GPU terminal rendering. Implementation waits
for explicit framing approval.
### Arc 6 — Folding (keystone gutter rider)

View File

@ -1,22 +1,31 @@
# Vterm — framing (Arc 5 stage 2, three-PR delivery)
**Revision 7 — 2026-07-21. Status: Stage 1 landed on `main` as PR #126
at merge `643d1e1`; Stage 2 is implemented on branch `vterm-tui` and Stage 3
is not implemented.**
**Revision 8 — 2026-07-22. Status: Stage 1 landed on `main` as PR #126
at merge `643d1e1`; Stage 2 landed as PR #130 at merge `86fc1bc`; Stage 3
is framed here and is not implemented.**
Revision 7 closes the final three precision findings: `at_bottom` is geometric
and distinct from live-tail following; the fixed `C-c` transport escape
deliberately makes ordinary `C-c`-leading bindings unreachable in terminal
windows; and context-implicit Lua view operations require an authenticated
interactive origin with exact boolean/error results. Revision 6's durable
controller and per-view identities, logical-cell anchors, frontend-explicit
grid rendering, per-frontend dispatch, authenticated v18 input, local
clipboard/BEL drainage, default-name uniquification, mouse override, and
resize ordering remain unchanged. Main-screen resize reflows while alternate
screen clips/pads; exited buffers remain with an Emacs-style process message;
protocol v19 is additive with complete frames; shared `Style` stays unchanged;
and one `BufferId` owns one shared process/screen whose most recently accepted
frontend/window context controls size.
Revision 8 re-scouts the final stage against the integrated protocol-v18 tree
and closes its remaining producer/frontend boundary decisions. Protocol v19
uses one validated complete `TerminalFrame`; a shared 8 MiB aggregate glyph
budget keeps the largest legal postcard message below the existing 16 MiB
transport cap instead of broadening every connection's allocation ceiling.
The first-frame bootstrap is explicit: after every `BufferSnapshot`, a v19 GPU
sends the document viewport and, when the drawable terminal cell size is
nonzero, terminal-cell geometry; the daemon accepts only the declaration
appropriate to the authenticated active buffer.
Semantic terminal rendering is per frontend/window. Passive views never resize
the PTY, and terminal mode retains existing statusline, menu, minibuffer, and
BEL/clipboard channels while suppressing document projection and presence.
Revision 7's geometric `at_bottom`, fixed `C-c` transport escape,
authenticated context-implicit Lua operations, durable controller and per-view
identities, logical-cell anchors, frontend-explicit grid rendering,
per-frontend dispatch, authenticated v18 input, local clipboard/BEL drainage,
default-name uniquification, mouse override, and resize ordering remain
unchanged. Main-screen resize reflows while alternate screen clips/pads;
exited buffers remain with an Emacs-style process message; shared `Style`
stays unchanged; and one `BufferId` owns one shared process/screen whose most
recently accepted frontend/window context controls size.
This framing follows the compile-mode terminal substrate that landed in PR
#113. `src/process.rs` already owns PTY creation, process groups, bounded
@ -26,7 +35,8 @@ emits only the line-oriented subset compile-mode needs. Vterm does not replace
either subsystem. It extends their contracts and adds the missing terminal
screen state machine.
Arc 5 stage 2 ships as three separately reviewed PRs:
Arc 5 stage 2 (vterm) ships as three separately reviewed internal stages,
one PR each:
1. **terminal core** — full-screen VT events, `TerminalScreen`, internal
session ownership/contracts, and headless real-PTY acceptance;
@ -38,7 +48,7 @@ Arc 5 stage 2 ships as three separately reviewed PRs:
There is no single mega-PR. Each stage is useful and testable by itself, and a
later stage starts only after the preceding stage lands on `main`.
## 0. Revision 7 — landed Stage 1 and reviewed Stage 2 contract
## 0. Revision 8 — landed internal Stages 12 and framed Stage 3
The first of the three vterm PRs landed on `main` at merge `643d1e1`.
Implementation commits `bbc1f33` and `962944b`, first-review fixes through
@ -189,14 +199,13 @@ The final framing review pinned three precision contracts:
`active_frontend`.
Stage 3 additionally owns `pmacs-gpu/src/attach.rs` for gated terminal
resize/pointer sending and coalescing. New daemon event variants must apply the
resize/pointer sending and coalescing. New daemon event variants apply the
same authenticated-source rule. Wire-facing terminal state, selection, and
limits live in or are re-exported from `pmacs-protocol`. The current 16 MiB
transport frame cap cannot hold the legal worst complete terminal frame (up to
roughly 64 MiB of cluster bytes before encoding overhead): Stage 3 must either
raise and test a measured cap at least as large as the legal worst case
(review estimate at least 80 MiB), or add a shared aggregate payload bound. It
must never silently chunk the locked complete-frame protocol.
limits live in or are re-exported from `pmacs-protocol`. Revision 8 resolves
the complete-frame size finding with a shared 8 MiB aggregate glyph-byte
bound: the maximum legal encoded frame is measured below the unchanged
16 MiB transport cap. The producer rejects rather than truncates or silently
chunks an over-bound internal snapshot.
### 0.5 Stage 1 review round 1
@ -245,6 +254,55 @@ Out-of-range DECSTBM bottom clamping, CSI-intermediate clone removal, and a
separately named configuration-time scrollback-row cap remain explicit
deferrals in §11.
### 0.7 Stage 2 landing and Stage 3 re-scout
Stage 2 landed on `main` as PR #130 at merge `86fc1bc` after two review
rounds. Its integrated tree is the Stage 3 base: protocol v18, four terminal
view-state acceptance cases in both default and CRDT builds, 109 required-GPU
tests, and the authenticated daemon/TUI seams described in §§5 and 9. Stage 3
does not reopen the landed escape, controller, selection, copy, resize, or Lua
contracts.
The current tree exposes five Stage 3 integration facts that are now locked:
- A semantic frontend learns a buffer switch from `BufferSnapshot`, but an
empty terminal identity snapshot does not identify itself as terminal.
Therefore the GPU sends both its ordinary byte viewport and a
version-gated terminal-cell size after each snapshot; the daemon ignores the
inapplicable declaration. No buffer-kind flag or pixel geometry is added.
- The existing TUI layout adapter subtracts modelines and handles splits from
a whole terminal size. Reusing it for the GPU would subtract chrome twice.
Stage 3 adds exact active-window semantic adapters whose `CellSize` already
describes the terminal content rectangle.
- `screen_generation` does not cover selection, scroll, or process-state
changes. Silence is therefore based on equality of the complete ordered
wire payload, not on any one generation counter.
- The legal Stage 1 cell bounds can exceed the 16 MiB transport cap when every
cell carries a maximal combining cluster. Rather than raising the allocation
ceiling for all pre-handshake and established messages, v19 adds an 8 MiB
aggregate glyph-byte limit and proves the largest legal encoded frame stays
below `MAX_FRAME_BYTES`.
- The GPU's document shaper cannot define terminal column origins. Terminal
mode uses fixed cell geometry: explicit row/column rectangles own
background, underline, selection, cursor, clipping, and hit testing; text
runs are positioned at cell origins and never determine later cell
positions.
### 0.8 Stage 3 framing review round 1
The first external Stage 3 review verified the Revision 8 base, named seams,
limits, Stage 1/2 compatibility, and continuity state and found no
architectural defect. This round closes its three precision findings:
- The measured maximum payload fixture now maximizes legal `Style` bytes on
every cell and distributes the exact glyph budget across legal clusters with
lengths chosen to maximize serialized length-prefix overhead.
- GPU acceptance names terminal copy through `InstanceSignal::Clipboard` and
the existing OS clipboard path; it does not imply that child OSC 52 is
honored.
- Arc 5 stage 2 is the vterm delivery; capitalized Stages 13 are its three
internal PR stages.
## 1. Problem and ownership boundary
Pmacs can supervise a PTY and can parse enough ANSI to turn command output into
@ -881,25 +939,29 @@ interval by adding the semantic terminal surface.
## 6. Stage 3 — protocol v19 and GPU integration
### 6.1 Wire additions
### 6.1 Protocol-owned wire contract
Protocol v19 appends, never inserts, these final variants:
Protocol v19 appends, never inserts, one instance message and two frontend
events after the final v18 variants:
```rust
InstanceMessage::TerminalFrame {
buffer_id: BufferId,
size: CellSize,
cells: Vec<Cell>,
cursor: Option<CellCoord>,
title: Option<String>,
screen_generation: u64,
selection: Vec<TerminalSelectionSpan>,
scroll_offset: u32,
at_bottom: bool,
pid: u32,
process: TerminalProcessState,
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TerminalFrame {
pub buffer_id: BufferId,
pub size: CellSize,
pub cells: Vec<Cell>,
pub cursor: Option<CellCoord>,
pub title: Option<String>,
pub screen_generation: u64,
pub selection: Vec<TerminalSelectionSpan>,
pub scroll_offset: u32,
pub at_bottom: bool,
pub pid: u32,
pub process: TerminalProcessState,
}
InstanceMessage::TerminalFrame(TerminalFrame)
FrontendEvent::TerminalResize {
frontend_id: FrontendId,
buffer_id: BufferId,
@ -915,75 +977,247 @@ FrontendEvent::TerminalPointer {
}
```
`TerminalProcessState`, `TerminalSelectionSpan`, and every limit needed to
validate these values move to or are re-exported from `pmacs-protocol`; core
paths may re-export them so Stage 1/2 callers do not gain duplicate types.
The shared limits are the landed row, column, visible-cell, grapheme, and
metadata bounds plus:
```rust
pub const MAX_TERMINAL_FRAME_GLYPH_BYTES: usize = 8 * 1024 * 1024;
```
The aggregate counts each `Char`'s UTF-8 length, every `Cluster` byte, and zero
for `Continuation`, with checked addition. `TerminalFrame::validate` is the
single structural policy used before daemon emission and after GPU decode.
`pmacs-protocol` takes the direct `unicode-width` dependency needed to validate
one/two-column glyph and continuation topology; another frontend must not
copy that policy.
The existing `MAX_FRAME_BYTES = 16 MiB` remains unchanged. A protocol test
constructs the maximum row/column frame with one maximal legal selection span
per row and maximum title/process metadata. Every cell carries a legal
one-column `Cluster` plus the maximal-encoding legal `Style`: RGB foreground,
background, and underline color, a non-`None` underline, and all boolean flags
set. The fixture distributes the exact aggregate budget across a legal cluster
in every cell and chooses cluster lengths to maximize total serialized
length-prefix overhead rather than packing bytes into a few maximal clusters.
This maximizes cluster and per-cell style overhead together. It serializes
the enclosing `InstanceMessage` with `postcard::to_allocvec` and asserts the
measured length is below `MAX_FRAME_BYTES`. A one-byte-over aggregate is
rejected before serialization.
This is a wire-specific bound, not a mutation of the TUI screen: if a child
constructs a larger internal snapshot, the semantic producer retains its last
valid baseline, emits nothing malformed or truncated, and logs the first
distinct bounded error until a valid frame clears the latch.
`TerminalFrame` is a complete visible-grid replacement. Empty is not a clear
sentinel: valid terminal sizes are non-zero and `cells.len()` must equal area.
Complete replacement is chosen over a second diff/cache protocol for the first
GPU stage. `screen_generation` advances on screen/process/title mutation;
scroll/selection have their own per-context epochs. The producer caches and
compares the complete context payload, so a view-only change still sends even
when `screen_generation` is unchanged, while an identical payload is silent.
sentinel: valid terminal dimensions are nonzero and `cells.len()` equals the
checked area exactly. `screen_generation` describes the published terminal
screen/title generation; selection, scroll, viewport, and process state may
change without it. The producer compares every ordered field against one
retained baseline per semantic frontend context. A view-only change therefore
sends; a byte-identical/equal payload is silent. Buffer snapshot, detach, and
context replacement clear that baseline so the next valid terminal frame is
authoritative.
All terminal frame fields are untrusted at the GPU boundary. Validation checks
shared row/column/area limits, exact area, cursor bounds, title length,
selection ordering/non-overlap/bounds, cluster UTF-8 and cluster-byte limits,
continuation structure, and attachment absence.
Invalid input is rejected atomically and the last valid terminal frame remains
painted.
Validation is atomic and covers:
The daemon routes terminal resize/pointer events by authenticated session
source. Claimed frontend and buffer must match the source's active terminal
window. A mismatch is dropped without resizing, selecting, or writing PTY
input.
- shared nonzero row/column/checked-area and aggregate-glyph limits;
- exact cell area; each caller separately requires the expected current
`buffer_id`;
- cursor bounds;
- title and process-state metadata length/control-character rules;
- valid nonempty cluster UTF-8 within the per-cluster limit;
- printable one/two-column leading glyphs, required wide continuations, and no
orphan continuation; continuation style is ignored in favor of its lead;
- no `Attachment` in any terminal cell;
- strictly increasing, one-per-row, nonempty selection spans inside the frame;
- `at_bottom == (scroll_offset == 0)`.
The protocol remains compatible with v18 where structurally possible:
Invalid daemon output is never written. Invalid GPU input retains the previous
valid frame, requests no redraw, and reports one latched diagnostic rather than
partially applying cells or metadata.
- v18 grid peers need no new message and continue to receive composed
`CellDelta` terminal windows;
Compatibility remains additive:
- v18 grid peers keep receiving the Stage 2 composed `CellDelta` terminal
windows;
- v18 semantic peers receive the immutable empty identity snapshot but no
terminal variant. They cannot display the terminal screen; terminal use from
those peers is unsupported, while normal document editing remains supported;
- v19 frontends gate the new outbound event variants on negotiated version;
- postcard byte pins cover the old final variants plus the newly appended
discriminants.
terminal message. Terminal use remains unsupported and invisible for those
peers; ordinary document editing remains supported;
- v19 frontends send `TerminalResize`/`TerminalPointer` only to a negotiated
v19 daemon;
- the v19 daemon filters `TerminalFrame` from every wire below v19;
- postcard pins preserve every v18 discriminant and pin all three appended
v19 discriminants.
### 6.2 Semantic producer
### 6.2 First-frame bootstrap and authenticated routing
When a semantic frontend's active buffer is a terminal, its producer emits
`TerminalFrame` plus the existing global theme/font/statusline facts that still
apply. It suppresses document-only style spans, decorations, inlays, block
adornments, folds, file summaries, line numbers, and document cursor layout for
that buffer. On switching back to a document, existing caches are invalidated
so the first document frame is a full authoritative resync.
`BufferSnapshot` remains the one semantic display-switch message. It carries
the terminal identity buffer's valid empty CRDT state and adds no terminal
flag. Immediately after applying any snapshot, a v19 GPU sends the existing
`Viewport` for the new replica/generation and, when its derived terminal
content rectangle has at least one row and column, `TerminalResize` with the
new `buffer_id` and size in cells. A zero-area window sends no terminal
declaration until a later geometry change yields a valid size.
The terminal frame is scoped to the authenticated frontend/window context,
because scrollback offset and selection are per view. A frame for one split or
frontend must never overwrite another context's baseline.
The daemon authenticates the connection source before reading any claimed
`frontend_id`. A document buffer accepts only `Viewport`; an active terminal
buffer accepts only `TerminalResize`. The inapplicable declaration is dropped
without mutation or logging noise. This dual declaration occurs only after a
snapshot or an actual geometry change, not every frame, and removes the
otherwise circular dependency where the GPU would need a terminal frame before
it knew to request one.
A GPU frontend reports its terminal viewport in **cells**, computed from its
own font metrics and pixel allocation. No pixel dimensions, glyph advances,
or DPI cross the daemon boundary. The daemon accepts a resize only from the
controlling active frontend defined in §5.4.
For an authenticated active terminal window, a valid `TerminalResize` always
records that exact `(frontend, window, buffer)` view size so passive frontends
can receive their own clipped/padded projection. It resizes the PTY only when
that exact view is the durable controller from §5.4; resize never claims
control. The semantic adapter consumes a content `CellSize` directly and does
not run the TUI placement helper or subtract a modeline again. Unchanged,
zero/out-of-range, passive, and failed resizes retain existing geometry under
the Stage 2 ordering contract.
### 6.3 GPU renderer
`TerminalPointer` must match the authenticated source, active terminal buffer,
and last accepted terminal viewport, and its coordinate must be in bounds.
Once accepted, it follows the same Stage 2 terminal pointer path: child SGR
mouse reporting when eligible, otherwise per-view scroll/selection/context
menu. Like other accepted pointer/input/focus events, it may claim control.
A forged source, stale buffer, missing declaration, or out-of-bounds coordinate
is dropped before view, controller, selection, menu, or PTY mutation.
The GPU keeps a dedicated terminal render mode keyed by active `buffer_id`.
It does not synthesize rope text from cells. Layout rules:
Key, paste, focus, detach, BEL, and clipboard keep their landed event/message
types. The daemon continues to overwrite client-claimed IDs with the
authenticated source before terminal dispatch. Terminal mode adds no raw-byte
input message and never sends child bytes through Lua or a shell.
- one terminal column equals the active monospace cell advance;
- `Glyph::Continuation` consumes a column and draws nothing;
- clusters shape as one cell origin with the declared one/two-column footprint;
- terminal foreground/background/reverse/style resolve from the cell, not
syntax or UI faces;
- selection spans resolve through `ui.selection` over child cells; cursor
placement comes from terminal snapshot state;
- rows never wrap in the frontend; clipping is by terminal cell bounds;
- status band remains outside the terminal grid;
- theme/font changes invalidate terminal shaping and geometry caches;
- a font-size or window-size change recomputes the cell viewport and sends one
`TerminalResize` after suppression of identical sizes.
### 6.3 Semantic producer and editor adapters
Terminal mouse hit-testing is frontend-local pixel -> terminal cell. The GPU
sends `TerminalPointer`, never a fake source byte offset.
`SemanticRenderState` stores the optional terminal viewport and last valid
terminal-frame baseline for its one authenticated frontend. When the active
buffer is terminal and a matching viewport exists, it requests an owned
snapshot for the exact active `TerminalViewKey`, validates/converts it, and
emits `TerminalFrame` only on complete-payload change.
The editor-side contract is narrow:
```rust
prepare_semantic_terminal_view(
frontend_id: FrontendId,
buffer_id: BufferId,
size: CellSize,
) -> Option<TerminalSnapshot>
sync_semantic_terminal_layout(
frontend_id: FrontendId,
buffer_id: BufferId,
size: CellSize,
) -> bool
dispatch_semantic_terminal_pointer(
frontend_id: FrontendId,
buffer_id: BufferId,
size: CellSize,
coord: CellCoord,
kind: MouseKind,
mods: Modifiers,
) -> bool
```
Each method derives the active `WindowId` from `frontend_id`, verifies that it
still displays `buffer_id`, and delegates to the existing manager/view/input
state machines. No method accepts a client-supplied window identity. Semantic
layout sync runs after event coalescing, before `tick_processes`, exactly beside
the landed grid sync; snapshot production occurs on the following render pass
from the already-published screen.
The terminal producer retains the buffer-independent/UI messages required by
the native frontend: `StatusFacts`, `ThemeFacts`, `FontFacts`,
`StatuslineSegments`, `MenuPrompt`, and `MinibufferPrompt`, plus daemon-owned
`DispatchIdle`, `Signal`, and lifecycle messages. The built-in terminal
statusline provider therefore remains the source of title/process/scroll text.
It suppresses document-only style spans, decorations, inlays, block
adornments, folds, file summaries, search/completion surfaces, line numbers,
document `CursorByte`, and presence for the terminal identity buffer.
On terminal activation the GPU clears/ignores every document-local visual
cache before painting the first frame. On switching back, snapshot reset clears
the producer's document baselines so the first matching document viewport
receives the existing full authoritative style/decoration/summary resync.
Terminal baselines are per frontend context; one split/frontend can never
suppress or overwrite another's scroll/selection projection.
### 6.4 GPU state and fixed-cell renderer
The GPU state machine is explicit: `Document` or
`Terminal { buffer_id, frame, derived paint caches }`. `BufferSnapshot`
immediately leaves terminal mode, clears the prior terminal frame and
terminal-only caches, and restores document defaults. A valid matching
`TerminalFrame` enters terminal mode. A stale-buffer frame is ignored; an
identical valid frame is retained without rebuild or redraw.
Terminal geometry is the drawable code rectangle above the existing status
band, with no document gutter or minimap. Rows and columns are
`floor(pixel_extent / active_cell_metric)`, clamped through the shared
nonzero protocol limits. Pixels, scale, DPI, and glyph advances never cross
the wire. Rows never wrap; excess frame rows/columns clip to the declared cell
rectangle and undersized content is padded with terminal defaults.
Painting is cell-derived rather than rope-derived:
- Every cell rectangle has a fixed origin from `(row, col)` and the active
monospace metrics. Backgrounds coalesce only adjacent equal resolved colors.
- `Default` foreground/background map to the GPU's existing plain-text/window
defaults; indexed colors use the existing xterm palette; truecolor is exact.
`reverse` swaps the two resolved colors. A continuation draws no glyph and
inherits its lead cell's paint semantics.
- Text shaping is split into explicitly positioned row runs. Contiguous
single-width ASCII may share one monospace buffer with rich attribute spans;
non-ASCII/cluster/wide leads start at an explicit cell origin and are clipped
to their declared one/two-cell footprint. A shaped advance never chooses the
next run's column.
- Bold and italic use font attributes. Single/double/dotted/dashed underlines
use fixed-cell quads; curly uses the existing squiggle pipeline. Default
underline color follows the post-reverse foreground.
- Terminal selection is a separate fixed-cell wash resolved through the
existing GPU `ui.selection` site; it never rewrites child cell styles.
Cursor visibility/position comes only from the frame and paints through the
existing caret primitive inside the terminal clip.
- The status band and its provider runs remain outside/above terminal paint.
Document decoration, presence, caret, gutter, and minimap batches are not
prepared or drawn in terminal mode.
### 6.5 GPU input, signals, and cache invalidation
Keyboard, paste, focus, and detach reuse existing attach messages and daemon
encoding. Inside the terminal clip, GPU mouse hit testing is
pixel-to-`CellCoord`; press/release/drag/move/wheel sends `TerminalPointer`
instead of a source-byte `Pointer`. The status band/outside clip is never a
terminal hit. Move/drag events coalesce only while kind, coordinate, and
modifiers are unchanged.
Window resize, scale change, accepted `FontFacts`, and buffer snapshot
recompute the cell viewport. One changed size sends one version-gated
`TerminalResize`; an equal size is silent. A font change clears terminal shape
and geometry caches until a matching-size authoritative frame arrives.
Invalidation is deliberately narrow:
- a changed terminal frame rebuilds cell text/background/underline/selection/
cursor data, but not statusline buffers;
- `ThemeFacts` rebuilds the selection/status color sites, not child cell
shaping;
- `FontFacts` rebuilds shape and geometry and emits a changed cell viewport;
- status/statusline/menu/minibuffer messages touch only their existing caches;
- a duplicate valid terminal frame and an unchanged geometry declaration do
no work.
`InstanceSignal::Bell` requests one frontend attention event for each new
active-terminal BEL; historical/passive suppression remains daemon-owned.
`InstanceSignal::Clipboard` keeps the existing OS clipboard path. OSC title is
sanitized frame/statusline metadata only and never becomes a raw window-title
or terminal-control operation.
## 7. Four-agent execution plan
@ -993,19 +1227,20 @@ coherent.
| Owner | Stable scope | Primary files |
| --- | --- | --- |
| Lead/integrator | contracts first; `TerminalManager`, Lua/builtin wiring, lifecycle/signal integration, shared acceptance, gates, docs, branches/PRs | `src/terminal/session.rs`, `src/lua_bindings/mod.rs`, `builtin/runtime/terminal.lua`, narrow Stage 2 authenticated-dispatch sections of `src/daemon.rs`, `tests/vterm_*_acceptance.rs`, docs |
| VT core agent | encoder corrections and screen query seams needed by view projection; no renderer ownership | `src/ansi.rs`, `src/terminal/screen.rs`, `src/terminal/input.rs` |
| TUI agent | view projection, frontend-explicit grid composition/cursor, per-frontend dispatch, local events, scroll/selection/copy/resize | `src/terminal/view.rs`, `src/instance_render.rs`, `src/frontend.rs`, owned sections of `src/editor.rs`, focused TUI tests |
| Protocol/GPU agent | Stage 2 contract review; Stage 3 v19 types/limits/gates, semantic producer, authenticated new-event routing, GPU state/render/hit-test | `pmacs-protocol`, `src/protocol.rs`, `src/semantic_render.rs`, Stage 3 sections of `src/daemon.rs`, `pmacs-gpu/src/{main,attach}.rs` |
| Lead/integrator | contracts first; Stage 1/2 manager/Lua lifecycle; Stage 3 semantic producer, authenticated daemon routing, shared acceptance, gates, docs, branches/PRs | `src/terminal/session.rs`, `src/lua_bindings/mod.rs`, `builtin/runtime/terminal.lua`, `src/semantic_render.rs`, owned Stage 3 sections of `src/daemon.rs`, `tests/vterm_*_acceptance.rs`, docs |
| VT core agent | encoder/screen seams; Stage 3 snapshot-to-wire conversion and shared terminal re-exports, no renderer ownership | `src/ansi.rs`, `src/terminal/{screen,input,session,view}.rs` in assigned non-overlapping sections |
| TUI agent | landed TUI projection/input; Stage 3 exact active-window semantic adapters and parity tests, no GPU/protocol files | owned sections of `src/editor.rs`, focused TUI/adapter tests |
| Protocol/GPU agent | protocol v19 types/limits/pins/gates and native GPU state/render/hit-test/attach sending | `pmacs-protocol`, `src/protocol.rs`, `pmacs-gpu/src/{main,attach}.rs` |
Coordination rules:
- Lead establishes types, invariants, and method signatures before another
lane edits callers.
- Strict file ownership. `src/editor.rs` passes from lead to TUI only after
construction wiring; lead and TUI coordinate exact non-overlapping
`src/daemon.rs`/signal hunks. Stage 3 daemon work begins only after Stage 2
lands.
- Lead establishes invariants and method signatures before another lane edits
callers; the protocol/GPU agent then implements the shared wire types.
- Strict Stage 3 file ownership follows the table. VT-core and TUI edits in
`src/terminal/{session,view}.rs` / `src/editor.rs` are agreed as exact
non-overlapping symbols before work starts. Only the lead edits
`src/semantic_render.rs`, Stage 3 daemon routing, or shared acceptance.
Stage 3 begins only from landed Stage 2.
- Workers do not update docs, ledgers, branches, or PRs and do not stash,
checkout, rebase, or merge.
- Workers add focused tests in owned modules. Lead alone owns shared
@ -1021,25 +1256,33 @@ Per-stage utilization:
- Stage 2: lead establishes manager/Lua contracts and authenticated adapters;
TUI implements projection/input/rendering; VT core adds only required
encoder/query corrections; protocol/GPU checks snapshot neutrality.
- Stage 3: protocol/GPU implements; TUI and VT core add parity cases in their
existing surfaces; lead integrates and gates.
- Stage 3: lead locks the protocol constants/types and editor method signatures,
then owns `src/semantic_render.rs`, authenticated `src/daemon.rs` routing,
shared acceptance, and integration. The protocol/GPU agent owns
`pmacs-protocol` plus `pmacs-gpu/src/{main,attach}.rs`; the VT-core agent owns
snapshot-to-wire conversion/shared terminal re-exports; the TUI agent owns
the exact semantic adapters in `src/editor.rs` and parity tests. All four run
in parallel only after the lead's contract checkpoint; no TUI rendering
behavior changes.
## 8. Branch and PR plan
Stage 1 landed on `main` as PR #126 at merge `643d1e1`. Continue one clean PR
at a time:
Stage 1 landed as PR #126 at merge `643d1e1`. Stage 2 landed as PR #130 at
merge `86fc1bc`. Revision 8 is preserved for approval on
`vterm-stage3-framing`, based on the integrated current `main`.
1. Revision 7 framing review is complete and the implementation contract is
approved; Stage 2 is implemented on `vterm-tui`, then gated and opened as
the second PR;
2. merge Stage 2 only when the user says;
3. create `pmacs-vterm-gpu`, branch `vterm-gpu`, from the then-current `main`;
implement, gate, and open the third PR.
After explicit framing approval:
The framing branch is `vterm-framing` in worktree `pmacs-vterm-framing`.
Implementation branches are not stacked across an unmerged parent. This avoids
base-branch deletion/auto-close risk and makes each PR's gate evidence honest.
1. create worktree `pmacs-vterm-gpu` and branch `vterm-gpu` from the then-current
canonical `githubsucks/main`;
2. implement only Stage 3 / criteria 2837;
3. run the complete sequential gate and bite suite;
4. open the third and final vterm PR for user review; never merge it without
explicit authorization.
The historical framing branch `vterm-framing` remains the Revision 7 record.
The Stage 3 implementation is not stacked on a documentation branch or an
unmerged feature parent.
## 9. Acceptance
@ -1184,47 +1427,97 @@ coverage remains beside the owning implementation. The criteria map as follows:
### Stage 3 — GPU/protocol
28. Protocol v19 appends all new variants after v18 pins; v18 grid traffic
round-trips unchanged and new outbound variants are version-gated.
29. Terminal frame validation accepts exact shared boundaries and atomically
rejects over-area, bad area, out-of-bounds cursor, malformed cluster,
orphan continuation, invalid selection spans, attachment, overlong title,
and overlong process-state text while retaining the prior valid frame.
30. Semantic terminal activation suppresses document-only messages; switching
back forces a complete document resync.
31. Two frontends/splits on one terminal keep independent scroll/selection
snapshots; only the active controlling context resizes or writes input.
32. Forged frontend/buffer IDs in terminal resize/pointer events cannot affect
another terminal or process.
33. Headless GPU rendering pins background rectangles, indexed/truecolor,
reverse, wide/combining cells, clipping, cursor visibility, status-band
separation, and no frontend wrapping.
34. Font/window resize emits cell dimensions, never pixels, and identical
resize requests are suppressed.
35. Theme/font/terminal generation changes invalidate exactly the affected
caches; an unchanged terminal frame produces no redraw message.
36. A real daemon + required-GPU smoke runs a full-screen alternate-screen
probe, handles input and resize, exits, and returns to the preserved main
screen.
28. Protocol v19 appends all three new variants after the v18 pins; v18 grid
traffic round-trips byte-identically, v18 semantic document traffic still
works, and both outbound directions are independently version-gated.
29. The measured maximum legal frame uses maximum dimensions, one maximum
selection span per row, maximum metadata, the exact aggregate glyph budget
present as one legal cluster per cell with lengths chosen to maximize
serialized length-prefix overhead, and the maximal-encoding legal style on
every cell. Its enclosing message encodes below the unchanged
16 MiB transport cap. Validation accepts exact shared boundaries and
atomically rejects one-byte-over aggregate, over-area, bad area,
out-of-bounds cursor, control/malformed/overlong clusters, orphan/missing
continuations, attachments, duplicate/out-of-order-row or otherwise
invalid selection spans, inconsistent bottom state, overlong title, and
overlong process text while retaining the prior valid frame.
30. First terminal activation emits one authoritative complete frame after the
dual viewport declaration, then stays silent for a completely equal
payload. View-only and process-only changes emit despite an unchanged
screen generation. Terminal activation suppresses document projection,
cursor, presence, gutter, and completion; switching back forces one
complete document resync.
31. Two semantic frontends over one terminal receive independent sizes,
scroll, selection, cursor visibility, and baselines while sharing one
process/screen. A passive declaration produces its clipped/padded frame but
does not resize; only the exact durable controller changes PTY geometry.
32. Forged frontend/buffer IDs, stale buffers, undeclared viewports, and
out-of-bounds terminal pointer/resize events cannot affect another view,
controller, terminal selection, menu, PTY size, or child input.
33. Headless GPU rendering pins default/indexed/truecolor foreground and
background, reverse, bold/italic, all supported underline forms, wide and
combining footprints, continuation inheritance, selection, cursor,
padding/clipping, status-band separation, and absence of frontend wrapping,
document gutter/minimap, and document overlays.
34. GPU key, paste, focus, press/release/drag/move/wheel input reaches the same
Stage 2 terminal encoders and ownership paths. Pixel hit testing yields only
in-bounds cells, never source bytes or wire pixels, and unchanged move/drag
cells coalesce.
35. Buffer/window/scale/font transitions emit exactly one changed cell
declaration and suppress identical sizes. Terminal, theme, font, and
statusline changes invalidate only their named caches; duplicate valid
frames request no redraw.
36. Each new active BEL produces one GPU attention action. Terminal copy
publishes through `InstanceSignal::Clipboard` and the existing OS
clipboard path exactly once. Sanitized OSC title/process/scroll metadata
reaches the terminal provider/statusline without becoming a raw host-title
or control effect.
37. A hermetic real daemon + required headless GPU smoke opens `/bin/sh`, runs
a full-screen alternate-screen probe, exercises key/paste/mouse/resize,
BEL/title metadata, scroll/select/copy through the clipboard signal, clean
exit, and buffer switch-back, then proves the preserved main screen and all
child/reader/session cleanup.
#### Stage 3 verification map
The cross-surface suite is `tests/vterm_stage3_acceptance.rs`; focused wire and
GPU assertions remain in `pmacs-protocol` and `pmacs-gpu` respectively.
- **2829:** postcard discriminant/round-trip pins, common
`TerminalFrame::validate` boundary table, measured maximum legal payload, and
v18/v19 daemon/frontend send filters.
- **3032:** semantic producer baseline/reset tests, dual-declaration
bootstrap, real dispatcher source-forgery tests, and two-frontend
controller/passive-view acceptance.
- **33:** pure fixed-cell paint-plan tests plus required headless offscreen
pixel probes for representative color/style/wide/selection/cursor/clipping
cases.
- **3436:** attach/event coalescing tests, authenticated daemon input tests,
and headless signal/statusline observations.
- **37:** one real-daemon/real-PTY/headless-wgpu acceptance path; it is not
replaced by a decoded-message fixture.
## 10. Gates and bite verification
Every PR runs the standing full gates from `AGENTS.md`, sequentially, plus its
stage acceptance suite. Stage 2 includes a real hermetic TUI PTY smoke; stage 3
includes `PMACS_REQUIRE_GPU=1 cargo test -p pmacs-gpu` and the real-daemon GPU
probe.
stage acceptance suite. Stage 2 included a real hermetic TUI PTY smoke. Stage 3
adds `cargo test --test vterm_stage3_acceptance`, its CRDT variant,
`PMACS_REQUIRE_GPU=1 cargo test -p pmacs-gpu`, the real-daemon/headless-GPU
probe, and the ordinary workspace sweep.
New behavioral acceptance must be bite-verified against the immediate
pre-stage tree with `scripts/bite` where the swapped files compile. Protocol
v19 tests additionally pin postcard bytes and verify the older-version daemon
filter; a test that merely fails to decode on old code is not a useful bite.
v19 tests additionally pin postcard bytes, prove the measured aggregate-bound
maximum stays below the unchanged transport cap, and verify both
older-version send filters; a test that merely fails to decode on old code is
not a useful bite.
## 11. Explicit deferrals
Not part of these three PRs:
- terminal image protocols (sixel, kitty graphics, iTerm images);
- OSC 52 host clipboard writes and OSC 8 hyperlink interaction;
- OSC 8 hyperlink interaction;
- faint, blink, conceal, and strikethrough additions to shared `Style`;
- kitty keyboard protocol, key release events, media keys, and IME preedit;
- cursor-shape/blink rendering and numeric-keypad distinction absent from the
@ -1264,7 +1557,7 @@ panic, unbounded allocation, or child leak.
## 12. Resolved decisions
The 2026-07-21 architecture, re-scout, and final framing review resolved every
The 2026-07-22 architecture, re-scout, and final framing review resolved every
current question:
1. Fixed terminal editor escape: `C-c`; `C-c C-c` sends literal Ctrl-C.
@ -1272,7 +1565,8 @@ current question:
3. Exit: retain the buffer and append the process PID/outcome line from §4.1.
4. Compatibility: additive v19; v18 grid remains supported, v18 semantic has
no terminal surface.
5. GPU wire: complete visible frames with complete-payload suppression.
5. GPU wire: complete visible frames with complete-payload suppression under
one shared 8 MiB aggregate glyph-byte bound; the 16 MiB transport cap stays.
6. Style: preserve the shared encoding and defer unsupported attributes.
7. Identity: one process/screen per terminal `BufferId`.
8. View state: logical-line/cell anchors per
@ -1293,3 +1587,11 @@ current question:
origin and otherwise error without mutation.
14. Host effects: clipboard and BEL use explicit frontend signals; OSC title
remains sanitized metadata.
15. Bootstrap: after every semantic snapshot, v19 sends both byte viewport and
terminal cell size; the authenticated daemon accepts only the declaration
matching the active buffer kind.
16. Semantic resize: the declaration records passive view geometry, but only
the exact durable controller changes the shared PTY/screen size.
17. GPU layout: fixed cell rectangles own geometry and hit testing; shaped
glyph advances never determine subsequent columns, and OSC title remains
metadata rather than a host control effect.