Cristales temporales, replay, lease/renew y audit streaming
- GapHistogram añade sum_squares_secs → stddev en O(1). GapStats serializable con count/mean/stddev/max. - Crystal incluye gap_stats?: GapStats. crystal_to_rule emite Sequence con within_ms = (mean+2σ)*1000 cuando gap_stats.count >= 4; fallback a Single. - audit::collect_chain_from_cas() recoge la cadena en orden cronológico. replay_chain() reconstruye RuleEngine aplicando PromoteCrystal/RemoveRule. Endpoint ReplayAudit + brainctl replay. - GrantedCapability con expires_at: Instant. DEFAULT_GRANT_TTL = 60s. EnteGraph::renew_grant + purge_expired_grants. Tick cada 10s en el bucle primordial. - AuditLog::subscribe() entrega un mpsc::UnboundedReceiver. append() empuja a todos los subscribers, purgando los muertos. IntrospectRequest::StreamAudit toma posesión de la conn y envía AuditStreamFrame en bucle. brainctl stream-audit imprime entries en directo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -237,6 +237,10 @@ async fn primordial_loop(
|
||||
};
|
||||
tokio::pin!(dev_exit);
|
||||
|
||||
// GC de capability grants expirados — corre cada 10 segundos.
|
||||
let mut grant_purge = tokio::time::interval(Duration::from_secs(10));
|
||||
grant_purge.tick().await; // descartar primer tick inmediato
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
biased;
|
||||
@@ -258,6 +262,13 @@ async fn primordial_loop(
|
||||
}
|
||||
}
|
||||
|
||||
_ = grant_purge.tick() => {
|
||||
let n = graph.purge_expired_grants();
|
||||
if n > 0 {
|
||||
info!(purged = n, active = graph.active_grants_count(), "GC capability grants");
|
||||
}
|
||||
}
|
||||
|
||||
_ = async { dev_exit.as_mut().as_pin_mut().unwrap().await }, if dev_mode => {
|
||||
info!("dev mode: timer expirado, cerrando bucle primordial");
|
||||
let _ = graph_tx.send(GraphEvent::Shutdown {
|
||||
|
||||
Reference in New Issue
Block a user