Task · TSO-0150

Diversify Grafana dashboard visualisations

Description

The generated dashboard family relies too heavily on conventional time series, stats, and tables, which hides relationship-heavy use cases such as network flow paths. The dashboard should use a broader but disciplined visual vocabulary, informed by the live m7kni Cloudflare flow dashboard, Grafana’s NetFlow integration dashboard, and Grafana Cloud’s installable panel catalogue, while remaining portable when optional plugins are absent.

Acceptance Criteria

Definition of Done

Implementation Plan

Dashboard visualisation diversity implementation plan

Goal: Add purpose-built relationship, composition, geography, state, distribution, and cardinality views without weakening native fallbacks, feature gates, PII gates, or dashboard portability.

Architecture: Extend the schema-v2 builder with deterministic option helpers and ordered transformations. Each domain tab owns its queries and layout; optional plugins remain additive panels beside native evidence. All artifacts continue to build in one process and publish only through GitSync.

Tech stack: Python 3 standard library and unittest, Grafana dashboard schema v2, PromQL, Loki, Grafana core panels, netsage-sankey-panel 1.1.4, marcusolsson-treemap-panel 2.1.1, just.

Spec: backlog/docs/specifications/doc-0006 - TSO-0150-dashboard-visualisation-redesign.md

Global constraints

Review focus

Task 1: Builder contracts for specialist panels

Files: Modify deploy/grafana/gen/builder.py; create deploy/grafana/gen/test_specialist_panels.py.

Interfaces: Extend organize(exclude=None, rename=None, index=None) so index becomes indexByName. Add pure option helpers pie_opts(), geomap_opts(location_field="lookup"), state_timeline_opts(), heatmap_opts(), sankey_opts(value_field="Value"), and treemap_opts(label_field, size_field, group_field=None). Continue using panel(..., ptype, version=...) for core and plugin groups.

Task 2: Flow topology and composition

Files: Modify deploy/grafana/gen/tabs/network.py; modify deploy/grafana/gen/test_network_diagnostics.py; generated deploy/grafana/tailscale2otel-tailnet.json is updated later in Task 5.

Interfaces: Add helper topology_sankey(title, metric, prerequisite) returning a panel name. Its instant table query is topk($topn, sum by (tailscale_src_node, tailscale_dst_node) (rate(<metric><scope-and-flow-filters>[$__rate_interval]))); organize fields in Source, Destination, Bytes/s order and set Sankey valueField to Bytes/s.

Task 3: Fleet, Kubernetes, and service relationship views

Files: Modify deploy/grafana/gen/tabs/devices_inventory.py, deploy/grafana/gen/tabs/security_compliance.py, deploy/grafana/gen/tabs/k8saudit.py, deploy/grafana/gen/tabs/policy_integrations.py; extend deploy/grafana/gen/test_specialist_panels.py and relevant existing fleet/policy tests.

Interfaces: Devices by country becomes core geomap with geo_country_iso_code renamed and ordered as lookup, then Devices. Device online state by node uses the per-device online gauge in a pii_perdevice row. Kubernetes request paths orders user, verb, resource, Value and is gated by has_k8s_audit plus pii_emails. VIP service topology orders service display name, host name, Value and is gated by has_svc plus pii_perdevice.

Task 4: Health state, distribution, and cardinality cost

Files: Modify deploy/grafana/gen/tabs/health_collection.py, deploy/grafana/gen/tabs/cardinality.py; extend deploy/grafana/gen/test_specialist_panels.py and existing self-observability coverage tests.

Interfaces: Convert Scrape success by collector to core state-timeline. Add Capability availability history from tailscale2otel_capability_status_ratio grouped by collector and state. Add Scrape duration distribution from sum by (le) (rate(tailscale2otel_scrape_duration_histogram_seconds_bucket<filters>[$__rate_interval])). Add plugin Active series by metric family from a top-N instant table over tailscale2otel_active_series, ordered metric_name then Value, using treemap label metric_name and size Value.

Task 5: Generate, review, publish, and prove the result

Files: Regenerate both deploy/grafana/*.json artifacts and any alert-link/docs outputs changed transitively by just gen-dashboards; update TSO-0150 only through Backlog CLI.

Plan correction from self-review

In Task 4, Active series by metric family must query topk($topn, max by (metric_name) (tailscale2otel_series_active)), not the nonexistent tailscale2otel_active_series. Its ordered table fields are metric_name, then Value; the treemap labels by metric_name and sizes by Value.

Implementation Notes

Design approved in chat on 2026-09-19. Audit baseline: 502 generated panels; m7kni confirms Sankey 1.1.4 and Treemap 2.1.1 installed. Written design is doc-0006 and awaits review before implementation planning.

Written spec approved by Rob on 2026-09-19. Native same-session execution selected by the instruction to continue autonomously; implementation begins after plan review per the writing-plans gate.

Plan self-review completed: spec coverage, placeholder scan, interface names, gates, and Review Focus tests checked. Corrected the cardinality metric name through an append-only plan amendment.

Validation and delivery evidence (2026-09-19):

Final Summary

Diversified both generated Grafana dashboards with purpose-built Sankey, pie, geomap, state-timeline, heatmap, and treemap panels while preserving native evidence, top-N bounds, raw/rollup separation, signal-presence gates, and PII gates. Verified deterministic generation and the full local gate, completed a clean sharded CodeRabbit review, proved exact-SHA CI and GitSync delivery, and visually exercised both deployed dashboards in native Chrome on m7kni.

References

View the source file on GitHub