Split the aggregate ObservabilityPage into three instance-scoped tabs on
their respective service pages, replacing the AlertsTab/LinksTab/
MetricsTab stubs.
AlertsTab (alertmanager): Alertmanager status line + active-alerts
summary (count + by severity) + expandable alert list (AlertItem with
severity badge, summary, description, labels, active-since). Empty
state when no alerts.
LinksTab (grafana): Grafana status line + machine-selector dropdown +
GrafanaLinkCards (Node Exporter metrics dashboard, Loki log explorer)
generated from instance.config.base_url. Empty states when no base_url
or no machine selected.
MetricsTab (prometheus): Prometheus status line + Node Exporter targets
table with labels badges. Empty state when no targets.
All three tabs use the existing observability hooks which are global /
first-configured (no service_id param yet). Per-instance scoping by
instance.id is a documented follow-up once the hooks gain the parameter
(same pattern as JobsTab slice 7). LinksTab does read
instance.config.base_url for the specific Grafana deep-link URL.
stubs.tsx loses AlertsTab/LinksTab/MetricsTab stubs (only OverviewTab
stub remains); index.ts wires the real components.
Old ObservabilityPage.tsx stays in the repo (route removed slice 4;
file deleted slice 11).
Tests: 2 per tab (renders content + empty/error states with mocked
hooks). 106 tests pass (+6); lint/build green.
Refs openspec/changes/services-as-hub-ia/ (spec R2.4/R8, tasks slice 9).