What's wrong
RELAY spec §18.3 ("Async-primary model") states: "All blocking operations MUST be async fn. Required runtime: tokio or compatible. If sync wrappers are provided, they MUST be in a blocking sub-module and MUST NOT be re-exported from the crate root."
rust-RCP is the opposite: Controller::send/subscribe/close and Registry::register/lookup/deregister/close (src/lib.rs) are plain blocking functions exported directly from the crate root, there is no tokio or async-trait dependency in Cargo.toml, and the README advertises this as an intentional design choice:
"Blocking synchronous API (no_std-compatible core, no tokio required)" — README.md:17
Compare with sibling rust-CAN, which pulls in tokio = { version = "1", features = ["full"] } and async-trait = "0.1" (verified via gh api repos/SoundMatt/rust-CAN/contents/Cargo.toml) and follows the async-primary model the spec requires — so this is achievable within the same org and is a real divergence, not an ecosystem-wide unmet requirement.
Expected per spec
Blocking operations MUST be async fn; any sync convenience API MUST live in a non-root blocking module.
Suggested fix
Either: (a) restructure the public API to async fn over tokio per §18.3, moving the current synchronous implementation into a rcp::blocking sub-module, or (b) if a sync, no_std-friendly API is a deliberate design goal for this safety-critical crate, raise it as spec feedback (an exception/profile for no_std targets) rather than silently diverging — as-is this is a documented, non-conformant divergence from a spec MUST.
Filed from the RELAY ecosystem audit (2026-07-27), category: spec-conformance, severity: P1.
What's wrong
RELAY spec §18.3 ("Async-primary model") states: "All blocking operations MUST be
async fn. Required runtime:tokioor compatible. If sync wrappers are provided, they MUST be in ablockingsub-module and MUST NOT be re-exported from the crate root."rust-RCP is the opposite:
Controller::send/subscribe/closeandRegistry::register/lookup/deregister/close(src/lib.rs) are plain blocking functions exported directly from the crate root, there is notokioorasync-traitdependency in Cargo.toml, and the README advertises this as an intentional design choice:Compare with sibling
rust-CAN, which pulls intokio = { version = "1", features = ["full"] }andasync-trait = "0.1"(verified viagh api repos/SoundMatt/rust-CAN/contents/Cargo.toml) and follows the async-primary model the spec requires — so this is achievable within the same org and is a real divergence, not an ecosystem-wide unmet requirement.Expected per spec
Blocking operations MUST be
async fn; any sync convenience API MUST live in a non-rootblockingmodule.Suggested fix
Either: (a) restructure the public API to
async fnovertokioper §18.3, moving the current synchronous implementation into arcp::blockingsub-module, or (b) if a sync,no_std-friendly API is a deliberate design goal for this safety-critical crate, raise it as spec feedback (an exception/profile forno_stdtargets) rather than silently diverging — as-is this is a documented, non-conformant divergence from a spec MUST.Filed from the RELAY ecosystem audit (2026-07-27), category: spec-conformance, severity: P1.