Files
manage/openspec/changes/grafana-metric-gateway/sync-report.md
T
Developer cb8dd13514 spec(grafana-metric-gateway): sync — FIRST non-additive (MODIFIED) canonical
16 MODIFIED prometheus-charting requirements (transport: direct Prom -> Grafana
gateway; intent preserved where applicable), 3 ADDED (SC-128 gateway status,
SC-129 startup validation, SC-130 sanctioned transport), 11 PRESERVED, 0 REMOVED.
All 16 MODIFIED headers matched canonical exactly. Post-sync: 30 requirements.
web-ui + service-storage canonicals untouched.
2026-07-09 22:01:55 +00:00

190 lines
13 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.
# Sync Report — `grafana-metric-gateway`
> Phase: **sync** · Change: `grafana-metric-gateway` · Repo: `/home/user/manage`
> Mode: file-backed (`artifactStore: openspec`). No source-code edits; only OpenSpec artifacts were
> written. Not committed (parent owns the commit). The change folder was **not** moved (that is
> `sdd-archive`'s job).
**Status: SYNCED.** The first non-additive canonical sync in the project. The `prometheus-charting`
canonical domain's transport requirements were **MODIFIED** in place (direct Prom → Grafana gateway),
durable behavior requirements were **PRESERVED** verbatim, and three genuinely new requirements were
**ADDED** (SC-128 … SC-130).
---
## 1. Executive summary
The `prometheus-charting` canonical domain (`openspec/specs/prometheus-charting/spec.md`) was created
by `prometheus-direct-charting` with 27 requirements (SC-101 … SC-127) describing the **direct**
Prometheus transport. The `grafana-metric-gateway` change switches the `prometheus` service to a
**Grafana gateway** transport (`POST {grafana_url}/api/ds/query`), renames the chart/gauge/mean
widgets to neutral `Metric*` components, and validates the gateway path — while preserving the durable
*behavior* contracts (multi-series chart, gauge threshold bands, windowed mean, scalar-only rules).
This sync authored a change-side **delta** spec with both `## MODIFIED Requirements` and
`## ADDED Requirements` (the project's first delta to use MODIFIED), then applied it to the canonical
spec by exact-ID block replacement. No requirements were REMOVED or RENAMED. Verify returned PASS
(verdict in `verify-report.md`: 15 PASS + GM-115 PARTIAL-on-coverage-only, treated as effectively
16/16 per the dispatch brief; `apply-progress.md` exists and reconciles the 33 task checkboxes the
verify report flagged). All five quality gates were green at the verified commits (`df80c68`, `7e91e7f`).
## 2. Structured status & actionContext findings
The native `gentle-pi.sdd-status` passed by the parent reports `changeName: null` /
`blockedReasons: ["Change selection is ambiguous: grafana-metric-gateway, per-instance-hook-scoping,
service-credential-tester."]` because the engine auto-detected three active changes. This sync task
was **explicitly assigned** `grafana-metric-gateway`; the ambiguity is a dispatch artifact and does
not block this phase (`isNonAuthoritative: false`).
- `artifactStore: openspec`; change root `openspec/changes/grafana-metric-gateway/`.
- Artifacts present: `proposal.md`, `spec.md` (flat, with §"Canonical delta intent" mapping),
`design.md`, `tasks.md`, `verify-report.md`, `apply-progress.md`.
- `verify: PASS` (verify-report verdict; gates green). The verify report's single CRITICAL was an
**archive** blocker (33 unchecked task checkboxes + missing `apply-progress.md`); `apply-progress.md`
now exists, and that condition does **not** block `sdd-sync` of the green code.
- `actionContext`: `mode: repo-local`, `workspaceRoot: /home/user/manage`,
`allowedEditRoots: ["/home/user/manage"]`, `warnings: []`. All three files written are inside the
authoritative workspace / allowed edit roots. ✓
- `relationships.sameDomainActiveChanges: []`, `collisions: []` — **no active same-domain
collisions**, so no archive/sync ordering decision was required.
- The `web-ui` and `service-storage` canonical domains were **not touched** (verified untouched by
`git status`).
## 3. Domains synced & canonical files updated
| Domain | Change-side delta (source) | Canonical (sync target) | Action |
|---|---|---|---|
| `prometheus-charting` | `openspec/changes/grafana-metric-gateway/specs/prometheus-charting/spec.md` | `openspec/specs/prometheus-charting/spec.md` | **MODIFIED + ADDED** — 16 requirement blocks replaced in place by exact ID; 3 new requirements appended |
- **Canonical file updated:** `openspec/specs/prometheus-charting/spec.md` — now 30 requirements
(SC-101 … SC-130).
- **Change-side delta created:** `openspec/changes/grafana-metric-gateway/specs/prometheus-charting/spec.md`
`## MODIFIED Requirements` (16) + `## ADDED Requirements` (3).
## 4. Requirement delta (MODIFIED / ADDED / PRESERVED)
### MODIFIED (16) — transport & naming requirements replaced in place by exact SC- ID
| Canonical ID | Header (matched exactly) | What changed (GM source) |
|---|---|---|
| SC-101 | Prometheus range query returns the existing series shape | direct Prom `/api/v1/query_range` → Grafana `POST /api/ds/query`; config `base_url``grafana_url`+`datasource_uid`; secret `api_key``grafana_api_key` (GM-101, GM-102) |
| SC-102 | Series label normalization is shared and Prometheus-native | shared module now holds both `normalize_prometheus_matrix` + `normalize_grafana_frames`; shared dedup (GM-104) |
| SC-103 | Range query errors degrade gracefully | gateway-specific failures (401/403, datasource-not-found) added (GM-103) |
| SC-104 | Step is derived from the window preset | step math reused, mapped to `intervalMs`/`maxDataPoints`/`from`-`to` (GM-105) |
| SC-105 | Chart widget moves from grafana to prometheus | kinds stay on `prometheus`; transport is gateway; `Metric*` component binding (GM-109, GM-112) |
| SC-107 | Chart supports multiple series | multi-series via gateway (GM-106) |
| SC-109 | Gauge renders an instant scalar | instant query via gateway (GM-107) |
| SC-111 | Gauge is scalar-only | scalar-only preserved through gateway (GM-107) |
| SC-112 | Mean computes client-side over a window | range query via gateway (GM-108) |
| SC-114 | Mean is scalar-only | scalar-only preserved through gateway (GM-108) |
| SC-115 | No grafana references in backend source | becomes "no `grafana` **service type**"; transport refs allowed |
| SC-116 | No grafana references in frontend source | grafana transport allowed; no service type / link widget |
| SC-121 | config.yaml matches implementation | config.yaml now references Grafana as sanctioned transport |
| SC-122 | CHANGELOG documents the migration | migration note → "reconfigure prometheus with gateway fields" (GM-114) |
| SC-125 | New widget kinds have tests | renamed `Metric*` widgets tested (GM-111) |
| SC-126 | No silent data migration | no auto-migrate of old-shape prometheus config; operator reconfigures (GM-113) |
### ADDED (3) — fresh canonical IDs continuing the SC- sequence
| Canonical ID | Header | GM source |
|---|---|---|
| SC-128 | get_prometheus_status validates the full gateway path | GM-110 |
| SC-129 | Startup logs old-shape prometheus config without crashing | GM-113 (new behavior) |
| SC-130 | Grafana is the sanctioned transport for the prometheus service | sanctioned-transport statement |
### PRESERVED (11) — unchanged in canonical; NOT in the delta
SC-106 (chart renderer reused), SC-108 (chart window preset), SC-110 (gauge threshold bands),
SC-113 (mean plain PromQL), SC-117 (no grafana service type in registries), SC-118 (grafana status/UI
removed), SC-119 (orphan degrade), SC-120 (grafana tests removed), SC-123 (backend tests pass),
SC-124 (frontend typecheck/build/lint), SC-127 (non-blocking on service-storage-harness).
> **Count reconciliation:** 16 MODIFIED + 11 PRESERVED = 27 pre-existing requirements (SC-101 …
> SC-127, all retained); + 3 ADDED (SC-128 … SC-130) = **30 total** in the canonical spec post-sync.
### REMOVED (0) · RENAMED (0)
No requirements were removed or renamed. RENAMED is intentionally unsupported by the native delta
helper; the GM→SC mapping was resolved as ADDED/MODIFIED, never RENAMED.
## 5. Guardrails, approvals & destructive-sync assessment
- **Same-domain collisions:** none (`sameDomainActiveChanges: []`, `collisions: []`). No ordering
decision was needed.
- **Destructive sync:** This is a **non-additive** (MODIFIED-heavy) sync — 16 MODIFIED blocks, 0
REMOVED. Per the sync contract, a destructive/large-MODIFIED sync requires explicit approval
recorded in the parent prompt. **Approval is recorded:** the dispatch brief explicitly identifies
this as "the project's first non-additive sync," enumerates the exact SC-xxx to modify (including
the partial ones), and directs the MODIFIED/ADDED/PRESERVED split. No REMOVED requirements are
used. Proceeding under that recorded approval.
- **MODIFIED-block matching:** every MODIFIED block header matched the canonical spec **exactly**
(verified by `grep` of all 16 headers pre-edit; all 16 replacements applied with zero header
mismatches). No `## RENAMED Requirements` section was authored.
- **Legacy flat spec:** the flat `spec.md` is intentionally **left in place** as the planning
artifact the work was built against (archive convention keeps flat specs); the new domain delta
sits alongside it under `specs/prometheus-charting/`.
- **Other-domain isolation:** `openspec/specs/web-ui/spec.md` and `openspec/specs/service-storage/spec.md`
were **not modified** (`git status --porcelain` empty for both).
## 6. Validation / checks performed (file-backed, read-only)
Run from `/home/user/manage` (no source edits, no test re-runs — owned by verify, already green):
| Check | Command | Result |
|---|---|---|
| Canonical requirement count | `grep -cE "^### Requirement: SC-"` | **30** ✓ (was 27; +3 ADDED) |
| Canonical ID sequence intact | `grep -oE "SC-[0-9]+" \| sort -un` | SC-101 … SC-130, contiguous, no gaps/dupes ✓ |
| MODIFIED headers all matched | 16 exact-header edits to canonical | all 19 edits applied (front-matter, Purpose, 16 bodies, append) with **zero header mismatches** ✓ |
| No direct-Prom residue in canonical | `grep -c "api/v1/query_range"` canonical | **1** — and it is SC-101's intentional "MUST NOT issue any direct `GET /api/v1/query_range`" negation ✓ |
| Preserved block integrity | spot-check SC-106/108/110/113/117/118/127 | preserved verbatim ✓ |
| Delta is MODIFIED + ADDED only | count delta section headers | MODIFIED=1, ADDED=1, REMOVED=0, RENAMED=0 ✓ (no REMOVED → no destructive removal) |
| Delta ADDED IDs are fresh | `grep "SC-12[89]\|SC-130"` delta | SC-128, SC-129, SC-130 ✓ (no GM- reuse in canonical) |
| `web-ui` / `service-storage` untouched | `git status --porcelain openspec/specs/{web-ui,service-storage}` | empty ✓ |
| Front-matter + Purpose consistent | re-read canonical head | transport narrative updated to gateway (no "no Grafana middleman" contradiction with SC-121/SC-130) ✓ |
| Markdown validity | write-time lint | all three files clean ✓ |
## 7. Matching issues
**None.** All 16 MODIFIED block headers matched the canonical spec exactly; no fallback or fuzzy
matching was required. The single `api/v1/query_range` occurrence in the canonical post-sync is the
intentional negation inside SC-101, not a stale direct-Prom requirement.
## 8. Carry-over / residual notes for the archive summary
1. **[COSMETIC, non-blocking]** SC-106 (PRESERVED) still reads "preserved in the rebranded
`PrometheusChartWidget`". This change renames that component to `MetricChartWidget` (GM-111), but
SC-106 was explicitly listed as **PRESERVED** (not MODIFIED) in the change's "Canonical delta
intent", so it was left verbatim. The *intent* (recharts renderer reused unchanged) remains true;
only the component name in that one block is a cosmetic carry-over. A future change may refresh
the name if desired.
2. **[VERIFY carry-over, non-blocking for sync]** GM-115 was PARTIAL in verify on enumerated
test-coverage only (no startup-validation test; no status 401/403 → `auth_failed` test). Functional
code is correct; the dispatch brief treats this as closed/effectively-PASS. The new SC-128
(status gateway path) and SC-129 (startup validation) requirements now canonicalize this behavior;
`sdd-archive` may note the test-coverage gap.
3. **[INFO]** `normalize_prometheus_matrix` is intentionally retained as dead production code
(future-proof for a possible `direct_url` path); canonicalized by the MODIFIED SC-102.
4. **[INFO]** Stale generated `.pi-map.md` artifacts still reference old `Prometheus*Widget` names;
not deliverable source — regenerate at the orchestrator's convenience.
5. **[INFO]** Two uncommitted whitespace-only edits exist in the working tree
(`PrometheusMetricWidget.tsx`, `ServicesPage.tsx`) — unrelated to this sync; no files were staged
by this phase (`git diff --cached` empty).
## 9. Next recommended phase
**`sdd-archive`** (clean). Re-scan the native status engine to confirm `specs: done` / `sync: ready`
/ `archive: ready`, then move the change to
`openspec/changes/archive/YYYY-MM-DD-grafana-metric-gateway`, carrying over the items in §8. Do
**not** commit or push — the parent owns the commit with explicit paths.
---
### Appendix — Files written by this sync (OpenSpec only; no source code)
- `openspec/changes/grafana-metric-gateway/specs/prometheus-charting/spec.md` — **change-side domain
delta** (`## MODIFIED Requirements` × 16 + `## ADDED Requirements` × 3).
- `openspec/specs/prometheus-charting/spec.md`**canonical spec** (MODIFIED × 16 in place, ADDED × 3
appended; now 30 requirements SC-101 … SC-130; front-matter + Purpose updated for transport
consistency).
- `openspec/changes/grafana-metric-gateway/sync-report.md` — this report.