feat(stats): add an 'all' time range to agent + hive stats

Adds a Window::All option to the per-agent stats page and the hive-wide
rollup, selectable as a new 'all' tab on both.

- hive-ag3nt (per-agent, time-bucketed): All ranges from MIN(started_at)
  to now (fallback to now on an empty table) with an adaptive bucket
  width laddered by span — hourly <=2d, daily <=90d, weekly <=2y, 30-day
  beyond — so the trend series stays bounded (~<=104 buckets) at any age.
- hive-c0re (swarm rollup, not time-bucketed): All sets from=0 so the
  aggregate covers every recorded turn across all agents.
- frontend: an 'all' button on both the agent stats and dashboard hive
  stats window selectors (createTabStrip + fetch already pass the window
  string through, so no JS change needed).

cargo check passes on both crates; FE builds clean. Fixes #1919.
This commit is contained in:
iris 2026-06-22 23:36:17 +02:00 committed by mara
commit 684c85686e
4 changed files with 60 additions and 5 deletions

View file

@ -35,6 +35,9 @@ pub enum Window {
ThreeDay,
Week,
Month,
/// All available data: aggregate over every recorded turn since the
/// earliest (`from == 0`), with no fixed lookback.
All,
}
impl Window {
@ -46,6 +49,7 @@ impl Window {
"3d" => Self::ThreeDay,
"7d" => Self::Week,
"30d" => Self::Month,
"all" => Self::All,
_ => Self::Day,
}
}
@ -58,6 +62,7 @@ impl Window {
Self::ThreeDay => "3d",
Self::Week => "7d",
Self::Month => "30d",
Self::All => "all",
}
}
@ -69,6 +74,9 @@ impl Window {
Self::ThreeDay => 3 * 24 * 3600,
Self::Week => 7 * 24 * 3600,
Self::Month => 30 * 24 * 3600,
// `All` has no fixed lookback; `hive_snapshot` uses `from == 0`
// (every recorded turn). 0 here is a consistent safe fallback.
Self::All => 0,
}
}
}
@ -314,7 +322,13 @@ fn read_bash_heads(conn: &Connection, from: i64) -> HashMap<String, u64> {
#[must_use]
pub fn hive_snapshot(window: Window, prices: &PriceTable) -> HiveStats {
let now = now_secs();
let from = now - window.span_secs();
// Fixed windows look back a constant span; `all` aggregates every
// recorded turn (`from == 0`). The hive rollup isn't time-bucketed, so
// unlike the per-agent snapshot it needs no adaptive bucket sizing.
let from = match window {
Window::All => 0,
_ => now - window.span_secs(),
};
let mut agents: Vec<AgentRollup> = Vec::new();
let mut model_mix: HashMap<String, u64> = HashMap::new();