diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/V17MigrationIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/V17MigrationIT.java
index cfd0965e..4854a9ce 100644
--- a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/V17MigrationIT.java
+++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/V17MigrationIT.java
@@ -35,14 +35,24 @@ class V17MigrationIT extends AbstractPostgresIT {
}
@Test
- void open_rule_index_predicate_is_reworked() {
- String def = jdbcTemplate.queryForObject("""
- SELECT pg_get_indexdef(indexrelid)
- FROM pg_index
+ void open_rule_index_exists_and_is_unique() {
+ // Structural check only — the pg_get_indexdef pretty-printer varies across
+ // Postgres versions. Predicate semantics (ack doesn't close; soft-delete
+ // frees the slot; RESOLVED excluded) are covered behaviorally by
+ // PostgresAlertInstanceRepositoryIT#findOpenForRule_* and
+ // #save_rejectsSecondOpenInstanceForSameRuleAndExchange.
+ Integer count = jdbcTemplate.queryForObject("""
+ SELECT COUNT(*)::int FROM pg_indexes
+ WHERE indexname = 'alert_instances_open_rule_uq'
+ AND tablename = 'alert_instances'
+ """, Integer.class);
+ assertThat(count).isEqualTo(1);
+
+ Boolean isUnique = jdbcTemplate.queryForObject("""
+ SELECT indisunique FROM pg_index
JOIN pg_class ON pg_class.oid = pg_index.indexrelid
WHERE pg_class.relname = 'alert_instances_open_rule_uq'
- """, String.class);
- assertThat(def).contains("state = ANY (ARRAY['PENDING'::alert_state_enum, 'FIRING'::alert_state_enum])");
- assertThat(def).contains("deleted_at IS NULL");
+ """, Boolean.class);
+ assertThat(isUnique).isTrue();
}
}
diff --git a/ui/src/components/AlertStateChip.test.tsx b/ui/src/components/AlertStateChip.test.tsx
index dbdc0785..336c5a75 100644
--- a/ui/src/components/AlertStateChip.test.tsx
+++ b/ui/src/components/AlertStateChip.test.tsx
@@ -11,7 +11,6 @@ describe('AlertStateChip', () => {
it.each([
['PENDING', /pending/i],
['FIRING', /firing/i],
- ['ACKNOWLEDGED', /acknowledged/i],
['RESOLVED', /resolved/i],
] as const)('renders %s label', (state, pattern) => {
renderWithTheme();
diff --git a/ui/src/components/AlertStateChip.tsx b/ui/src/components/AlertStateChip.tsx
index a81548f0..4d1a47ee 100644
--- a/ui/src/components/AlertStateChip.tsx
+++ b/ui/src/components/AlertStateChip.tsx
@@ -6,14 +6,12 @@ type State = NonNullable;
const LABELS: Record = {
PENDING: 'Pending',
FIRING: 'Firing',
- ACKNOWLEDGED: 'Acknowledged',
RESOLVED: 'Resolved',
};
const COLORS: Record = {
PENDING: 'warning',
FIRING: 'error',
- ACKNOWLEDGED: 'warning',
RESOLVED: 'success',
};
diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx
index f2c49ea7..2775f6d1 100644
--- a/ui/src/components/LayoutShell.tsx
+++ b/ui/src/components/LayoutShell.tsx
@@ -368,7 +368,7 @@ function LayoutContent() {
const { data: envRecords = [] } = useEnvironments();
// Open alerts + rules for CMD-K (env-scoped).
- const { data: cmdkAlerts } = useAlerts({ state: ['FIRING', 'ACKNOWLEDGED'], limit: 100 });
+ const { data: cmdkAlerts } = useAlerts({ state: ['FIRING'], acked: false, limit: 100 });
const { data: cmdkRules } = useAlertRules();
// Merge environments from both the environments table and agent heartbeats