Skip to main content

CapabilitySet

Struct CapabilitySet 

Source
pub struct CapabilitySet {
    pub tags: HashSet<Tag>,
    pub metadata: BTreeMap<String, String>,
}
Expand description

Complete capability set for a node.

Phase A.5.N.3 final shape: a typed tags: HashSet<Tag> plus a metadata: BTreeMap for data that can’t safely round-trip through the tag wire format. Hardware / Software / Model / Tool / ResourceLimits are projections of these two fields, computed on demand via views() / the From<&CapabilitySet> impls. Typed-struct fields no longer exist on the storage shape — every read goes through the projection layer; every write goes through the typed setters which re-encode into the canonical tag set.

Fields§

§tags: HashSet<Tag>

Canonical typed tag set. Holds:

  • Tag::AxisPresent / Tag::AxisValue axis-prefixed tags (hardware.gpu, hardware.memory_gb=64, software.model.0.id=llama-3.1-70b, …) that encode the five projections.
  • Tag::Reserved cross-axis tags (scope:tenant:foo, causal:<hex>, fork-of:<hex>, heat:*).
  • Tag::Legacy untyped tags (free-form strings, e.g. nat:full-cone / nrpc:<service>).

Wire format emits tags in sorted Tag::to_string() order so every serialization is canonical. The HashSet keeps O(1) membership for in-memory lookups; the serialize_with hook flattens to a sorted Vec on the way out. Two sides of a signed-announcement round-trip therefore produce identical bytes regardless of HashSet iteration order (which is process-local random and would otherwise cause spurious signature-verification failures across processes).

§metadata: BTreeMap<String, String>

Free-form key-value metadata.

Phase A.5.N introduction. Carries data that doesn’t fit the typed-tag taxonomy:

  • Tool schemas: tool::<tool_id>::input_schema and tool::<tool_id>::output_schema keys hold JSON Schema strings (the =/:/, characters in JSON make these unsafe to round-trip through the tag wire format).
  • Intent: intent key carries the application-defined placement intent (Phase F).
  • Colocation hints: colocate-with key carries a chain origin hash for chain-aware placement.
  • Application-defined keys (subject to the metadata size cap in Phase C: 4 KB soft / 16 KB hard).

BTreeMap for deterministic iteration order over the wire.

Implementations§

Source§

impl CapabilitySet

Source

pub fn new() -> CapabilitySet

Create empty capability set

Source

pub fn with_hardware(self, hardware: HardwareCapabilities) -> CapabilitySet

Set hardware capabilities

Source

pub fn with_software(self, software: SoftwareCapabilities) -> CapabilitySet

Set software capabilities

Source

pub fn add_model(self, model: ModelCapability) -> CapabilitySet

Add model capability. Read-modify-write through views() since models live in the canonical tag set as software.model.<i>.* indexed-encoding.

Source

pub fn add_tool(self, tool: ToolCapability) -> CapabilitySet

Add tool capability. Read-modify-write through views() since tools live in the canonical tag set as software.tool.<i>.* indexed-encoding; schemas are mirrored into metadata by set_tools.

Source

pub fn add_tag(self, tag: impl Into<String>) -> CapabilitySet

Add a tag (parsed via the application-facing parser, which rejects reserved cross-axis prefixes — use the dedicated scope helpers for those). Untyped strings parse as Tag::Legacy; axis-prefixed strings (hardware.gpu, software.os=linux) parse as AxisPresent / AxisValue. Empty tags and reserved-prefix tags are silently dropped (the parser returns Err and we ignore it).

Source

pub fn with_blob_capability(self, blob: BlobCapability) -> CapabilitySet

Add a typed BlobCapability projection. Emits the matching dataforts.blob.* tags via the projection’s write_into. Builder-style; producer-side counterpart to BlobCapability::from_capability_set. Round-tripping through both functions returns the original projection.

Source

pub fn with_greedy_capability(self, greedy: GreedyCapability) -> CapabilitySet

Add a typed GreedyCapability projection. Emits dataforts.greedy.* tags.

Source

pub fn with_gravity_capability( self, gravity: GravityCapability, ) -> CapabilitySet

Add a typed GravityCapability projection. Emits dataforts.gravity.* tags.

Source

pub fn with_tenant_scope(self, tenant_id: impl Into<String>) -> CapabilitySet

Add a scope:tenant:<id> reserved tag, marking this announcement as advertised under the given tenant. Idempotent — repeated calls with the same id do not duplicate. Empty tenant_id is silently dropped (matches the scope resolver, which rejects empty ids).

Source

pub fn with_region_scope(self, region: impl Into<String>) -> CapabilitySet

Add a scope:region:<name> reserved tag, marking this announcement as advertised under the given region. Idempotent. Empty region is silently dropped.

Source

pub fn with_subnet_local_scope(self) -> CapabilitySet

Add the scope:subnet-local reserved tag, opting this announcement out of cross-subnet discovery. The strictest scope wins: any tenant / region tags also present on this set are ignored by the scope resolver while scope:subnet-local is set. Idempotent.

Source

pub fn require_chain(self, chain_hash: impl AsRef<str>) -> CapabilitySet

Declare this node holds the chain identified by chain_hash.

Emits the causal:<chain_hash> reserved tag. Idempotent — repeated calls with the same hash do not duplicate.

Source

pub fn require_chain_tip( self, chain_hash: impl AsRef<str>, tip_seq: u64, ) -> CapabilitySet

Declare this node holds the chain <chain_hash> up to the named tip_seq.

Emits causal:<chain_hash>:<tip_seq>. Per CAPABILITY_SYSTEM_PLAN.md §2: receivers downsample chains shorter than they need, so a peer announcing a tip_seq is implicitly also a holder for every prefix of that chain.

Source

pub fn require_chain_range( self, chain_hash: impl AsRef<str>, start_seq: u64, end_seq: u64, ) -> CapabilitySet

Declare this node holds the half-open range [start_seq..end_seq) of the chain <chain_hash>.

Emits causal:<chain_hash>[<start>..<end>]. The validator enforces start_seq < end_seq; equal or inverted ranges are silently dropped.

Source

pub fn require_any_chain<I, S>(self, chain_hashes: I) -> CapabilitySet
where I: IntoIterator<Item = S>, S: AsRef<str>,

Declare this node holds any of the named chains. One causal:<hash> reserved tag emitted per non-empty hash. Empty / blank hashes in the iterator are silently skipped.

Source

pub fn from_fork(self, parent_chain_hash: impl AsRef<str>) -> CapabilitySet

Declare this chain forks from parent_chain_hash.

Emits the fork-of:<parent_chain_hash> reserved tag, used by the chain-discovery layer for lineage walks.

Source

pub fn heat_level(self, chain_hash: impl AsRef<str>, rate: f64) -> CapabilitySet

Declare this node’s heat (read-rate / activity score) for the named chain.

rate is clamped to [0.0, 1.0] and emitted with two-decimal precision (heat:<chain_hash>=0.85). Heat is per-chain, not per-node; one call per chain.

Source

pub fn with_limits(self, limits: ResourceLimits) -> CapabilitySet

Set resource limits

Source

pub fn with_metadata( self, key: impl Into<String>, value: impl Into<String>, ) -> CapabilitySet

Set or overwrite a metadata key-value entry.

CR-16: silently drops writes whose key matches a substrate-reserved prefix (tool::). Those keys are authored by the substrate’s own codecs (the tool codec emits tool::<id>::input_schema etc.) and user code must not collide with them — same shape as Tag::parse_user rejecting reserved tag prefixes.

Note: the schema’s metadata_reserved exact-match list (intent, colocate-with, priority, owner) is intentionally NOT gated — those are well-known user-facing scheduler hints; the substrate reads them to make placement decisions, but user code is expected to set them. The validator (validate_capabilities) does flag user writes onto exact-match reserved keys as a MetadataReservedKey warning so misconfiguration is visible without being fatal.

Substrate-internal callers that need to emit tool::* keys use the with_metadata_unchecked sibling (crate-private).

Source

pub fn set_hardware(&mut self, hardware: HardwareCapabilities)

Replace the hardware projection in-place.

Phase A.5.N.3: clears every hardware.* tag (excluding hardware.limits.* which belongs to ResourceLimits) and re-emits the new ones via hardware_to_tags.

Source

pub fn set_software(&mut self, software: SoftwareCapabilities)

Replace the software projection in-place.

Phase A.5.N.3: clears every software.* tag (excluding software.model.* and software.tool.* which belong to model/tool sub-collections) and re-emits the new ones.

Source

pub fn set_limits(&mut self, limits: ResourceLimits)

Replace the resource-limits projection in-place.

Phase A.5.N.3: clears every hardware.limits.* tag and re-emits the new ones.

Source

pub fn set_models(&mut self, models: Vec<ModelCapability>)

Replace the loaded-model list in-place.

Phase A.5.N.3: clears every software.model.* tag and re-emits the new indexed encoding via models_to_tags.

Source

pub fn set_tools(&mut self, tools: Vec<ToolCapability>)

Replace the available-tool list in-place.

Phase A.5.N.3: clears every software.tool.* tag, prunes stale tool::<id>::*_schema metadata, re-emits the indexed tag encoding, and mirrors fresh schemas into metadata.

Source

pub fn has_tag(&self, tag: &str) -> bool

Check if has a specific tag.

The query string is parsed via the permissive parser (Tag::parse) so reserved-prefix queries (scope:tenant:foo) resolve correctly. Set membership is exact: a query for hardware.gpu matches the AxisPresent tag, not an AxisValue with a different value.

Source

pub fn has_model(&self, model_id: &str) -> bool

Check if has a specific model.

Phase A.5.N.3: scans for software.model.<i>.id=<model_id> directly in the canonical tag set rather than reconstructing the full Vec<ModelCapability> via views().

Source

pub fn has_tool(&self, tool_id: &str) -> bool

Check if has a specific tool.

Phase A.5.N.3: scans for software.tool.<i>.tool_id=<tool_id> directly in the canonical tag set.

Source

pub fn has_gpu(&self) -> bool

Check if has GPU.

Phase A.5.N.3: looks for the hardware.gpu AxisPresent marker directly. Cheaper than reconstructing the full HardwareCapabilities projection.

Source

pub fn model_ids(&self) -> Vec<String>

Get all model IDs.

Phase A.5.N.3: returns owned Strings (rather than borrowed &str over a typed-struct field that no longer exists).

Source

pub fn tool_ids(&self) -> Vec<String>

Get all tool IDs.

Source

pub fn to_bytes(&self) -> Vec<u8>

Serialize to bytes (compact binary format)

Source

pub fn from_bytes(data: &[u8]) -> Option<CapabilitySet>

Deserialize from bytes

Source

pub fn diff(&self, prev: &CapabilitySet) -> CapabilitySetDiff

Compute the structural change from prev to self.

Phase 1 of CAPABILITY_ENHANCEMENTS_PLAN.md: a cheap before/after change detector that returns the raw set/map difference — added tags, removed tags, and per-key metadata changes (Added / Removed / Updated). Powers event-driven placement updates, capability-aware dashboards, and delta-based metadata propagation.

Cost: O(|tags| + |metadata|). Two HashSet::difference scans + a BTreeMap walk; no allocation beyond the output collections.

Composes with crate::adapter::net::behavior::diff::DiffEngine: DiffEngine::diff produces structural DiffOps (used by the propagation path); this method returns the raw set/map diff (better for change-event consumers). Same input data; pick the surface that matches the consumer’s shape.

Source

pub fn views(&self) -> CapabilityViews<'_>

All five view projections rolled into one struct, computed once per call. Cheaper than calling each From<&CapabilitySet> individually when the consumer reads more than one of them.

let caps = CapabilitySet::new();
let views = caps.views();
let _ = views.hardware();
let _ = views.software();
let _ = views.resource_limits();
let _ = views.models();
let _ = views.tools();

Borrowing handle exposing the five typed projections (HardwareCapabilities, SoftwareCapabilities, ResourceLimits, Vec<ModelCapability>, Vec<ToolCapability>).

Phase A.5.N.3 + Phase 1 of CAPABILITY_ENHANCEMENTS_PLAN.md: each projection is decoded from the canonical tag set (+ metadata, for tool schemas) on first access and cached for the lifetime of the handle. Repeated reads of the same projection hit the cache; reads of unrelated projections don’t force the full set of decoders.

The handle borrows self. Mutations to self invalidate the handle (compiler-enforced through the lifetime).

Source

pub fn typed_tags(&self) -> HashSet<Tag>

All capability data as a typed-tag set, including the hardware / software / models / tools / limits structs re-encoded as axis-prefixed tags AND the legacy tags Vec<String> parsed via Tag::parse. The future wire format (Phase A.5.2+) is exactly this HashSet<Tag>.

Round-trip-stable: Self::from_typed_tags(&caps.typed_tags()) produces a CapabilitySet semantically equal to caps, modulo the documented order non-preservation for non-indexed Vec fields (runtimes / frameworks / drivers).

Cost: linear in tag count. Currently computed on every call; downstream callers that read in a hot loop should cache the result.

Source

pub fn from_typed_tags(tags: &HashSet<Tag>) -> CapabilitySet

Build a CapabilitySet from a typed-tag set. Inverse of Self::typed_tags; uses the per-struct decoders to reconstruct the typed fields plus a legacy-carrier scan for reserved-prefix tags + unknown axis tags.

See Self::typed_tags for the round-trip contract.

Trait Implementations§

Source§

impl Clone for CapabilitySet

Source§

fn clone(&self) -> CapabilitySet

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CapabilitySet

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for CapabilitySet

Source§

fn default() -> CapabilitySet

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for CapabilitySet

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<CapabilitySet, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl From<&CapabilitySet> for HardwareCapabilities

Source§

fn from(caps: &CapabilitySet) -> HardwareCapabilities

Converts to this type from the input type.
Source§

impl From<&CapabilitySet> for ResourceLimits

Source§

fn from(caps: &CapabilitySet) -> ResourceLimits

Converts to this type from the input type.
Source§

impl From<&CapabilitySet> for SoftwareCapabilities

Source§

fn from(caps: &CapabilitySet) -> SoftwareCapabilities

Converts to this type from the input type.
Source§

impl PartialEq for CapabilitySet

Source§

fn eq(&self, other: &CapabilitySet) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for CapabilitySet

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for CapabilitySet

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,