grid: adopt in-band resize notify (?2048) #214

Merged
natsukium merged 3 commits from feat/in-band-resize-189 into main 2026-09-08 01:35:00 +09:00
Owner

Fixes #189.

Implements in-band resize notification (DECSET/DECRST ?2048), so a program that
opts in learns about every geometry change from the terminal itself instead of
racing SIGWINCH against its own reads.

  • felis-grid tracks the mode as grid state, exposes it through the sink, and
    answers DECRQM for it.
  • The daemon reports once immediately when a program sets the mode, and then on
    every geometry change while the mode stays set — the report rides the same PTY
    write path as the rest of the reply traffic.
  • Clearing the mode stops the reports; the shipped default is off.

Doc cascade: docs/reference/protocols/vt-compliance.md and
docs/reference/protocols/support-matrix.md move ?2048 out of the
consumed-without-effect set and state the shipped behavior; CHANGELOG.md records
the user-affecting default.

Verified: just check green (fmt, clippy, nextest, deny, proto-compat); reviewed by
pi luna + pi sol; docs proofread by Gemini gemini-3.8-flash-high

Follow-ups

  • #213 test: no daemon test drives DECSET 2048 through the real parser/drain_effects/reconcile wiring

Deferred

  • esctest baseline ratchet — esctest has no ?2048 coverage, so PASS_BASELINE does not move.
  • A fuzz seed for \x1b[?2048h — the mode arm adds no new parse shape: one more integer in the existing DECSET dispatch, already covered by the parser totality proptest and the existing fuzz targets.
  • skills/felis/SKILL.md — no CLI or IPC surface changed; the mode is terminal-side only.
Fixes #189. Implements in-band resize notification (DECSET/DECRST `?2048`), so a program that opts in learns about every geometry change from the terminal itself instead of racing `SIGWINCH` against its own reads. - `felis-grid` tracks the mode as grid state, exposes it through the sink, and answers DECRQM for it. - The daemon reports once immediately when a program sets the mode, and then on every geometry change while the mode stays set — the report rides the same PTY write path as the rest of the reply traffic. - Clearing the mode stops the reports; the shipped default is off. Doc cascade: `docs/reference/protocols/vt-compliance.md` and `docs/reference/protocols/support-matrix.md` move `?2048` out of the consumed-without-effect set and state the shipped behavior; `CHANGELOG.md` records the user-affecting default. Verified: just check green (fmt, clippy, nextest, deny, proto-compat); reviewed by pi luna + pi sol; docs proofread by Gemini gemini-3.8-flash-high ## Follow-ups - #213 test: no daemon test drives DECSET 2048 through the real parser/drain_effects/reconcile wiring ## Deferred - esctest baseline ratchet — esctest has no `?2048` coverage, so `PASS_BASELINE` does not move. - A fuzz seed for `\x1b[?2048h` — the mode arm adds no new parse shape: one more integer in the existing DECSET dispatch, already covered by the parser totality proptest and the existing fuzz targets. - `skills/felis/SKILL.md` — no CLI or IPC surface changed; the mode is terminal-side only.
felis's PTY geometry moves from directions a program cannot observe —
a window resize, a `window retarget`, a second attached client taking
the size — and SIGWINCH answers none of them in order against the
input around it. So the mode is recorded here and reported by the
daemon, the set's own answer included: a report the grid queued into
the parse-effect queue would carry the geometry that was live when the
set was parsed, which a resize written straight to the PTY can
overtake.

The pixel axes carry the `0` stub `CSI 14 t` answers: window extents
are one window's fact and the grid is shared by every mirror of the
session, so the notification never widens what a program can learn
about the host.

Refs #189
Only the daemon knows when a resize landed, and it owns the PTY
writer, so it is the single emitter: the set's own answer and every
later report are one path, compared against the geometry the program
was last told. Two emitters would double-report one geometry, since
the grid's mode flag and the daemon's resize edge are set by different
threads with no ordering between them.

The write is deferred to the run loop's reconcile like the focus and
scheme reports, because `apply_size` runs on sync paths that have no
way to carry a PTY error out. Input that transfers size ownership is
the exception: it reports before writing its own bytes, or the program
would see the keystroke that implied the new geometry ahead of the
geometry.

Refs #189
docs: state in-band resize notify as shipped
All checks were successful
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 50s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m9s
pr / nix flake check (pull_request) Successful in 30s
pr / cargo build / clippy / test / deny (pull_request) Successful in 2m1s
pr / wire schema is compatible with the base (pull_request) Successful in 11s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 54s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 3s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 15s
windows / cargo nextest (Windows) (pull_request) Successful in 4m13s
windows / frontend smoke (Windows) (pull_request) Successful in 1m36s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (push) Has been skipped
darwin / detect relevant changes (push) Successful in 3s
darwin / darwin docs-only no-op (push) Has been skipped
darwin / build felis (aarch64-darwin) (push) Successful in 13s
fuzz / cargo fuzz smoke (per target) (push) Successful in 1m5s
pr / nix flake check (push) Successful in 6s
pr / cargo build / clippy / test / deny (push) Successful in 1m38s
pr / wire schema is compatible with the base (push) Successful in 12s
pr / frontend smoke (x86_64-linux) (push) Successful in 6s
windows / detect relevant changes (push) Successful in 3s
windows / windows docs-only no-op (push) Has been skipped
pr / publish felis (x86_64-linux) (push) Successful in 9s
windows / cargo clippy (Windows cross) (push) Successful in 13s
windows / cargo nextest (Windows) (push) Successful in 3m59s
windows / frontend smoke (Windows) (push) Successful in 1m58s
windows / package felis (x86_64-pc-windows-msvc) (push) Successful in 2m9s
9d2653b387
The stance and its rationale were already recorded in the protocol
landscape; what was missing is the normative shape a program can code
against and the status row it looks the mode up in.

Refs #189
natsukium deleted branch feat/in-band-resize-189 2026-09-08 01:35:00 +09:00
Sign in to join this conversation.
No description provided.