# 주제: EVD-294(bounded purge 미호출)의 구현 측 확인 —
#       프로덕션은 무제한 DELETE 한 방을 쏘고, 그것을 가리는 것은 스크립트 대역이다
# revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
# severity: P1 (EVD-294 와 동일 항목의 구현 측 근거)

# ---- 구현: 두 오버로드 ----
# JdbcOutboxRepository.java:486-518   bounded
#   public int purgePublishedBefore(Instant publishedBefore, int limit) {
#     if (limit < 1) throw new IllegalArgumentException("a bounded purge deletes at least one row per call");
#     // The CTE picks a bounded set of ids with SKIP LOCKED and deletes exactly those. An unbounded
#     // DELETE holds locks and writes WAL in proportion to the whole backlog, which stalls the relay
#     // and the business writes behind retention.
#     WITH expired AS (
#         SELECT message_id FROM messaging_outbox
#         WHERE status = 'PUBLISHED' AND published_at < ?
#         ORDER BY published_at LIMIT ? FOR UPDATE SKIP LOCKED)
#     DELETE FROM messaging_outbox o USING expired e WHERE o.message_id = e.message_id
#
# JdbcOutboxRepository.java:519-533   unbounded
#   public int purgePublishedBefore(Instant publishedBefore) {
#     "DELETE FROM messaging_outbox WHERE status = 'PUBLISHED' AND published_at < ?"
#   }

# ---- 호출자는 무제한 쪽을 부른다 ----
# OutboxCleanupJob.java:44-57
#   int removed = 0;
#   for (int batch = 0; batch < maxBatches; batch++) {
#     int deleted = outbox.purgePublishedBefore(cutoff);      <-- 무제한 오버로드
#     removed += deleted;
#     if (deleted == 0) break;
#   }
# => 1회차가 전체를 지우고, 2회차가 0을 반환해 break. maxBatches 는 실질적으로 죽은 값이다.

# ---- 배선 ----
# MessagingReliabilityAutoConfiguration.java:140-141
#   public OutboxCleanupJob outboxCleanupJob(OutboxRepository outbox, OutboxProperties properties) {
#     return new OutboxCleanupJob(outbox, properties, 20);
#   }
# MessagingReliabilityAutoConfiguration.java:169-170
#   return new InboxCleanupJob(inbox, policy, 20);
# => 둘 다 빈이며 maxBatches=20 하드코딩. 둘 다 무제한 오버로드를 부른다.

# ---- 왜 테스트가 잡지 못하는가 ----
# OutboxOperationsTest.java:120-134  RecordingRepository
#   @Override
#   public int purgePublishedBefore(Instant publishedBefore, int limit) {
#     return Math.min(purgePublishedBefore(publishedBefore), limit);    <-- 전부 지우고 숫자만 깎는다
#   }
#   @Override
#   public int purgePublishedBefore(Instant publishedBefore) {
#     cutoffs.add(publishedBefore);
#     return pass < deletions.size() ? deletions.get(pass++) : 0;       <-- 스크립트
#   }
#
# OutboxOperationsTest.java:157-165
#   void cleanupDeletesInBoundedBatchesRatherThanOneLongStatement() {
#     RecordingRepository repository = new RecordingRepository(List.of(1000, 1000, 250));
#     int removed = new OutboxCleanupJob(repository, OutboxProperties.defaults(), 10).runOnce(NOW);
#     assertThat(removed).isEqualTo(2250);
#     assertThat(repository.cutoffs).hasSize(4);
#   }
# => "여러 번 나눠 지운다" 는 관측은 전적으로 대역의 스크립트(1000,1000,250,0)가 만든 것이다.
#    실제 JdbcOutboxRepository 를 넣으면 1회차에 전체가 지워지고 cutoffs 는 2가 된다.
#
# 실 DB 테스트도 무제한 쪽만 부른다:
# OutboxPostgresIT.java:202   int removed = repository.purgePublishedBefore(NOW.plusSeconds(1));
# => bounded 오버로드는 전 저장소에서 호출부 0건이라는 EVD-294 의 판정이 구현 측에서도 확인된다.
#    (이 리프의 대역 2개 + inbox 대역 3개 + 포트 선언 2개 + 구현 2개 = 9개 등장, 호출 0)
