deps: follow felis to 105b0899 (wire-baseline reset) #3
Loading…
Reference in a new issue
No description provided.
Delete branch "follow-felis-105b0899"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follows felis from
32775067(2026-07-16) to105b089979369fd310757375af3df7900ae7e523. felis reset its wire baseline to1.0 on 2026-09-05, so this is a break-for-break adaptation, not a version bump.
What felis changed, and what it forced here
The shadow screen
ShadowGridisShadowScreen, constructed from(rows, cols)alone —with_encodingwent with the proto3-JSON leg, so the shadow always decodes thepacked row codec. A
.fcastand the gateway both carry rows in thestructural-JSON view, so
applyJsonnow recodes throughfelis_grid::transcode::rows_to_wirebefore applying. Recoding rather thanteaching the view a second row encoding: the codec's version tag is what gates
a future layout, and only one side of a recode may know it.
ShadowScreen::screen()replacesgrid(),applyno longer mirrorsOSC 10/11/12 (the view keeps the three channels itself for
themeJson), andkitty_kbd_flags()/modify_other_keys()return typed values.The row codec
encode_row_with/decode_row_withsplit intoencode_row/decode_row(packed) and
encode_row_json/decode_row_json, taking aRowEncodewithan explicit
pad_to. The replay scrollback ring stores the packed form now —nothing outside the ring reads those bytes, and it is about a third the size.
Message shapes
RowDeltacarriesrows: [(row, payload)]and absorbedRowDeltaBatch;GridSizeisSize { dims };RehydrateBeginis payload-free. Imagetransfers are canonical:
Headercarries anImageTarget,total_bytesand achunk's
offsetare gone,ImageShadow::applyis fallible, and a malformedsequence surfaces as a JS error.
virtual_placement(id)became thevirtual_placements()slice.GridMsg::ScrollbackRowis gone with the family split — a capture reply isRegionMsg::Row, carrying text the daemon already resolved. ThecaptureRowwasm export decoded that payload and has no source left, so it goes; its
real-daemon row fixture moves onto
applyJson, where those same bytes nowarrive as a
RowDelta.Capabilities
The per-feature bitmap is gone: a connection states one
ConnectionModeandnegotiates a protocol minor.
Attached.capsbecomesAttached.minorandcaps()becomesprotocolMinor(). Both transports already carry it — thegateway's attach reply names
minor, a.fcastv2 header namesproto_minor.Search and export, removed from the browser's reach
Search and scrollback export left
InputMsgin the same reset: they areSearch/Regionrequests now, correlated families whose ids the connectiondriver allocates, and the gateway's broker routes neither direction of either
(
felis-web-gatewaydocs/broker.md, "Stream frames"). Sosearch(),cancelSearch()andcaptureText()for anything but"visible"refuselocally, and the reply plumbing they fed is removed.
Leaving the old calls would have been worse than useless: an undecodable frame
is no longer skipped, it ends the connection, so pressing search would have
cost the user their session. Tracked as #2 with the work needed to restore it.
Verified
Against a felis checkout patched with the natsukium/felis#195 fix (the three
modules gated behind
native), by[patch]ing the four felis crates to localpaths — no repo file was changed to make these pass:
Unpatched, against felis main as pinned, every cargo step fails in
felis-client-coreand nothing downstream of it runs.nix build .#webgets as far as the samefelis-client-corefailure; itsoutputHashesare updated for the new rev and the vendoring resolves, so thederivation is correct up to that point.
The bench harness is not a CI gate; its workload generator emits the new
RowDeltashape but has not been run.Open
felis-client-coredoes not build withdefault-features = false. Blocks every gate here.dev/flake-module.nixclaims CI guards this configuration; no recipe or workflow actually builds
it, which is how it rotted.
transcode's JSONview renders a
RowDeltarow as a byte array rather than a structural row.This branch decodes that shape correctly. If felis restores the inline
RawValuesplice,RowPayloadstops deserializing fromVec<u8>andapplyJsonwill need to follow.web/public/*.fcastpredates the reset and no longer decodes,so the demo gallery is empty. Regenerating needs
felis-fcast's own followplus a live daemon.
felis reset its wire baseline to 1.0 on 2026-09-05, so the pin this crate carried (32775067, 2026-07-16) reads a protocol that no longer exists. Bump every felis-* rev in lockstep and adapt the wasm core to what the reset left: - `ShadowGrid` is `ShadowScreen`, built from `(rows, cols)` alone. The per-connection `Encoding` is gone with the proto3-JSON leg, so the shadow always decodes the packed row codec; `applyJson` recodes a frame's structural-JSON rows through `felis_grid::transcode` rather than teaching the view a second row encoding, because the codec's version tag gates a future layout and only one side may know it. - `RowDelta` carries `rows: [(row, payload)]` and absorbed `RowDeltaBatch`; `GridSize` is `Size { dims }`; `RehydrateBegin` is payload-free. - `encode_row_with` / `decode_row_with` split into `encode_row` / `decode_row` (packed) and their `_json` twins, and take a `RowEncode` with an explicit `pad_to`. The replay scrollback ring stores the packed form now: nothing outside it reads those bytes. - `key_encode::encode` takes `KittyKbdFlags` and `ModifyOtherKeys` instead of raw levels; the JS mirror keeps its numeric wire shape and converts at the boundary. - the shadow no longer mirrors OSC 10/11/12, so the view keeps the three theme channels itself for `themeJson`. - image transfers are canonical: `Header` carries an `ImageTarget`, and `total_bytes` / a chunk's `offset` are gone. `ImageShadow::apply` is fallible now, and a malformed sequence surfaces as a JS error. - `virtual_placement(id)` became the `virtual_placements()` slice. `GridMsg::ScrollbackRow` is gone with the family split: a capture reply is `RegionMsg::Row`, which carries text the daemon already resolved. The `captureRow` export decoded that payload and has no source left, so it goes; its real-daemon row fixture moves onto `applyJson`, where the same bytes now arrive.The reset took the capability bitmap with it: a connection now states one `ConnectionMode` and negotiates a protocol minor, and there is nothing per-feature left to intersect. So `Attached.caps` becomes `Attached.minor` and `caps()` becomes `protocolMinor()` — the number a browser feature needing a wire addition gates on. Both transports already carry it: the gateway's attach reply names `minor`, and a `.fcast` v2 header names `proto_minor`. Search and scrollback export left `InputMsg` in the same reset. They are `Search` / `Region` requests now, correlated families whose request ids the connection driver allocates, and the gateway's broker routes neither direction of either — so a browser has no way to ask. Keeping the old `sendInput` calls would be worse than useless: an undecodable frame no longer gets skipped, it ends the connection, so pressing search would have cost the user their session. `search`, `cancelSearch` and `captureText` for anything but `"visible"` refuse locally instead, and the reply plumbing they fed goes with them. `captureText("visible")` still answers from the shadow screen, this side of the wire. The bench workload generator emits `RowDelta`'s new `(row, payload)` shape, and `docs/mobile.md` gains a preface saying which of its wire facts the reset invalidated — the same treatment its paths got when the gateway split out, and for the same reason: it records a decision sequence, so rewriting it would make it claim a wire that did not exist while the work was done. `nix/web.nix`'s vendoring hash follows the rev.felis 105b0899's wire reset moved InputMsg::Resize's four axes behind a `dims` field, wrapped GridMsg::ClipboardSet's body in `write`, and merged Bell/Notify into GridMsg::Attention. The follow commit missed all three, and each fails silently on a live session: - the gateway drops the flat Resize as `missing field dims` with only an eprintln, so `resize="fit"` is inert and the daemon never learns the cell pixel metrics a Kitty-graphics producer reads out of ws_xpixel/ws_ypixel; - every OSC 52 reaches onClipboard as `{text: "", clipboard: false}` — a lie rather than a no-op — and the clipboardMode="write" shortcut, gated on that flag, never fires; - routeGrid's default arm swallows Attention, so onNotify never fires. Attention carries both a bell and a desktop notification, and felis routes the two into one client-side handler, so onNotify fires for either; its doc comment claimed OSC 9/99/777 only and still named the NOTIFY cap the reset removed. Refs natsukium/felis-web-component#4, #5, #6. Assisted-by: Claude CodePushed two commits fixing the four cross-check findings (#4-#7); each shape was re-verified against felis
main's serde definitions before editing.d2c915d—fix(web): follow felis's wire reset for resize, clipboard and attention(#4, #5, #6)sendResizenow emits{"Resize":{"dims":{rows,cols,pixel_w,pixel_h}}}, matchingInputMsg::Resize { dims: RequestedDims }.routeGrid'sClipboardSetarm unwrapswritebefore readingselection/data, matchingClipboardSet { write: ClipboardWrite }(selectionstays the rawu8bits —ClipboardSelection's hand-writtenSerializeis unchanged).Notifyarm becameAttention.AttentionSourceis not passed through: felis routesBellandNotificationinto one client-side handler, soonNotifyfires for either. Its doc comment said "OSC 9/99/777" only and still named theNOTIFYcap the reset removed; both are corrected, as is theREADME.mdbullet and the staleInputMsg::Resize { rows, cols, … }row indocs/mobile.md.02c6764—fix(web): carry the post-exit grace onto broker roster rows(#7)SessionEntrygainsexited: booleanandlastExitCode: number | null;toEntryreadsexited/last_exit_code.web/mobile.htmlmarks a restored exited tab with☠and an exit-code tooltip, kept distinct from the dead-stream⚠— that one promises a re-attach, which an exited shell cannot honour.idleSeconds' doc comment corrected:nullwhile attached, so0is "detached for under a second".Gates
nix develop -c tsgo -p . --noEmit— pass (against a freshly builtweb/pkg).nix develop -c cargo fmt --all --check— pass.nix develop -c cargo deny check— pass.cargo build/test --target wasm32-unknown-unknown— still red for the reason tracked in natsukium/felis#195; untouched here.No test was added: all four fixes live in the TypeScript layer, and the repo has no TS test harness (
tests/iswasm-bindgenRust,bench/is a render harness, and no package script runs a JS runner).tests/apply.rscannot see any of these — it decodes through the typed enum, which is exactly why the follow commit passed its gates.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.