[H1][PROMQL_VALIDATOR]
Dictum: Validation catches errors that generation misses.
Validate PromQL for Prometheus 3.8-3.10 (native histograms stable, feature flag no-op since 3.9). Cross-references: promql-generator for query creation, observability-stack for alert rule deployment.
Tasks:
- Syntax:
python3 .claude/skills/promql-validator/scripts/validate_syntax.py validate "<query>".
- Best Practices:
python3 .claude/skills/promql-validator/scripts/check_best_practices.py check "<query>".
- Explain: Parse and describe -- metrics, types, functions, output labels, result structure.
- Clarify Intent (STOP AND WAIT): Ask user -- goal, metric type, time window, aggregation, use case.
- Compare: Highlight mismatches between intent and implementation.
- Optimize: Suggest recording rules, better matchers, appropriate ranges.
- Refine: Offer alternatives, explain trade-offs, iterate.
[1][VERSION_MATRIX]
Dictum: Version awareness prevents false positives.
| [INDEX] |
[VERSION] |
[KEY_CHANGES] |
| [1] |
3.0 |
UTF-8 {"my.metric"}, info() experimental, holt_winters renamed. |
| [2] |
3.5 LTS |
mad_over_time, ts_of_min/max/last_over_time experimental. |
| [3] |
3.6 |
step(), duration expressions (promql-duration-expr flag). |
| [4] |
3.7 |
first_over_time, anchored+smoothed rate. |
| [5] |
3.8 |
Native histograms stable (scrape_native_histograms: true in scrape config). |
| [6] |
3.9 |
Native histogram flag is no-op; /api/v1/features endpoint. |
| [7] |
3.10 |
Maintenance release (Feb 2026); stability fixes only. |
[2][VALIDATION_RULES]
Dictum: Rules detect errors before Prometheus does.
| [INDEX] |
[CATEGORY] |
[RULE] |
[SEVERITY] |
| [1] |
Syntax |
Metric names: [a-zA-Z_:][a-zA-Z0-9_:]* or UTF-8 {"metric"}. |
error. |
| [2] |
Syntax |
Label matchers: =, !=, =~, !~ only. |
error. |
| [3] |
Syntax |
Durations: [0-9]+(ms|s|m|h|d|w|y). |
error. |
| [4] |
Semantic |
rate()/irate() only on counters (_total, _count, _bucket). |
warning. |
| [5] |
Semantic |
Never rate() on gauges -- use avg_over_time() or direct. |
warning. |
| [6] |
Semantic |
histogram_quantile() needs rate() on _bucket + le in by(). |
warning. |
| [7] |
Semantic |
Never average summary quantiles -- use histogram buckets. |
error. |
| [8] |
Semantic |
holt_winters() deprecated 3.0 -- use double_exponential_smoothing(). |
warning. |
| [9] |
Perf |
Always use specific label matchers to reduce cardinality. |
warning. |
| [10] |
Perf |
= over =~ for exact matches (5-10x faster index lookup). |
info. |
| [11] |
Perf |
rate() range >= 4x scrape interval (typically [2m] minimum). |
warning. |
| [12] |
Perf |
irate() range <= 5m (only uses last 2 samples). |
warning. |
| [13] |
Perf |
Subquery ranges < 7d; recording rules for longer. |
warning. |
| [14] |
Native |
Native histogram queries omit le from by() clause. |
info. |
| [15] |
Native |
histogram_avg(rate(m[5m])) replaces _sum/_count division (3.8+). |
info. |
| [16] |
Native |
histogram_fraction(0, t, rate(m[5m])) for latency SLOs (3.8+). |
info. |
[3][ANTI_PATTERNS]
Dictum: Anti-patterns waste resources or produce incorrect results.
| [INDEX] |
[ANTI_PATTERN] |
[BAD] |
[GOOD] |
| [1] |
No filters |
http_requests_total{}. |
http_requests_total{job="api"}. |
| [2] |
Regex for exact |
{status=~"200"}. |
{status="200"}. |
| [3] |
Raw counter |
http_requests_total. |
rate(http_requests_total[5m]). |
| [4] |
Rate on gauge |
rate(memory_usage_bytes[5m]). |
avg_over_time(memory_usage_bytes[5m]). |
| [5] |
Avg quantiles |
avg(metric{quantile="0.95"}). |
histogram_quantile(0.95, sum by (le) (rate(bucket[5m]))). |
| [6] |
Long irate |
irate(metric[1h]). |
rate(metric[1h]) or irate(metric[2m]). |
| [7] |
Deprecated fn |
holt_winters(m[5m], 0.5, 0.5). |
double_exponential_smoothing(m[5m], 0.5, 0.5). |
| [8] |
Classic when native avail |
sum by (job, le) (rate(m_bucket[5m])). |
sum by (job) (rate(m[5m])). |
| [9] |
Missing group_left |
metric * on(l) info_metric. |
metric * on(l) group_left(labels) info_metric. |
| [10] |
Unquoted UTF-8 (3.0+) |
http.server.request.duration. |
{"http.server.request.duration"}. |
[4][OUTPUT_FORMAT]
Dictum: Structured output enables actionable remediation.
## PromQL Validation Results
### Syntax Check
- Status: VALID / WARNING / ERROR
- Issues: [list with severity and WHY]
### Semantic Check
- Status: VALID / WARNING / ERROR
- Issues: [list with severity and WHY]
### Performance Analysis
- Status: OPTIMIZED / CAN BE IMPROVED / INEFFICIENT
- Suggestions: [list with estimated improvement]
### Query Explanation
- Metrics: [names and types]
- Functions: [what each does]
- Output Labels: [labels in result, or "None (fully aggregated)"]
- Expected Result Structure: [instant/range vector, scalar] with [series count]
### Intent Verification
1. What are you measuring?
2. Counter/gauge/histogram/summary?
3. Time window?
4. Aggregation labels?
5. Alerting, dashboarding, or analysis?
[5][KNOWN_LIMITATIONS]
Dictum: Known boundaries set realistic expectations.
- Metric type detection: Heuristic from naming conventions; custom names may misclassify.
- Native histogram detection: Cannot distinguish classic from native without runtime context.
- No runtime context: Cannot verify metric existence or label validity -- test against Prometheus.
[6][CITATION_SOURCES]
Dictum: Source attribution enables verification.
scripts/_common.py -- shared constants, CheckSpec dataclass, parsing utilities.
scripts/validate_syntax.py -- data-driven syntax validation via CheckSpec tuples.
scripts/check_best_practices.py -- data-driven semantic/performance checks.
docs/best_practices.md -- rules reference with native histogram patterns.
docs/anti_patterns.md -- 33 anti-patterns with WHY column.
1---2name: promql-validator3description: Validates existing PromQL query syntax, detects anti-patterns, checks best practices, and optimizes performance. Use when validating/auditing/reviewing queries, NOT creating new ones (use promql-generator instead).4---5
6# [H1][PROMQL_VALIDATOR]
7>**Dictum:** *Validation catches errors that generation misses.*
8
9<br>
10
11Validate PromQL for Prometheus 3.8-3.10 (native histograms stable, feature flag no-op since 3.9). Cross-references: **promql-generator** for query creation, **observability-stack** for alert rule deployment.
12
13**Tasks:**
141. **Syntax**: `python3 .claude/skills/promql-validator/scripts/validate_syntax.py validate "<query>"`.
152. **Best Practices**: `python3 .claude/skills/promql-validator/scripts/check_best_practices.py check "<query>"`.
163. **Explain**: Parse and describe -- metrics, types, functions, output labels, result structure.
174. **Clarify Intent (STOP AND WAIT)**: Ask user -- goal, metric type, time window, aggregation, use case.
185. **Compare**: Highlight mismatches between intent and implementation.
196. **Optimize**: Suggest recording rules, better matchers, appropriate ranges.
207. **Refine**: Offer alternatives, explain trade-offs, iterate.
21
22---
23## [1][VERSION_MATRIX]
24>**Dictum:** *Version awareness prevents false positives.*
25
26<br>
27
28| [INDEX] | [VERSION] | [KEY_CHANGES] |
29| :-----: | ----------- | --------------------------------------------------------------------------------- |
30| [1] | **3.0** | UTF-8 `{"my.metric"}`, `info()` experimental, `holt_winters` renamed. |
31| [2] | **3.5 LTS** | `mad_over_time`, `ts_of_min/max/last_over_time` experimental. |
32| [3] | **3.6** | `step()`, duration expressions (`promql-duration-expr` flag). |
33| [4] | **3.7** | `first_over_time`, anchored+smoothed rate. |
34| [5] | **3.8** | Native histograms **stable** (`scrape_native_histograms: true` in scrape config). |
35| [6] | **3.9** | Native histogram flag is **no-op**; `/api/v1/features` endpoint. |
36| [7] | **3.10** | Maintenance release (Feb 2026); stability fixes only. |
37
38---
39## [2][VALIDATION_RULES]
40>**Dictum:** *Rules detect errors before Prometheus does.*
41
42<br>
43
44| [INDEX] | [CATEGORY] | [RULE] | [SEVERITY] |
45| :-----: | ------------ | ------------------------------------------------------------------------ | ---------- |
46| [1] | **Syntax** | Metric names: `[a-zA-Z_:][a-zA-Z0-9_:]*` or UTF-8 `{"metric"}`. | error. |
47| [2] | **Syntax** | Label matchers: `=`, `!=`, `=~`, `!~` only. | error. |
48| [3] | **Syntax** | Durations: `[0-9]+(ms\|s\|m\|h\|d\|w\|y)`. | error. |
49| [4] | **Semantic** | `rate()`/`irate()` only on counters (`_total`, `_count`, `_bucket`). | warning. |
50| [5] | **Semantic** | Never `rate()` on gauges -- use `avg_over_time()` or direct. | warning. |
51| [6] | **Semantic** | `histogram_quantile()` needs `rate()` on `_bucket` + `le` in `by()`. | warning. |
52| [7] | **Semantic** | Never average summary quantiles -- use histogram buckets. | error. |
53| [8] | **Semantic** | `holt_winters()` deprecated 3.0 -- use `double_exponential_smoothing()`. | warning. |
54| [9] | **Perf** | Always use specific label matchers to reduce cardinality. | warning. |
55| [10] | **Perf** | `=` over `=~` for exact matches (5-10x faster index lookup). | info. |
56| [11] | **Perf** | `rate()` range >= 4x scrape interval (typically `[2m]` minimum). | warning. |
57| [12] | **Perf** | `irate()` range <= 5m (only uses last 2 samples). | warning. |
58| [13] | **Perf** | Subquery ranges < 7d; recording rules for longer. | warning. |
59| [14] | **Native** | Native histogram queries omit `le` from `by()` clause. | info. |
60| [15] | **Native** | `histogram_avg(rate(m[5m]))` replaces `_sum/_count` division (3.8+). | info. |
61| [16] | **Native** | `histogram_fraction(0, t, rate(m[5m]))` for latency SLOs (3.8+). | info. |
62
63---
64## [3][ANTI_PATTERNS]
65>**Dictum:** *Anti-patterns waste resources or produce incorrect results.*
66
67<br>
68
69| [INDEX] | [ANTI_PATTERN] | [BAD] | [GOOD] |
70| :-----: | ----------------------------- | ---------------------------------------- | ----------------------------------------------------------- |
71| [1] | **No filters** | `http_requests_total{}`. | `http_requests_total{job="api"}`. |
72| [2] | **Regex for exact** | `{status=~"200"}`. | `{status="200"}`. |
73| [3] | **Raw counter** | `http_requests_total`. | `rate(http_requests_total[5m])`. |
74| [4] | **Rate on gauge** | `rate(memory_usage_bytes[5m])`. | `avg_over_time(memory_usage_bytes[5m])`. |
75| [5] | **Avg quantiles** | `avg(metric{quantile="0.95"})`. | `histogram_quantile(0.95, sum by (le) (rate(bucket[5m])))`. |
76| [6] | **Long irate** | `irate(metric[1h])`. | `rate(metric[1h])` or `irate(metric[2m])`. |
77| [7] | **Deprecated fn** | `holt_winters(m[5m], 0.5, 0.5)`. | `double_exponential_smoothing(m[5m], 0.5, 0.5)`. |
78| [8] | **Classic when native avail** | `sum by (job, le) (rate(m_bucket[5m]))`. | `sum by (job) (rate(m[5m]))`. |
79| [9] | **Missing group_left** | `metric * on(l) info_metric`. | `metric * on(l) group_left(labels) info_metric`. |
80| [10] | **Unquoted UTF-8 (3.0+)** | `http.server.request.duration`. | `{"http.server.request.duration"}`. |
81
82---
83## [4][OUTPUT_FORMAT]
84>**Dictum:** *Structured output enables actionable remediation.*
85
86<br>
87
88```
89## PromQL Validation Results
90
91### Syntax Check
92- Status: VALID / WARNING / ERROR
93- Issues: [list with severity and WHY]
94
95### Semantic Check
96- Status: VALID / WARNING / ERROR
97- Issues: [list with severity and WHY]
98
99### Performance Analysis
100- Status: OPTIMIZED / CAN BE IMPROVED / INEFFICIENT
101- Suggestions: [list with estimated improvement]
102
103### Query Explanation
104- Metrics: [names and types]
105- Functions: [what each does]
106- Output Labels: [labels in result, or "None (fully aggregated)"]
107- Expected Result Structure: [instant/range vector, scalar] with [series count]
108
109### Intent Verification
1101. What are you measuring?
1112. Counter/gauge/histogram/summary?
1123. Time window?
1134. Aggregation labels?
1145. Alerting, dashboarding, or analysis?
115```
116
117---
118## [5][KNOWN_LIMITATIONS]
119>**Dictum:** *Known boundaries set realistic expectations.*
120
121<br>
122
123- **Metric type detection**: Heuristic from naming conventions; custom names may misclassify.
124- **Native histogram detection**: Cannot distinguish classic from native without runtime context.
125- **No runtime context**: Cannot verify metric existence or label validity -- test against Prometheus.
126
127---
128## [6][CITATION_SOURCES]
129>**Dictum:** *Source attribution enables verification.*
130
131<br>
132
133- `scripts/_common.py` -- shared constants, CheckSpec dataclass, parsing utilities.
134- `scripts/validate_syntax.py` -- data-driven syntax validation via CheckSpec tuples.
135- `scripts/check_best_practices.py` -- data-driven semantic/performance checks.
136- `docs/best_practices.md` -- rules reference with native histogram patterns.
137- `docs/anti_patterns.md` -- 33 anti-patterns with WHY column.