--- tags: [report, wzp] type: report status: Pending Review --- # T3.3 — SignalMessage version field (W12) **Status:** Pending Review **Agent:** Kimi Code CLI **Started:** 2026-05-11T16:29Z **Completed:** 2026-05-11T16:29Z **Commit:** (see git log) **PRD:** ../PRD-protocol-hardening.md ## What I changed - `crates/wzp-proto/src/packet.rs:540-551` — Added rustdoc explaining `#[serde(other)]` feasibility research and version-field semantics. - `crates/wzp-proto/src/packet.rs:556-1209` — Added `#[serde(default = "default_signal_version")] version: u8` as the first field to all 38 non-unit `SignalMessage` variants. - `crates/wzp-proto/src/packet.rs:1217-1220` — Added `pub fn default_signal_version() -> u8 { 1 }`. - `crates/wzp-proto/src/packet.rs:2590-2669` — Added backward-compat tests: `old_payload_without_version_deserializes` and `new_payload_with_version_deserializes`. - `crates/wzp-proto/src/lib.rs:32-37` — Re-exported `default_signal_version`. - `crates/wzp-client/src/handshake.rs`, `crates/wzp-client/src/cli.rs`, `crates/wzp-client/src/ice_agent.rs`, `crates/wzp-client/src/reflect.rs`, `crates/wzp-client/src/analyzer.rs`, `crates/wzp-client/src/featherchat.rs`, `crates/wzp-client/tests/handshake_integration.rs` — Updated constructors and patterns for `SignalMessage` variants to include `version` field. - `crates/wzp-relay/src/main.rs`, `crates/wzp-relay/src/federation.rs`, `crates/wzp-relay/src/handshake.rs`, `crates/wzp-relay/src/probe.rs`, `crates/wzp-relay/src/relay_link.rs`, `crates/wzp-relay/src/room.rs`, `crates/wzp-relay/src/route.rs`, `crates/wzp-relay/src/signal_hub.rs` — Updated constructors and patterns for `SignalMessage` variants. - `crates/wzp-relay/tests/cross_relay_direct_call.rs`, `crates/wzp-relay/tests/federation.rs`, `crates/wzp-relay/tests/handshake_integration.rs`, `crates/wzp-relay/tests/hole_punching.rs`, `crates/wzp-relay/tests/multi_reflect.rs`, `crates/wzp-relay/tests/reflect.rs` — Updated test constructors and patterns. - `crates/wzp-android/src/engine.rs` — Updated constructors and patterns. - `crates/wzp-web/src/main.rs` — Updated import ordering (cargo fmt). - `crates/wzp-crypto/tests/featherchat_compat.rs` — Updated import ordering (cargo fmt). - `desktop/src-tauri/src/engine.rs`, `desktop/src-tauri/src/lib.rs` — Updated patterns and constructors. ## Why these choices - Used `#[serde(default = "default_signal_version")]` instead of plain `#[serde(default)]` because the spec explicitly required a named helper `fn default_signal_version() -> u8 { 1 }`. The explicit function is also clearer for readers and makes the default value discoverable via rustdoc. - Unit variants (`Hold`, `Unhold`, `Mute`, `Unmute`, `Reflect`, `TransferAck`) were intentionally left without a `version` field because they carry no struct fields to attach metadata to. Adding a phantom `version` to a unit variant would change its JSON representation from `"Hold"` to `{"Hold": {"version": 1}}`, which is a wire-format break. - The `Unknown` variant with `#[serde(other)]` was researched and skipped per the spec's own fallback instruction: `#[serde(other)]` only works for internally/externally tagged enums where the tag is a string or integer value. With externally tagged representation (Rust's default), the variant name IS the tag, so there is no "other" value to catch. `bincode` also does not support `#[serde(other)]`. This limitation is documented in the `SignalMessage` rustdoc. - Removed the unused `is_default_version` helper that the previous session had added; it was dead code after `skip_serializing_if` was dropped (bincode does not support `skip_serializing_if`). ## Deviations from the task spec - **Step 2:** Did not add `#[serde(other)] Unknown` variant. The spec explicitly allows skipping this if "not feasible" after research. Research confirmed it is not feasible with externally tagged enums + bincode. The limitation is documented in the `SignalMessage` rustdoc. - **Step 3:** No decode-path warning for `Unknown` because the `Unknown` variant does not exist. Unknown variants naturally produce a serde deserialization error, which is the correct behavior for the signal protocol. ## Verification output ``` $ cargo test -p wzp-proto --lib running 121 tests ... test result: ok. 121 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s ``` ``` $ cargo test -p wzp-proto -- transport_feedback running 2 tests test packet::tests::transport_feedback_default_version ... ok test packet::tests::transport_feedback_roundtrip ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 119 filtered out; finished in 0.00s ``` ``` $ cargo test -p wzp-proto -- old_payload running 1 test test packet::tests::old_payload_without_version_deserializes ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 120 filtered out; finished in 0.00s ``` ``` $ cargo test -p wzp-proto -- new_payload running 1 test test packet::tests::new_payload_with_version_deserializes ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 120 filtered out; finished in 0.00s ``` ``` $ cargo test --workspace --exclude wzp-android --no-fail-fast ... (all crates pass) Total: 610 passed; 0 failed ``` ## Test summary - Tests added: 2 - `old_payload_without_version_deserializes` — proves old `CallOffer`, `Ping`, and `Hangup` JSON without `version` deserialize with default `1` - `new_payload_with_version_deserializes` — proves explicit `version: 2` in JSON is preserved on deserialize - Tests modified: 1 - `transport_feedback_default_version` — updated expected version from `0` to `1` to match new default semantic - Workspace test count before: ~571 (per TASKS.md env setup) / after: 610 - `cargo clippy --workspace --all-targets -- -D warnings`: fails in pre-existing debt only (`warzone-protocol` 3 errors, `wzp-codec` 9 errors; see PROTOCOL-AUDIT.md). Crate touched by this task (`wzp-proto`) is clean. - `cargo fmt --all -- --check`: pass ## Risks / follow-ups - **T3.2 status corruption:** The status board shows T3.2 as `Committed`, which is not a valid workflow status. Per the agent instructions, I did not touch already-reviewed tasks. The reviewer should flip T3.2 to `Approved` (its actual status from prior review). - Unit variants (`Hold`, `Unhold`, `Mute`, `Unmute`, `Reflect`, `TransferAck`) have no `version` field. If future protocol evolution requires versioning these, they will need to be converted to struct variants, which is a wire-format change. - The `cargo test -p wzp-proto signal_message` filter pattern from the task spec matches 0 tests because no test names contain "signal_message". The actual tests (`transport_feedback_default_version`, `old_payload_without_version_deserializes`, `new_payload_with_version_deserializes`) verify the behavior. ## 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