@forgecart/flight-observability 0.202608221935.0 → 0.202609190800.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.
@@ -25,6 +25,42 @@ pg_idle_in_tx:
25
25
  usage: GAUGE
26
26
  description: Number of idle-in-transaction backends
27
27
 
28
+ # Attribution for the FcIdleInTxAge class (run 32930565055 forensics: a 9.7min
29
+ # idle-in-tx squatter blocked a scope boot and nothing named the owner). Top-1
30
+ # oldest idle-in-tx session WITH identity labels. Cardinality is safe by
31
+ # construction: zero rows — and therefore ZERO series — whenever no squatter
32
+ # exists; during an incident exactly one label tuple lives for the session's
33
+ # lifetime. query_head is whitespace-collapsed and truncated so a label value
34
+ # can never carry a full statement.
35
+ pg_idle_in_tx_top:
36
+ query: >-
37
+ SELECT
38
+ COALESCE(datname, '') AS datname,
39
+ COALESCE(usename, '') AS usename,
40
+ COALESCE(application_name, '') AS application_name,
41
+ COALESCE(left(regexp_replace(query, '\s+', ' ', 'g'), 60), '') AS query_head,
42
+ EXTRACT(EPOCH FROM (now() - xact_start))::float AS age_seconds
43
+ FROM pg_stat_activity
44
+ WHERE backend_type = 'client backend' AND state = 'idle in transaction'
45
+ ORDER BY xact_start ASC
46
+ LIMIT 1
47
+ metrics:
48
+ - datname:
49
+ usage: LABEL
50
+ description: Database of the oldest idle-in-transaction session
51
+ - usename:
52
+ usage: LABEL
53
+ description: Role of the oldest idle-in-transaction session
54
+ - application_name:
55
+ usage: LABEL
56
+ description: application_name of the oldest idle-in-transaction session
57
+ - query_head:
58
+ usage: LABEL
59
+ description: First 60 chars of the session's last statement (whitespace-collapsed)
60
+ - age_seconds:
61
+ usage: GAUGE
62
+ description: Age of the oldest idle-in-transaction session (seconds)
63
+
28
64
  pg_citus_backends:
29
65
  query: >-
30
66
  SELECT
@@ -62,3 +98,25 @@ pg_outbox:
62
98
  - oldest_unsent_seconds:
63
99
  usage: GAUGE
64
100
  description: Age of the oldest due-but-unsent outbox row (seconds)
101
+
102
+ # Marketing-event flush health (#1074) — the sensor run 32584944772 lacked: a
103
+ # batch consumed with zero dispatch was invisible. WHERE-form ON PURPOSE, not
104
+ # pg_outbox's FILTER shape: FILTER predicates are evaluated at the aggregate
105
+ # node over an unqualified scan, so on the unreaped firehose table every
106
+ # scrape would seq-scan ALL rows; the WHERE form is served by the partial
107
+ # index IDX_marketing_event_outbox_unflushed and stays O(backlog) — the 097
108
+ # shop_outbox_metrics() precedent. Column names quoted (TypeORM camelCase).
109
+ pg_marketing_outbox:
110
+ query: >-
111
+ SELECT
112
+ count(*)::float AS backlog,
113
+ COALESCE(EXTRACT(EPOCH FROM (now() - min("ingestedAt"))), 0)::float AS oldest_pending_seconds
114
+ FROM marketing_event_outbox
115
+ WHERE "flushedAt" IS NULL
116
+ metrics:
117
+ - backlog:
118
+ usage: GAUGE
119
+ description: Pending (unflushed) marketing-event outbox rows
120
+ - oldest_pending_seconds:
121
+ usage: GAUGE
122
+ description: Age of the oldest pending marketing-event outbox row (seconds)
@@ -54,7 +54,7 @@ groups:
54
54
  severity: warning
55
55
  annotations:
56
56
  summary: 'Idle-in-transaction backend older than 120s'
57
- description: 'Oldest idle-in-tx = {{ $value }}s — a held-open transaction pins a real coordinator connection through the pooler (tech-debt #10).'
57
+ description: 'Oldest idle-in-tx = {{ $value }}s — a held-open transaction pins a real coordinator connection through the pooler (tech-debt #10). Owner: db={{ with query "topk(1, pg_idle_in_tx_top_age_seconds)" }}{{ . | first | label "datname" }} user={{ . | first | label "usename" }} app={{ . | first | label "application_name" }} q="{{ . | first | label "query_head" }}"{{ end }}'
58
58
 
59
59
  - name: fc-alerts-pooler
60
60
  rules:
@@ -156,6 +156,14 @@ groups:
156
156
  annotations:
157
157
  summary: 'Oldest due-but-unsent outbox row over 120s'
158
158
  description: 'oldest = {{ $value }}s, backlog = {{ with query "fc:outbox:backlog" }}{{ . | first | value }}{{ end }} — the relay is stalled or the broker is refusing publishes.'
159
+ - alert: FcMarketingFlushLag
160
+ expr: fc:marketing:flush_lag_seconds > 60
161
+ for: 5m
162
+ labels:
163
+ severity: warning
164
+ annotations:
165
+ summary: 'Oldest pending marketing-event outbox row over 60s'
166
+ description: 'oldest = {{ $value }}s, backlog = {{ with query "fc:marketing:backlog" }}{{ . | first | value }}{{ end }} — flush workers stalled, claim starvation, or every claimer erroring (#1074).'
159
167
 
160
168
  - name: fc-alerts-doctrine
161
169
  rules:
@@ -224,6 +224,12 @@ groups:
224
224
  # F4: the REAL effective prefetch — the HOL-utilisation divisor.
225
225
  - record: fc:mq:prefetch_effective
226
226
  expr: max by (service) (fc_mq_prefetch_effective)
227
+ # #1172: AMQP liveness per service — min, so ANY disconnected replica
228
+ # drags the series to 0 (the loud direction). The cause line under an
229
+ # outbox mute: eligible depth climbing at 0 = genuine broker mute;
230
+ # climbing at 1 = a claim/delivery defect.
231
+ - record: fc:mq:connected
232
+ expr: min by (service) (fc_mq_connected)
227
233
  # The register-trigger meter (debt #3 ≥1k, debt #2/Kafka ≥5-10k): the
228
234
  # 1k/5k reference lines live on the dashboard panel.
229
235
  - record: fc:ingest:events_per_second
@@ -240,6 +246,16 @@ groups:
240
246
  expr: max by (service, target) (fc_grpc_ready)
241
247
  - record: fc:grpc:inflight
242
248
  expr: sum by (service, target) (fc_grpc_inflight)
249
+ # Ads gateway closure (#933, register #10): staleness/lag/depth gauges + the
250
+ # re-auth counter rate — bounded provider label by construction.
251
+ - record: fc:ads:spend_sync_staleness_seconds
252
+ expr: max by (service, provider) (fc_ads_spend_sync_staleness_seconds)
253
+ - record: fc:ads:audience_watermark_lag_seconds
254
+ expr: max by (service, provider) (fc_ads_audience_watermark_lag_seconds)
255
+ - record: fc:ads:conversion_dlq_depth
256
+ expr: max by (service) (fc_ads_conversion_dlq_depth)
257
+ - record: fc:ads:token_refresh_failure_rate
258
+ expr: sum by (provider, reason) (rate(fc_ads_token_refresh_failures_total[5m]))
243
259
  - record: fc:grpc:transient_failure_rate
244
260
  expr: sum by (service, target) (rate(fc_grpc_transient_failure_seconds_total[5m]))
245
261
  # Model-provider limit rejections (run 32571110796's invisible class):
@@ -388,6 +404,40 @@ groups:
388
404
  expr: max(pg_outbox_oldest_unsent_seconds)
389
405
  - record: fc:outbox:backlog
390
406
  expr: max(pg_outbox_backlog)
407
+ # #1172: the relay's own lane-scoped census — the ELIGIBILITY-AWARE
408
+ # truth. The pg_outbox_* pair above is eligibility-blind by construction
409
+ # (it counts future-dated re-arm slots and foreign-prefix CI orphans,
410
+ # and ages rows from birth — the 2026-08-29 false "hard-mute"): keep it
411
+ # for exporter parity, but alert predicates belong on THESE series.
412
+ - record: fc:outbox:eligible_depth
413
+ expr: max by (service) (fc_outbox_eligible_depth)
414
+ - record: fc:outbox:scheduled_depth
415
+ expr: max by (service) (fc_outbox_scheduled_depth)
416
+ - record: fc:outbox:retrying_depth
417
+ expr: max by (service) (fc_outbox_retrying_depth)
418
+ - record: fc:outbox:dead_depth
419
+ expr: max by (service) (fc_outbox_dead_depth)
420
+ - record: fc:outbox:oldest_eligible_seconds
421
+ expr: max by (service) (fc_outbox_oldest_eligible_seconds)
422
+ - record: fc:outbox:dead_lettered_rate
423
+ expr: sum by (service) (rate(fc_outbox_dead_lettered_total[5m]))
424
+ - name: fc-marketing
425
+ interval: 15s
426
+ rules:
427
+ # Marketing-event flush health (#1074) — pg_marketing_outbox is the
428
+ # WHERE-form probe (partial-index-served; never the FILTER full-scan).
429
+ - record: fc:marketing:backlog
430
+ expr: max(pg_marketing_outbox_backlog)
431
+ - record: fc:marketing:flush_lag_seconds
432
+ expr: max(pg_marketing_outbox_oldest_pending_seconds)
433
+ # Planned-vs-fired imbalance panel — both counters at-least-once, so
434
+ # panels read rate trends, never exact equality (#1074).
435
+ - record: fc:automation:planned_match_rate
436
+ expr: sum(rate(fc_automation_dispatch_matches_total[5m]))
437
+ - record: fc:automation:fire_rate
438
+ expr: sum by (outcome) (rate(fc_automation_fire_total[5m]))
439
+ - record: fc:automation:rule_cache_rate
440
+ expr: sum by (outcome) (rate(fc_automation_rule_cache_total[5m]))
391
441
  - name: fc-workspace
392
442
  interval: 15s
393
443
  rules:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgecart/flight-observability",
3
- "version": "0.202608221935.0",
3
+ "version": "0.202609190800.0",
4
4
  "private": false,
5
5
  "description": "Flight Deck dashboards, fc: recording/alert rules, and the pg-custom-queries contract — the version-pinned sync artifact between shop-beta and forgecart/cloud (launch#46 P4).",
6
6
  "files": [