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
@@ -211,7 +211,10 @@ pub async fn run_pipeline(
i
);
let socket = crate::flow_channel::default_flow_socket_path(&id);
match crate::flow_channel::FlowChannel::with_replay_cap(socket.clone(), spec.discern.replay_chunks) {
match crate::flow_channel::FlowChannel::with_replay_caps(
socket.clone(),
crate::flow_channel::ReplayCaps::new(spec.discern.replay_chunks, spec.discern.replay_bytes),
) {
Ok(fc) => {
senders_per_edge.push(Some(fc.sender_handle()));
paths_per_edge.push(Some(socket));
@@ -693,6 +696,7 @@ mod tests {
sample_bytes: 4096,
enrich_producer: true,
replay_chunks: 32,
replay_bytes: 0,
},
};
let disc = Arc::new(DiscernPipeline::default_pipeline());