Summary
Grafana template variables of type interval are dropped during migration. No Kibana control is emitted for them, nothing in the migrated artifact references them, and no warning is raised — even though the variable may be controlling the rate window of every query on the dashboard.
Grafana community dashboard 9852 "node-exporter disk graphs" declares:
{ "name": "RateInterval", "type": "interval", "query": "20s,1m,5m" }
and 16 of its targets use it as the rate window, e.g.
rate(node_disk_written_bytes_total{instance=~"$Node", device!="sr0", device=~"$Disk"}[$RateInterval])
After migration:
- Controls emitted:
Node, CPU, Disk. No RateInterval.
- The string
RateInterval does not appear anywhere in the native dashboard artifact (it survives only in migration_report.json / verification_packets.json as a copy of the original PromQL).
CONTROL WARNINGS (3) covers the multi-select semantics of Node, CPU and Disk. There is no warning that a fourth variable was discarded.
The operator loses a control that was on the source dashboard, and is not told.
Why this is more than a missing dropdown
In Grafana the rate window and the display resolution are independent: [$RateInterval] defaults to 1m, so with a 15s scrape each point averages ~4 samples and the line is smooth, regardless of how wide the chart is.
In the migrated panel the rate window is implicitly whatever TBUCKET chose. On a 15-minute range TBUCKET(100, ?_tstart, ?_tend) resolves to 10-second buckets (confirmed in the response metadata: "_meta":{"bucket":{"interval":10,"unit":"second"}}), which is narrower than the 15s scrape interval. The same panel that is smooth in Grafana comes out stair-stepped with periodic gaps in Kibana, and the operator has no 1m/5m option to smooth it back.
So dropping the variable does not just remove a widget — it silently transfers control of the rate window to the bucket heuristic, and the two are not equivalent.
Environment
Reproduction
obs-migrate migrate \
--source grafana \
--input-mode api \
--grafana-url "$GRAFANA_URL" \
--field-profile prometheus_native \
--output-dir ./out
Then:
grep -c RateInterval ./out/dashboards/native/*.json # 0
python -c "import json,glob; \
print([c['config']['title'] for c in json.load(open(glob.glob('./out/dashboards/native/*.json')[0]))['payload']['pinned_panels']])"
# ['Node', 'CPU', 'Disk']
Suggested fix
Two parts, and the first matters more than the second:
- Disclose it. An
interval variable that is referenced by panel queries and then dropped should produce a warning in the same list as the other control warnings, naming the variable and what now determines the rate window. Silent loss of a source control is the part that conflicts with the "degrade gracefully, do not hide semantic gaps" rule in AGENTS.md.
- Optionally support it. The values are a fixed list (
20s,1m,5m), so it could map to a Kibana ES|QL control bound into the bucket/window expression, giving back the smoothing choice.
Related
Summary
Grafana template variables of type
intervalare dropped during migration. No Kibana control is emitted for them, nothing in the migrated artifact references them, and no warning is raised — even though the variable may be controlling the rate window of every query on the dashboard.Grafana community dashboard 9852 "node-exporter disk graphs" declares:
{ "name": "RateInterval", "type": "interval", "query": "20s,1m,5m" }and 16 of its targets use it as the rate window, e.g.
After migration:
Node,CPU,Disk. NoRateInterval.RateIntervaldoes not appear anywhere in the native dashboard artifact (it survives only inmigration_report.json/verification_packets.jsonas a copy of the original PromQL).CONTROL WARNINGS (3)covers the multi-select semantics ofNode,CPUandDisk. There is no warning that a fourth variable was discarded.The operator loses a control that was on the source dashboard, and is not told.
Why this is more than a missing dropdown
In Grafana the rate window and the display resolution are independent:
[$RateInterval]defaults to1m, so with a 15s scrape each point averages ~4 samples and the line is smooth, regardless of how wide the chart is.In the migrated panel the rate window is implicitly whatever
TBUCKETchose. On a 15-minute rangeTBUCKET(100, ?_tstart, ?_tend)resolves to 10-second buckets (confirmed in the response metadata:"_meta":{"bucket":{"interval":10,"unit":"second"}}), which is narrower than the 15s scrape interval. The same panel that is smooth in Grafana comes out stair-stepped with periodic gaps in Kibana, and the operator has no1m/5moption to smooth it back.So dropping the variable does not just remove a widget — it silently transfers control of the rate window to the bucket heuristic, and the two are not equivalent.
Environment
feat/curated-dashboard-packs(PR feat!: curated dashboard packs, PromQL fidelity, and native-only dashboard artifacts #346) at5db742f9.5.0-SNAPSHOTnode_exporter, 15s scrape--field-profile prometheus_native, no curated pack appliesReproduction
obs-migrate migrate \ --source grafana \ --input-mode api \ --grafana-url "$GRAFANA_URL" \ --field-profile prometheus_native \ --output-dir ./outThen:
Suggested fix
Two parts, and the first matters more than the second:
intervalvariable that is referenced by panel queries and then dropped should produce a warning in the same list as the other control warnings, naming the variable and what now determines the rate window. Silent loss of a source control is the part that conflicts with the "degrade gracefully, do not hide semantic gaps" rule inAGENTS.md.20s,1m,5m), so it could map to a Kibana ES|QL control bound into the bucket/window expression, giving back the smoothing choice.Related
TBUCKET(100, ?_tstart, ?_tend)yields sub-scrape-interval buckets, soIRATE/RATEpanels are empty on normal time ranges #348 —TBUCKET(100, ?_tstart, ?_tend)producing sub-scrape-interval buckets, which is what the dropped variable would otherwise have masked