Skip to content

nexum-world: settle the vocabulary style, enums over const strings #547

Description

@mfw78

From a question raised while reviewing #461: should nexum-world's vocabulary consts be enums with strum, as ChainMethod, RetryAction and the SDK's Fault already are? Target: nexum-world (L1). Related: #523, whose item 2 folds ChainMethod into this crate.

nexum-world declares two vocabularies as const &str groups, while the rest of the workspace expresses closed vocabularies as strum enums (ChainMethod, RetryAction, Fault, manifest errors, log levels, provider pool). Once #523 lands, nexum-world will hold both styles side by side, so it is worth settling which one this crate is.

The two groups are not the same case.

fault_labels - convertible, and worth it

Seven consts plus a hand-maintained pub const ALL: [&str; 7]. The array must be updated by hand whenever a fault case is added, with no compiler enforcement. An enum with strum derives replaces it: VARIANTS supersedes ALL, EnumString gives fail-closed parsing, and adding a WIT fault case forces the enum to be updated.

What this does not do, and why the module must stay: nexum-runtime's fault_label maps crate::bindings::nexum::host::types::Fault, a wit-bindgen generated type that cannot carry a strum derive, and nexum-runtime does not depend on nexum-sdk. The SDK's own Fault is a separate hand-written mirror carrying IntoStaticStr. nexum-world is the only crate both sides depend on, so it is the correct home for the shared vocabulary, and the hand-written match in fault_label stays regardless. The fault_labels_match_the_single_source_vocabulary test in nexum-sdk is what currently binds the guest mirror to it and should continue to.

caps - convertible only with a const accessor

caps::* are consumed in const evaluation, not just at runtime:

pub const CORE: &[Capability] = &[ Capability { name: caps::CHAIN, .. }, .. ];
const fn core_iface_count() -> usize { /* walks CORE */ }
pub const CORE_IFACES: [&str; core_iface_count()] = { /* const loop over CORE */ };

CORE_IFACES is a const array whose length comes from a const fn over the const table. strum::IntoStaticStr generates impl From<Enum> for &'static str, which is not const, so name: Cap::Chain.into() will not compile in a const item. Converting therefore means an enum plus a hand-written const fn as_str(self) -> &'static str (a match in a const fn is allowed), with strum carrying only the parse direction. That is still worthwhile for exhaustiveness and a real type at manifest boundaries, but the const machinery is load-bearing and must be preserved deliberately rather than derived away.

Acceptance criteria

  • nexum-world expresses its closed vocabularies in one style, consistent with ChainMethod once sdk: harden the chain provider - bound block_on and guard ChainMethod drift #523 lands.
  • No hand-maintained parallel array (ALL) remains; the variant list is derived.
  • CORE, core_iface_count and CORE_IFACES still evaluate in const context.
  • nexum-sdk's guest-mirror agreement test still binds the SDK Fault to the shared vocabulary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    component/capabilitiescapability negotiation, allowlist, optional-cap trap stubscomponent/wit-abiWIT packages, worlds, wit-bindgen, host/guest contractdebtCode works but makes future work harder.effort/hoursFew hours. Single PR.p3-maybeNice to have. Probably never happens.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions