Files
manage/openspec/changes/grafana-metric-gateway/apply-progress.md
T
Developer c886fcdf09 spec(grafana-metric-gateway): verify + close GM-115 + reconcile tracking
Add 3 test cases (startup old-config validation warning; status auth_failed
for 401/403) closing the GM-115 PARTIAL. Write apply-progress.md, tick all 33
tasks, add verify-report.md (15/16 PASS, 1 PARTIAL->PASS). Gates green: 331+
pytest, ruff clean, npm build+lint 0 errors, 151 vitest.
2026-07-09 21:53:18 +00:00

3.9 KiB

Apply Progress: Grafana Metric Gateway

Change: grafana-metric-gateway Phase: apply-progress Date: 2026-07-09 Status: complete — all 33 tasks done, all gates green, verified (see verify-report.md)

Slices delivered

Two slices, each its own commit, each leaving pytest / npm run build / npm run lint / ruff green.

Slice 1 — Backend gateway transport (commit df80c68, amended)

  • integrations/prometheus.pyPrometheusConfig rewritten: dropped base_url; added grafana_url: ServiceBaseUrl + datasource_uid: str = "prometheus" + kept timeout_seconds; secret_fields now grafana_api_key (required, encrypted). Widget kinds chart/gauge/mean/metric unchanged (GM-101).
  • widgets/prometheus_range.py — added normalize_grafana_frames(raw) refactored from the recovered 65bae95 code; shares _dedup_label with the retained normalize_prometheus_matrix (DRY). step_for_window preserved (qBit dependency) (GM-104).
  • widgets/sources.py — renamed PrometheusWidgetSourceMetricSource (SERVICE_ADAPTERS key stays "prometheus"). All four kinds (chart/gauge/mean/metric) now route through one _gateway_query POSTing {grafana_url}/api/ds/query with Authorization: Bearer {api_key} + datasource {uid, type:"prometheus"}; window presets map to from/intervalMs/maxDataPoints. Zero direct /api/v1/query[_range] calls remain (GM-102/106/107/108/109).
  • routers/monitoring.pyget_prometheus_status runs expr:"up" through the gateway; maps failures (auth/unreachable/datasource) (GM-110).
  • main.py — startup old-config validation: detects persisted prometheus services with the old shape (base_url/no grafana_url) and logs a migration warning. Best-effort, no crash (GM-113).
  • CHANGELOG.md[Unreleased] BREAKING entry: reconfigure prometheus services with grafana_url/datasource_uid/grafana_api_key (GM-114).
  • Tests rewritten: chart/gauge/mean adapter tests assert POST /api/ds/query + frames mock (not direct Prom). test_prometheus_range.py gains normalize_grafana_frames tests.

Slice 2 — Frontend widget renames (commit 7e91e7f)

  • git mv (R100, history preserved): PrometheusChartWidget.tsxMetricChartWidget.tsx (+ test); same for Gauge + Mean. Exports renamed; tests updated (GM-111).
  • integrations/registry.tsprometheus binding's component refs updated to MetricChartWidget/MetricGaugeWidget/MetricMeanWidget. Kinds stay chart/gauge/mean/metric. Barrel widgets/index.ts updated (GM-112).
  • PrometheusMetricWidget deliberately KEPT under that name (design §3.1) — it's the instant-query numeric widget, adapted (design §3.4 Option A) to read the gateway's normalized {result:[{label,points}]} shape via last-point extraction.
  • Rendering unchanged: LineSeriesChart, gauge bands, mean windowing preserved verbatim. qBit widgets untouched.

Deviations from tasks.md

  • None functional. PrometheusMetricWidget was not renamed (design §3.1 explicitly kept it); its data-shape was adapted per design §3.4 Option A.

Final gate results

Gate Result
backend && PYTHONPATH=src python3 -m pytest -q 331 passed, 2 warnings (pre-existing pythonjsonlogger DeprecationWarning)
backend && PYTHONPATH=src python3 -m ruff check src tests All checks passed
frontend && npm run build exit 0 (pre-existing chunk-size warning)
frontend && npm run lint 0 errors, 1 pre-existing warning (WidgetConfigDialog.tsx, untouched)
frontend && npx vitest run 151 passed — renamed Metric* tests + qBit speed (LineSeriesChart non-regression) all green

Verification

See verify-report.md — adversarial fresh-context review: 15/16 PASS, 1 PARTIAL (GM-115 coverage gap: no startup-validation or status-auth-failed enumerated tests; code paths correct). No blocking code findings. The partial is a coverage gap, not a defect; can be closed with two small tests if desired before archive.