What's wrong
rcp capabilities hardcodes "adapt": true (src/bin/rcp.rs:95), but the crate exports no Adapt()/adapt() function anywhere, and has no dependency on any relay/relay-rs crate to return relay::Node/relay::Caller types from in the first place:
$ grep -rin "fn adapt\b|relay::Node|relay::Caller" src/ Cargo.toml
(no matches)
Per RELAY spec §12.2: "adapt MUST be true if the package exports Adapt() per §10.3." §10.3 requires a concrete adapter function (Rust: something returning a relay::Node/relay::Caller-equivalent, using to_message()/from_message() internally). rust-RCP has none of this — src/adapt.rs implements an unrelated generic Adapter<M> trait for converting between Command/Response and an arbitrary external type M; it never touches relay::Message/relay::Node/relay::Caller.
Separately, the same capabilities doc hardcodes "optional_interfaces": [] (src/bin/rcp.rs:94) even though the crate does implement LoaningController (src/lib.rs:513, impl LoaningController for LoanPoolController in src/loan.rs:118) — an optional interface per spec §9/Appendix A that should be listed there (the RCP "loaning" feature flag hints at it, but optional_interfaces is the field the spec actually defines for this).
Evidence
Live binary output (built from this checkout):
$ ./target/debug/rcp capabilities
{
...
"interfaces": ["Controller","Registry"],
"optional_interfaces": [],
"adapt": true
}
Why relay conform doesn't catch it
RELAY's own cmd/relay/conform.go:236-238 only emits a WARN when adapt=false (as a reminder Adapt() isn't exported); it has no way to statically verify a true claim. So this binary passes relay conform --strict cleanly (verified) while actively misreporting its capability set — which is exactly the kind of self-reported metadata that relay compare, relay probe, and relay interop (§11.2.1) trust to decide interchangeability and routing eligibility.
Expected per spec
"adapt" MUST be false until a real Adapt()/adapt() is implemented (§10.3/§12.2), and "optional_interfaces" MUST include "LoaningController" since it is implemented.
Suggested fix
Flip "adapt": true to "adapt": false in src/bin/rcp.rs:95 until a real adapter exists (tracked by the broader gap below), and populate "optional_interfaces" with ["LoaningController"] in src/bin/rcp.rs:94.
Filed from the RELAY ecosystem audit (2026-07-27), category: bug, severity: P0.
What's wrong
rcp capabilitieshardcodes"adapt": true(src/bin/rcp.rs:95), but the crate exports noAdapt()/adapt()function anywhere, and has no dependency on anyrelay/relay-rscrate to returnrelay::Node/relay::Callertypes from in the first place:Per RELAY spec §12.2: "
adaptMUST betrueif the package exportsAdapt()per §10.3." §10.3 requires a concrete adapter function (Rust: something returning arelay::Node/relay::Caller-equivalent, usingto_message()/from_message()internally). rust-RCP has none of this —src/adapt.rsimplements an unrelated genericAdapter<M>trait for converting betweenCommand/Responseand an arbitrary external typeM; it never touchesrelay::Message/relay::Node/relay::Caller.Separately, the same capabilities doc hardcodes
"optional_interfaces": [](src/bin/rcp.rs:94) even though the crate does implementLoaningController(src/lib.rs:513,impl LoaningController for LoanPoolControllerin src/loan.rs:118) — an optional interface per spec §9/Appendix A that should be listed there (the RCP"loaning"feature flag hints at it, butoptional_interfacesis the field the spec actually defines for this).Evidence
Live binary output (built from this checkout):
Why
relay conformdoesn't catch itRELAY's own
cmd/relay/conform.go:236-238only emits a WARN whenadapt=false(as a reminder Adapt() isn't exported); it has no way to statically verify atrueclaim. So this binary passesrelay conform --strictcleanly (verified) while actively misreporting its capability set — which is exactly the kind of self-reported metadata thatrelay compare,relay probe, andrelay interop(§11.2.1) trust to decide interchangeability and routing eligibility.Expected per spec
"adapt"MUST befalseuntil a realAdapt()/adapt()is implemented (§10.3/§12.2), and"optional_interfaces"MUST include"LoaningController"since it is implemented.Suggested fix
Flip
"adapt": trueto"adapt": falsein src/bin/rcp.rs:95 until a real adapter exists (tracked by the broader gap below), and populate"optional_interfaces"with["LoaningController"]in src/bin/rcp.rs:94.Filed from the RELAY ecosystem audit (2026-07-27), category: bug, severity: P0.