What's wrong
rust-RCP has no dependency on any shared relay/relay-rs crate (Cargo.toml:19-27 dependency list: thiserror, parking_lot, serde, serde_json, serde_yaml only), and consequently:
- No
to_message()/from_message() conversions between Command/Response/Status and a canonical relay::Message exist anywhere (grep -rn "relay::Message|to_message|from_message" src/ outside adapt.rs's unrelated generic trait returns nothing).
- The spec-version constant is named
SPEC_VERSION (src/lib.rs:120) rather than RELAY_SPEC_VERSION, which §18.3 states "MUST be exported from the crate root" and §19.4 gives verbatim as pub const RELAY_SPEC_VERSION: &str = "1.11";.
- The canonical types
Command, Response, Status (src/lib.rs, #[derive(Debug, Clone, Default, PartialEq)]) and Zone/Priority/CommandType/ResponseStatus derive no Serialize/Deserialize at all, contradicting §18.3: "All canonical types MUST derive Clone, Debug, and serde Serialize/Deserialize with the field names from the §15 JSON tags."
Zone/Priority/CommandType/ResponseStatus are hand-rolled tuple structs (pub struct Zone(pub u8)) rather than the #[repr(u8)] enum shapes the spec gives verbatim in §18.3's "Core types (Rust)" block.
This is not a whole-ecosystem gap — it's a regression relative to this org's own sibling crate. rust-CAN (same org, same language) already has all of this:
$ gh api repos/SoundMatt/rust-CAN/contents/src/lib.rs --jq .content | base64 -d | grep -n "SPEC_VERSION|fn adapt|to_message"
62:pub use adapt::{adapt, from_message, to_message};
75:pub const SPEC_VERSION: &str = "1.10";
77:/// Alias for `SPEC_VERSION` for explicitness in CLI contexts.
78:pub const RELAY_SPEC_VERSION: &str = "1.10";
rust-CAN also has a real src/adapt.rs, src/relay.rs, and a src/mock submodule wired into the canonical conversion path — none of which rust-RCP has.
Expected per spec
§18.3 in full: crate-root RELAY_SPEC_VERSION, canonical types deriving Serialize/Deserialize per the §15.5 JSON field names, and to_message()/from_message() conversions using the shared relay::Message envelope.
Suggested fix
Adopt rust-CAN's pattern: add a relay-equivalent dependency (or vendor the minimal relay::Message/Error types until relay-rs is published), add RELAY_SPEC_VERSION alongside SPEC_VERSION, derive Serialize/Deserialize on Command/Response/Status/Zone/Priority/CommandType/ResponseStatus with the §15.5 JSON tag names, and implement real to_message()/from_message() + Adapt() (which then legitimately flips "adapt" to true, see the companion P0 finding).
Filed from the RELAY ecosystem audit (2026-07-27), category: spec-conformance, severity: P1.
What's wrong
rust-RCP has no dependency on any shared
relay/relay-rscrate (Cargo.toml:19-27 dependency list:thiserror,parking_lot,serde,serde_json,serde_yamlonly), and consequently:to_message()/from_message()conversions betweenCommand/Response/Statusand a canonicalrelay::Messageexist anywhere (grep -rn "relay::Message|to_message|from_message" src/outside adapt.rs's unrelated generic trait returns nothing).SPEC_VERSION(src/lib.rs:120) rather thanRELAY_SPEC_VERSION, which §18.3 states "MUST be exported from the crate root" and §19.4 gives verbatim aspub const RELAY_SPEC_VERSION: &str = "1.11";.Command,Response,Status(src/lib.rs,#[derive(Debug, Clone, Default, PartialEq)]) andZone/Priority/CommandType/ResponseStatusderive noSerialize/Deserializeat all, contradicting §18.3: "All canonical types MUST deriveClone,Debug, and serdeSerialize/Deserializewith the field names from the §15 JSON tags."Zone/Priority/CommandType/ResponseStatusare hand-rolled tuple structs (pub struct Zone(pub u8)) rather than the#[repr(u8)] enumshapes the spec gives verbatim in §18.3's "Core types (Rust)" block.This is not a whole-ecosystem gap — it's a regression relative to this org's own sibling crate.
rust-CAN(same org, same language) already has all of this:rust-CAN also has a real
src/adapt.rs,src/relay.rs, and asrc/mocksubmodule wired into the canonical conversion path — none of which rust-RCP has.Expected per spec
§18.3 in full: crate-root
RELAY_SPEC_VERSION, canonical types derivingSerialize/Deserializeper the §15.5 JSON field names, andto_message()/from_message()conversions using the sharedrelay::Messageenvelope.Suggested fix
Adopt rust-CAN's pattern: add a
relay-equivalent dependency (or vendor the minimalrelay::Message/Errortypes untilrelay-rsis published), addRELAY_SPEC_VERSIONalongsideSPEC_VERSION, deriveSerialize/DeserializeonCommand/Response/Status/Zone/Priority/CommandType/ResponseStatuswith the §15.5 JSON tag names, and implement realto_message()/from_message()+Adapt()(which then legitimately flips"adapt"totrue, see the companion P0 finding).Filed from the RELAY ecosystem audit (2026-07-27), category: spec-conformance, severity: P1.