1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
//! Capability declarations — what a node can do.
//!
//! `CapabilitySet` describes hardware (CPU / GPU / memory), software
//! (OS / runtimes / frameworks), loaded models, available tools, and
//! free-form tags. `CapabilityFilter` lets peers query for nodes that
//! match a requirement; `CapabilityAnnouncement` is the signed
//! on-wire form.
//!
//! # Example
//!
//! ```
//! use net_sdk::capabilities::{
//! CapabilityFilter, CapabilitySet, GpuInfo, GpuVendor, HardwareCapabilities,
//! };
//!
//! // Declare: "this node has one RTX 4090 + 64 GB RAM, tagged `prod`".
//! let hw = HardwareCapabilities::new()
//! .with_cpu(16, 32)
//! .with_memory(64)
//! .with_gpu(GpuInfo::new(GpuVendor::Nvidia, "RTX 4090", 24));
//! let caps = CapabilitySet::new().with_hardware(hw).add_tag("prod");
//!
//! // Match-ability: does this node satisfy "needs GPU ≥ 16 GB VRAM"?
//! let filter = CapabilityFilter::new().require_gpu().with_min_vram(16);
//! assert!(filter.matches(&caps));
//! ```
//!
//! # Cross-node (direct-peer, one-hop)
//!
//! With `--features net`, `Mesh` has
//! [`announce_capabilities`](crate::mesh::Mesh::announce_capabilities)
//! and [`find_nodes`](crate::mesh::Mesh::find_nodes). Announce-side
//! self-indexes, so a single-node test is round-trippable:
//!
//! ```
//! # #[cfg(feature = "net")]
//! # async fn doc() -> net_sdk::error::Result<()> {
//! use net_sdk::capabilities::{CapabilityFilter, CapabilitySet};
//! use net_sdk::mesh::MeshBuilder;
//!
//! let node = MeshBuilder::new("127.0.0.1:0", &[0x42u8; 32])?
//! .build()
//! .await?;
//!
//! // Announce; also self-indexes.
//! node.announce_capabilities(CapabilitySet::new().add_tag("gpu"))
//! .await?;
//!
//! // Self-match hits.
//! let hits = node.find_nodes(&CapabilityFilter::new().require_tag("gpu"));
//! assert!(hits.contains(&node.node_id()));
//!
//! node.shutdown().await?;
//! # Ok(())
//! # }
//! ```
//!
//! Multi-hop propagation is deferred — peers more than one hop away
//! will not see the announcement. TTL + GC eviction match the core
//! defaults (`capability_gc_interval` on [`net::adapter::net::MeshNodeConfig`]).
//!
//! # Phase A — typed taxonomy + lazy view projections
//!
//! `CapabilitySet`'s wire format is two opaque fields: `tags:
//! HashSet<Tag>` and `metadata: BTreeMap<String, String>`. The
//! per-axis typed shapes (`HardwareCapabilities`,
//! `SoftwareCapabilities`, …) are *projections* — derived on demand
//! via [`CapabilitySet::views`] and cached lazily per access:
//!
//! ```
//! use net_sdk::capabilities::{CapabilitySet, HardwareCapabilities};
//!
//! let caps = CapabilitySet::new()
//! .with_hardware(HardwareCapabilities::new().with_memory(64))
//! .with_metadata("intent", "ml-training");
//!
//! let v = caps.views();
//! assert_eq!(v.hardware().memory_gb, 64); // first call: decodes hardware tags
//! assert_eq!(v.hardware().memory_gb, 64); // cached; pointer load only
//! ```
//!
//! Mutations to `caps` invalidate the handle (compiler-enforced via
//! the `&caps` borrow held by `views()`).
//!
//! # `CapabilitySet::diff` — change detection
//!
//! Two-line diff between successive announcements; powers
//! event-driven placement, dashboards, and delta propagation.
//!
//! ```
//! use net_sdk::capabilities::{CapabilitySet, MetadataChange};
//!
//! let prev = CapabilitySet::new().with_metadata("intent", "embedding-cache");
//! let curr = CapabilitySet::new().with_metadata("intent", "ml-training");
//!
//! let diff = curr.diff(&prev);
//! assert!(diff.added_tags.is_empty());
//! assert_eq!(diff.changed_metadata.len(), 1);
//! assert!(matches!(
//! &diff.changed_metadata[0],
//! MetadataChange::Updated { key, new_value, .. }
//! if key == "intent" && new_value == "ml-training",
//! ));
//! ```
//!
//! # Chain composition helpers
//!
//! Sugar over the `causal:` / `fork-of:` / `heat:` reserved-prefix
//! tags from the substrate's discovery primitive:
//!
//! ```
//! use net_sdk::capabilities::CapabilitySet;
//!
//! let caps = CapabilitySet::new()
//! .require_chain("origin-hash-abc")
//! .require_chain_range("range-chain", 100, 500)
//! .from_fork("parent-hash")
//! .heat_level("origin-hash-abc", 0.85);
//!
//! assert_eq!(caps.tags.len(), 4);
//! ```
//!
//! See [`docs/CAPABILITY_ENHANCEMENTS_USAGE.md`](https://github.com/ai-2070/net/blob/main/net/crates/net/docs/CAPABILITY_ENHANCEMENTS_USAGE.md)
//! for the full set of patterns.
// =============================================================================
// Substrate-layer types — Phase A foundation.
// =============================================================================
pub use ;
// =============================================================================
// Typed taxonomy — Phase A.1 of `CAPABILITY_SYSTEM_PLAN.md`.
//
// `Tag` is the parsed representation of a capability tag; `TagKey`
// is the `(axis, key)` half used by predicate variants that match
// on the key without the value. The four-axis ontology is fixed:
// `Hardware` / `Software` / `Devices` / `Dataforts`.
// =============================================================================
pub use ;
pub use ;
// =============================================================================
// Lazy view projections — Phase 1 of `CAPABILITY_ENHANCEMENTS_PLAN.md`.
//
// `caps.views()` returns a borrowing handle whose per-axis fields
// decode on first access and cache for the handle's lifetime.
// Reading only one axis no longer pays for the others.
// =============================================================================
pub use CapabilityViews;
// =============================================================================
// `CapabilitySet::diff` + `MetadataChange` — Phase 1 of
// `CAPABILITY_ENHANCEMENTS_PLAN.md`. Cheap before/after change
// detection over tag sets + metadata maps.
// =============================================================================
pub use ;
// =============================================================================
// Cardinality — Phase 4 follow-on of `CAPABILITY_ENHANCEMENTS_PLAN.md`.
//
// `CapabilityIndex` exposes O(1) cardinality lookups via the
// `CardinalityProvider` trait. `CardinalityCache<'a>` snapshots
// the lookups with a TTL to drop DashMap shard contention on
// hot loops; passes through the same trait so the planner uses
// either as a drop-in.
// =============================================================================
pub use ;
// =============================================================================
// Placement filter — Phase F slice 1 of `CAPABILITY_SYSTEM_PLAN.md`.
//
// `PlacementFilter::placement_score(target, artifact) -> Option<f32>`
// is the substrate's "score a candidate for placing an artifact"
// primitive. `LegacyPlacement` preserves today's
// `find_migration_targets` behavior (any node matching the
// `CapabilityFilter` is eligible at score 1.0) so the scheduler
// migration window swaps cleanly. `StandardPlacement` (the multi-
// axis reference impl) lands in slice 2 alongside `IntentRegistry`
// + the tie-breaking comparator.
// =============================================================================
pub use ;
// Phase 7 of the SDK plan — registry mapping SDK-generated IDs
// (`pf-N` from `placementFilterFromFn` in TS/Python/Go) to
// `Arc<dyn PlacementFilter>`. Bindings register their language-
// specific `PlacementFilter` wrappers here; scheduler-invoking
// code resolves an SDK ID to an impl before passing
// `&dyn PlacementFilter` to the scheduler.
pub use ;
// =============================================================================
// Required capability + macros — Phase A.3 of
// `CAPABILITY_SYSTEM_PLAN.md`. Used by `IntentRegistry` (Phase F)
// to declare per-intent placement requirements.
// =============================================================================
pub use ;
// Re-export the require! / require_axis! / require_axis_value! macros
// so callers can build `RequiredCapability` values without naming the
// underlying `TagKey` constructor.
pub use ;
// =============================================================================
// Predicate AST + planner + wire format — Phases 4 / 5 / 6 of
// `CAPABILITY_ENHANCEMENTS_PLAN.md`.
// =============================================================================
/// Predicate AST + evaluation, debug session, wire format, and
/// nRPC envelope helpers.
///
/// Phases 4 (planner), 5 (wire format + nRPC envelope), and 6
/// (debug session) of `CAPABILITY_ENHANCEMENTS_PLAN.md`.
///
/// ```
/// use net_sdk::capabilities::predicate::{
/// EvalContext, Predicate, RPC_WHERE_HEADER, predicate_to_rpc_header,
/// };
/// use net_sdk::capabilities::{Tag, TagKey, TaxonomyAxis};
/// use std::collections::BTreeMap;
///
/// // Build a predicate: GPU + memory ≥ 32 GB + intent = ml-training.
/// let pred = Predicate::And(vec![
/// Predicate::Exists {
/// key: TagKey::new(TaxonomyAxis::Hardware, "gpu"),
/// },
/// Predicate::NumericAtLeast {
/// key: TagKey::new(TaxonomyAxis::Hardware, "memory_gb"),
/// threshold: 32_768.0,
/// },
/// Predicate::MetadataEquals {
/// key: "intent".into(),
/// value: "ml-training".into(),
/// },
/// ]);
///
/// // Encode for an nRPC request header.
/// let header = predicate_to_rpc_header(&pred).expect("encode");
/// assert_eq!(header.0, RPC_WHERE_HEADER);
///
/// // Evaluate against a candidate.
/// let tags: Vec<Tag> = vec![Tag::AxisPresent {
/// axis: TaxonomyAxis::Hardware,
/// key: "gpu".into(),
/// }];
/// let mut metadata = BTreeMap::new();
/// metadata.insert("intent".into(), "ml-training".into());
/// let _ctx = EvalContext::new(&tags, &metadata);
/// // pred.evaluate(&_ctx) → false: an `And` is true only when ALL
/// // clauses are true. The candidate has gpu and intent=ml-training,
/// // but no `hardware.memory_gb` tag, so the NumericAtLeast clause
/// // fails and short-circuits the And to false.
/// ```
// Promote the `pred!` macro to the top-level `capabilities` module
// for ergonomics — most call sites read like `pred!(...)` rather
// than `predicate::pred!(...)`.
pub use pred;
// =============================================================================
// Schema + validation — Phase 2 of `CAPABILITY_ENHANCEMENTS_PLAN.md`.
//
// Per-binding canonical-doc-mirroring schema with a lightweight
// validator. Drives auto-completion, runtime validation, and CI
// drift detection (binding regenerators check against
// `CAPABILITIES_SCHEMA.md`).
// =============================================================================
/// Axis schemas + capability-set validation.
///
/// Phase 2 of `CAPABILITY_ENHANCEMENTS_PLAN.md`. `AXIS_SCHEMA`
/// mirrors the canonical
/// [`CAPABILITIES_SCHEMA.md`](https://github.com/ai-2070/net/blob/main/net/crates/net/docs/CAPABILITIES_SCHEMA.md);
/// `validate_capabilities(&caps)` returns a structured
/// [`schema::ValidationReport`].
///
/// ```
/// use net_sdk::capabilities::CapabilitySet;
/// use net_sdk::capabilities::schema::validate_capabilities;
///
/// let caps = CapabilitySet::new().add_tag("nat:full-cone");
/// let report = validate_capabilities(&caps);
/// assert!(report.is_valid()); // legacy tag is a warning, not error
/// assert!(!report.warnings.is_empty());
/// ```
// =============================================================================
// Diff engine — `behavior::diff::DiffEngine` is exposed alongside
// the simpler `CapabilitySet::diff` so callers picking the
// structural-ops shape (for propagation paths) reach for it via
// the same `capabilities::` namespace.
// =============================================================================
pub use ;