@intentius/chant-lexicon-prometheus 0.100.0 → 0.102.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +5 -2
  2. package/dist/alertmanager.d.ts.map +1 -1
  3. package/dist/codegen/docs.d.ts.map +1 -1
  4. package/dist/composites/catalog.d.ts.map +1 -1
  5. package/dist/composites/genai.d.ts +224 -0
  6. package/dist/composites/genai.d.ts.map +1 -0
  7. package/dist/composites/index.d.ts +2 -0
  8. package/dist/composites/index.d.ts.map +1 -1
  9. package/dist/composites/slo.d.ts +1 -1
  10. package/dist/composites/slo.d.ts.map +1 -1
  11. package/dist/import/embedded.d.ts +12 -3
  12. package/dist/import/embedded.d.ts.map +1 -1
  13. package/dist/import/generator.d.ts +14 -0
  14. package/dist/import/generator.d.ts.map +1 -1
  15. package/dist/import/parser.d.ts.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/init-templates.d.ts +11 -2
  19. package/dist/init-templates.d.ts.map +1 -1
  20. package/dist/integrations.d.ts.map +1 -1
  21. package/dist/integrity.json +8 -7
  22. package/dist/lint/audit-catalog.d.ts.map +1 -1
  23. package/dist/lint/audit-lineage.d.ts +33 -0
  24. package/dist/lint/audit-lineage.d.ts.map +1 -0
  25. package/dist/lint/post-synth/index.d.ts.map +1 -1
  26. package/dist/lint/post-synth/prom-helpers.d.ts +1 -1
  27. package/dist/lint/post-synth/prom208.d.ts +1 -1
  28. package/dist/lint/post-synth/prom209.d.ts +1 -1
  29. package/dist/lint/post-synth/prom210.d.ts +8 -0
  30. package/dist/lint/post-synth/prom210.d.ts.map +1 -0
  31. package/dist/manifest.json +1 -1
  32. package/dist/okf/index.md +1 -0
  33. package/dist/okf/rules/PROM210.md +11 -0
  34. package/dist/plugin.d.ts.map +1 -1
  35. package/dist/rule-eval.d.ts +10 -4
  36. package/dist/rule-eval.d.ts.map +1 -1
  37. package/dist/rules/prom-helpers.ts +1 -1
  38. package/dist/rules/prom208.ts +1 -1
  39. package/dist/rules/prom209.ts +1 -1
  40. package/dist/rules/prom210.ts +17 -0
  41. package/dist/skill-defs.d.ts +1 -1
  42. package/dist/skill-defs.d.ts.map +1 -1
  43. package/dist/skills/chant-prometheus-alertmanager.md +3 -1
  44. package/dist/skills/chant-prometheus.md +22 -0
  45. package/dist/validate-config.d.ts +2 -2
  46. package/dist/validate-config.d.ts.map +1 -1
  47. package/dist/validate-integrations.d.ts +37 -0
  48. package/dist/validate-integrations.d.ts.map +1 -0
  49. package/package.json +4 -3
  50. package/src/codegen/docs.ts +5 -0
  51. package/src/composites/catalog.test.ts +1 -1
  52. package/src/composites/catalog.ts +70 -0
  53. package/src/composites/genai.test.ts +307 -0
  54. package/src/composites/genai.ts +678 -0
  55. package/src/composites/index.ts +15 -0
  56. package/src/composites/slo-burn.test.ts +25 -1
  57. package/src/import/embedded.test.ts +52 -3
  58. package/src/import/embedded.ts +37 -5
  59. package/src/import/generator.ts +19 -1
  60. package/src/index.ts +14 -0
  61. package/src/init-templates.test.ts +37 -11
  62. package/src/init-templates.ts +75 -6
  63. package/src/lint/audit-catalog.ts +13 -2
  64. package/src/lint/audit-lineage.ts +69 -0
  65. package/src/lint/post-synth/index.ts +2 -0
  66. package/src/lint/post-synth/post-synth.test.ts +34 -0
  67. package/src/lint/post-synth/prom-helpers.ts +1 -1
  68. package/src/lint/post-synth/prom208.ts +1 -1
  69. package/src/lint/post-synth/prom209.ts +1 -1
  70. package/src/lint/post-synth/prom210.ts +17 -0
  71. package/src/plugin.test.ts +1 -0
  72. package/src/plugin.ts +8 -4
  73. package/src/rule-eval.ts +72 -7
  74. package/src/skills/chant-prometheus-alertmanager.md +3 -1
  75. package/src/skills/chant-prometheus.md +22 -0
  76. package/src/testdata/integration-cases.ts +96 -0
  77. package/src/tools.test.ts +6 -0
  78. package/src/typecheck.test.ts +88 -0
  79. package/src/validate-config.ts +8 -31
  80. package/src/validate-integrations.ts +389 -0
@@ -26,7 +26,7 @@ export interface FoundDocs {
26
26
  export declare function prometheusDocs(ctx: PostSynthContext): FoundDocs;
27
27
  /** Diagnostics for one rule-file code (PROM101-PROM107) across every rule file in the output. */
28
28
  export declare function ruleFileDiagnostics(ctx: PostSynthContext, code: PrometheusIssueCode): PostSynthDiagnostic[];
29
- /** Diagnostics for one Alertmanager code (PROM201, PROM203-PROM209) across every `alertmanager.yml` in the output. */
29
+ /** Diagnostics for one Alertmanager code (PROM201, PROM203-PROM210) across every `alertmanager.yml` in the output. */
30
30
  export declare function alertmanagerDiagnostics(ctx: PostSynthContext, code: PrometheusIssueCode): PostSynthDiagnostic[];
31
31
  /** PROM202: joins every rule file in the output against every Alertmanager config in it. Silent when either is absent. */
32
32
  export declare function routingDiagnostics(ctx: PostSynthContext): PostSynthDiagnostic[];
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * PROM208: An Alertmanager duration is not a duration
3
3
  *
4
- * group_wait, group_interval, repeat_interval, resolve_timeout and webhook timeout take durations such as 30s or 4h.
4
+ * group_wait, group_interval, repeat_interval, resolve_timeout and Jira reopen_duration take Prometheus durations (30s, 4h, 1d); the timeout of webhook, Slack, PagerDuty and incident.io, and Pushover retry, expire and ttl take Go durations (10s, 1m30s, 500ms).
5
5
  */
6
6
  import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
7
7
  export declare const prom208: PostSynthCheck;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * PROM209: A receiver integration is missing its destination or credential
3
3
  *
4
- * A webhook needs url or url_file, Slack an api_url (or the global one), PagerDuty a routing_key or service_key, and email a to address, a smarthost and a from address (or their global defaults).
4
+ * Every one of Alertmanager's 18 integrations is checked for the destination, credential and required fields its config validation asks for, with the global defaults it falls back to: e.g. a webhook url, an Opsgenie api_key (or global.opsgenie_api_key), a Telegram chat_id and bot token, a Webex room_id and authorization, an SNS target, a Jira project and issue_type.
5
5
  */
6
6
  import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
7
7
  export declare const prom209: PostSynthCheck;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * PROM210: A receiver integration or global setting is one Alertmanager rejects
3
+ *
4
+ * Two settings that exclude each other (a value and its *_file, a Slack api_url and app_token, Pushover html and monospace, two SNS targets), or a value outside the allowed set (WeChat message_type, Telegram parse_mode, Jira api_type, an Opsgenie responder type, a VictorOps reserved custom field, a smarthost that is not host:port, a Slack or Mattermost field without title and value).
5
+ */
6
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
7
+ export declare const prom210: PostSynthCheck;
8
+ //# sourceMappingURL=prom210.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prom210.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/prom210.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAG9G,eAAO,MAAM,OAAO,EAAE,cAOrB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prometheus",
3
- "version": "0.100.0",
3
+ "version": "0.102.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "Prometheus",
6
6
  "intrinsics": [],
package/dist/okf/index.md CHANGED
@@ -32,3 +32,4 @@ okf_version: '0.2'
32
32
  * [PROM207](/rules/PROM207.md) - A receiver is declared but no route sends to it
33
33
  * [PROM208](/rules/PROM208.md) - An Alertmanager duration is not a duration
34
34
  * [PROM209](/rules/PROM209.md) - A receiver integration is missing its destination or credential
35
+ * [PROM210](/rules/PROM210.md) - A receiver integration or global setting is one Alertmanager rejects
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: PROM210
4
+ description: A receiver integration or global setting is one Alertmanager rejects
5
+ id: PROM210
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: prometheus
9
+ docs: https://intentius.io/chant/lexicons/prometheus/rules/
10
+ ---
11
+ A receiver integration or global setting is one Alertmanager rejects
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA+B9D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAyG9B,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA+B9D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,aA6G9B,CAAC"}
@@ -7,10 +7,15 @@
7
7
  * The PromQL it understands is the subset the lexicon's generated rules use:
8
8
  * number literals, vector and range selectors with `=`, `!=`, `=~` and `!~`
9
9
  * matchers, `rate`, `increase`, `avg_over_time`, `sum_over_time`,
10
- * `count_over_time`, `vector`, `sum` (with `by` or `without`), the
11
- * arithmetic and comparison operators and `and`, `or` and `unless` (with
12
- * `on` or `ignoring`). Anything else throws, so a test never passes by
13
- * silently evaluating something it does not understand.
10
+ * `count_over_time`, `vector`, `histogram_quantile`, `sum` (with `by` or
11
+ * `without`), the arithmetic and comparison operators (one-to-one, or
12
+ * many-to-one with `group_left` and no extra labels) and `and`, `or` and
13
+ * `unless` (with `on` or `ignoring`). Anything else throws, so a test never
14
+ * passes by silently evaluating something it does not understand.
15
+ *
16
+ * `histogram_quantile` interpolates linearly inside the bucket the rank
17
+ * falls in, as Prometheus does for classic buckets, and returns the upper
18
+ * bound of the highest finite bucket when the rank falls in `+Inf`.
14
19
  *
15
20
  * `rate` is the increase between the first and last sample in the range
16
21
  * over the time between them, without Prometheus's extrapolation to the
@@ -61,6 +66,7 @@ export declare class RuleEvaluator {
61
66
  private node;
62
67
  private args;
63
68
  private call;
69
+ private histogramQuantile;
64
70
  private aggregate;
65
71
  private binary;
66
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rule-eval.d.ts","sourceRoot":"","sources":["../src/rule-eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAA8D,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAI3G,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC5C,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AACD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AACD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAiCD,8DAA8D;AAC9D,qBAAa,aAAa;IAKZ,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;gBAErC,MAAM,EAAE,eAAe,EAAE;IAEtD,wEAAwE;IACxE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAU/C,yFAAyF;IACzF,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE;IA8B9B,yFAAyF;IACzF,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE;IAK/C,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,MAAM;IAId,iCAAiC;IACjC,OAAO,CAAC,MAAM;IAcd,OAAO,CAAC,IAAI;IAyBZ,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,IAAI;IAuCZ,OAAO,CAAC,SAAS;IA4BjB,OAAO,CAAC,MAAM;CA0Gf"}
1
+ {"version":3,"file":"rule-eval.d.ts","sourceRoot":"","sources":["../src/rule-eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,EAA8D,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAI3G,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC5C,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AACD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AACD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAkCD,8DAA8D;AAC9D,qBAAa,aAAa;IAKZ,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAElE,YAA6B,MAAM,EAAE,eAAe,EAAE,EAAI;IAE1D,wEAAwE;IACxE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ9C;IAED,yFAAyF;IACzF,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CA4B7B;IAED,yFAAyF;IACzF,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAG9C;IAED,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,MAAM;IAId,iCAAiC;IACjC,OAAO,CAAC,MAAM;IAcd,OAAO,CAAC,IAAI;IAyBZ,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,IAAI;IA0CZ,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,SAAS;IA4BjB,OAAO,CAAC,MAAM;CA2Hf"}
@@ -71,7 +71,7 @@ export function ruleFileDiagnostics(ctx: PostSynthContext, code: PrometheusIssue
71
71
  );
72
72
  }
73
73
 
74
- /** Diagnostics for one Alertmanager code (PROM201, PROM203-PROM209) across every `alertmanager.yml` in the output. */
74
+ /** Diagnostics for one Alertmanager code (PROM201, PROM203-PROM210) across every `alertmanager.yml` in the output. */
75
75
  export function alertmanagerDiagnostics(ctx: PostSynthContext, code: PrometheusIssueCode): PostSynthDiagnostic[] {
76
76
  return prometheusDocs(ctx).alertmanager.flatMap(({ source, config }) =>
77
77
  validateAlertmanagerConfig(config)
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * PROM208: An Alertmanager duration is not a duration
3
3
  *
4
- * group_wait, group_interval, repeat_interval, resolve_timeout and webhook timeout take durations such as 30s or 4h.
4
+ * group_wait, group_interval, repeat_interval, resolve_timeout and Jira reopen_duration take Prometheus durations (30s, 4h, 1d); the timeout of webhook, Slack, PagerDuty and incident.io, and Pushover retry, expire and ttl take Go durations (10s, 1m30s, 500ms).
5
5
  */
6
6
 
7
7
  import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * PROM209: A receiver integration is missing its destination or credential
3
3
  *
4
- * A webhook needs url or url_file, Slack an api_url (or the global one), PagerDuty a routing_key or service_key, and email a to address, a smarthost and a from address (or their global defaults).
4
+ * Every one of Alertmanager's 18 integrations is checked for the destination, credential and required fields its config validation asks for, with the global defaults it falls back to: e.g. a webhook url, an Opsgenie api_key (or global.opsgenie_api_key), a Telegram chat_id and bot token, a Webex room_id and authorization, an SNS target, a Jira project and issue_type.
5
5
  */
6
6
 
7
7
  import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * PROM210: A receiver integration or global setting is one Alertmanager rejects
3
+ *
4
+ * Two settings that exclude each other (a value and its *_file, a Slack api_url and app_token, Pushover html and monospace, two SNS targets), or a value outside the allowed set (WeChat message_type, Telegram parse_mode, Jira api_type, an Opsgenie responder type, a VictorOps reserved custom field, a smarthost that is not host:port, a Slack or Mattermost field without title and value).
5
+ */
6
+
7
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
8
+ import { alertmanagerDiagnostics } from "./prom-helpers";
9
+
10
+ export const prom210: PostSynthCheck = {
11
+ id: "PROM210",
12
+ description: "A receiver integration or global setting is one Alertmanager rejects",
13
+
14
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
15
+ return alertmanagerDiagnostics(ctx, "PROM210");
16
+ },
17
+ };
@@ -1,3 +1,3 @@
1
1
  /** The prometheus lexicon's AI skills, read from src/skills/. */
2
- export declare const prometheusSkills: () => import("packages/core/src").SkillDefinition[];
2
+ export declare const prometheusSkills: () => import("@intentius/chant").SkillDefinition[];
3
3
  //# sourceMappingURL=skill-defs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-defs.d.ts","sourceRoot":"","sources":["../src/skill-defs.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,qDAuC3B,CAAC"}
1
+ {"version":3,"file":"skill-defs.d.ts","sourceRoot":"","sources":["../src/skill-defs.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,oDAuC3B,CAAC"}
@@ -57,6 +57,8 @@ Import it rather than retyping it: `chant import alertmanager.yml --output src`
57
57
  - Routes name receivers and time intervals that exist (PROM201, PROM204). Reference the entity rather than a string and TypeScript does most of this.
58
58
  - Every `severity` an alert in the same build root carries is matched by some route below the root (PROM202). The check only sees one build root (chant #1939): keep the rules and the Alertmanager config in the same one, or it goes quiet.
59
59
  - Credentials go in `*_file` fields. Alertmanager does not expand environment variables in its config, and a literal `api_url`, `routing_key` or `auth_password` is flagged (PROM001).
60
- - Each integration has somewhere to send (PROM209): a webhook `url`, a Slack `api_url` (or `global.slack_api_url`), a PagerDuty key, an email `to`/`smarthost`/`from` (or the global SMTP defaults).
60
+ - Each integration has its destination, credential and required fields, or the `global` default it falls back to (PROM209): a webhook `url`, a Slack `api_url` or app token, an Opsgenie `api_key`, a Telegram `chat_id` and bot token, a Webex `room_id` and `http_config.authorization`, one SNS target, a Jira `project` and `issue_type`, an email `to`/`smarthost`/`from`, and so on.
61
+ - No setting Alertmanager rejects (PROM210): a value and its `*_file` both set, a Slack `api_url` with an app token, `update_message` without `api_url: https://slack.com/api/chat.postMessage`, a WeChat `message_type` other than `text`/`markdown`, a Telegram `parse_mode` other than `Markdown`/`MarkdownV2`/`HTML`.
62
+ - Durations parse (PROM208). Route timers and `resolve_timeout` take `1d`; the integration `timeout`s and Pushover `retry`/`expire`/`ttl` are Go durations and take `24h`, not `1d`.
61
63
 
62
64
  Run `amtoolCheckConfig(alertmanagerYaml(entities))` in a test to have `amtool check-config` confirm it when installed.
@@ -100,3 +100,25 @@ sloMetrics(checkout).errorRatio["1h"]; // "slo:sli_error:ratio_rate1h"
100
100
  - Write the objective as a fraction strictly between 0 and 1, and put `{{window}}` where each SLI expression's range goes (PROM003).
101
101
  - Alerts carry `severity` `page` or `ticket`; route both (PROM202).
102
102
  - Read series names from `sloMetrics()` in dashboards instead of repeating them.
103
+
104
+ ## GenAI rules
105
+
106
+ `GenAiRules` builds rules for the otel lexicon's GenAI collector preset from the same `genAiMetrics(options)` the collector was built with: request rate, error ratio (also by `error.type`) and p50/p95/p99 latency per provider, model and operation, token rates, spend per second from a price table the project declares, and per-tool call rate, error ratio and p95 latency. Alerts are off unless `alerts` names them.
107
+
108
+ ```ts
109
+ import { genAiMetrics } from "@intentius/chant-lexicon-otel";
110
+ import { GenAiRules, genAiRuleMetrics } from "@intentius/chant-lexicon-prometheus";
111
+
112
+ export const genai = GenAiRules({
113
+ genAi: genAiMetrics({ clientMetrics: "derive" }),
114
+ prices: [{ provider: "anthropic", model: "claude-x", inputPerMTok: 3, outputPerMTok: 15, currency: "USD", source: "https://example.com/pricing", asOf: "2026-09-29" }],
115
+ alerts: { errorRatio: true, latency: { thresholdSeconds: 20 }, budgets: [{ amount: 50, currency: "USD", per: "day" }] },
116
+ });
117
+
118
+ genAiRuleMetrics(genai).cost; // "gen_ai:cost:rate5m"
119
+ ```
120
+
121
+ - Pass the collector's own options to `genAiMetrics()`; never write a metric name by hand.
122
+ - Ship no prices in a lexicon or template. The project declares them, with `currency` and `source` on each.
123
+ - A model missing from `prices` gets no cost series, so a sum of the cost series covers priced models only.
124
+ - Read series names from `genAiRuleMetrics()` in dashboards.
@@ -7,7 +7,7 @@
7
7
  * `PrometheusRule`'s groups, or on a file parsed by some other tool.
8
8
  */
9
9
  import { type AlertmanagerConfig, type RuleFileConfig } from "./model.js";
10
- export type PrometheusIssueCode = "PROM101" | "PROM102" | "PROM103" | "PROM104" | "PROM105" | "PROM106" | "PROM107" | "PROM201" | "PROM202" | "PROM203" | "PROM204" | "PROM205" | "PROM206" | "PROM207" | "PROM208" | "PROM209";
10
+ export type PrometheusIssueCode = "PROM101" | "PROM102" | "PROM103" | "PROM104" | "PROM105" | "PROM106" | "PROM107" | "PROM201" | "PROM202" | "PROM203" | "PROM204" | "PROM205" | "PROM206" | "PROM207" | "PROM208" | "PROM209" | "PROM210";
11
11
  export interface PrometheusIssue {
12
12
  code: PrometheusIssueCode;
13
13
  severity: "error" | "warning";
@@ -19,7 +19,7 @@ export interface PrometheusIssue {
19
19
  export declare function validateRuleFile(file: RuleFileConfig): PrometheusIssue[];
20
20
  /** Every severity value an alert in these rule files carries, with the alerts carrying it. */
21
21
  export declare function alertSeverities(files: RuleFileConfig[]): Map<string, string[]>;
22
- /** Check an `alertmanager.yml` on its own (PROM201, PROM203-PROM209). */
22
+ /** Check an `alertmanager.yml` on its own (PROM201, PROM203-PROM210). */
23
23
  export declare function validateAlertmanagerConfig(config: AlertmanagerConfig): PrometheusIssue[];
24
24
  /**
25
25
  * PROM202: every severity an alert carries is taken by some route below the
@@ -1 +1 @@
1
- {"version":3,"file":"validate-config.d.ts","sourceRoot":"","sources":["../src/validate-config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAGL,KAAK,kBAAkB,EAIvB,KAAK,cAAc,EAEpB,MAAM,SAAS,CAAC;AAGjB,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,eAAe,EAAE,CAsHxE;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAa9E;AAsBD,yEAAyE;AACzE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,eAAe,EAAE,CA4HxF;AAYD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,kBAAkB,GAAG,eAAe,EAAE,CA6BlH"}
1
+ {"version":3,"file":"validate-config.d.ts","sourceRoot":"","sources":["../src/validate-config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAGL,KAAK,kBAAkB,EAIvB,KAAK,cAAc,EAEpB,MAAM,SAAS,CAAC;AAIjB,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,eAAe,EAAE,CAsHxE;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAa9E;AAsBD,yEAAyE;AACzE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,eAAe,EAAE,CAmGxF;AAYD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,kBAAkB,GAAG,eAAe,EAAE,CA6BlH"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Receiver integration and `global:` checks for `alertmanager.yml`
3
+ * (PROM208-PROM210), one case per validation Alertmanager v0.34.1 makes when
4
+ * it loads the file (see ./pin.ts). Sources, under
5
+ * github.com/prometheus/alertmanager at that tag:
6
+ *
7
+ * - `config/notifiers.go`: the `UnmarshalYAML` of the Email, Slack (and its
8
+ * fields, actions and confirmations), WeChat, VictorOps, Pushover, SNS,
9
+ * Rocket.Chat and Webex configs.
10
+ * - `notify/<name>/config.go`: the `UnmarshalYAML` of the Discord,
11
+ * incident.io, Jira, Mattermost (and its fields), MS Teams, MS Teams v2,
12
+ * Opsgenie, PagerDuty, Telegram and webhook configs.
13
+ * - `config/config.go`: `Config.UnmarshalYAML`, which fills each
14
+ * integration from its `global:` default and then rejects what is still
15
+ * missing, and the `global:` "at most one of" checks; `HostPort` for
16
+ * `smarthost`.
17
+ *
18
+ * Durations come in two grammars. `model.Duration` fields (`resolve_timeout`,
19
+ * the route timers, Jira `reopen_duration`) use Prometheus's, see
20
+ * ./duration.ts. `time.Duration` fields (the `timeout` of webhook, Slack,
21
+ * PagerDuty and incident.io, and Pushover's `retry`, `expire` and `ttl`)
22
+ * use Go's `time.ParseDuration`: `1.5s` and `300ms` are valid, `1d` is not.
23
+ *
24
+ * Alertmanager stops at the first error; these checks report every one.
25
+ * PROM209 is something missing (a destination, credential or required
26
+ * field), PROM210 a setting Alertmanager rejects (two settings that exclude
27
+ * each other, or a value outside the allowed set), PROM208 a duration.
28
+ */
29
+ import type { AlertmanagerGlobalConfig, ReceiverConfig } from "./model.js";
30
+ import type { PrometheusIssue } from "./validate-config.js";
31
+ /** True when `value` is a Go `time.ParseDuration` duration (`0`, `1.5s`, `1h30m`, `300ms`). */
32
+ export declare function isValidGoDuration(value: unknown): boolean;
33
+ /** PROM208-PROM210 findings for every integration of one receiver. */
34
+ export declare function validateReceiverIntegrations(receiver: ReceiverConfig, global: AlertmanagerGlobalConfig): PrometheusIssue[];
35
+ /** PROM208 and PROM210 findings for `global:` (config/config.go `Config.UnmarshalYAML`). */
36
+ export declare function validateGlobalSettings(global: AlertmanagerGlobalConfig): PrometheusIssue[];
37
+ //# sourceMappingURL=validate-integrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-integrations.d.ts","sourceRoot":"","sources":["../src/validate-integrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAoB,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAwBzD,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKzD;AA6RD,sEAAsE;AACtE,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,wBAAwB,GAAG,eAAe,EAAE,CAS1H;AAgBD,4FAA4F;AAC5F,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,wBAAwB,GAAG,eAAe,EAAE,CAe1F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-prometheus",
3
- "version": "0.100.0",
3
+ "version": "0.102.0",
4
4
  "description": "Prometheus lexicon for chant — typed recording and alerting rule groups and Alertmanager routing, serialized to a rule file and alertmanager.yml",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -56,9 +56,10 @@
56
56
  "validate": "tsx src/validate-cli.ts",
57
57
  "docs": "tsx src/codegen/docs-cli.ts",
58
58
  "prepack": "npm run generate && npm run bundle && npm run validate && npm run build",
59
- "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete"
59
+ "build": "../../scripts/tsc7.sh -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete"
60
60
  },
61
61
  "dependencies": {
62
+ "@intentius/chant-lexicon-otel": "*",
62
63
  "@lezer/highlight": "^1.2.4",
63
64
  "@lezer/lr": "^1.4.10",
64
65
  "@prometheus-io/lezer-promql": "0.315.0",
@@ -71,7 +72,7 @@
71
72
  "typescript": "^5.9.3"
72
73
  },
73
74
  "peerDependencies": {
74
- "@intentius/chant": "^0.100.0",
75
+ "@intentius/chant": "^0.102.0",
75
76
  "typescript": "^5.9.3"
76
77
  }
77
78
  }
@@ -42,6 +42,11 @@ The \`Slo\` composite builds a service level objective to a \`RuleGroup\`:
42
42
  error ratios per window, the error budget left, and the SRE Workbook's
43
43
  multiwindow multi-burn-rate alerts. See [SLOs](./slos/).
44
44
 
45
+ The \`GenAiRules\` composite builds recording rules, opt-in alerts and spend
46
+ from a declared price table for the otel lexicon's GenAI collector preset,
47
+ reading every metric name from its \`GenAiMetrics\`. See
48
+ [GenAI Rules](./genai-rules/).
49
+
45
50
  Checks run at build time: PromQL syntax in every \`expr\` (PROM104), unique
46
51
  group names (PROM101), valid durations (PROM103), routes that name
47
52
  declared receivers (PROM201), and every alert severity routed by some route
@@ -19,7 +19,7 @@ const catalogued = compositeCatalog.map((entry) => entry.name).sort();
19
19
 
20
20
  describe("the prometheus composite catalog", () => {
21
21
  test("every exported composite has an entry, and every entry names an exported composite", () => {
22
- expect(exported).toEqual(["Slo"]);
22
+ expect(exported).toEqual(["GenAiRules", "Slo"]);
23
23
  expect(catalogued, "regenerate with `npm run generate:composite-catalogs -- prometheus`").toEqual(exported);
24
24
  });
25
25
 
@@ -4,6 +4,76 @@
4
4
  import type { CompositeEntry } from "@intentius/chant/lexicon";
5
5
 
6
6
  export const compositeCatalog: CompositeEntry[] = [
7
+ {
8
+ "name": "GenAiRules",
9
+ "lexicon": "prometheus",
10
+ "description": "Recording rules and opt-in alerts for GenAI calls, from the otel preset's metrics.",
11
+ "bundles": [
12
+ "RuleGroup"
13
+ ],
14
+ "params": [
15
+ {
16
+ "name": "genAi",
17
+ "type": "GenAiMetrics | { metrics: GenAiMetrics }",
18
+ "required": true,
19
+ "description": "The preset's metrics: `genAiMetrics(options)` with the options the collector was built with, or `genAiComponents(options)`."
20
+ },
21
+ {
22
+ "name": "source",
23
+ "type": "\"client\" | \"spans\"",
24
+ "required": false,
25
+ "description": "Which metrics the model rules read (default `client` when the metrics include the conventions' client metrics, else `spans`)."
26
+ },
27
+ {
28
+ "name": "prices",
29
+ "type": "GenAiPrice[]",
30
+ "required": false,
31
+ "description": "Prices per provider and model."
32
+ },
33
+ {
34
+ "name": "alerts",
35
+ "type": "GenAiAlerting",
36
+ "required": false,
37
+ "description": "Opt-in alerts (default: none)."
38
+ },
39
+ {
40
+ "name": "name",
41
+ "type": "string",
42
+ "required": false,
43
+ "description": "The rule group's name (default `genai`)."
44
+ },
45
+ {
46
+ "name": "prefix",
47
+ "type": "string",
48
+ "required": false,
49
+ "description": "The first part of every recorded series name (default `gen_ai`)."
50
+ },
51
+ {
52
+ "name": "rateWindow",
53
+ "type": "string",
54
+ "required": false,
55
+ "description": "The range every `rate` reads (default `5m`)."
56
+ },
57
+ {
58
+ "name": "groupBy",
59
+ "type": "string[]",
60
+ "required": false,
61
+ "description": "More Prometheus labels every rule keeps, e.g. `job` or `service_name`."
62
+ },
63
+ {
64
+ "name": "labels",
65
+ "type": "LabelSet",
66
+ "required": false,
67
+ "description": "Labels added to every rule, e.g. `team`."
68
+ },
69
+ {
70
+ "name": "interval",
71
+ "type": "string",
72
+ "required": false,
73
+ "description": "Evaluation interval of the group (default: Prometheus's `evaluation_interval`)."
74
+ }
75
+ ]
76
+ },
7
77
  {
8
78
  "name": "Slo",
9
79
  "lexicon": "prometheus",