feat(shipote): CPU% + pipeline live-tail + replay por bytes (fase J)

- CPU% derivado server-side entre samples (WorkspaceState.last_cpu_sample).
  100% = 1 core saturado. Primer sample devuelve None (sin baseline).
- shipote pipeline run --tail: tras lanzar, suscribe al primer flow_socket
  y vuelca bytes hasta EOF. Auto-implica --tap.
- DiscernPolicy.replay_bytes: cap adicional por bytes para el replay
  buffer del FlowChannel. evict_for_incoming considera el chunk entrante
  para que post-push el buffer NUNCA exceda los caps.
- shipote-shell: stats history extiende sparkline con %CPU.

80 tests pasan (ente-incarnate 16, nouser-core 27, shipote-card 8,
shipote-core 21, 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 00:57:04 +00:00
parent 36dac00c8d
commit d8727a3038
9 changed files with 216 additions and 37 deletions
+10 -5
View File
@@ -389,19 +389,24 @@ impl Render for Shell {
.map(|h| h.iter().map(|s| s.rss_bytes.unwrap_or(0)).collect())
.unwrap_or_default();
let spark = sparkline(&rss_series, STATS_HISTORY_LEN);
let (rss_now, peak) = history
.and_then(|h| h.back())
.map(|s| (s.rss_bytes.unwrap_or(0), s.rss_peak_bytes.unwrap_or(0)))
.unwrap_or((0, 0));
let latest = history.and_then(|h| h.back());
let (rss_now, peak, cpu_pct) = latest
.map(|s| (
s.rss_bytes.unwrap_or(0),
s.rss_peak_bytes.unwrap_or(0),
s.cpu_percent.unwrap_or(0.0),
))
.unwrap_or((0, 0, 0.0));
let rss_mb = rss_now as f64 / 1024.0 / 1024.0;
let peak_mb = peak as f64 / 1024.0 / 1024.0;
format!(
"{:<14} {:<14} {} {:>6.1}M peak {:>6.1}M",
"{:<14} {:<14} {} {:>6.1}M peak {:>6.1}M {:>5.1}%cpu",
&w.id.to_string()[20..],
w.label,
spark,
rss_mb,
peak_mb,
cpu_pct,
)
})
.collect();