You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
expect(targets.some((target)=>target.expr==="sum by (result) (rate(loopover_github_response_cache_total[5m]))")).toBe(true);
103
-
expect(targets.some((target)=>target.expr==="sum by (class, result) (loopover_github_response_cache_total)")).toBe(true);
102
+
expect(targets.some((target)=>target.expr==="sum by (result) ((rate(loopover_github_response_cache_total[5m]) or rate(gittensory_github_response_cache_total[5m])))")).toBe(true);
103
+
expect(targets.some((target)=>target.expr==="sum by (class, result) ((loopover_github_response_cache_total or gittensory_github_response_cache_total))")).toBe(true);
expect(targets.some((target)=>target.expr==="sum by (remaining_bucket, key_scope) (rate(loopover_github_rest_rate_limit_observations_total[5m])) or vector(0)")).toBe(true);
106
-
expect(targets.some((target)=>target.expr==="sum by (status, retry, key_scope) (rate(loopover_github_rest_rate_limit_responses_total[5m])) or vector(0)")).toBe(true);
107
-
expect(targets.some((target)=>target.expr==="sum by (kind, key_scope, job_type) (rate(loopover_jobs_rate_limit_admission_deferred_total[5m])) or vector(0)")).toBe(true);
108
-
expect(targets.some((target)=>target.expr==="sum by (kind, key_scope, job_type) (rate(loopover_jobs_rate_limit_budget_deferred_total[5m])) or vector(0)")).toBe(true);
109
-
expect(targets.some((target)=>target.expr==="sum by (kind, key_scope, job_type) (rate(loopover_jobs_rate_limited_by_type_total[5m])) or vector(0)")).toBe(true);
105
+
expect(targets.some((target)=>target.expr==="sum by (remaining_bucket, key_scope) ((rate(loopover_github_rest_rate_limit_observations_total[5m]) or rate(gittensory_github_rest_rate_limit_observations_total[5m]))) or vector(0)")).toBe(true);
106
+
expect(targets.some((target)=>target.expr==="sum by (status, retry, key_scope) ((rate(loopover_github_rest_rate_limit_responses_total[5m]) or rate(gittensory_github_rest_rate_limit_responses_total[5m]))) or vector(0)")).toBe(true);
107
+
expect(targets.some((target)=>target.expr==="sum by (kind, key_scope, job_type) ((rate(loopover_jobs_rate_limit_admission_deferred_total[5m]) or rate(gittensory_jobs_rate_limit_admission_deferred_total[5m]))) or vector(0)")).toBe(true);
108
+
expect(targets.some((target)=>target.expr==="sum by (kind, key_scope, job_type) ((rate(loopover_jobs_rate_limit_budget_deferred_total[5m]) or rate(gittensory_jobs_rate_limit_budget_deferred_total[5m]))) or vector(0)")).toBe(true);
109
+
expect(targets.some((target)=>target.expr==="sum by (kind, key_scope, job_type) ((rate(loopover_jobs_rate_limited_by_type_total[5m]) or rate(gittensory_jobs_rate_limited_by_type_total[5m]))) or vector(0)")).toBe(true);
110
110
// The AI request/fallback + cost/token panels moved to the consolidated grafana/dashboards/ai-usage.json
111
111
// (Phase B2, 2026-07) — see test/unit/selfhost-grafana-ai-usage-dashboard.test.ts for their coverage there.
expect(targets.some((target)=>target.expr==="loopover_orb_events_exported_total or vector(0)")).toBe(true);
132
-
expect(targets.some((target)=>target.expr==="loopover_orb_export_errors_total or vector(0)")).toBe(true);
133
-
expect(targets.some((target)=>target.expr==="sum by (result) (rate(loopover_orb_webhook_total[5m])) or vector(0)")).toBe(true);
131
+
expect(targets.some((target)=>target.expr==="(loopover_orb_events_exported_total or gittensory_orb_events_exported_total) or vector(0)")).toBe(true);
132
+
expect(targets.some((target)=>target.expr==="(loopover_orb_export_errors_total or gittensory_orb_export_errors_total) or vector(0)")).toBe(true);
133
+
expect(targets.some((target)=>target.expr==="sum by (result) ((rate(loopover_orb_webhook_total[5m]) or rate(gittensory_orb_webhook_total[5m]))) or vector(0)")).toBe(true);
134
134
});
135
135
136
136
it("no longer references loopover_orb_events_recorded_total / loopover_orb_installs_total, retired with the per-instance Orb App in #1256 but never cleaned out of the dashboard (2026-07 fix)",()=>{
expect(targets.some((target)=>target.expr==='topk(10, pg_stat_user_tables_n_live_tup{datname="loopover"}) or vector(0)')).toBe(true);
189
189
expect(targets.some((target)=>target.expr==='topk(10, pg_stat_user_tables_n_dead_tup{datname="loopover"}) or vector(0)')).toBe(true);
190
190
expect(targets.some((target)=>target.expr==='sum by (relname) (increase(pg_stat_user_tables_autovacuum_count{datname="loopover"}[1h])) or vector(0)')).toBe(true);
191
-
expect(targets.some((target)=>target.expr==='loopover_backup_files{target=~"postgres|sqlite|qdrant"} or vector(0)')).toBe(true);
191
+
expect(targets.some((target)=>target.expr==='(loopover_backup_files or gittensory_backup_files){target=~"postgres|sqlite|qdrant"} or vector(0)')).toBe(true);
192
192
});
193
193
194
194
it("ships Postgres and backup alerts for the same dashboarded failure modes",()=>{
expect(targets.some((target)=>target.expr==="sum by (reason, job_type) (rate(loopover_jobs_maintenance_admission_deferred_by_reason_total[5m])) or vector(0)")).toBe(true);
228
-
expect(targets.some((target)=>target.expr==="sum(rate(loopover_jobs_maintenance_admission_deferred_total[5m])) or vector(0)")).toBe(true);
227
+
expect(targets.some((target)=>target.expr==="sum by (reason, job_type) ((rate(loopover_jobs_maintenance_admission_deferred_by_reason_total[5m]) or rate(gittensory_jobs_maintenance_admission_deferred_by_reason_total[5m]))) or vector(0)")).toBe(true);
228
+
expect(targets.some((target)=>target.expr==="sum((rate(loopover_jobs_maintenance_admission_deferred_total[5m]) or rate(gittensory_jobs_maintenance_admission_deferred_total[5m]))) or vector(0)")).toBe(true);
229
229
});
230
230
231
231
it("surfaces self-host runtime-drift signal panels, every counter query fleet-aggregated",()=>{
// Every stat-panel counter is sum()-wrapped, matching its siblings -- a multi-instance self-host scrape
249
249
// must render one fleet-level value per stat, not one value per target (gate finding, #chore-runtime-drift).
250
-
expect(targets.some((target)=>target.expr==="sum(loopover_jobs_maintenance_trickle_admitted_persisted_total) or vector(0)")).toBe(true);
251
-
expect(targets.some((target)=>target.expr==='sum(loopover_orb_relay_register_total{result="failed"}) or vector(0)')).toBe(true);
252
-
expect(targets.some((target)=>target.expr==='sum(loopover_installation_health_broker_probe_total{result="failed"}) or vector(0)')).toBe(true);
250
+
expect(targets.some((target)=>target.expr==="sum((loopover_jobs_maintenance_trickle_admitted_persisted_total or gittensory_jobs_maintenance_trickle_admitted_persisted_total)) or vector(0)")).toBe(true);
251
+
expect(targets.some((target)=>target.expr==='sum((loopover_orb_relay_register_total or gittensory_orb_relay_register_total){result="failed"}) or vector(0)')).toBe(true);
252
+
expect(targets.some((target)=>target.expr==='sum((loopover_installation_health_broker_probe_total or gittensory_installation_health_broker_probe_total){result="failed"}) or vector(0)')).toBe(true);
253
253
expect(targets.some((target)=>target.expr==="sum(loopover_agent_action_permission_denied_total) or vector(0)")).toBe(true);
254
254
// Grouped (sum-by) queries must NOT have "or vector(0)": Prometheus's `or` unions result sets, and
255
255
// vector(0) is a single unlabeled series that can't match the actionClass/mode,result label set --
256
256
// that renders a bogus extra unlabeled zero-series alongside the real labeled series (gate finding).
257
257
expect(targets.some((target)=>target.expr==="sum by (actionClass) (rate(loopover_agent_action_permission_denied_total[5m]))")).toBe(true);
258
258
expect(targets.some((target)=>target.expr==="sum by (actionClass) (rate(loopover_agent_action_permission_denied_suppressed_total[5m]))")).toBe(true);
259
-
expect(targets.some((target)=>target.expr==="sum by (mode, result) (rate(loopover_orb_relay_register_total[5m]))")).toBe(true);
259
+
expect(targets.some((target)=>target.expr==="sum by (mode, result) ((rate(loopover_orb_relay_register_total[5m]) or rate(gittensory_orb_relay_register_total[5m])))")).toBe(true);
260
260
// #selfhost-runtime-drift follow-up: the streak-vs-drain-progress panel is the dashboard-visible
261
261
// counterpart to isOrbRelayRegistrationAlerting's gate -- a lone registration timeout must not read as
262
262
// a dashboard error on its own as long as the drain loop is still making progress.
263
-
expect(targets.some((target)=>target.expr==="loopover_orb_relay_register_consecutive_failures or vector(0)")).toBe(true);
264
-
expect(targets.some((target)=>target.expr==="loopover_orb_relay_drain_seconds_since_last or vector(0)")).toBe(true);
263
+
expect(targets.some((target)=>target.expr==="(loopover_orb_relay_register_consecutive_failures or gittensory_orb_relay_register_consecutive_failures) or vector(0)")).toBe(true);
264
+
expect(targets.some((target)=>target.expr==="(loopover_orb_relay_drain_seconds_since_last or gittensory_orb_relay_drain_seconds_since_last) or vector(0)")).toBe(true);
expect(targets.some((target)=>target.expr==="(loopover_queue_backlog_convergence_pending or gittensory_queue_backlog_convergence_pending)")).toBe(true);
287
+
expect(targets.some((target)=>target.expr==="(loopover_queue_fresh_intake_pending or gittensory_queue_fresh_intake_pending)")).toBe(true);
288
+
expect(targets.some((target)=>target.expr==="(loopover_github_rest_rate_limit_remaining or gittensory_github_rest_rate_limit_remaining)")).toBe(true);
289
+
expect(targets.some((target)=>target.legendFormat==="{{key_scope}}"&&target.expr==="(loopover_github_rest_rate_limit_remaining or gittensory_github_rest_rate_limit_remaining)")).toBe(true);
290
+
expect(targets.some((target)=>target.expr==="sum by (lane) ((rate(loopover_jobs_claimed_by_lane_total[5m]) or rate(gittensory_jobs_claimed_by_lane_total[5m]))) or vector(0)")).toBe(true);
291
+
expect(targets.some((target)=>target.expr==="(loopover_queue_backlog_by_repo or gittensory_queue_backlog_by_repo)"&&target.format==="table"&&target.instant===true)).toBe(true);
0 commit comments