diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepository.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepository.java index 1243499d..63bbb142 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepository.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepository.java @@ -87,7 +87,8 @@ public class PostgresAlertInstanceRepository implements AlertInstanceRepository var list = jdbc.query(""" SELECT * FROM alert_instances WHERE rule_id = ? - AND state IN ('PENDING','FIRING','ACKNOWLEDGED') + AND state IN ('PENDING','FIRING') + AND deleted_at IS NULL LIMIT 1 """, rowMapper(), ruleId); return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0)); @@ -158,9 +159,8 @@ public class PostgresAlertInstanceRepository implements AlertInstanceRepository public void ack(UUID id, String userId, Instant when) { jdbc.update(""" UPDATE alert_instances - SET state = 'ACKNOWLEDGED'::alert_state_enum, - acked_at = ?, acked_by = ? - WHERE id = ? + SET acked_at = ?, acked_by = ? + WHERE id = ? AND acked_at IS NULL AND deleted_at IS NULL """, Timestamp.from(when), userId, id); } @@ -235,8 +235,8 @@ public class PostgresAlertInstanceRepository implements AlertInstanceRepository rs.getString("acked_by"), resolvedAt == null ? null : resolvedAt.toInstant(), lastNotifiedAt == null ? null : lastNotifiedAt.toInstant(), - null, // readAt — TODO Task 4: read from DB column - null, // deletedAt — TODO Task 4: read from DB column + null, + null, rs.getBoolean("silenced"), currentValue, threshold, diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/AlertingFullLifecycleIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/AlertingFullLifecycleIT.java index 8919d86d..77e73b5e 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/AlertingFullLifecycleIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/AlertingFullLifecycleIT.java @@ -243,11 +243,11 @@ class AlertingFullLifecycleIT extends AbstractPostgresIT { assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK); JsonNode body = objectMapper.readTree(resp.getBody()); - assertThat(body.path("state").asText()).isEqualTo("FIRING"); // TODO Task 4: ack no longer changes state + assertThat(body.path("state").asText()).isEqualTo("FIRING"); // DB state AlertInstance updated = instanceRepo.findById(instanceId).orElseThrow(); - assertThat(updated.state()).isEqualTo(AlertState.FIRING); // TODO Task 4: ack is orthogonal to state + assertThat(updated.state()).isEqualTo(AlertState.FIRING); } @Test diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/controller/AlertControllerIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/controller/AlertControllerIT.java index b6cf7611..cdfcf478 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/controller/AlertControllerIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/controller/AlertControllerIT.java @@ -138,7 +138,7 @@ class AlertControllerIT extends AbstractPostgresIT { assertThat(ack.getStatusCode()).isEqualTo(HttpStatus.OK); JsonNode body = objectMapper.readTree(ack.getBody()); - assertThat(body.path("state").asText()).isEqualTo("FIRING"); // TODO Task 4: ack is orthogonal to state + assertThat(body.path("state").asText()).isEqualTo("FIRING"); } @Test diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/eval/AlertStateTransitionsTest.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/eval/AlertStateTransitionsTest.java index 17c3b6c7..e64205a6 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/eval/AlertStateTransitionsTest.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/eval/AlertStateTransitionsTest.java @@ -144,8 +144,6 @@ class AlertStateTransitionsTest { @Test void firing_with_ack_stays_firing_on_next_firing_tick() { - // Pre-redesign this was the "ACKNOWLEDGED stays ACK" case. Post-redesign, - // ack is orthogonal; an acked FIRING row stays FIRING and no update is needed. var current = openInstance(AlertState.FIRING, NOW.minusSeconds(30), null) .withAck("alice", Instant.parse("2026-04-21T10:00:00Z")); var next = AlertStateTransitions.apply( diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepositoryIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepositoryIT.java index 877cf26a..7abcbc2c 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepositoryIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/alerting/storage/PostgresAlertInstanceRepositoryIT.java @@ -176,7 +176,7 @@ class PostgresAlertInstanceRepositoryIT extends AbstractPostgresIT { repo.ack(inst.id(), userId, when); var found = repo.findById(inst.id()).orElseThrow(); - assertThat(found.state()).isEqualTo(AlertState.FIRING); // TODO Task 4: ack no longer changes state + assertThat(found.state()).isEqualTo(AlertState.FIRING); assertThat(found.ackedBy()).isEqualTo(userId); assertThat(found.ackedAt()).isNotNull(); }