Files
manage/openspec/changes/prometheus-direct-charting/apply-progress.md
T
Developer 7440603cdb spec(prometheus-direct-charting): verify + close SC-125 + reconcile tracking
Add loading-state tests to the three Prometheus widget test files
(closes SC-125 PARTIAL). Write apply-progress.md, tick all 39 tasks,
add verify-report.md (26/27 PASS, 1 PARTIAL->PASS). All gates green:
293 pytest, ruff clean, npm build+lint 0 errors. No blocking findings.
2026-07-08 22:50:30 +00:00

55 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Apply Progress: Prometheus Direct Charting
**Change:** `prometheus-direct-charting`
**Phase:** apply-progress
**Date:** 2026-07-08
**Status:** complete — all 39 tasks done, all gates green, verified (see `verify-report.md`)
## Slices delivered
Three slices, each its own commit, each leaving `pytest` / `npm run build` / `npm run lint` / `ruff` green.
### Slice 1 — Prometheus range query + chart rebrand (commit `5dad982`, amended)
- Created `backend/src/media_library_viewer_api/widgets/prometheus_range.py` with `step_for_window(s)` (`max(15, round(s/200))` → ~200 pts/window) and `normalize_prometheus_matrix(result)` (shared label rule extracted from the to-be-removed Grafana path; drops `__name__`/`__*`, joins sorted `k=v`, falls back to `"value"`, dedups with `(n)`).
- Extended `PrometheusWidgetSource.fetch` to dispatch `widget_kind == "chart"``_fetch_chart` hitting `/api/v1/query_range` directly, returning `{series:[...]}` (SC-101..104). Grafana path left intact at this slice.
- Declared `chart` widget kind in `integrations/prometheus.py` (config: `promql`, `window``{1h,6h,24h,7d}`).
- `git mv GrafanaChartWidget.tsx → PrometheusChartWidget.tsx` (recharts body preserved verbatim; empty-state copy updated); `git mv` of its test. Rebound `chart` grafana→prometheus in both registries (SC-105..108).
- Backend tests: new `test_prometheus_range.py` (step + normalization); chart-adapter test in `test_widgets.py`. Frontend registry test updated.
### Slice 2 — Gauge + mean widgets (commit `58be6e0`, amended)
- Extracted shared `_instant_query` helper; added `_fetch_gauge` (instant → scalar, multi-series → `{error}`) and `_fetch_mean` (range query over preset → client-side arithmetic mean of non-null values, scalar-only).
- Declared `gauge` (`promql`, `warn_at`/`crit_at`/`min`/`max`/`unit`) and `mean` (`promql`, `window`, `unit`) kinds in `integrations/prometheus.py`.
- Created `PrometheusGaugeWidget.tsx` (recharts `RadialBarChart`; green/amber/red threshold bands when `warn_at`+`crit_at` set; neutral single track otherwise) and `PrometheusMeanWidget.tsx` (MetricCard-style single value). Wired both into the frontend `prometheus` binding + barrel.
- Tests: backend adapter tests (scalar-only enforcement, mean aggregation incl. NaN-skip, error cases); frontend component tests (error + rendered, gauge with/without bands, mean with/without unit).
### Slice 3 — Grafana removal + config + changelog (commit `ba94317`, amended)
- Deleted `integrations/grafana.py`, `GrafanaLinkWidget.tsx`, `service-tabs/LinksTab.tsx` (+ test). Removed `GrafanaWidgetSource` + adapter registration; `grafana` from `SERVICE_DEFINITIONS`/`SERVICE_ADAPTERS` (BE) and `SERVICE_REGISTRY`/`BUILTIN_WIDGETS` (FE); `get_grafana_status` endpoint; `useGrafanaStatus`/`fetchGrafanaStatus`/`GrafanaStatus`; nav entry; `service-tabs/index.ts` grafana case; `Dashboard.tsx` `OBSERVABILITY_TYPES` grafana member; `ServicesPage.tsx` empty-state copy; grafana tests.
- Rewrote `openspec/config.yaml`: removed stale "Do NOT re-implement charting in-app" + "No recharts/d3" claims; states Manage renders Prometheus-backed metrics directly via recharts and that Grafana is no longer integrated.
- Added `CHANGELOG.md` `[Unreleased]` entry: **BREAKING** — Grafana service type removed; migrate by deleting grafana instances and recreating as Prometheus; `grafana/chart` widgets → `prometheus/chart`.
- Net: **920 lines** across 27 files.
### Coverage close — SC-125 loading-state tests
- Added one `it("renders skeleton while loading")` case to each of the three Prometheus widget test files, asserting the `Skeleton` (`data-slot="skeleton"`) renders under `{ data: undefined, isLoading: true }`. Closes the PARTIAL finding on SC-125.
## Deviations from tasks.md
- None functional. The only textual drift is SC-118: `ObservabilityPage.tsx` had already been refactored into `service-tabs/` (the project map was stale). Removal targets adjusted to the real files (`LinksTab.tsx`, `service-tabs/index.ts`, `navEntries.ts`, `Dashboard.tsx`, `ServicesPage.tsx`); the spec was patched (SC-116/SC-118) to reflect this before apply. SC-118's *intent* (no Grafana UI surface) is fully satisfied.
## Final gate results (re-run after coverage close)
| Gate | Result |
|---|---|
| `backend && PYTHONPATH=src python3 -m pytest -q` | **293 passed**, 2 warnings (pre-existing pythonjsonlogger DeprecationWarning) |
| `backend && PYTHONPATH=src python3 -m ruff check src tests` | **All checks passed** |
| `frontend && npm run build` (`tsc -b` + `vite build`) | **exit 0** (pre-existing chunk-size warning) |
| `frontend && npm run lint` | **0 errors**, 1 pre-existing warning (`WidgetConfigDialog.tsx:370`, untouched) |
| `frontend && npx vitest run` (3 Prom widget tests) | **14 passed** (11 original + 3 new loading) |
## Verification
See `verify-report.md` — adversarial fresh-context review: **26/27 fully PASS, 1 PARTIAL→PASS** (SC-125 closed here). No blocking findings remain.