From a workspace consistency audit of hand-rolled newtype trait impls against the derive_more crate, in the reth/alloy idiom (zero-cost newtypes, derives over hand-rolled forwarding).
Why
derive_more is already declared as a workspace dependency (root Cargo.toml:102, version = "2", default-features = false, features = ["full"], with the comment at :98 naming "newtype boilerplate (Deref, From, Display, ...)"). First-party adoption is currently zero: every in-tree reference in Cargo.lock is transitive via alloy. The dependency is already paid for in the build and lock graph, so the first real use costs nothing new and sets the idiom for future newtypes.
The poster child is VenueId(String) (crates/videre-host/src/registry.rs:59), which hand-rolls From<String>, From<&str>, and Display, each a mechanical forward that a derive reproduces. This tracks replacing that boilerplate with derive_more derives, in the alloy-primitives style where thin wrappers lean on derive-generated forwarding rather than hand impls.
Scope is deliberately narrow. The workspace has very few tuple newtypes, and an exhaustive sweep found exactly one clean first-party candidate plus one optional low-value rider in a test-support crate. This is not a broad sweep; it is a targeted rationalization that establishes the pattern.
Scope
| Layer |
Type |
File:line |
Current impls |
derive_more derives |
| L2 videre-host |
VenueId(String) |
crates/videre-host/src/registry.rs:59 |
From<String> (:68), From<&str> (:74), Display (:80) |
#[derive(From, Display)] with #[from(forward)] on the field and #[display("{_0}")] |
| L1 test-support (optional) |
FieldValue (enum) |
crates/nexum-sdk-test/src/lib.rs:466 |
5-arm Display (each variant renders its single field) |
#[derive(Display)] (single-field variants defer to inner Display; #[display("{_0}")] optional) |
Notes on the VenueId swap:
- Plain
#[derive(From)] generates only From<String>. From<&str> is used at real call sites (client.rs, registry.rs str literals like "cow", "unlisted"), so #[from(forward)] is mandatory: it emits From<T: Into<String>>, covering both existing impls. This is a strict superset (also admits Box<str>, Cow), behaviour-preserving at every existing call site.
- Keep the inherent
as_str(&self) -> &str (:63); derive_more has no inherent-accessor derive, and adding AsRef<str> would change the API surface, so it is out of scope.
Display via #[display("{_0}")] is a transparent delegation to the inner Display, which forwards formatter flags (width, precision, fill, align). This is a superset of the hand-rolled f.write_str(&self.0), which ignores flags. It is observationally identical here because every current call site is flag-free ({venue}, %venue, %venue_id), verified. Describe it as a transparent-Display superset, not a byte-equivalent swap.
Not in scope
SubmitQuota::new (crates/nexum-runtime/src/engine_config.rs:77) and the sibling WatchLimit::new (:110) are const fn. derive_more::Constructor emits a non-const new, which narrows the API. Excluded.
- All other hand-rolled
From/Display impls across nexum-runtime, nexum-venue-sdk, nexum-sdk, videre-host, and the L3 surface are branching, validating, or field-remapping transforms between distinct types or enum variants (ComponentKind validates against WORKER_KIND, ChainError/Fault classify, faults.rs/body.rs remap variants, header.rs Golden* projections). derive_more cannot reproduce them.
- Error source chaining stays on
thiserror (#[from], #[error(transparent)]). Swapping to derive_more::Error would lose #[error(...)] message derivation for no gain.
- Do not add
Deref/DerefMut to identifier-style newtypes. VenueId is not a smart pointer; clippy discourages Deref for non-pointer wrappers, and the reth/alloy convention reserves it for genuinely pointer-like types. The as_str() accessor is the idiomatic choice.
modules/, tools/, and the L1 guest SDK crates contain zero mechanical candidates. No changes there.
Constraints
derive_more is already default-features = false, features = ["full"] at the workspace root. From and Display are both no_std-capable derives, so per-derive opt-in via #[derive(...)] keeps the guest crates (wasm32-wasip2) safe. Both target crates here are std host crates, so this is moot for the actual change set.
- Venue-agnostic gate stays green:
derive_more matches none of videre|intent|venue|cow, and neither videre-host nor nexum-sdk-test is reachable from the L1 graphs scanned by scripts/check-venue-agnostic.sh. derive_more is already present transitively in those graphs via alloy.
- Add
derive_more.workspace = true to each touched crate's Cargo.toml (crates/videre-host, and crates/nexum-sdk-test if the optional rider lands).
Timing
Best landed before the M5 three-repo split, as a single monorepo PR. After the carve, the L1/L2/L3 crates fan into three separate repos, so a workspace-wide idiom change is cheaper to do while everything still lives in one tree.
Acceptance criteria
Why
derive_moreis already declared as a workspace dependency (rootCargo.toml:102,version = "2", default-features = false, features = ["full"], with the comment at:98naming "newtype boilerplate (Deref,From,Display, ...)"). First-party adoption is currently zero: every in-tree reference inCargo.lockis transitive via alloy. The dependency is already paid for in the build and lock graph, so the first real use costs nothing new and sets the idiom for future newtypes.The poster child is
VenueId(String)(crates/videre-host/src/registry.rs:59), which hand-rollsFrom<String>,From<&str>, andDisplay, each a mechanical forward that a derive reproduces. This tracks replacing that boilerplate withderive_morederives, in the alloy-primitives style where thin wrappers lean on derive-generated forwarding rather than hand impls.Scope is deliberately narrow. The workspace has very few tuple newtypes, and an exhaustive sweep found exactly one clean first-party candidate plus one optional low-value rider in a test-support crate. This is not a broad sweep; it is a targeted rationalization that establishes the pattern.
Scope
VenueId(String)crates/videre-host/src/registry.rs:59From<String>(:68),From<&str>(:74),Display(:80)#[derive(From, Display)]with#[from(forward)]on the field and#[display("{_0}")]FieldValue(enum)crates/nexum-sdk-test/src/lib.rs:466Display(each variant renders its single field)#[derive(Display)](single-field variants defer to innerDisplay;#[display("{_0}")]optional)Notes on the
VenueIdswap:#[derive(From)]generates onlyFrom<String>.From<&str>is used at real call sites (client.rs,registry.rsstr literals like"cow","unlisted"), so#[from(forward)]is mandatory: it emitsFrom<T: Into<String>>, covering both existing impls. This is a strict superset (also admitsBox<str>,Cow), behaviour-preserving at every existing call site.as_str(&self) -> &str(:63);derive_morehas no inherent-accessor derive, and addingAsRef<str>would change the API surface, so it is out of scope.Displayvia#[display("{_0}")]is a transparent delegation to the innerDisplay, which forwards formatter flags (width, precision, fill, align). This is a superset of the hand-rolledf.write_str(&self.0), which ignores flags. It is observationally identical here because every current call site is flag-free ({venue},%venue,%venue_id), verified. Describe it as a transparent-Display superset, not a byte-equivalent swap.Not in scope
SubmitQuota::new(crates/nexum-runtime/src/engine_config.rs:77) and the siblingWatchLimit::new(:110) areconst fn.derive_more::Constructoremits a non-constnew, which narrows the API. Excluded.From/Displayimpls acrossnexum-runtime,nexum-venue-sdk,nexum-sdk,videre-host, and the L3 surface are branching, validating, or field-remapping transforms between distinct types or enum variants (ComponentKindvalidates againstWORKER_KIND,ChainError/Faultclassify,faults.rs/body.rsremap variants,header.rsGolden*projections).derive_morecannot reproduce them.thiserror(#[from],#[error(transparent)]). Swapping toderive_more::Errorwould lose#[error(...)]message derivation for no gain.Deref/DerefMutto identifier-style newtypes.VenueIdis not a smart pointer; clippy discouragesDereffor non-pointer wrappers, and the reth/alloy convention reserves it for genuinely pointer-like types. Theas_str()accessor is the idiomatic choice.modules/,tools/, and the L1 guest SDK crates contain zero mechanical candidates. No changes there.Constraints
derive_moreis alreadydefault-features = false, features = ["full"]at the workspace root.FromandDisplayare both no_std-capable derives, so per-derive opt-in via#[derive(...)]keeps the guest crates (wasm32-wasip2) safe. Both target crates here are std host crates, so this is moot for the actual change set.derive_morematches none ofvidere|intent|venue|cow, and neithervidere-hostnornexum-sdk-testis reachable from the L1 graphs scanned byscripts/check-venue-agnostic.sh.derive_moreis already present transitively in those graphs via alloy.derive_more.workspace = trueto each touched crate'sCargo.toml(crates/videre-host, andcrates/nexum-sdk-testif the optional rider lands).Timing
Best landed before the M5 three-repo split, as a single monorepo PR. After the carve, the L1/L2/L3 crates fan into three separate repos, so a workspace-wide idiom change is cheaper to do while everything still lives in one tree.
Acceptance criteria
VenueId's three hand-rolled impls (From<String>,From<&str>,Display) are replaced by#[derive(From, Display)]with#[from(forward)]and#[display("{_0}")]; the inherentas_str()is retained.crates/videre-host/Cargo.tomlgainsderive_more.workspace = true.VenueIdcall sites (str-literal andStringconstruction,Displayinterpolation) compile and behave unchanged.FieldValue::Displayis replaced by#[derive(Display)]withderive_more.workspace = trueadded tocrates/nexum-sdk-test/Cargo.toml.scripts/check-venue-agnostic.shand the full build/test/clippy battery pass.Deref/DerefMut, noConstructor, and noderive_more::Errorare introduced.