docs(runtime): document and test the kitty query-response filter as a load-bearing divergence (#93)

The parseKeypress kitty query-response filter (ESC[?Nu -> {ignore:true}, dropped by useInput)
was assumed to be a redundant second net duplicating the upstream kitty-keyboard detection
strip. Verified it is NOT redundant: the upstream strip runs only in the one-shot
confirmKittySupport detection listener (a private buffer), not on the steady-state input path
(stdin 'data' -> inputParser -> emitInput -> useInput -> parseKeypress). Removing the filter
leaks a stray query-response to handlers as spurious "[?1u" input in enabled mode, auto mode,
and split delivery (inputParser reassembles, so the upstream partial-handling doesn't apply).
Ink has the same gap (its parse-keypress has no query filter; its steady-state input uses
'readable', not 'data').

Keeps the filter (adds a why-comment) and records it as an additive divergence in
ink-divergences.md. Adds 4 end-to-end regression tests proving the filter is load-bearing.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-31 17:02:40 +08:00
committed by GitHub
parent 4c18ec0dd0
commit 8e14081a7c
3 changed files with 107 additions and 2 deletions
+17
View File
@@ -64,6 +64,23 @@ deliberate. Divergences fall into a few kinds:
Maintainer decision (2026-05-30): KEEP. Tests: `usePaste-only app exits on {legacy,kitty} Ctrl+C`
in `input-kitty.test.ts`.
### `parseKeypress` filters kitty query-responses (second safety net)
- **Ink:** filters kitty keyboard-protocol query-responses (`ESC[?Nu`) in exactly **one** place —
the auto-detection lifecycle in `ink.tsx` (`stripKittyQueryResponsesAndTrailingPartial` on a
private `onData` buffer). Its `parse-keypress.ts` has no query-response branch.
- **vue-tui:** mirrors that detection layer (in `kitty-keyboard.ts`) **and** adds a second net —
`parseKeypress` returns `{ ignore: true }` for `ESC[?Nu`, which `useInput` then drops.
- **Why:** the detection layer does **not** cover the real input pipeline (`stdin 'data'` →
`inputParser` → `emitInput` → `useInput` → `parseKeypress`). In `enabled` mode it never runs;
in `auto` mode its `onData` listener and the stdin controller's `handleData` both subscribe to
the same `'data'` event, so stripping its private buffer can't stop the chunk reaching
`handleData`; and after detection settles the listener is gone. Empirically (Layer 2 removed,
rebuilt) a stray query-response reaches a `useInput` handler as spurious `"[?1u"` input in all
of those cases — including a response split across two reads, which `inputParser` reassembles
before dispatch. So this is load-bearing, not redundant. Introduced 2026-05-31. Tests: "kitty
query-response - end-to-end filtering" in `kitty-lifecycle.test.ts` (RED without it).
### Non-`Error` thrown values keep their message in the error overview
- **Ink:** `ErrorOverview` renders `error.message`; a thrown non-`Error` (`throw 'boom'`) has no