Public dry run dryrun-529dbe43b301

This commit is contained in:
Michel Paulissen 2026-07-03 19:44:27 +02:00
parent 16cb76e6e2
commit bef088c34c
3 changed files with 205 additions and 27 deletions

View file

@ -1,7 +1,7 @@
{
"kind": "disasmer-filtered-public-tree",
"source_commit": "22f391eb394afc47797118ce3a8b98cc36ba2a45",
"release_name": "dryrun-22f391eb394a",
"source_commit": "529dbe43b301d0436dbb4739b399daf4709b89ea",
"release_name": "dryrun-529dbe43b301",
"filtered_out": [
"private/**",
"experiments/**",

View file

@ -9,7 +9,8 @@ use anyhow::{Context, Result};
use clap::{Args, Parser, Subcommand};
use disasmer_core::{
BrowserLoginFlow, BundleIdentityInputs, BundleMetadata, Capability, CliLoginFlow, Digest,
NodeCapabilities, ProjectModel, SelectedInput, SourceProviderKind, SourceProviderManifest,
LimitKind, NodeCapabilities, ProjectModel, ResourceLimits, SelectedInput, SourceProviderKind,
SourceProviderManifest,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
@ -1290,18 +1291,30 @@ fn debug_attach_report(args: DebugAttachArgs) -> Result<Value> {
}))
}
fn quota_status_report(args: QuotaStatusArgs) -> Result<Value> {
fn quota_status_report(args: QuotaStatusArgs, cwd: PathBuf) -> Result<Value> {
let config = read_project_config(&cwd)?;
let effective_scope = effective_project_scope(&args.scope, config.as_ref());
let coordinator = effective_scope.coordinator.clone();
let attached_nodes =
list_attached_nodes_if_available(coordinator.as_deref(), &effective_scope)?;
let task_events =
list_task_events_if_available(coordinator.as_deref(), &effective_scope, None)?;
let current_usage = quota_current_usage(&attached_nodes, task_events.as_ref());
Ok(json!({
"command": "quota status",
"tenant": args.scope.tenant,
"project": args.scope.project,
"coordinator": args.scope.coordinator,
"tenant": effective_scope.tenant,
"project": effective_scope.project,
"user": effective_scope.user,
"coordinator": coordinator,
"project_config": config,
"policy_surface": "generic public quota categories; hosted tuning remains private policy",
"limits": {
"artifact_download_bytes": "community-tier policy before dispatch",
"rendezvous_attempts": "community-tier policy before dispatch",
"hosted_wasm": "fuel/memory/wall-clock/state/logs/metadata/ui/api limits before start"
},
"limits": quota_limits_value(),
"current_usage": current_usage,
"attached_nodes": attached_nodes,
"task_events": task_events,
"next_blocked_action": quota_next_blocked_action(&current_usage),
"community_tier_language": true,
"billing_required": false,
"private_abuse_heuristics_exposed": false,
}))
}
@ -1469,6 +1482,17 @@ fn human_report(value: &Value) -> String {
if let Some(current_usage) = value.pointer("/quota_posture/current_usage") {
lines.push(format!("quota usage: {}", compact_json(current_usage)));
}
if let Some(current_usage) = value.get("current_usage") {
lines.push(format!("quota usage: {}", compact_json(current_usage)));
}
if let Some(next_blocked_action) = value.get("next_blocked_action") {
if !next_blocked_action.is_null() {
lines.push(format!(
"next blocked action: {}",
compact_json(next_blocked_action)
));
}
}
if let Some(flow) = value.get("human_flow") {
if let Some(device) = flow.get("Device") {
lines.push("flow: device".to_owned());
@ -1839,7 +1863,10 @@ fn main() -> Result<()> {
command: QuotaCommands::Status(args),
} => {
let json_output = args.scope.json;
emit_report(&quota_status_report(args)?, json_output)?;
emit_report(
&quota_status_report(args, std::env::current_dir()?)?,
json_output,
)?;
}
Commands::Admin { command } => {
let (report, json_output) = match command {
@ -2131,6 +2158,19 @@ fn task_event_count(task_events: Option<&Value>) -> usize {
}
fn project_quota_posture(attached_nodes: &Value, task_events: Option<&Value>) -> Value {
let current_usage = quota_current_usage(attached_nodes, task_events);
let next_blocked_action = quota_next_blocked_action(&current_usage);
json!({
"source": "cli_project_status_summary",
"current_usage": current_usage,
"limits": quota_limits_value(),
"next_blocked_action": next_blocked_action,
"billing_required": false,
"private_abuse_heuristics_exposed": false,
})
}
fn quota_current_usage(attached_nodes: &Value, task_events: Option<&Value>) -> Value {
let attached_node_count = attached_nodes
.get("count")
.and_then(Value::as_u64)
@ -2140,23 +2180,51 @@ fn project_quota_posture(attached_nodes: &Value, task_events: Option<&Value>) ->
.and_then(Value::as_u64)
.unwrap_or(0);
json!({
"source": "cli_project_status_summary",
"current_usage": {
"attached_nodes": attached_node_count,
"online_nodes": online_node_count,
"observed_task_events": task_event_count(task_events),
},
"limits": {
"artifact_download_bytes": "checked before download link creation",
"rendezvous_attempts": "checked before rendezvous plan creation",
"hosted_wasm": "checked before hosted coordinator-side work starts",
},
"next_blocked_action": null,
"billing_required": false,
"private_abuse_heuristics_exposed": false,
"artifact_download_bytes": 0,
"rendezvous_attempts": 0,
"hosted_wasm_processes": 0,
})
}
fn quota_limits_value() -> Value {
let limits = ResourceLimits::community_tier_defaults();
json!({
"api_calls": limits.limit(&LimitKind::ApiCall),
"spawns": limits.limit(&LimitKind::Spawn),
"log_bytes": limits.limit(&LimitKind::LogBytes),
"metadata_bytes": limits.limit(&LimitKind::MetadataBytes),
"debug_read_bytes": limits.limit(&LimitKind::DebugReadBytes),
"ui_events": limits.limit(&LimitKind::UiEvent),
"rendezvous_attempts": limits.limit(&LimitKind::RendezvousAttempt),
"artifact_download_bytes": limits.limit(&LimitKind::ArtifactDownloadBytes),
"hosted_fuel": limits.limit(&LimitKind::HostedFuel),
"hosted_memory_bytes": limits.limit(&LimitKind::HostedMemoryBytes),
"hosted_wall_clock_ms": limits.limit(&LimitKind::HostedWallClockMs),
"hosted_state_bytes": limits.limit(&LimitKind::HostedStateBytes),
"hosted_tuning_private": true,
})
}
fn quota_next_blocked_action(current_usage: &Value) -> Value {
if current_usage
.get("online_nodes")
.and_then(Value::as_u64)
.unwrap_or(0)
== 0
{
return json!({
"action": "node_work_requires_online_attached_node",
"category": "capability",
"quota_related": false,
"message": "no online attached node is visible for work that requires a user node"
});
}
Value::Null
}
fn login_plan(args: LoginArgs) -> LoginPlan {
login_plan_with_nonce(args, login_nonce())
}
@ -3822,6 +3890,114 @@ mod tests {
);
}
#[test]
fn quota_status_uses_project_config_and_generic_public_limits() {
let temp = tempfile::tempdir().unwrap();
write_project_config(
temp.path(),
&ProjectConfig {
tenant: "tenant-quota".to_owned(),
project: "project-quota".to_owned(),
user: "user".to_owned(),
coordinator: None,
},
)
.unwrap();
let status = quota_status_report(
QuotaStatusArgs {
scope: CliScopeArgs {
coordinator: None,
tenant: "tenant".to_owned(),
project: "project".to_owned(),
user: "user".to_owned(),
json: false,
},
},
temp.path().to_path_buf(),
)
.unwrap();
assert_eq!(status["command"], "quota status");
assert_eq!(status["tenant"], "tenant-quota");
assert_eq!(status["project"], "project-quota");
assert_eq!(status["current_usage"]["attached_nodes"], 0);
assert_eq!(status["limits"]["artifact_download_bytes"], 268_435_456);
assert_eq!(status["community_tier_language"], true);
assert_eq!(status["billing_required"], false);
assert_eq!(
status["next_blocked_action"]["action"],
"node_work_requires_online_attached_node"
);
}
#[test]
fn quota_status_queries_public_coordinator_usage() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap().to_string();
let server = std::thread::spawn(move || {
for _ in 0..2 {
let (mut stream, _) = listener.accept().unwrap();
let mut reader = BufReader::new(stream.try_clone().unwrap());
let mut line = String::new();
reader.read_line(&mut line).unwrap();
if line.contains("\"type\":\"list_node_descriptors\"") {
assert!(line.contains("\"tenant\":\"tenant-live\""));
stream
.write_all(
br#"{"type":"node_descriptors","descriptors":[{"id":"node-a","online":true},{"id":"node-b","online":false}],"actor":"user"}"#,
)
.unwrap();
stream.write_all(b"\n").unwrap();
} else if line.contains("\"type\":\"list_task_events\"") {
assert!(line.contains("\"project\":\"project-live\""));
stream
.write_all(
br#"{"type":"task_events","events":[{"process":"vp-live","task":"task-a"},{"process":"vp-live","task":"task-b"}]}"#,
)
.unwrap();
stream.write_all(b"\n").unwrap();
} else {
panic!("unexpected coordinator request: {line}");
}
}
});
let temp = tempfile::tempdir().unwrap();
write_project_config(
temp.path(),
&ProjectConfig {
tenant: "tenant-live".to_owned(),
project: "project-live".to_owned(),
user: "user".to_owned(),
coordinator: Some(addr.clone()),
},
)
.unwrap();
let status = quota_status_report(
QuotaStatusArgs {
scope: CliScopeArgs {
coordinator: None,
tenant: "tenant".to_owned(),
project: "project".to_owned(),
user: "user".to_owned(),
json: false,
},
},
temp.path().to_path_buf(),
)
.unwrap();
server.join().unwrap();
assert_eq!(status["coordinator"], addr);
assert_eq!(status["current_usage"]["attached_nodes"], 2);
assert_eq!(status["current_usage"]["online_nodes"], 1);
assert_eq!(status["current_usage"]["observed_task_events"], 2);
assert!(status["next_blocked_action"].is_null());
assert_eq!(status["task_events"]["response"]["type"], "task_events");
}
#[test]
fn build_command_reuses_bundle_inspection_without_full_repo_upload() {
let temp = tempfile::tempdir().unwrap();

View file

@ -108,6 +108,8 @@ for (const [name, pattern] of [
["doctor ping reachability coverage", /fn doctor_pings_configured_coordinator\(\)/],
["project local config coverage", /fn project_init_select_and_status_use_local_project_config\(\)/],
["project coordinator status coverage", /fn project_status_queries_public_coordinator_state\(\)/],
["quota local status coverage", /fn quota_status_uses_project_config_and_generic_public_limits\(\)/],
["quota coordinator usage coverage", /fn quota_status_queries_public_coordinator_usage\(\)/],
["build no full repo upload coverage", /fn build_command_reuses_bundle_inspection_without_full_repo_upload\(\)/],
["safe coordinator-required plans", /fn node_enroll_and_process_commands_have_safe_plan_without_coordinator\(\)/],
]) {