search() and captureText() beyond "visible" are unreachable: Search/Region are unrouted correlated families #2

Open
opened 2026-09-07 21:02:04 +09:00 by natsukium · 0 comments
Owner

Summary

Terminal.search(), cancelSearch() and captureText() for anything but
"visible" now refuse locally: there is no path from a browser to either
operation. captureText("visible") is unaffected — it reads the shadow screen
on this side of the wire.

This is a capability regression against the pre-reset build, tracked here so
it is not mistaken for a decision to drop the features.

Why

Before felis's wire-baseline reset both rode InputMsg on the attached
stream: InputMsg::Search / SearchCancel answered by
GridMsg::SearchMatch / SearchDone, and InputMsg::CaptureScrollback /
CaptureRegion answered by GridMsg::ScrollbackRow / ScrollbackDone /
CaptureRegion. The broker carried them for free, because it relays the whole
Input family in one direction and the whole Grid family in the other.

At 105b089979369fd310757375af3df7900ae7e523 none of those variants exist.
Search is SearchMsg::QuerySearchMsg::MatchConnMsg::End, and export
is RegionMsg::RowsRegionMsg::RowRegionMsg::RowsDoneConnMsg::End
— correlated families whose stream ids the connection driver allocates. The
gateway's broker routes neither, and says so
(felis-web-gateway docs/broker.md, "Stream frames"):

The Input family is the whole of what this path carries. Search and
scrollback export are correlated families of their own (Search, Region),
whose request ids are allocated by the connection driver the relay drops
when it splits a stream into a reader task and a writer task — so neither is
routed in either direction, and no sid frame carries one.

Leaving the old sendInput calls in place would have been worse than removing
them. A frame the daemon cannot decode is no longer skipped — it ends the
connection with a typed error — so a search box that still wrote
{"Search": …} would have cost the user the session behind the tab.

What it costs today

  • web/mobile.html's search box and its "last command output" button report
    the refusal instead of answering.
  • Its export button falls back to the visible screen.
  • revealLine() survives (it takes a line index, whatever produced it), but
    nothing in the browser produces search hits to feed it.

Work

Restoring either needs the gateway to route a correlated family, which is a
gateway change first:

  1. Have the relay keep (or re-create) a connection driver per stream so a
    request id can be allocated for a browser-originated Search / Region
    request, and route the matching reply items and the ConnMsg::End /
    ConnMsg::Error terminator back under the stream's sid.
  2. Here: restore search() / cancelSearch() / captureText(scrollback | command_output | last_command) and their pending-reply plumbing against
    the shapes the broker settles on. SearchMsg::Match carries line_index,
    text, byte_spans, col_spans as before; RegionMsg::Row carries
    resolved text plus soft_wrap_continued, so the wasm side needs no row
    decode this time (the old FelisView::captureRow export is gone with its
    frame and should not come back).
  3. Gate both on protocolMinor() if the routing lands behind a wire minor.
## Summary `Terminal.search()`, `cancelSearch()` and `captureText()` for anything but `"visible"` now refuse locally: there is no path from a browser to either operation. `captureText("visible")` is unaffected — it reads the shadow screen on this side of the wire. This is a capability regression against the pre-reset build, tracked here so it is not mistaken for a decision to drop the features. ## Why Before felis's wire-baseline reset both rode `InputMsg` on the attached stream: `InputMsg::Search` / `SearchCancel` answered by `GridMsg::SearchMatch` / `SearchDone`, and `InputMsg::CaptureScrollback` / `CaptureRegion` answered by `GridMsg::ScrollbackRow` / `ScrollbackDone` / `CaptureRegion`. The broker carried them for free, because it relays the whole `Input` family in one direction and the whole `Grid` family in the other. At `105b089979369fd310757375af3df7900ae7e523` none of those variants exist. Search is `SearchMsg::Query` → `SearchMsg::Match` → `ConnMsg::End`, and export is `RegionMsg::Rows` → `RegionMsg::Row` → `RegionMsg::RowsDone` → `ConnMsg::End` — correlated families whose stream ids the connection driver allocates. The gateway's broker routes neither, and says so (`felis-web-gateway` `docs/broker.md`, "Stream frames"): > The `Input` family is the whole of what this path carries. Search and > scrollback export are correlated families of their own (`Search`, `Region`), > whose request ids are allocated by the connection driver the relay drops > when it splits a stream into a reader task and a writer task — so neither is > routed in either direction, and no `sid` frame carries one. Leaving the old `sendInput` calls in place would have been worse than removing them. A frame the daemon cannot decode is no longer skipped — it ends the connection with a typed error — so a search box that still wrote `{"Search": …}` would have cost the user the session behind the tab. ## What it costs today - `web/mobile.html`'s search box and its "last command output" button report the refusal instead of answering. - Its export button falls back to the visible screen. - `revealLine()` survives (it takes a line index, whatever produced it), but nothing in the browser produces search hits to feed it. ## Work Restoring either needs the gateway to route a correlated family, which is a gateway change first: 1. Have the relay keep (or re-create) a connection driver per stream so a request id can be allocated for a browser-originated `Search` / `Region` request, and route the matching reply items and the `ConnMsg::End` / `ConnMsg::Error` terminator back under the stream's `sid`. 2. Here: restore `search()` / `cancelSearch()` / `captureText(scrollback | command_output | last_command)` and their pending-reply plumbing against the shapes the broker settles on. `SearchMsg::Match` carries `line_index`, `text`, `byte_spans`, `col_spans` as before; `RegionMsg::Row` carries resolved `text` plus `soft_wrap_continued`, so the wasm side needs no row decode this time (the old `FelisView::captureRow` export is gone with its frame and should not come back). 3. Gate both on `protocolMinor()` if the routing lands behind a wire minor.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
natsukium/felis-web-component#2
No description provided.