--- title: error / archunit-empty-should-anchor-2026-05-27 source_type: error-note status: raw related_branches: [feature-skeleton-package-blueprint-contract] related_projects: [ca-skeleton] tags: [error, ca-skeleton, architecture, testing, archunit, clean-architecture] created: 2026-05-27 status_label: resolved --- # error: archunit-empty-should-anchor-2026-05-27 > Layer: `raw/errors/` — 작업 중 마주친 단일 실패·트러블슈팅 기록. 원본은 raw에 영구 보관한다. ## Parent / 부모 - [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — skeleton package/module blueprint 구현 중 빈 production anchor package가 ArchUnit rule의 empty check에 걸렸다. - [[raw/project-notes/ca-skeleton-operational-contract]] — ca-tmpl skeleton의 package/module boundary 검증 이슈다. ## 증상 / Symptom - 에러 메시지 (원문 그대로): ```text Rule 'no classes that reside in a package '..domain..' should depend on classes that reside in any package ...' failed to check any classes. ``` - 발생 컨텍스트: `cd src && ./gradlew clean test` 실행 중 `CleanArchitectureTest`의 `domain_is_pure`, `application_does_not_depend_on_adapters_or_transport`, `persistence_adapter_does_not_depend_on_web_or_outbound_adapters`, `web_dtos_stay_in_web_adapter`가 실패. - 발생 시점: 2026-05-27 - 발생 환경: local ca-tmpl repository. - 재현 가능 여부: `always` — production 샘플 도메인을 `sample-ticket`으로 격리하고 본체 모듈이 anchor/package-info 중심이 되면 재현. ## 재현 절차 / Reproduction 1. production 모듈에서 reference domain/application/persistence DTO class를 제거하고 skeleton anchor만 남긴다. 2. `cd src && ./gradlew clean test`를 실행한다. 3. 기대 결과: 빈 anchor module도 skeleton blueprint의 유효한 상태로 인정된다. 4. 실제 결과: ArchUnit 기본 설정이 empty `that()` clause를 실패로 처리한다. ## 조사 단계 / Investigation log - 2026-05-27 — full test 실행 → `CleanArchitectureTest` 4개 rule 실패. - 2026-05-27 — test result XML 확인 → 실제 dependency violation이 아니라 검사 대상 class가 없는 empty should 실패임을 확인. - 2026-05-27 — 빈 skeleton package가 의도된 상태인 rule에만 `allowEmptyShould(true)` 적용. - 2026-05-27 — full `./gradlew test` 재실행 → 성공. ## 근본 원인 / Root cause - 직접 원인: ArchUnit은 기본적으로 `that()` 조건에 매칭되는 class가 없으면 rule 실패로 처리한다. - 근본 원인: skeleton template에서는 production domain/application/persistence/dto가 아직 비어 있을 수 있는데, 기존 ArchUnit rule은 "빈 anchor도 유효한 skeleton 상태"라는 전제를 표현하지 않았다. - 트리거 조건: sample/reference 코드를 `sample-ticket`으로 격리하여 production 모듈의 일부 package가 빈 상태가 됨. ## Sources / 근거 - [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] — 빈 anchor module과 ArchUnit guardrail을 함께 유지하기로 한 branch 결정. - [[wiki/projects/ca-tmpl/clean-architecture-package-layout]] — ca-tmpl에 실제 적용된 module/package layout canonical. ## 해결 / Resolution - 적용한 조치: 빈 상태가 skeleton contract상 유효한 rule에만 `allowEmptyShould(true)`를 붙였다. - 검증 방법: - `cd src && ./gradlew test` 성공. - `cd src && ./gradlew verifyCleanArchitectureDependencies` 성공. - 잔여 위험 / 후속 작업: 실제 production domain/application class가 생긴 뒤에도 동일 rule이 의존성 위반을 잡는지 red/green test로 보강할 필요가 있다. ## 회고 / Lessons - 빨리 감지하는 신호: ArchUnit failure message에 "failed to check any classes"가 나오면 dependency violation이 아니라 empty rule 문제일 가능성이 높다. - 예방 체크리스트 항목 후보: skeleton anchor package를 허용하는 rule과 실제 production code가 있어야 하는 rule을 구분한다. - wiki로 끌어올릴 가치가 있는 일반화된 교훈: template repository에서는 "아직 비어 있음"이 실패가 아니라 의도된 중간 상태일 수 있으므로 architecture test가 그 상태를 명시해야 한다. ## Related / 관련 - 트리거된 daily note: [[raw/daily-notes/2026-05-27]] - 관련 branch note: [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] - 관련 wiki 개념: [[wiki/concepts/clean-architecture-package-layout]]