# T1.6 — Protocol version negotiation in handshake **Status:** Pending Review **Agent:** Kimi Code CLI **Started:** 2026-05-11T10:20Z **Completed:** 2026-05-11T11:05Z **Commit:** 69a627b **PRD:** ../PRD-wire-format-v2.md + ../PRD-protocol-hardening.md (W12) ## What I changed - `crates/wzp-proto/src/packet.rs:545-561` — Added `protocol_version: u8` and `supported_versions: Vec` to `CallOffer` with `#[serde(default = "...")]` helpers. - `crates/wzp-proto/src/packet.rs:1106-1119` — Added `ProtocolVersionMismatch { server_supported: Vec }` variant to `HangupReason`. - `crates/wzp-proto/src/packet.rs:1121-1128` — Added `default_proto_version()` and `default_supported_versions()` helpers. - `crates/wzp-client/src/handshake.rs` — Added `HandshakeError` typed error enum with `ProtocolVersionMismatch` variant. Changed return type from `anyhow::Error` to `HandshakeError`. Client now sets `protocol_version: 2` and `supported_versions: vec![2]` on outgoing `CallOffer`. On receiving `Hangup::ProtocolVersionMismatch`, returns `HandshakeError::ProtocolVersionMismatch`. - `crates/wzp-relay/src/handshake.rs:38-66` — Relay now checks `protocol_version == 2` after parsing `CallOffer`. If not, sends `Hangup::ProtocolVersionMismatch { server_supported: vec![2] }` and returns an error. - `crates/wzp-relay/tests/handshake_integration.rs:305-372` — Added `handshake_rejects_v1_protocol_version` test: sends `protocol_version: 1`, verifies relay rejects with typed hangup. - `crates/wzp-client/tests/handshake_integration.rs:186-226` — Added `client_receives_protocol_version_mismatch` test: mock relay sends mismatch, client returns typed error. Also fixed T1.5 migration gaps discovered during T1.6: - `desktop/src-tauri/src/engine.rs` — `.is_repair` → `.is_repair()`, `seq: u16` → `u32` in DRED tracking - `crates/wzp-client/src/cli.rs:727` — `.is_repair` → `.is_repair()` - `crates/wzp-android/src/engine.rs` + `pipeline.rs` — Full v2 field migration (subagent) ## Why these choices The typed `HandshakeError` gives callers a way to distinguish protocol version mismatch from other handshake failures (network, bad signature, etc.) without string-matching. `#[serde(default)]` on the new fields means old JSON payloads without `protocol_version` deserialize as v2, which is the correct behavior for the current codebase that speaks v2 wire format. ## Deviations from the task spec None. The task spec said to add `ProtocolVersionMismatch` to the reason enum or as a structured `SignalMessage` variant — the existing `Hangup` already had a `reason` field, so adding to `HangupReason` was the natural fit. ## Verification output ```bash $ cargo test -p wzp-relay --test handshake_integration running 5 tests test auth_then_handshake ... ok test handshake_rejects_bad_signature ... ok test handshake_rejects_v1_protocol_version ... ok test handshake_succeeds ... ok test handshake_verifies_identity ... ok test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` ```bash $ cargo test -p wzp-client --test handshake_integration running 3 tests test client_receives_protocol_version_mismatch ... ok test full_handshake_both_sides_derive_same_session ... ok test handshake_rejects_tampered_signature ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` ```bash $ cargo test --workspace --exclude wzp-android --no-fail-fast # Total: 613 passed; 0 failed ``` ```bash $ cargo clippy -p wzp-proto -p wzp-client -p wzp-relay -p wzp-desktop --all-targets -- -D warnings # Clean ``` ```bash $ cargo fmt --all -- --check # Clean ``` ## Test summary - Tests added: 2 (`handshake_rejects_v1_protocol_version`, `client_receives_protocol_version_mismatch`) - Tests modified: 0 - Workspace test count before: 572 / after: 613 (includes T1.5 android/desktop fixes) - `cargo clippy -p wzp-proto -p wzp-client -p wzp-relay -p wzp-desktop --all-targets -- -D warnings`: pass - `cargo fmt --all -- --check`: pass ## Risks / follow-ups - `wzp-android` requires NDK to link; the Rust source compiles but the crate cannot be fully built on macOS. The T1.5 migration fixes were verified via `cargo check -p wzp-android`. - The `deps/featherchat` submodule has 3 pre-existing clippy errors documented in `PROTOCOL-AUDIT.md`. ## Reviewer checklist (filled in by reviewer) - [ ] Code matches PRD intent - [ ] Verification output is real (re-run if suspicious) - [ ] No backward-incompat surprises - [ ] Tests cover the new behavior - [ ] Approved