--- title: error / scheduled-reaper-wrong-config-prefix-2026-06-09 source_type: error-note status: raw related_branches: [feature-rate-limit-idempotency-contract] related_projects: [ca-skeleton] tags: [error, ca-skeleton, spring, scheduling, configuration] created: 2026-06-09 status_label: resolved --- # error: scheduled-reaper-wrong-config-prefix-2026-06-09 > Layer: `raw/errors/` — 코드 리뷰(ca-quality-reviewer)가 잡은 silent config 키 불일치. ## Parent / 부모 - [[raw/branch-notes/feature-rate-limit-idempotency-contract]] ## 증상 / Symptom `IdempotencyReaper`의 `@Scheduled(fixedDelayString = "${ca-skeleton.rate-limit.reaper-interval:PT10M}")`가 **잘못된 prefix**(`rate-limit`)를 참조. 실제 바인딩 속성은 `ca-skeleton.idempotency.reaper-interval` (`IdempotencyProperties` 소유). 컴파일/테스트는 통과하지만 운영자가 `ca-skeleton.idempotency.reaper-interval`을 조정해도 무시되고 항상 하드코딩 기본값 `PT10M`로 동작. `IdempotencyProperties.reaperInterval`은 dead letter. ## 원인 / Root cause `@Scheduled` SpEL placeholder는 키가 없으면 inline default(`:PT10M`)로 **조용히** 폴백 → 오타/잘못된 prefix가 런타임 예외 없이 묻힘. 빌드 게이트가 placeholder–property 정합을 검증하지 않음. ## 해결 / Resolution `@Scheduled` 표현식을 `${ca-skeleton.idempotency.reaper-interval:PT10M}`로 수정. 정적 테스트로는 잡기 어려워 코드 리뷰 단계에서 포착됨(테스트는 `reap()` 반환값만 검증, 스케줄 wiring 미검증). ## 교훈 / Lesson `@Scheduled(...:default)` / `@Value(...:default)` 처럼 **inline default가 있는 placeholder는 오타가 silent**. 같은 의미의 값이 두 곳(property record + 어노테이션 문자열)에 있으면 drift 위험. 가능하면 단일 출처(설정 record 주입)로 통일하거나, 키 정합을 검증하는 테스트를 둔다. 관련: [[raw/branch-notes/feature-rate-limit-idempotency-contract]]