Swarm v2 fleet dashboard and alert contract (SV2-OBS-05)
The fleet dashboard is a projection of recorded observations. It holds no authority, starts no work and never acts on an alert. Panels, labels, limits and alert rules live in observability/swarm-v2.json; scripts.swarm_v2.fleet_dashboard reads them.
Sample
One observation of the fleet at at_ms, numbered by a rising seq.
| Field | Shape | Source |
|---|---|---|
pools | pool, configured_maximum, nodes, template.cpu_millis, template.memory_mib | Declared ASG ceilings and node templates; nodes is the joined, ready count. A deployed controller’s worker pool reading sets configured_maximum to the Pod policy worker_pool.pods limit and nodes to the distinct nodes running live worker Pods, with no template. It is one pool per controller, named by the worker namespace, and the Kubernetes attempts and pending admissions carry that pool |
attempts | execution_id, seat, task, phase (active or pending), pool, permitted_pools, requested, pending_since_ms, protected, idle_since_ms, terminal, authority | Execution registry and runtime observation |
quota | account, state (waiting or allowed), since_ms, resets_at_ms | Fleet quota readings |
archive | The SV2-OBS-04 diagnose archive entry: execution_id, seat, process, activity, heartbeat_at_ms, watermark, advanced_at_ms, state, observed_at_ms | Health.diagnose |
checkpoints | execution_id, seat, taken_at_ms of the newest checkpoint | Each pointer the controller artifacts API commits; an active execution with none yet ages from its start; a reading expires seven days after its execution leaves the active set |
brain.feed_at_ms | Time of the newest brain feed | Brain adapter |
brain.denials | denial_id, at_ms, requester_scope, target_brain, session_title | Brain routing refusals; not measured yet, because the brain does not refuse a cross scope query |
Panels
| Panel | Series | Meaning |
|---|---|---|
attempts | active, pending | Admitted attempts running, and admitted attempts waiting for a node |
capacity | configured_maximum, observed_nodes, active_tasks, pending_requests per pool | A configured maximum is a declared ceiling, never a live node count; each series carries its own label |
quota_wait | waiting_accounts, longest_wait_ms | Accounts held by quota and the longest current hold |
archive_lag | lagging, worst_lag_ms | Executions whose archive watermark has not advanced within archive_lag_ms |
checkpoint_age | stale, oldest_age_ms | Executions whose newest checkpoint is older than checkpoint_stale_ms |
connectivity | terminal, authority | Operator terminal transport and worker execution authority, counted apart; a disconnected terminal is not a dead worker |
knowledge | feed_age_ms, cross_scope_denials, stale, denials | Brain feed freshness and the denied cross scope queries |
An age equal to its limit is not stale. A denial’s session_title and target_brain are shown only to a viewer whose grant names that brain; every other viewer reads the withheld marker. The viewer comes from a grant’s brains list. A display label, a role name or an actor name never grants a brain, and a grant without a brains list is refused.
Alerts
| Rule | Holds when | Window |
|---|---|---|
protected_idle_pod | An active attempt carries scale down protection and has been idle since idle_since_ms | for_ms 600000 |
impossible_pending | A pending attempt’s request fits no permitted pool template (no_permitted_template_fits), or every fitting permitted pool is at its configured maximum (permitted_pools_at_configured_maximum) | for_ms 120000 |
A pool sample reports its node count, not free room on each node. permitted_pools_at_configured_maximum is therefore a proxy: the autoscaler can add no node, and a request still pending after the window is taken as one the existing nodes cannot place. | cross_scope_denial | A brain query was denied across scopes | for_ms 0 |
- At most
limitalerts per rule per evaluation, longest held first; the rest are counted insuppressedand listed by fingerprint inheldwith the shown ones. - An alert carries its subject, sanitized facts, owner and action, and
automaticfalse. It never carries a session title or a target brain name. alert_actionability_reviewcounts alerts whose owner and action match their rule, that name their subject and never act, and lists the rest asunactionable.
Incidents
IncidentStore keeps one incident per fingerprint (rule and subject) under the swarm’s fleet-incidents hash and the last recorded seq under fleet-incidents-seq.
- An evaluation whose
seqis not above the recorded one is stale and changes nothing, so a replay after an alert backend restart never duplicates an incident. - Only shown alerts open incidents. An open incident resolves only when its fingerprint is no longer in
held, so a suppressed condition never reads as cleared; a condition that returns after resolving opens a new incident. A suppressed incident keeps thefactsandlast_seqof the last evaluation that showed it. deliverhands each opened incident to the sink once, identified as<fingerprint>:<opened_seq>; a failing sink leaves it for the next delivery. Delivery only notifies. Every store write watches its keys and retries up to five times when another writer changed them. Delivery is at least once at one edge: when the notified mark still fails after those retries,deliverraises after the sink ran and the next delivery sends the sameincident_idagain, so a sink deduplicates by it.
Entrypoint and recorded canary
python -m scripts.swarm_v2.fleet_view --grant <grant.json> with either --samples <trace.json> (a JSON list of samples) or --canary <SV2-CAP-02 result> --overlay <readings.json> prints, per trace, the dashboard of its last sample, the alerts held at every sample and the actionability review. A grant without a brains list exits 2 with the refusal on stderr.
scripts.swarm_v2.fleet_canary turns each live run of the recorded antoncore SV2-CAP-02 scaling canary into one sample at the canary Pod’s creation and one per recorded stage: the anton-k3s-swarm group with its configured maximum, the node once it is ready, and the Pod pending until it starts. The overlay joins the quota, archive, checkpoint and brain readings. The record carries no resource request or node template, and an unknown shape never proves a request impossible, so only the at maximum test applies to recorded runs.
Compatibility
- The archive panel reads the SV2-OBS-04
Health.diagnosearchive entry unchanged. - The dashboard, alerts and incidents add the keys
fleet-incidentsandfleet-incidents-sequnder each swarm and change no existing key, command or API. - The local swarm path never reads the definition or the module; with the module absent or alerts off, local execution behaves as before.
Rollback
AGENTIHOOKS_FLEET_ALERTS=off stops evaluation, recording and delivery of alerts. The dashboard, the recorded incidents and worker execution are untouched.
Data safety: the execution registry, quota, archive, checkpoint and brain records are authoritative and only read. The incident hash and evaluated sequence are operational records owned by this package; a rollback leaves them in place for audit, and removing them never touches an authoritative object.