protocol, transport, daemon: give the preface replies and key ids narrow types #472

Merged
natsukium merged 5 commits from cleanup/preface into main 2026-09-26 03:17:25 +09:00
Owner

Why

Pre-release cleanup. The daemon built its preface reply with DaemonPreface::select() / refuse(), whose signatures return the full three-arm wire enum although each only ever builds one arm, so exchange_bootstrap destructured the value it had just built behind two unreachable!s. named_key_to_wire had the same shape: Option whose None meant "an F key", re-matched by its caller behind a third unreachable!.

What

  • felis-protocol: DaemonAccept { major, minor } with select(ClientPreface) -> Option<DaemonAccept> and DaemonRefuse { min_major, max_major } with CURRENT, each Into<DaemonPreface>. The decode-side DaemonPreface is unchanged.
  • felis-transport: write_daemon_preface takes impl Into<DaemonPreface>.
  • felis-daemon: exchange_bootstrap reads the narrow values; both unreachable!s are gone.
  • named_key_to_wire returns the v1::key_id::Key arm directly; the caller's unreachable! is gone.
  • New byte assertion pins DaemonRefuse::CURRENT's encoding.

Wire unchanged: preface bytes and key encoding are identical (just proto-compat green).

Verification

  • cargo nextest run -p felis-protocol -p felis-daemon -p felis-transport -p felis-client-core --all-features (1476 passed), clippy -D warnings incl. felis-cli, just schema no diff, just prose-check: green.
  • pi review (sol): PASS, no findings.
## Why Pre-release cleanup. The daemon built its preface reply with `DaemonPreface::select()` / `refuse()`, whose signatures return the full three-arm wire enum although each only ever builds one arm, so `exchange_bootstrap` destructured the value it had just built behind two `unreachable!`s. `named_key_to_wire` had the same shape: `Option` whose `None` meant "an F key", re-matched by its caller behind a third `unreachable!`. ## What - felis-protocol: `DaemonAccept { major, minor }` with `select(ClientPreface) -> Option<DaemonAccept>` and `DaemonRefuse { min_major, max_major }` with `CURRENT`, each `Into<DaemonPreface>`. The decode-side `DaemonPreface` is unchanged. - felis-transport: `write_daemon_preface` takes `impl Into<DaemonPreface>`. - felis-daemon: `exchange_bootstrap` reads the narrow values; both `unreachable!`s are gone. - `named_key_to_wire` returns the `v1::key_id::Key` arm directly; the caller's `unreachable!` is gone. - New byte assertion pins `DaemonRefuse::CURRENT`'s encoding. Wire unchanged: preface bytes and key encoding are identical (`just proto-compat` green). ## Verification - `cargo nextest run -p felis-protocol -p felis-daemon -p felis-transport -p felis-client-core --all-features` (1476 passed), clippy `-D warnings` incl. felis-cli, `just schema` no diff, `just prose-check`: green. - pi review (sol): PASS, no findings.
`DaemonPreface::select` returned `Option<DaemonPreface>` and `refuse`
returned `DaemonPreface`, yet each only ever built one variant. The
daemon's bootstrap then destructured the reply back into that variant
behind two `unreachable!`s, a panic path the type system could have
ruled out.

`DaemonAccept::select` and `DaemonRefuse::CURRENT` now carry exactly the
reply they build, and `write_daemon_preface` takes `impl
Into<DaemonPreface>` so the widening happens once at the write. The
decoded three-arm `DaemonPreface` is unchanged, as are the preface bytes;
a new assertion pins the bytes of this build's refusal.

Assisted-by: Claude Code
protocol: return the key id arm from named_key_to_wire
All checks were successful
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 14s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 53s
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 12s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / frontend smoke (Windows) (pull_request) Successful in 42s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
windows / cargo nextest (Windows) (pull_request) Successful in 3m24s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m5s
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m48s
pr / wire schema is compatible with the base (pull_request) Successful in 16s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 42s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 24s
bench / Criterion regression gate (pull_request) Successful in 2m21s
pr / nix flake check (pull_request) Successful in 35s
8a3317c4dc
`named_key_to_wire` returned `None` for F keys alone, so its only caller
matched on the key a second time and kept an `unreachable!` for the
non-F `None` case the first match already excluded. Returning the
`KeyId` oneof arm directly makes the split total: F keys go to
`function`, every other named key to the `NamedKey` enum. The encoded
bytes are unchanged.

Assisted-by: Claude Code
Merge remote-tracking branch 'origin/main' into cleanup/preface
Some checks failed
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 53s
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 14s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 13s
windows / windows docs-only no-op (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Failing after 2m28s
pr / nix flake check (pull_request) Successful in 35s
pr / cargo build / clippy / test / deny (pull_request) Successful in 2m0s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
pr / wire schema is compatible with the base (pull_request) Successful in 12s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m10s
windows / cargo nextest (Windows) (pull_request) Successful in 3m43s
windows / frontend smoke (Windows) (pull_request) Successful in 33s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 24s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 12s
54fb83088e
ci: rerun the bench gate after a load-noise failure
Some checks failed
darwin / build felis (aarch64-darwin) (pull_request) Successful in 53s
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m5s
windows / cargo nextest (Windows) (pull_request) Successful in 3m24s
pr / nix flake check (pull_request) Successful in 8s
windows / frontend smoke (Windows) (pull_request) Successful in 50s
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 14s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 15s
windows / windows docs-only no-op (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Failing after 2m27s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m51s
pr / wire schema is compatible with the base (pull_request) Successful in 14s
windows / cargo clippy (Windows cross) (pull_request) Successful in 12s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 24s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
31f55e6793
The Criterion gate flagged daemon_side and multi_cycle benches the
preface change does not reach while the runner host was at load ~10.

Assisted-by: Claude Code
Merge remote-tracking branch 'origin/main' into cleanup/preface
Some checks failed
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 14s
windows / detect relevant changes (pull_request) Successful in 22s
windows / windows docs-only no-op (pull_request) Has been skipped
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m4s
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m42s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 25s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 12s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 53s
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Failing after 2m22s
windows / cargo nextest (Windows) (pull_request) Successful in 3m18s
pr / nix flake check (pull_request) Successful in 35s
pr / wire schema is compatible with the base (pull_request) Successful in 12s
windows / frontend smoke (Windows) (pull_request) Successful in 35s
60fe12c9e7
natsukium deleted branch cleanup/preface 2026-09-26 03:17:25 +09:00
Author
Owner

Merged with the Criterion gate red. It flagged daemon_side/plaintext_scroll (+39 to +45%) three times, in runs that overlapped other CI jobs on the same host. A local A/B on a quiet host, with a separate target dir for each side, found no difference:

round main (a15562e8) this branch
1 59.8 µs 61.2 µs
2 60.1 µs 58.7 µs
3 59.4 µs 60.7 µs

daemon_side/shell_prompt swings between about 31 µs and 64 µs within one checkout, on both sides. The daemon_side group is bimodal on this runner, and the branch only touches the preface handshake and key-id encoding, which these benches never reach.

Merged with the Criterion gate red. It flagged `daemon_side/plaintext_scroll` (+39 to +45%) three times, in runs that overlapped other CI jobs on the same host. A local A/B on a quiet host, with a separate target dir for each side, found no difference: | round | main (a15562e8) | this branch | |---|---|---| | 1 | 59.8 µs | 61.2 µs | | 2 | 60.1 µs | 58.7 µs | | 3 | 59.4 µs | 60.7 µs | `daemon_side/shell_prompt` swings between about 31 µs and 64 µs within one checkout, on both sides. The daemon_side group is bimodal on this runner, and the branch only touches the preface handshake and key-id encoding, which these benches never reach.
Commenting is not possible because the repository is archived.
No description provided.