--- title: error / archunit-b7-configprops-nested-record-accessor-outbound-2026-06-13 source_type: error-note status: raw related_branches: [feature-background-job-async-contract, feature-outbound-http-client-baseline] related_projects: [ca-skeleton] tags: [error, ca-skeleton, archunit, configuration-properties, record, adapter-outbound, pre-existing] created: 2026-06-13 status_label: 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 - 에러 메시지 (원문 그대로): ```text 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 1. 현재 HEAD(`feature/domain-event-outbox-contract`, commit f5e2311)에서 background-job 변경분을 `git stash -u` 로 전부 치워 working tree 를 깨끗이 한다. 2. `cd src && ./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest'` 실행. 3. 결과: 50 tests, 1 failed — `outbound_adapter_method_returns_only_domain_or_primitives` 가 동일하게 실패. 4. 결론: 이 실패는 background-job 변경과 **무관한 선재(pre-existing) 실패**. (background-job 변경분을 다시 pop 해도 실패 1건은 동일.) ## 근본 원인 / Root cause - 직접 원인: `OutboundHttpSettings`(`@ConfigurationProperties` record, `..adapter.outbound.httpclient` 패키지)의 accessor 메서드 `retry()` / `circuitBreaker()` 가 같은 패키지의 중첩 record `OutboundHttpSettings.Retry` / `OutboundHttpSettings.CircuitBreaker` 를 반환한다. B7 ArchUnit 규칙은 outbound adapter 의 public 메서드 반환형을 domain/primitive/wrapper/Optional 로 제한하고 `@Configuration @Bean` 팩토리 메서드만 예외 처리한다 — `@ConfigurationProperties` record 의 component accessor 는 예외 목록에 없다. - 근본 원인: feature-outbound-http-resilience-config 작업(중첩 `Retry`/`CircuitBreaker` record 도입, commit d702572/2613561)이 B7 규칙의 예외 목록을 함께 갱신하지 않음. 규칙이 새 코드 형태(설정 record 의 중첩 record accessor)를 모름. - 트리거 조건: outbound 패키지의 `@ConfigurationProperties` record 가 중첩 설정 record 를 accessor 로 노출. ## Sources / 근거 - 로컬 검증: `git stash -u` baseline 에서 `: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`/`CircuitBreaker` record 를 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` 후 실행)을 습관화하면, 내 변경과 선재 실패를 정직하게 분리할 수 있다.