4.6 KiB
4.6 KiB
title, source_type, status, related_branches, related_projects, tags, created, status_label
| title | source_type | status | related_branches | related_projects | tags | created | status_label | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| error / archunit-b7-configprops-nested-record-accessor-outbound-2026-06-13 | error-note | raw |
|
|
|
2026-06-13 | unresolved |
error: archunit-b7-configprops-nested-record-accessor-outbound-2026-06-13
Layer:
raw/errors/— 작업 중 마주친 단일 실패·트러블슈팅 기록. 원본은 raw에 영구 보관한다.
Parent / 부모
- raw/branch-notes/feature-background-job-async-contract — 본 branch 구현 후
:app-bootstrap:test전체 실행 중 발견. 원인 코드는 본 branch 와 무관 — owner 는 raw/branch-notes/feature-outbound-http-client-baseline.
증상 / Symptom
- 에러 메시지 (원문 그대로):
CleanArchitectureTest > outbound_adapter_method_returns_only_domain_or_primitives FAILED Architecture Violation [Priority: MEDIUM] - Rule 'B7: outbound adapter public methods must return domain types (or primitives/wrappers/Optional) ...' was violated (2 times): Method <...OutboundHttpSettings.circuitBreaker()> has raw return type ... in (OutboundHttpSettings.java:36) Method <...OutboundHttpSettings.retry()> has raw return type ... in (OutboundHttpSettings.java:36) - 발생 컨텍스트:
:app-bootstrap:test전체 실행 시 257개 중 1개 실패. async/background-job 변경분(256개)은 전부 green. - 발생 환경: local, Gradle, Spring Boot 3.5.x.
- 재현 가능 여부:
always.
재현 절차 / Reproduction
- 현재 HEAD(
feature/domain-event-outbox-contract, commit f5e2311)에서 background-job 변경분을git stash -u로 전부 치워 working tree 를 깨끗이 한다. cd src && ./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest'실행.- 결과: 50 tests, 1 failed —
outbound_adapter_method_returns_only_domain_or_primitives가 동일하게 실패. - 결론: 이 실패는 background-job 변경과 무관한 선재(pre-existing) 실패. (background-job 변경분을 다시 pop 해도 실패 1건은 동일.)
근본 원인 / Root cause
- 직접 원인:
OutboundHttpSettings(@ConfigurationPropertiesrecord,..adapter.outbound.httpclient패키지)의 accessor 메서드retry()/circuitBreaker()가 같은 패키지의 중첩 recordOutboundHttpSettings.Retry/OutboundHttpSettings.CircuitBreaker를 반환한다. B7 ArchUnit 규칙은 outbound adapter 의 public 메서드 반환형을 domain/primitive/wrapper/Optional 로 제한하고@Configuration @Bean팩토리 메서드만 예외 처리한다 —@ConfigurationPropertiesrecord 의 component accessor 는 예외 목록에 없다. - 근본 원인: feature-outbound-http-resilience-config 작업(중첩
Retry/CircuitBreakerrecord 도입, commit d702572/2613561)이 B7 규칙의 예외 목록을 함께 갱신하지 않음. 규칙이 새 코드 형태(설정 record 의 중첩 record accessor)를 모름. - 트리거 조건: outbound 패키지의
@ConfigurationPropertiesrecord 가 중첩 설정 record 를 accessor 로 노출.
Sources / 근거
- 로컬 검증:
git stash -ubaseline 에서:app-bootstrap:test --tests '*CleanArchitectureTest'→ 동일 1건 실패 확인(50 tests, 1 failed). background-job 변경분 적용 후에도 동일 1건만 실패(257 tests, 1 failed) — 신규 위반 0건.
권고 해결 / Recommended resolution (미적용 — owner branch 영역)
- 옵션 A: B7 규칙에
@ConfigurationProperties타입의 component accessor 를 예외로 추가(@Configuration @Bean예외와 동일 취지 — 설정 record 는 adapter 응답 표면이 아니다). - 옵션 B: 중첩
Retry/CircuitBreakerrecord 를 settings 전용 별도 위치/패키지로 분리해 B7 스코프(..adapter.outbound..응답 표면)에서 제외. - 본 background-job branch 범위 밖이라 수정하지 않음. owner = feature-outbound-http-client-baseline / feature-outbound-http-resilience-config 에 이관 권고. 그 전까지
./gradlew check는 이 1건으로 red.
교훈 / Lesson
- 새 코드 형태(중첩 설정 record, 새 어노테이션 패턴)를 도입할 때는 그것을 검사하는 ArchUnit 규칙의 예외 목록을 같은 PR 에서 갱신해야 한다 — "guardrail 이 새 코드를 모르면 지키지 못한다"(root CLAUDE.md).
- 새 기능을 올리기 전
./gradlew check가 이미 red 인지 baseline 확인(git stash후 실행)을 습관화하면, 내 변경과 선재 실패를 정직하게 분리할 수 있다.