summaryrefslogtreecommitdiff
path: root/docs/detached.md
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-03 13:11:14 -0300
committerGabriel Schneider <[email protected]>2026-09-03 13:11:14 -0300
commite81b63106b83bce66641e8dd27d6aa348252baf1 (patch)
tree2bdd2427353f5fff7fa1c976194467a5da3a7c96 /docs/detached.md
parentffc8c1f6f19a5dc48e98f99938b438baf9a97165 (diff)
downloadpardes-e81b63106b83bce66641e8dd27d6aa348252baf1.tar.gz
pardes-e81b63106b83bce66641e8dd27d6aa348252baf1.zip
detached: a big screen can attach, and the frame it asks for fits the wire
Two defects, and either fix alone makes the other one worse. No frontend ever clamped its window to the protocol's grid ceiling — the hello carried it raw — so a 4K display at a small font, already past max_rows 128, had its geometry refused by the session's decoder as BadValue. That path answers with close(.protocol) and no refuse behind it, so the frontend was told only that the session "hung up on the connect": at a session with all 32 slots free. client.zig now asks for the largest grid the wire carries, which is what its own GEOMETRY note already promises a frontend gets — the session is drawn at its own size in the corner of a bigger window, exactly as when another frontend is the smaller one. A ZERO geometry is dropped rather than clamped, because the session grid is the smallest common one and a frontend reporting 1 would collapse everybody else; TIOCGWINSZ answers 0x0 during a teardown and the tty shell forwarded it, which was the same mute hangup by another route. That clamp alone would have replaced one bug with a worse one. max_cols * max_rows is 65536 and a run's length prefix is a u16, so the single grid legal at both bounds is the one grid whose full frame — and an attach always produces a full frame — cannot be described by one run. encodeFrame's @intCast panicked in a safe build and was illegal behaviour in a fast one. The encoder splits the run instead, bounding the CURSOR rather than the run because the gap lookahead runs ahead of it, and frameBound had already paid for the extra header. wire.version 1 -> 2 for the same reason: the geometry a v2 frontend now asks for is one a v1 daemon panics encoding, and `zig build` replacing the binary under a running session is exactly what that field exists for. A v1 daemon answers Refusal.version instead of dying with every pane shell it owns. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_016Q4RATpafkwahrovHQLKRf
Diffstat (limited to 'docs/detached.md')
-rw-r--r--docs/detached.md17
1 files changed, 13 insertions, 4 deletions
diff --git a/docs/detached.md b/docs/detached.md
index 58a2f9c6..0902f78a 100644
--- a/docs/detached.md
+++ b/docs/detached.md
@@ -255,6 +255,13 @@ Stated rather than papered over:
* **The screen is shared, at the smallest common grid.** Two frontends of
different sizes converge on the smaller; the larger window letterboxes. Same
semantics as tmux.
+* **A frontend asks for at most `max_cols` x `max_rows`** (512x128, above).
+ A window bigger than that — a 4K display at a small font is already past 128
+ rows — attaches at 512x128 and letterboxes the rest, exactly as it does
+ beside a smaller frontend. `client.zig` clamps the hello and every resize,
+ because the geometry itself does not fit the wire: an unclamped one was
+ refused by the session's decoder as `BadValue`, and that refusal reaches the
+ frontend as a bare hangup with no reason attached.
* **No LSP and no selection pipe** in a detached session. The daemon implements
**seventeen** of `Host.VTable`'s **twenty-one** methods — fewer than the tty
and SDL shells, which install nineteen each, everything but
@@ -299,8 +306,8 @@ Stated rather than papered over:
## Tests
-`zig build unit-test` runs eleven tests in `src/detached/client.zig`. Ten drive a
-real core over a real socket: a frontend is greeted
+`zig build unit-test` runs twelve tests in `src/detached/client.zig`. Eleven
+drive a real core over a real socket: a frontend is greeted
and sent a screen; input comes back as a diff; two frontends share one screen
at the smallest common grid; a frontend that dies takes nothing with it; a
wrong-version peer is refused, loudly; a peer that sends an undefined tag byte
@@ -309,9 +316,11 @@ the grid where the last one left it, and lets the next one take it over; the
three surviving effects route as documented above — `set_clipboard` to both
frontends, `read_clipboard` and `open_link` to the origin, and to the primary
once the origin is gone; the client table refuses rather than queues; and a
-frontend that stops reading is dropped.
+frontend that stops reading is dropped; and a window bigger than the protocol's
+grid attaches at `max_cols` x `max_rows` rather than being refused, which is
+also the one test that drives a full frame of the largest grid the wire carries.
-The eleventh builds no harness, opens no socket and touches no core, and that is
+The twelfth builds no harness, opens no socket and touches no core, and that is
the point: it pins the DESIGN rather than the behaviour, and `wire.zig` has its
mirror, one test per direction. "A frontend is never asked to fork, write, or
watch" walks