Description
Resolved by SKT-0010.01 lane L12, 2026-08-27: the capture is faithful and synthkit emission is wrong.
Prometheus v3 normalises the le label for classic histograms and the quantile label for summaries to a float-like representation on ingestion, so metric identity is consistent regardless of scrape protocol (Prometheus migration guide, read via context7 2026-08-27). Alloy 1.x embeds Prometheus v3 scrape, so anything Alloy scrapes reaches Mimir in dot-zero form. The migration guide even ships a metric_relabel_configs recipe with regex: "(\\d+)\\.0+" for operators who need the old values back — which is itself proof of the new default.
Corroborated three ways from the corpus rather than from the doc alone: across the entire reality corpus there are 154 le values and zero bare integers; non-integral bounds (0.005, 2.5, 0.00025) match synth exactly while only integral ones diverge, so it is a rendering convention rather than a formatter bug; and histogram.bucket_bounds produces zero mismatches, so the numeric bucket sets are already identical and only the label STRING differs.
The concrete harm: a dashboard or recording rule with le="1" matches nothing against real Grafana Cloud data while working perfectly against synthkit. That is the exact failure this whole audit exists to prevent.
synthkit already has the mechanism. internal/state/state.go defines both LEBare and LEDotZero and formatLE implements them. The defect is the belief encoded in the doc comment — that LEBare is “the Prometheus-native scrape” convention. True before v3, false now. For a family modelling a Prometheus-v3 scrape, dot-zero is the native form and bare is the exception.
Scope is catalogue-wide, and much larger than the 7 findings that made it visible. Roughly 120 state.LEBare call sites across 21 files. Every family whose bucket set contains an integral bound is emitting a label value no real Alloy would produce; the 7 corpus findings are only the subset the corpus can currently see. Proven-wrong call sites to fix first are recorded in the SKT-0010.01 notes with file:line.
This needs a rule, not a blanket replace. The question per family is “does this model a Prometheus-v3 scrape?” — if yes, dot-zero. A family modelling a direct remote-write producer with no scrape in between legitimately stays bare, and flipping those would introduce the mirror-image defect.
One precision item: formatLE renders dot-zero via a fixed-notation format plus a ".0" suffix. For every bound currently in the corpus the two agree exactly, but confirm against the Prometheus source before adding any bound at the extremes where fixed and general notation diverge. The migration guide does not name the formatter.
Acceptance Criteria
- #1 Families modelling a Prometheus-v3 scrape emit the float-normalised le form
- #2 The decision is made per family against a stated rule, not by a blanket replace
- #3 A family modelling a direct remote-write producer with no scrape keeps the bare form, and that reasoning is recorded
- #4 The state.go doc comment no longer claims bare le is the Prometheus-native scrape convention
- #5 make signal-fidelity reports no remaining labels.le contradiction
- #6 signals/k8s.md and signals/k8s-addons.md record the observed rendering with provenance
- #7 The formatter is confirmed correct at the notation extremes, or the limitation is recorded
Definition of Done
- #1 make gate (build vet test race rw-proto-check spdx-check forbidden-words)
- #2 make blueprint-schema (only if a blueprint field or construct/workload config struct changed)
- #3 DRY_RUN=true go run ./cmd/synthkit -once -dump — inventory diffed against signals/
Final Summary
The sweep landed, and the formatter question this task flagged as a precision item turned out to be the substantive finding rather than a footnote.
THE RULE, now carried in internal/state and applicable by a contributor unaided: pick the le/quantile style from how the series REACHES MIMIR, not from how the exporter prints it. A Prometheus-v3 scraper in the path (Alloy scraping a /metrics endpoint) means the printed form is irrelevant because v3 normalises on ingestion. A producer that remote-writes its own series with no scrape in between keeps the bare form. The OTLP-to-Prometheus translation keeps dot-zero.
THE FORMATTER WAS WRONG, and not hypothetically. The old dot-zero path used FIXED notation plus a forced “.0”. Prometheus uses labels.FormatOpenMetricsFloat, which is GENERAL notation — read from prometheus/prometheus model/labels/float.go and model/textparse/openmetricsparse.go at v0.310.0, since context7 returned only migration prose that does not name the formatter. So a bound at or past 1e6 stores as 2.592e+06, NOT 2592000.0. Two live families cross that switch point: karpenter lifetime buckets and nettopo payload buckets. Had the sweep reused LEDotZero it would have shipped a form no real Alloy produces, for the families most likely to be queried by range.
That is why a THIRD style (LEPromV3) was the right modelling rather than reusing the existing one: flipping LEDotZero would have silently rewritten gen_ai_client_token_usage bounds for workload families with zero evidence — the mirror-image defect this task explicitly warned against.
102 call sites across 16 files moved to LEPromV3, each an Alloy-scraped /metrics surface, with the per-file justification recorded. The quantile half was audited too and only karpenter was affected, in the values 0 and 1.
DELIBERATELY LEFT BARE, with reason: probe_all_duration_seconds on the synthetic-monitoring construct. The SM agent remote-writes its own series and no scrape sits between it and Mimir, so nothing normalises the label — precisely the exception the rule carves out. Flagged as reasoned from collection topology rather than measured, since SM has no corpus area; a cantfind PENDING is proposed.
Verified by baseline rather than assertion: short-circuiting the new branch reproduced exactly the 7 labels.le findings this task named; restored, zero. bucket_bounds findings stayed at zero, so the numeric sets were never disturbed.
Signals text applied to k8s.md and k8s-addons.md including the karpenter bucket lists rewritten to their STORED form, and the stale “Prometheus-native scrape” claim removed from internal/telemetryspec with the gap recorded — that spec surface cannot express a v3 scrape at all, which is follow-up work.