feat(shipote): health endpoint + audit log + token-bucket real (fase R)

- Request::Health → Response::Health { version, uptime_ms, alive_*,
  active_flows, dirty }. CLI: shipote health.
- handle_client lee peer_uid una vez al accept. audit_request emite
  info!(target: "audit", uid, action, detail) por mutación (create/stop/
  run/pipeline.*/flow.drop). Reads omitidos. Filtrable con SHIPOTE_LOG=
  warn,audit=info.
- TokenBucket real reemplaza rate_limit_sleep: refill por wall time,
  capacity = 1s de rate, debt negativo dispara sleep proporcional.
  Permite burst real, no chunk-by-chunk uniforme.

85 tests pasan (ente-incarnate 16, nouser-core 27, shipote-card 8,
shipote-core 26, shipote-discern 5, yahweh-provider-fs 3).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-11 16:58:10 +00:00
parent 18c0344a52
commit a9124449f9
5 changed files with 180 additions and 13 deletions
+27
View File
@@ -24,6 +24,9 @@ enum Cmd {
/// Health-check del daemon.
Ping,
/// Health endpoint estructurado.
Health,
/// Capacidades runtime detectadas por el daemon.
Caps,
@@ -195,6 +198,30 @@ async fn main() -> Result<()> {
}
}
Cmd::Health => {
let resp = round_trip(&mut stream, Request::Health).await?;
match resp {
Response::Health {
version,
uptime_ms,
alive_workspaces,
alive_commands,
alive_pipelines,
active_flows,
dirty,
} => {
println!("version: {version}");
println!("uptime: {} ms", uptime_ms);
println!("alive_workspaces: {alive_workspaces}");
println!("alive_commands: {alive_commands}");
println!("alive_pipelines: {alive_pipelines}");
println!("active_flows: {active_flows}");
println!("dirty: {dirty}");
}
other => print_unexpected(&other),
}
}
Cmd::Caps => {
let resp = round_trip(&mut stream, Request::Capabilities).await?;
match resp {