Skip to content

Commit 2f44002

Browse files
westgatewestgate
authored andcommitted
S191: Wire Standard L3 cost_estimates + primal-name cleanup
Implement compute-cost-as-energy model for capabilities.list: per-method cost_estimates (cpu, gpu_eligible, latency_ms, energy, memory_pressure) and operation_dependencies DAG. Cost expressed as energy/time/compute intensity — dollar value is an end-user concern built on these primitives. Remove last 4 user-visible hardcoded primal names from CLI strings: cli_root banner, dispatch manifest, universal adapter error messages. Made-with: Cursor
1 parent 0ec944e commit 2f44002

4 files changed

Lines changed: 294 additions & 9 deletions

File tree

crates/cli/src/cli_root.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ manifest files (biome.yaml).
2222
2323
🎯 SOVEREIGN SCIENCE: Your compute, your data, your control
2424
🚀 UNIVERSAL COMPUTE: If it has a chip and memory, ToadStool runs on it
25-
🔒 ZERO TRUST: BearDog cryptographic security by default
25+
🔒 ZERO TRUST: Cryptographic security by default
2626
")]
2727
pub struct Cli {
2828
/// Top-level subcommand (ecosystem, universal, daemon, etc.)

crates/cli/src/commands/dispatch/manifest.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ pub async fn execute_validate(
6868
);
6969
println!(" Primals: {}", manifest.primals.len());
7070
println!(" Services: {}", manifest.services.len());
71-
println!(" BearDog Required: {}", manifest.security.beardog_required);
71+
println!(
72+
" Security Required: {}",
73+
manifest.security.beardog_required
74+
);
7275
}
7376
}
7477

crates/cli/src/ecosystem/adapters/universal.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! ## Protocol Priority (UNIVERSAL_IPC_STANDARD_V3)
88
//!
99
//! JSON-RPC 2.0 over Unix sockets is preferred (pure Rust, no tonic/protobuf).
10-
//! HTTP is deprecated for primal-to-primal; use Songbird for external HTTP.
10+
//! HTTP is deprecated for primal-to-primal; use coordination service for external HTTP.
1111
1212
use crate::{CliContextExt, Result};
1313
use serde::{Deserialize, Serialize};
@@ -143,7 +143,7 @@ impl UniversalServiceAdapter {
143143
Err(crate::CliError::Other(
144144
"gRPC protocol not supported. Migrate to JSON-RPC over Unix socket: \
145145
use UnixJsonRpcClient from toadstool_common::unix_jsonrpc_client. \
146-
(UNIVERSAL_IPC_STANDARD_V3). For external HTTP, route through Songbird."
146+
(UNIVERSAL_IPC_STANDARD_V3). For external HTTP, route through coordination service."
147147
.to_string(),
148148
))?
149149
}
@@ -253,7 +253,7 @@ impl UniversalServiceAdapter {
253253
/// Invoke via HTTP/REST — always returns an error.
254254
///
255255
/// HTTP is not supported for primal-to-primal. External HTTP routes through
256-
/// Songbird (Concentrated Gap architecture).
256+
/// the coordination service (Concentrated Gap architecture).
257257
#[deprecated(
258258
since = "0.92.0",
259259
note = "HTTP adapter removed. Use Unix socket RPC for primal-to-primal."
@@ -267,14 +267,14 @@ impl UniversalServiceAdapter {
267267
_provider: &ServiceProvider,
268268
_request: Request,
269269
) -> Result<Response> {
270-
// External HTTP should go through Songbird (Concentrated Gap architecture)
270+
// External HTTP should go through the coordination service (Concentrated Gap architecture)
271271
tracing::error!(
272272
"HTTP invoke deprecated - use Unix socket RPC for primal-to-primal communication"
273273
);
274274

275275
Err(crate::CliError::Other(
276276
"HTTP adapter removed. Use Unix socket RPC instead. \
277-
For external HTTP, route through Songbird (Concentrated Gap architecture)."
277+
For external HTTP, route through the coordination service (Concentrated Gap architecture)."
278278
.to_string(),
279279
))?
280280
}

crates/server/src/pure_jsonrpc/handler/core.rs

Lines changed: 284 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,14 @@ fn all_callable_methods(semantic_registry: &SemanticMethodRegistry) -> Vec<&str>
146146
methods
147147
}
148148

149-
/// Wire Standard L2 `capabilities.list` response.
149+
/// Wire Standard L3 `capabilities.list` response.
150150
///
151-
/// Returns `{primal, version, methods, provided_capabilities}` per
151+
/// Returns `{primal, version, methods, provided_capabilities, cost_estimates,
152+
/// operation_dependencies, consumed_capabilities}` per
152153
/// `CAPABILITY_WIRE_STANDARD.md` v1.0.
154+
///
155+
/// Cost model: energy/time/compute, not monetary. Dollar value is an
156+
/// end-user concern built on top of these primitives.
153157
#[expect(
154158
clippy::unused_async,
155159
reason = "handler signature requires async for uniform dispatch"
@@ -223,11 +227,261 @@ pub(crate) async fn capabilities_list(
223227
"coordination.register",
224228
"coordination.discover"
225229
],
230+
"cost_estimates": cost_estimates(),
231+
"operation_dependencies": operation_dependencies(),
226232
"protocol": "jsonrpc-2.0",
227233
"transport": ["uds", "tcp"]
228234
}))
229235
}
230236

237+
/// Wire Standard L3: per-method compute cost estimates.
238+
///
239+
/// Models cost as energy, time, and compute intensity — not monetary.
240+
/// Dollar value is an end-user concern built on these primitives.
241+
///
242+
/// Fields per method:
243+
/// - `cpu`: negligible | low | medium | high | variable
244+
/// - `gpu_eligible`: whether this method can trigger GPU work
245+
/// - `latency_ms`: expected p50 latency in milliseconds
246+
/// - `energy`: negligible | low | medium | high | variable
247+
/// - `memory_pressure`: none | low | medium | high | variable
248+
fn cost_estimates() -> serde_json::Value {
249+
let mut map = serde_json::Map::with_capacity(60);
250+
251+
let cost = |cpu: &str, gpu: bool, latency: u32, energy: &str, mem: &str| -> serde_json::Value {
252+
serde_json::json!({
253+
"cpu": cpu, "gpu_eligible": gpu, "latency_ms": latency,
254+
"energy": energy, "memory_pressure": mem
255+
})
256+
};
257+
258+
// Meta / discovery — pure in-memory, no I/O
259+
for m in [
260+
"health.liveness",
261+
"health.check",
262+
"health.readiness",
263+
"capabilities.list",
264+
"identity.get",
265+
"toadstool.version",
266+
"provenance.query",
267+
] {
268+
map.insert(m.into(), cost("negligible", false, 0, "negligible", "none"));
269+
}
270+
271+
// Workload lifecycle
272+
map.insert(
273+
"toadstool.submit_workload".into(),
274+
cost("variable", true, 50, "variable", "variable"),
275+
);
276+
map.insert(
277+
"toadstool.query_status".into(),
278+
cost("negligible", false, 1, "negligible", "none"),
279+
);
280+
map.insert(
281+
"toadstool.cancel_workload".into(),
282+
cost("low", false, 5, "low", "none"),
283+
);
284+
map.insert(
285+
"toadstool.list_workloads".into(),
286+
cost("low", false, 2, "low", "low"),
287+
);
288+
map.insert(
289+
"toadstool.query_capabilities".into(),
290+
cost("low", false, 5, "low", "low"),
291+
);
292+
293+
// Resource estimation
294+
map.insert(
295+
"resources.estimate".into(),
296+
cost("medium", false, 10, "low", "low"),
297+
);
298+
map.insert(
299+
"resources.validate_availability".into(),
300+
cost("medium", false, 10, "low", "low"),
301+
);
302+
map.insert(
303+
"resources.suggest_optimizations".into(),
304+
cost("medium", false, 20, "low", "low"),
305+
);
306+
307+
// GPU job queue
308+
map.insert(
309+
"compute.submit".into(),
310+
cost("variable", true, 50, "variable", "variable"),
311+
);
312+
map.insert(
313+
"compute.status".into(),
314+
cost("negligible", false, 1, "negligible", "none"),
315+
);
316+
map.insert(
317+
"compute.result".into(),
318+
cost("low", false, 5, "low", "medium"),
319+
);
320+
map.insert(
321+
"compute.cancel".into(),
322+
cost("low", false, 2, "low", "none"),
323+
);
324+
map.insert("compute.list".into(), cost("low", false, 2, "low", "low"));
325+
326+
// Shader dispatch — high GPU, high energy
327+
map.insert(
328+
"shader.dispatch".into(),
329+
cost("high", true, 100, "high", "high"),
330+
);
331+
map.insert(
332+
"compute.dispatch.submit".into(),
333+
cost("high", true, 100, "high", "high"),
334+
);
335+
map.insert(
336+
"compute.dispatch.status".into(),
337+
cost("negligible", false, 1, "negligible", "none"),
338+
);
339+
map.insert(
340+
"compute.dispatch.result".into(),
341+
cost("low", false, 10, "low", "medium"),
342+
);
343+
map.insert(
344+
"compute.dispatch.forward".into(),
345+
cost("medium", false, 50, "medium", "low"),
346+
);
347+
348+
// Hardware learning — BAR0/MMIO reads
349+
map.insert(
350+
"compute.hardware.observe".into(),
351+
cost("medium", false, 20, "medium", "low"),
352+
);
353+
map.insert(
354+
"compute.hardware.distill".into(),
355+
cost("high", false, 100, "medium", "medium"),
356+
);
357+
map.insert(
358+
"compute.hardware.apply".into(),
359+
cost("medium", false, 50, "medium", "low"),
360+
);
361+
map.insert(
362+
"compute.hardware.share_recipe".into(),
363+
cost("low", false, 10, "low", "low"),
364+
);
365+
map.insert(
366+
"compute.hardware.auto_init".into(),
367+
cost("high", false, 200, "high", "medium"),
368+
);
369+
map.insert(
370+
"compute.hardware.auto_init_all".into(),
371+
cost("high", false, 500, "high", "medium"),
372+
);
373+
map.insert(
374+
"compute.hardware.status".into(),
375+
cost("low", false, 5, "low", "none"),
376+
);
377+
map.insert(
378+
"compute.hardware.vfio_devices".into(),
379+
cost("low", false, 10, "low", "none"),
380+
);
381+
382+
// Performance surface
383+
map.insert(
384+
"compute.performance_surface.report".into(),
385+
cost("medium", false, 20, "low", "medium"),
386+
);
387+
map.insert(
388+
"compute.performance_surface.query".into(),
389+
cost("medium", false, 10, "low", "low"),
390+
);
391+
map.insert(
392+
"compute.performance_surface.list".into(),
393+
cost("low", false, 2, "low", "low"),
394+
);
395+
map.insert(
396+
"compute.route.multi_unit".into(),
397+
cost("medium", false, 15, "low", "low"),
398+
);
399+
400+
// GPU telemetry — sysfs/BAR0 reads
401+
map.insert(
402+
"gpu.query_info".into(),
403+
cost("low", false, 10, "low", "low"),
404+
);
405+
map.insert(
406+
"gpu.query_memory".into(),
407+
cost("low", false, 5, "low", "none"),
408+
);
409+
map.insert(
410+
"gpu.query_telemetry".into(),
411+
cost("low", false, 10, "low", "none"),
412+
);
413+
414+
// Gate routing — network I/O
415+
map.insert("gate.update".into(), cost("low", false, 5, "low", "none"));
416+
map.insert("gate.remove".into(), cost("low", false, 2, "low", "none"));
417+
map.insert("gate.list".into(), cost("low", false, 1, "low", "low"));
418+
map.insert(
419+
"gate.route".into(),
420+
cost("medium", false, 30, "medium", "low"),
421+
);
422+
423+
// Transport — DMA/device I/O
424+
map.insert(
425+
"transport.discover".into(),
426+
cost("medium", false, 50, "medium", "low"),
427+
);
428+
map.insert(
429+
"transport.list".into(),
430+
cost("low", false, 2, "low", "none"),
431+
);
432+
map.insert(
433+
"transport.route".into(),
434+
cost("medium", false, 20, "medium", "low"),
435+
);
436+
map.insert(
437+
"transport.open".into(),
438+
cost("medium", false, 50, "medium", "medium"),
439+
);
440+
map.insert(
441+
"transport.stream".into(),
442+
cost("high", false, 100, "high", "high"),
443+
);
444+
map.insert(
445+
"transport.status".into(),
446+
cost("low", false, 2, "low", "none"),
447+
);
448+
449+
// Ember — device lifecycle
450+
map.insert("ember.list".into(), cost("low", false, 5, "low", "none"));
451+
map.insert("ember.status".into(), cost("low", false, 5, "low", "none"));
452+
453+
serde_json::Value::Object(map)
454+
}
455+
456+
/// Wire Standard L3: method prerequisite DAG.
457+
///
458+
/// Maps methods to their prerequisites — what must be called (or
459+
/// have completed) before a given method is meaningful.
460+
fn operation_dependencies() -> serde_json::Value {
461+
serde_json::json!({
462+
"compute.status": ["compute.submit"],
463+
"compute.result": ["compute.submit"],
464+
"compute.cancel": ["compute.submit"],
465+
"toadstool.query_status": ["toadstool.submit_workload"],
466+
"toadstool.cancel_workload":["toadstool.submit_workload"],
467+
"compute.dispatch.status": ["compute.dispatch.submit"],
468+
"compute.dispatch.result": ["compute.dispatch.submit"],
469+
"compute.hardware.distill": ["compute.hardware.observe"],
470+
"compute.hardware.apply": ["compute.hardware.distill"],
471+
"compute.hardware.share_recipe": ["compute.hardware.distill"],
472+
"compute.hardware.auto_init": ["compute.hardware.observe"],
473+
"compute.hardware.auto_init_all":["compute.hardware.observe"],
474+
"compute.performance_surface.query": ["compute.performance_surface.report"],
475+
"compute.route.multi_unit": ["compute.performance_surface.report"],
476+
"gate.route": ["gate.update"],
477+
"gate.remove": ["gate.update"],
478+
"transport.route": ["transport.discover"],
479+
"transport.open": ["transport.discover"],
480+
"transport.stream": ["transport.open"],
481+
"transport.status": ["transport.open"]
482+
})
483+
}
484+
231485
/// Returns discovered capabilities including semantic methods.
232486
///
233487
/// Legacy `compute.discover_capabilities` — returns node capabilities
@@ -440,6 +694,34 @@ mod tests {
440694

441695
assert!(cap["consumed_capabilities"].as_array().is_some());
442696
assert_eq!(cap["protocol"], "jsonrpc-2.0");
697+
698+
// Wire Standard L3: cost_estimates
699+
let costs = cap["cost_estimates"].as_object().expect("cost_estimates");
700+
assert!(
701+
costs.len() >= 40,
702+
"should have cost estimates for most methods"
703+
);
704+
let health_cost = &costs["health.liveness"];
705+
assert_eq!(health_cost["cpu"], "negligible");
706+
assert_eq!(health_cost["energy"], "negligible");
707+
assert_eq!(health_cost["gpu_eligible"], false);
708+
let dispatch_cost = &costs["shader.dispatch"];
709+
assert_eq!(dispatch_cost["cpu"], "high");
710+
assert_eq!(dispatch_cost["energy"], "high");
711+
assert_eq!(dispatch_cost["gpu_eligible"], true);
712+
let submit_cost = &costs["compute.submit"];
713+
assert_eq!(submit_cost["cpu"], "variable");
714+
assert_eq!(submit_cost["energy"], "variable");
715+
716+
// Wire Standard L3: operation_dependencies
717+
let deps = cap["operation_dependencies"]
718+
.as_object()
719+
.expect("operation_dependencies");
720+
assert!(deps.len() >= 15, "should have dependency entries");
721+
let status_deps = deps["compute.status"].as_array().expect("array");
722+
assert!(status_deps.iter().any(|d| d == "compute.submit"));
723+
let stream_deps = deps["transport.stream"].as_array().expect("array");
724+
assert!(stream_deps.iter().any(|d| d == "transport.open"));
443725
}
444726

445727
#[tokio::test]

0 commit comments

Comments
 (0)