@obsunified/collector 2.3.0 → 2.4.3

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 (34) hide show
  1. package/dist/auth.d.ts +2 -1
  2. package/dist/index.d.ts +264 -62
  3. package/dist/index.js +850 -61
  4. package/dist/index.js.map +1 -1
  5. package/dist/{ingest-auth-BmP5-f96.d.ts → ingest-auth-BTowieER.d.ts} +66 -2
  6. package/package.json +2 -2
  7. package/src/framework/env.ts +9 -1
  8. package/src/index.ts +14 -0
  9. package/src/lib/alert-email.ts +104 -0
  10. package/src/lib/alerts-store.test.ts +116 -2
  11. package/src/lib/alerts-store.ts +421 -57
  12. package/src/lib/metric-alerts.test.ts +769 -0
  13. package/src/lib/metric-alerts.ts +640 -0
  14. package/src/lib/metrics-store.ts +9 -2
  15. package/src/lib/sql-db-postgres.integration.test.ts +247 -0
  16. package/src/lib/store/trace-queries.ts +1 -1
  17. package/src/migrations/054_alert_rules_pending_secs.sql +11 -0
  18. package/src/migrations/055_alert_state_pending_since.sql +12 -0
  19. package/src/migrations/056_metric_point_series_received.sql +9 -0
  20. package/src/migrations/057_alert_evaluations_outcome.sql +11 -0
  21. package/src/migrations/058_alert_state_pending_seen_at.sql +12 -0
  22. package/src/migrations/059_alert_evaluations_error.sql +11 -0
  23. package/src/migrations-postgres/054_alert_rules_pending_secs.sql +7 -0
  24. package/src/migrations-postgres/055_alert_state_pending_since.sql +6 -0
  25. package/src/migrations-postgres/056_metric_point_series_received.sql +7 -0
  26. package/src/migrations-postgres/057_alert_evaluations_outcome.sql +6 -0
  27. package/src/migrations-postgres/058_alert_state_pending_seen_at.sql +6 -0
  28. package/src/migrations-postgres/059_alert_evaluations_error.sql +6 -0
  29. package/src/migrations-postgres/README.md +13 -0
  30. package/src/plugins/alerts-evaluator-pending.test.ts +322 -0
  31. package/src/plugins/alerts-evaluator-retention.test.ts +2 -0
  32. package/src/plugins/alerts-evaluator.test.ts +10 -2
  33. package/src/plugins/alerts-evaluator.ts +239 -40
  34. package/src/plugins/alerts-routes.ts +17 -2
package/dist/auth.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import 'hono';
2
- export { n as createIngestAuth, r as resetIngestAuthCache } from './ingest-auth-BmP5-f96.js';
2
+ export { p as createIngestAuth, s as resetIngestAuthCache } from './ingest-auth-BTowieER.js';
3
+ import '@obsunified/types';
package/dist/index.d.ts CHANGED
@@ -2,9 +2,9 @@ import * as hono from 'hono';
2
2
  import { MiddlewareHandler, Hono, Context } from 'hono';
3
3
  import * as hono_types from 'hono/types';
4
4
  import * as _obsunified_types from '@obsunified/types';
5
- import { StoredSpan, TelemetryOverviewOptions, TelemetryOverviewResponse, TelemetryTraceDetailResponse, TelemetryInstrumentationGapsResponse, TelemetryIssueOptions, TelemetryIssueOverviewResponse, TelemetryIssueDetailResponse, UsageEventRecord, UsageOverviewOptions, UsageOverviewResponse, UsageSessionDetailResponse, UsageSessionSummary, AlertRuleInput, AlertRule, AlertStateRow, AlertState, AlertEvaluationsListResponse, AlertComparison, ChangeBlastRadiusResult, ContentionCandidate, ChangeEvent, ChangeEventInput, InvestigationFinding, InvestigationFindingInput, OntologyNode, OntologyEdge, CanonicalNodeIdentity, OntologyGraphResponse, RelationshipCertainty, CausalTriple, IncidentInvestigation, RemediationProposal, EvidenceEntityKind, RemediationProposalInput, JsonValue, EvidenceReference, EvidenceReferenceContract, Project, IngestKey, IngestKeyWithPlaintext } from '@obsunified/types';
6
- import { e as CollectorEnv, L as Logger, c as ChildSpanRunner, j as CollectorRouteContext } from './ingest-auth-BmP5-f96.js';
7
- export { C as COLLECTOR_HOST_MANAGED_ENV_KEYS, a as COLLECTOR_OPTIONAL_STRING_ENV_KEYS, b as COLLECTOR_STRING_ENV_MANIFEST, d as CollectorApp, f as CollectorHostManagedEnvKey, g as CollectorManifestStringEnvKey, h as CollectorObjectBindingKey, i as CollectorOptionalStringEnvKey, k as CollectorStringEnvKey, l as assertCollectorEnvManifestCompleteness, m as consoleLogger, n as createIngestAuth } from './ingest-auth-BmP5-f96.js';
5
+ import { StoredSpan, TelemetryOverviewOptions, TelemetryOverviewResponse, TelemetryTraceDetailResponse, TelemetryInstrumentationGapsResponse, TelemetryIssueOptions, TelemetryIssueOverviewResponse, TelemetryIssueDetailResponse, UsageEventRecord, UsageOverviewOptions, UsageOverviewResponse, UsageSessionDetailResponse, UsageSessionSummary, AlertRuleInput, AlertRule, AlertStateRow, AlertState, AlertEvaluationOutcome, AlertEvaluationsListResponse, AlertComparison, ChangeBlastRadiusResult, ContentionCandidate, ChangeEvent, ChangeEventInput, InvestigationFinding, InvestigationFindingInput, OntologyNode, OntologyEdge, CanonicalNodeIdentity, OntologyGraphResponse, RelationshipCertainty, CausalTriple, IncidentInvestigation, RemediationProposal, EvidenceEntityKind, RemediationProposalInput, JsonValue, EvidenceReference, EvidenceReferenceContract, AlertQueryMetrics, AlertMetricAggregation, AlertMetricField, Project, IngestKey, IngestKeyWithPlaintext } from '@obsunified/types';
6
+ import { g as CollectorEnv, L as Logger, e as ChildSpanRunner, l as CollectorRouteContext, a as AlertEmailTransport } from './ingest-auth-BTowieER.js';
7
+ export { A as AlertEmailMessage, b as AlertNotificationPayload, C as COLLECTOR_HOST_MANAGED_ENV_KEYS, c as COLLECTOR_OPTIONAL_STRING_ENV_KEYS, d as COLLECTOR_STRING_ENV_MANIFEST, f as CollectorApp, h as CollectorHostManagedEnvKey, i as CollectorManifestStringEnvKey, j as CollectorObjectBindingKey, k as CollectorOptionalStringEnvKey, m as CollectorStringEnvKey, n as assertCollectorEnvManifestCompleteness, o as consoleLogger, p as createIngestAuth, q as formatAlertEmail, r as isValidEmailAddress } from './ingest-auth-BTowieER.js';
8
8
  import { ActionConfidence } from '@obsunified/types/constants';
9
9
  import { Pool } from 'pg';
10
10
 
@@ -488,15 +488,178 @@ declare const aiReceiverPlugin: CollectorPlugin;
488
488
 
489
489
  declare const aiSpanPayloadsProcessorPlugin: CollectorPlugin;
490
490
 
491
+ /** A rule's value, and whether a metrics rule found no fresh data. */
492
+ interface AlertRuleEvaluation {
493
+ value: number;
494
+ noData: boolean;
495
+ }
496
+
497
+ interface AlertsStoreOptions {
498
+ /** Permit webhook targets on loopback / private / link-local hosts. */
499
+ allowPrivateWebhookTargets?: boolean;
500
+ /**
501
+ * Whether this collector can send email (a transport is bound as
502
+ * `env.ALERT_EMAIL`). Rules with an email channel are refused otherwise.
503
+ */
504
+ emailDeliveryAvailable?: boolean;
505
+ }
506
+ declare function compareValue(value: number, threshold: number, comparison: AlertComparison): boolean;
507
+ declare class AlertsStore {
508
+ private readonly db;
509
+ private readonly options;
510
+ constructor(db: SqlDb, options?: AlertsStoreOptions);
511
+ validateInput(input: AlertRuleInput): void;
512
+ listRules(projectId: string): Promise<AlertRule[]>;
513
+ /**
514
+ * The newest evaluation of every rule in the project, one query. Falls
515
+ * back to the pre-057/059 column set on older databases.
516
+ */
517
+ private lastEvaluations;
518
+ getRule(id: string, projectId: string): Promise<AlertRule | null>;
519
+ createRule(projectId: string, input: AlertRuleInput): Promise<AlertRule>;
520
+ updateRule(id: string, projectId: string, patch: Partial<AlertRuleInput>): Promise<AlertRule | null>;
521
+ /**
522
+ * Clears a rule's pending period. Tolerates databases that have not
523
+ * applied 055/058 (there is nothing to clear on them).
524
+ */
525
+ resetPending(ruleId: string, projectId: string): Promise<void>;
526
+ /**
527
+ * Runs `current`; on a database that has not applied migration 054 (no
528
+ * `alert_rules.pending_secs`) a rule without a pending duration is
529
+ * written with the legacy statement so rolling deploys keep working. A
530
+ * rule that needs the column is refused with a clear message instead of
531
+ * silently losing its pending duration.
532
+ */
533
+ private withPendingColumnFallback;
534
+ deleteRule(id: string, projectId: string): Promise<boolean>;
535
+ listEnabledRules(): Promise<AlertRule[]>;
536
+ getState(ruleId: string, projectId: string): Promise<AlertStateRow | null>;
537
+ /**
538
+ * Record a state transition with its notification still outstanding
539
+ * (`notified = 0`); `markNotified` flips it once a channel accepts the
540
+ * alert. On a database that has not applied migration 049 the column is
541
+ * missing: the transition is still written (legacy statement) so alerting
542
+ * keeps working through a rolling deploy, and the evaluator treats a row
543
+ * without the column as delivered.
544
+ */
545
+ transitionState(ruleId: string, projectId: string, newState: AlertState, now: string): Promise<void>;
546
+ /**
547
+ * Mark the transition `(state, lastStateChange)` as delivered. Scoped to
548
+ * the exact transition the caller notified for: if the rule changed state
549
+ * again while the webhook was in flight, the newer transition keeps its
550
+ * own outstanding flag. Returns false when nothing matched (stale or
551
+ * already marked). On a pre-049 schema there is nothing to mark.
552
+ */
553
+ markNotified(ruleId: string, projectId: string, state: AlertState, lastStateChange: string): Promise<boolean>;
554
+ /**
555
+ * Record (`{ since, seenAt }`) or clear (`null`) the pending period of a
556
+ * rule that has a pending duration (migrations 055, 058): when the
557
+ * condition started holding, and the last evaluation that saw it hold.
558
+ * A rule without a state row gets one in state `ok` since its creation,
559
+ * already delivered (nothing is owed for a rule that never changed
560
+ * state).
561
+ */
562
+ setPending(ruleId: string, projectId: string, pending: {
563
+ since: string;
564
+ seenAt: string;
565
+ } | null, ruleCreatedAt: string): Promise<void>;
566
+ recordEvaluation(ruleId: string, projectId: string, value: number, state: AlertState, notified: boolean, outcome?: AlertEvaluationOutcome, errorMessage?: string): Promise<void>;
567
+ listEvaluations(params: {
568
+ ruleId: string;
569
+ projectId?: string;
570
+ hours: number;
571
+ limit?: number;
572
+ }): Promise<AlertEvaluationsListResponse>;
573
+ evaluateRule(rule: AlertRule, now?: Date): Promise<number>;
574
+ /** Like `evaluateRule`, plus whether a metrics rule found no fresh data. */
575
+ evaluateRuleWithStatus(rule: AlertRule, now?: Date): Promise<AlertRuleEvaluation>;
576
+ private evaluateCountRule;
577
+ /**
578
+ * Stage 6 — fetch the latest narrative associated with this rule's
579
+ * bound analysis. Used by the evaluator when firing an analysis-bound
580
+ * alert so the webhook payload includes the human-readable
581
+ * narrative, not just a threshold crossing.
582
+ */
583
+ getAnalysisNarrative(projectId: string, analysisId: string): Promise<{
584
+ narrative: string | null;
585
+ status: string | null;
586
+ } | null>;
587
+ private evaluateSpanRule;
588
+ private evaluateLogRule;
589
+ private evaluateUsageRule;
590
+ private evaluateAIRule;
591
+ }
592
+
491
593
  /** Resolve a hostname to its addresses (e.g. `dns.lookup(host, { all: true })`). */
492
594
  type HostLookup = (hostname: string) => Promise<string[]>;
493
595
 
596
+ interface AlertEvaluatorStore {
597
+ listEnabledRules(): Promise<AlertRule[]>;
598
+ evaluateRule(rule: AlertRule): Promise<number>;
599
+ /** Preferred when present: also says whether a metrics rule had no data. */
600
+ evaluateRuleWithStatus?(rule: AlertRule): Promise<AlertRuleEvaluation>;
601
+ getState(ruleId: string, projectId: string): Promise<{
602
+ current_state: AlertState;
603
+ last_state_change: string;
604
+ /** 0 while the transition's notification is owed; absent pre-049 (= delivered). */
605
+ notified?: number;
606
+ /** Start of the current pending period (migration 055); null/absent when not pending. */
607
+ pending_since?: string | null;
608
+ /** Last evaluation that saw the pending condition hold (migration 058). */
609
+ pending_seen_at?: string | null;
610
+ } | null>;
611
+ /** Record (`{ since, seenAt }`) or clear (null) the rule's pending period. */
612
+ setPending(ruleId: string, projectId: string, pending: {
613
+ since: string;
614
+ seenAt: string;
615
+ } | null, ruleCreatedAt: string): Promise<void>;
616
+ /** Flip the exact transition `(state, lastStateChange)` to delivered. */
617
+ markNotified(ruleId: string, projectId: string, state: AlertState, lastStateChange: string): Promise<boolean>;
618
+ getAnalysisNarrative(projectId: string, analysisId: string): Promise<{
619
+ narrative: string | null;
620
+ status: string | null;
621
+ } | null>;
622
+ transitionState(ruleId: string, projectId: string, newState: AlertState, now: string): Promise<void>;
623
+ recordEvaluation(ruleId: string, projectId: string, value: number, state: AlertState, notified: boolean, outcome?: AlertEvaluationOutcome,
624
+ /** With outcome `error`: why (the store sanitizes it). */
625
+ errorMessage?: string): Promise<void>;
626
+ }
627
+ declare function evaluateRuleBatch(store: AlertEvaluatorStore, rules: AlertRule[], options?: {
628
+ logger?: Logger;
629
+ tracer?: ChildSpanRunner;
630
+ concurrency?: number;
631
+ ruleTimeoutMs?: number;
632
+ allowPrivateWebhookTargets?: boolean;
633
+ hostLookup?: HostLookup;
634
+ email?: AlertEmailTransport;
635
+ onAlertFiring?: (rule: AlertRule) => Promise<void>;
636
+ /**
637
+ * Longest gap between two evaluations that still continues a pending
638
+ * hold. Default `DEFAULT_MAX_EVALUATION_GAP_MS` (two 5-minute ticks);
639
+ * pass twice the host's evaluation interval.
640
+ */
641
+ maxEvaluationGapMs?: number;
642
+ /**
643
+ * ISO start of this collector process. A hold last seen before it
644
+ * starts over, as Prometheus resets `for` on restart. Unset on hosts
645
+ * without a long-lived process (Workers), where the gap rule applies.
646
+ */
647
+ holdStartedAt?: string;
648
+ }): Promise<{
649
+ evaluated: number;
650
+ fired: number;
651
+ resolved: number;
652
+ /** Notifications for an earlier transition that were delivered on this tick. */
653
+ redelivered: number;
654
+ }>;
494
655
  declare function evaluateAllRules(env: CollectorEnv, options?: {
495
656
  logger?: Logger;
496
657
  tracer?: ChildSpanRunner;
497
658
  concurrency?: number;
498
659
  ruleTimeoutMs?: number;
499
660
  hostLookup?: HostLookup;
661
+ maxEvaluationGapMs?: number;
662
+ holdStartedAt?: string;
500
663
  }): Promise<{
501
664
  evaluated: number;
502
665
  fired: number;
@@ -1024,64 +1187,6 @@ declare class ActionStore {
1024
1187
  listArtifactsByAction(projectId: string, actionId: string, limit?: number): Promise<ArtifactRef[]>;
1025
1188
  }
1026
1189
 
1027
- interface AlertsStoreOptions {
1028
- /** Permit webhook targets on loopback / private / link-local hosts. */
1029
- allowPrivateWebhookTargets?: boolean;
1030
- }
1031
- declare function compareValue(value: number, threshold: number, comparison: AlertComparison): boolean;
1032
- declare class AlertsStore {
1033
- private readonly db;
1034
- private readonly options;
1035
- constructor(db: SqlDb, options?: AlertsStoreOptions);
1036
- validateInput(input: AlertRuleInput): void;
1037
- listRules(projectId: string): Promise<AlertRule[]>;
1038
- getRule(id: string, projectId: string): Promise<AlertRule | null>;
1039
- createRule(projectId: string, input: AlertRuleInput): Promise<AlertRule>;
1040
- updateRule(id: string, projectId: string, patch: Partial<AlertRuleInput>): Promise<AlertRule | null>;
1041
- deleteRule(id: string, projectId: string): Promise<boolean>;
1042
- listEnabledRules(): Promise<AlertRule[]>;
1043
- getState(ruleId: string, projectId: string): Promise<AlertStateRow | null>;
1044
- /**
1045
- * Record a state transition with its notification still outstanding
1046
- * (`notified = 0`); `markNotified` flips it once a channel accepts the
1047
- * alert. On a database that has not applied migration 049 the column is
1048
- * missing: the transition is still written (legacy statement) so alerting
1049
- * keeps working through a rolling deploy, and the evaluator treats a row
1050
- * without the column as delivered.
1051
- */
1052
- transitionState(ruleId: string, projectId: string, newState: AlertState, now: string): Promise<void>;
1053
- /**
1054
- * Mark the transition `(state, lastStateChange)` as delivered. Scoped to
1055
- * the exact transition the caller notified for: if the rule changed state
1056
- * again while the webhook was in flight, the newer transition keeps its
1057
- * own outstanding flag. Returns false when nothing matched (stale or
1058
- * already marked). On a pre-049 schema there is nothing to mark.
1059
- */
1060
- markNotified(ruleId: string, projectId: string, state: AlertState, lastStateChange: string): Promise<boolean>;
1061
- recordEvaluation(ruleId: string, projectId: string, value: number, state: AlertState, notified: boolean): Promise<void>;
1062
- listEvaluations(params: {
1063
- ruleId: string;
1064
- projectId?: string;
1065
- hours: number;
1066
- limit?: number;
1067
- }): Promise<AlertEvaluationsListResponse>;
1068
- evaluateRule(rule: AlertRule): Promise<number>;
1069
- /**
1070
- * Stage 6 — fetch the latest narrative associated with this rule's
1071
- * bound analysis. Used by the evaluator when firing an analysis-bound
1072
- * alert so the webhook payload includes the human-readable
1073
- * narrative, not just a threshold crossing.
1074
- */
1075
- getAnalysisNarrative(projectId: string, analysisId: string): Promise<{
1076
- narrative: string | null;
1077
- status: string | null;
1078
- } | null>;
1079
- private evaluateSpanRule;
1080
- private evaluateLogRule;
1081
- private evaluateUsageRule;
1082
- private evaluateAIRule;
1083
- }
1084
-
1085
1190
  declare function recordChangeEvent(db: SqlDb, projectId: string, input: ChangeEventInput): Promise<ChangeEvent>;
1086
1191
  declare function listChangeEvents(db: SqlDb, options: {
1087
1192
  projectId: string;
@@ -1698,6 +1803,103 @@ declare class EvalCasesStore {
1698
1803
  private buildMetadata;
1699
1804
  }
1700
1805
 
1806
+ /**
1807
+ * `metrics` alert signal: validation and evaluation of an
1808
+ * `AlertQueryMetrics` against `metric_series` / `metric_point`.
1809
+ *
1810
+ * Evaluation, per selector (numerator, then the optional denominator):
1811
+ *
1812
+ * 1. Series: `metric_series` rows of the project whose name is one of the
1813
+ * selector's names (and whose `service_name` matches, when given), kept
1814
+ * when every listed data-point / resource attribute equals the rule's
1815
+ * value. Attribute values are compared as strings, so `200` matches a
1816
+ * stored `"200"` and vice versa.
1817
+ * 2. Points: the series' points whose `received_at` (the collector's clock,
1818
+ * as for every other alert signal) is inside the rule window, ordered by
1819
+ * producer time (`ts_ns`). The number read is `field` (`value`, or a
1820
+ * histogram/summary `count` / `sum`); points without it are skipped.
1821
+ * 3. Staleness: for `last`, `min`, `max`, `avg` and `sum` a series takes
1822
+ * part only when its newest point is at most `staleSecs` (default 300)
1823
+ * old, so a series that stopped reporting (a renamed host, a replaced
1824
+ * pod) no longer adds its last value. `increase` / `rate` keep every
1825
+ * series with points in the window: growth that happened is real even
1826
+ * if the series stopped afterwards.
1827
+ * 4. Each series is reduced on its own (`reduceSeries`), and the per-series
1828
+ * results are summed. A series with no usable point adds nothing.
1829
+ *
1830
+ * When no series takes part (in the numerator or the denominator) the
1831
+ * result is "no data": the value is 0 and `noData` is true. The rule's
1832
+ * `noData` policy decides what that means (`zero`: evaluate 0 as usual;
1833
+ * `keep`: leave the alert state as it is).
1834
+ *
1835
+ * `age_seconds` ignores the window: it is the seconds since the newest
1836
+ * `received_at` of any matching series. When no matching series has any
1837
+ * stored point (never reported, or everything aged out of retention) it is
1838
+ * the seconds since the rule was created, a finite number that grows until
1839
+ * the threshold is crossed, so "never reported" fires after the same grace
1840
+ * period as "stopped reporting".
1841
+ *
1842
+ * `age_seconds` is never "no data".
1843
+ *
1844
+ * Ratio: with a `denominator`, value = numerator / denominator when the
1845
+ * denominator is > 0 and >= minDenominator (default 0), else 0.
1846
+ *
1847
+ * Cost bounds: at most `MAX_MATCHED_SERIES` series and `MAX_LOADED_POINTS`
1848
+ * points per selector; past either the evaluation fails with an error (the
1849
+ * evaluator records it as an `error` evaluation) rather than returning a
1850
+ * value computed from part of the data. Metric rule windows are at most
1851
+ * `MAX_METRIC_WINDOW_MINS`.
1852
+ */
1853
+
1854
+ /** Throws an Error with a user-facing message when `query` is malformed. */
1855
+ declare function validateMetricQuery(query: unknown): void;
1856
+ interface MetricPointSample {
1857
+ tsNs: string;
1858
+ startTsNs: string | null;
1859
+ value: number | null;
1860
+ count: number | null;
1861
+ sum: number | null;
1862
+ receivedAt: string;
1863
+ }
1864
+ interface SeriesReduceOptions {
1865
+ /**
1866
+ * The series has no history before the window (its `metric_series` row
1867
+ * was created inside it): a cumulative counter's first point then counts
1868
+ * as growth from 0 instead of being the baseline.
1869
+ */
1870
+ bornInWindow?: boolean;
1871
+ aggregation: Exclude<AlertMetricAggregation, "age_seconds">;
1872
+ field: AlertMetricField;
1873
+ /** `metric_series.temporality`: 1 delta, 2 cumulative, null for gauges. */
1874
+ temporality: number | null;
1875
+ /** Start of the window in Unix nanoseconds. */
1876
+ windowStartNs: bigint;
1877
+ windowSecs: number;
1878
+ }
1879
+ /**
1880
+ * Reduces one series' window points to a number, or null when the series
1881
+ * has no point carrying `field` in the window.
1882
+ */
1883
+ declare function reduceSeries(points: MetricPointSample[], opts: SeriesReduceOptions): number | null;
1884
+ interface MetricEvalContext {
1885
+ projectId: string;
1886
+ windowMins: number;
1887
+ /** The rule's `createdAt`; the reference for "never reported". */
1888
+ ruleCreatedAt: string;
1889
+ now: Date;
1890
+ /** Staleness bound for gauge-style aggregations; default 300. */
1891
+ staleSecs?: number;
1892
+ /** Point cap per selector; default MAX_LOADED_POINTS (tests lower it). */
1893
+ maxLoadedPoints?: number;
1894
+ }
1895
+ interface MetricEvaluation {
1896
+ value: number;
1897
+ /** No series took part; see the module comment. Never true for age_seconds. */
1898
+ noData: boolean;
1899
+ }
1900
+ /** Evaluates a validated metrics query to a finite number. */
1901
+ declare function evaluateMetricQuery(db: SqlDb, query: AlertQueryMetrics, ctx: MetricEvalContext): Promise<MetricEvaluation>;
1902
+
1701
1903
  type MetricType = "gauge" | "sum" | "histogram" | "exp_histogram" | "summary";
1702
1904
  /**
1703
1905
  * A metric data point normalized for storage. Series-identifying fields
@@ -1855,4 +2057,4 @@ declare const _default: hono.Hono<{
1855
2057
  Bindings: CollectorEnv;
1856
2058
  }, hono_types.BlankSchema, "/">;
1857
2059
 
1858
- export { type ActionGraphPurgeSummary, type ActionGraphRetentionOptions, type ActionRecord, ActionStore, type AgentRunRecord, AlertsStore, type AnalysesRunSummary, type ArtifactRecord, type BlobListOptions, type BlobListResult, type BlobObject, type BlobPutOptions, type BlobStore, BlobStoreToR2Adapter, type CollectorAuthConfig, type CollectorConfig, CollectorEnv, type CollectorPlugin, CollectorRouteContext, CollectorRuntime, CounterfactualVerificationError, D1Adapter, type DashboardAuthConfig, type EvalCase, type EvalCaseInput, type EvalCaseListOptions, type EvalCaseSourceLinks, EvalCaseSourceNotFoundError, type EvalCaseSourceType, EvalCasesStore, type EvalResultRecord, type EvalRun, type EvalRunCandidate, type EvalRunInput, type EvalRunSourceCase, type EvalRunStatus, type EvalRunsListOptions, type HostLookup, Logger, MetricsStore, PostgresAdapter, type PostgresAdapterOptions, type PostgresTypeParserRegistry, ProjectsStore, R2BlobStore, RemediationGateError, type RetentionCleanupSummary, type RetrievalEventRecord, S3BlobStore, type S3BlobStoreOptions, type ScheduledTaskHandler, type SpanProcessorPlugin, type SqlDb, type SqlDbFactory, type SqlStatement, type TailEvent, TailHub, type TailKind, type ToolCallRecord, type UsageEventProcessorPlugin, type WatchdogEvaluationSummary, acquireIncidentLease, actionRetentionCutoff, actionRoutesPlugin, aiReceiverPlugin, aiSpanPayloadsProcessorPlugin, alertsRoutesPlugin, allPlugins, analysesRoutesPlugin, approveRemediationProposal, askRoutesPlugin, autosreRoutesPlugin, botFilterPlugin, claimRemediationGrant, compareValue, completeRemediationProposal, computeChangeBlastRadius, computeTarjanScc, configurePostgresTypeParsers, connectedRoutesPlugin, createAlertEvaluatorHandler, createAnalysesRunHandler, createDashboardAuth, createDefaultCollectorApp, createRetentionCleanupHandler, createTelemetryCollectorApp, dashboardRoutesPlugin, _default as default, defaultSpanEnrichmentPlugin, dispatchIncidentWebhook, evalCasesRoutesPlugin, evaluateAllRules, evaluateRemediationWatchdogs, evidenceRetrievalRoutesPlugin, extractSpanLineageAndTopology, failRemediationProposal, findCrossTraceContention, genAiNormalizerPlugin, getChangeEvent, getIncidentInvestigation, getInvestigationFinding, getOntologyGraph, getRemediationProposal, identityReceiverPlugin, isEvalCaseSourceType, isEvalRunStatus, issueEnrichmentPlugin, issueInsightsPlugin, listChangeEvents, listIncidentInvestigations, listRemediationProposals, loadTraceFaultLocusFromDb, localizeTraceFaultLocus, logsReceiverPlugin, metricsReceiverPlugin, onboardingRoutesPlugin, openOrDeduplicateIncident, otlpReceiverPlugin, platformRoutesPlugin, profileRoutesPlugin, projectsRoutesPlugin, proposeRemediationAction, purgeExpiredActionGraph, queryRoutesPlugin, recordChangeEvent, recordInvestigationFinding, redactionProcessorPlugin, rejectRemediationProposal, replayQueryRoutesPlugin, replayReceiverPlugin, searchInvestigationFindings, tailRoutesPlugin, timelineRoutesPlugin, uaEnrichmentPlugin, upsertOntologyFromSpans, usageNormalizationPlugin, usagePrivacyPlugin, usageQueryRoutesPlugin, usageReceiverPlugin, usersQueryRoutesPlugin, utmEnrichmentPlugin, verifyPairedCounterfactualProof };
2060
+ export { type ActionGraphPurgeSummary, type ActionGraphRetentionOptions, type ActionRecord, ActionStore, type AgentRunRecord, AlertEmailTransport, AlertsStore, type AnalysesRunSummary, type ArtifactRecord, type BlobListOptions, type BlobListResult, type BlobObject, type BlobPutOptions, type BlobStore, BlobStoreToR2Adapter, type CollectorAuthConfig, type CollectorConfig, CollectorEnv, type CollectorPlugin, CollectorRouteContext, CollectorRuntime, CounterfactualVerificationError, D1Adapter, type DashboardAuthConfig, type EvalCase, type EvalCaseInput, type EvalCaseListOptions, type EvalCaseSourceLinks, EvalCaseSourceNotFoundError, type EvalCaseSourceType, EvalCasesStore, type EvalResultRecord, type EvalRun, type EvalRunCandidate, type EvalRunInput, type EvalRunSourceCase, type EvalRunStatus, type EvalRunsListOptions, type HostLookup, Logger, MetricsStore, PostgresAdapter, type PostgresAdapterOptions, type PostgresTypeParserRegistry, ProjectsStore, R2BlobStore, RemediationGateError, type RetentionCleanupSummary, type RetrievalEventRecord, S3BlobStore, type S3BlobStoreOptions, type ScheduledTaskHandler, type SpanProcessorPlugin, type SqlDb, type SqlDbFactory, type SqlStatement, type TailEvent, TailHub, type TailKind, type ToolCallRecord, type UsageEventProcessorPlugin, type WatchdogEvaluationSummary, acquireIncidentLease, actionRetentionCutoff, actionRoutesPlugin, aiReceiverPlugin, aiSpanPayloadsProcessorPlugin, alertsRoutesPlugin, allPlugins, analysesRoutesPlugin, approveRemediationProposal, askRoutesPlugin, autosreRoutesPlugin, botFilterPlugin, claimRemediationGrant, compareValue, completeRemediationProposal, computeChangeBlastRadius, computeTarjanScc, configurePostgresTypeParsers, connectedRoutesPlugin, createAlertEvaluatorHandler, createAnalysesRunHandler, createDashboardAuth, createDefaultCollectorApp, createRetentionCleanupHandler, createTelemetryCollectorApp, dashboardRoutesPlugin, _default as default, defaultSpanEnrichmentPlugin, dispatchIncidentWebhook, evalCasesRoutesPlugin, evaluateAllRules, evaluateMetricQuery, evaluateRemediationWatchdogs, evaluateRuleBatch, evidenceRetrievalRoutesPlugin, extractSpanLineageAndTopology, failRemediationProposal, findCrossTraceContention, genAiNormalizerPlugin, getChangeEvent, getIncidentInvestigation, getInvestigationFinding, getOntologyGraph, getRemediationProposal, identityReceiverPlugin, isEvalCaseSourceType, isEvalRunStatus, issueEnrichmentPlugin, issueInsightsPlugin, listChangeEvents, listIncidentInvestigations, listRemediationProposals, loadTraceFaultLocusFromDb, localizeTraceFaultLocus, logsReceiverPlugin, metricsReceiverPlugin, onboardingRoutesPlugin, openOrDeduplicateIncident, otlpReceiverPlugin, platformRoutesPlugin, profileRoutesPlugin, projectsRoutesPlugin, proposeRemediationAction, purgeExpiredActionGraph, queryRoutesPlugin, recordChangeEvent, recordInvestigationFinding, redactionProcessorPlugin, reduceSeries, rejectRemediationProposal, replayQueryRoutesPlugin, replayReceiverPlugin, searchInvestigationFindings, tailRoutesPlugin, timelineRoutesPlugin, uaEnrichmentPlugin, upsertOntologyFromSpans, usageNormalizationPlugin, usagePrivacyPlugin, usageQueryRoutesPlugin, usageReceiverPlugin, usersQueryRoutesPlugin, utmEnrichmentPlugin, validateMetricQuery, verifyPairedCounterfactualProof };