elastic / elastic/observability-migration-platform
Curated pack `status_override: migrated` reports full confidence while the hand-written ES|QL drops source series
- Dominant language
- Python
- Stars
- 6
- Forks
- 8
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 23
Description
**Severity: high — the report actively tells the operator a panel is perfect when series are missing.**
### What happens
Panels whose ES|QL is hand-written in the curated pack omit source targets, and because the pack
also sets `status_override: migrated`, the migration report shows
`status=migrated, confidence=1.0, reasons=[]`. The operator has no signal that anything was lost.
| Panel | Source targets | Series in migrated query | Dropped |
|---|---|---|---|
| `Pressure` | 4 (CPU, Mem, I/O, **Irq**) | 3 | `node_pressure_irq_stalled_seconds_total` |
| `CPU` | 9 (8 modes + **Guest**) | 8 | `node_cpu_guest_seconds_total` |
| `TCP Errors` | 9 | 7 | `node_netstat_TcpExt_TCPRcvQDrop`, `node_netstat_TcpExt_TCPTimeouts` |
### The dropped metrics are present in the target
This is not a data-readiness gap. Both fields below exist in the target index, so the series could
have been rendered:
```
IN ELASTICSEARCH metrics.node_pressure_irq_stalled_seconds_total
IN ELASTICSEARCH metrics.node_cpu_guest_seconds_total
```
(For `TCP Errors` the two metrics happen to be absent from my target index, so that row alone
cannot distinguish a pack omission from a data gap. `Pressure` and `CPU` can.)
### Why this is worse than a rendering bug
The omission is baked into the saved object. If the operator later starts ingesting
`node_pressure_irq_stalled_seconds_total`, the panel *still* will not show Irq, because the series
was never in the query.
### Inconsistent with the tool's own behaviour elsewhere
The same run handles the identical condition loudly for non-pack panels:
```
IRQ Detail status=migrated_with_warnings conf=0.4
reason: Target telemetry missing: node_interrupts_total
Hardware Temperature Monitor status=migrated_with_warnings conf=0.4
reason: Target telemetry missing: node_hwmon_chip_names, node_hwmon_temp_crit_celsius
```
So the pack path is the only one that hides the gap, which conflicts with the repo's
"degrade gracefully — do not silently hide semantic gaps" rule.
### Suggested fix
- Validate each pack `query_overrides` entry against the source panel's target list at translation
time; if a source metric is absent from the hand-written ES|QL, downgrade to
`migrated_with_warnings` and attach an explicit reason naming the dropped series.
- Treat `status_override` as a *ceiling*, not an assignment, so it cannot mask a detected gap.
- Add the missing series to the 1860 pack's `Pressure`, `CPU`, and `TCP Errors` queries.
## How this was found
Manual end-to-end test of #346: Grafana community dashboard 1860 migrated with
`obs-migrate` and uploaded to a local Kibana, then compared panel-by-panel
against the source Grafana rendering the same node_exporter metrics.
Environment
- Branch: `pr-346` (`feat!: curated dashboard packs, PromQL fidelity, and native-only dashboard artifacts`)
- Source: Grafana OSS, community dashboard **1860 "Node Exporter Full"** imported live (`gnetId: 1860`, JSON `version: 101`)
- Curated pack: `grafana_1860_node_exporter_full` (auto-activated by gnetId)
- Target: Elasticsearch + Kibana 9.5.0-SNAPSHOT (elastic-package stack), index `metrics-node.prometheus-default`, `--field-profile prometheus_native`
- Ingest: node_exporter scraped every **15 s** into both Prometheus (for Grafana) and Elasticsearch (for Kibana), same series in both
Contributor guide
Assessment
This issue has not been assessed yet.