--- title: error / archunit-no-uuid-random-trace-id-false-positive-2026-06-01 source_type: error-note status: raw related_branches: [feature-resource-identifier-contract] related_projects: [ca-skeleton] tags: [error, ca-skeleton, architecture, archunit, identifier, trace-id, scoping] created: 2026-06-01 status_label: resolved --- # error: archunit-no-uuid-random-trace-id-false-positive-2026-06-01 > Layer: `raw/errors/` — 작업 중 마주친 단일 실패·트러블슈팅 기록. 원본은 raw에 영구 보관한다. ## Parent / 부모 - [[raw/branch-notes/feature-resource-identifier-contract]] — D17 `no_uuid_random_in_controller` rule이 *resource id 생성*이 아닌 *correlation/trace id 생성*까지 잡는 false positive를 냈다. - [[raw/project-notes/ca-skeleton-operational-contract]] — ca-tmpl ArchUnit guardrail의 scope 정밀도 이슈다. ## 증상 / Symptom - 에러 메시지 (원문 그대로): ```text Rule 'D5/D17 no_uuid_random_in_controller: ...' was violated (1 times): Method calls method in (RequestLoggingFilter.java:43) ``` - 발생 컨텍스트: `cd src && ./gradlew :app-bootstrap:test` 실행 중 `CleanArchitectureTest.no_uuid_random_in_controller` 실패. - 발생 시점: 2026-06-01 (D17 rule을 boundary suite에 추가한 직후 1차 실행) - 재현 가능 여부: `always` — rule 대상 package를 `..adapter.web..`(광범위)로 두면 기존 `RequestLoggingFilter`가 항상 걸림. ## 재현 절차 / Reproduction 1. `no_uuid_random_in_controller`를 `noClasses().that().resideInAnyPackage("..adapter.web..", "..application..")`로 작성. 2. `cd src && ./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest'` 실행. 3. 기대 결과: resource id 생성만 차단. 4. 실제 결과: `RequestLoggingFilter`의 `X-Request-Id` 생성(`UUID.randomUUID()`)까지 위반으로 잡힘. ## 근본 원인 / Root cause - 직접 원인: rule의 selector가 `..adapter.web..` 전체였는데, web filter는 controller가 아니며 correlation/trace id를 생성한다. - 근본 원인: spec D17 **결정 텍스트**는 "controller / service / use case layer"로 한정했으나, §6 **reference 코드**는 광범위한 `..adapter.web..`를 썼다. 둘 사이의 미세 불일치가 구현 시 노출. 또한 trace/correlation id는 D18에서 *본 branch 범위 밖*(distributed-tracing-contract)으로 명시돼 있어, resource-id rule이 잡으면 안 되는 대상이었다. - 트리거 조건: 기존 production filter가 합법적으로 `UUID.randomUUID()`를 trace id 용도로 사용 중. ## 해결 / Resolution - 적용한 조치: selector를 D17 결정 텍스트에 맞춰 `..adapter.web..controller..` + `..application..`로 좁혔다. trace/correlation id 생성(web filter)은 의도적으로 scope 밖임을 rule `.as(...)` 설명에 명시. - 검증 방법: - `cd src && ./gradlew :app-bootstrap:test verifyCleanArchitectureDependencies` 성공. - `cd src && ./gradlew check` 전체 성공. - 잔여 위험 / 후속 작업: filter/interceptor가 *resource* id를 생성하는 안티패턴은 이 rule로는 안 잡힌다(범위 밖). 필요 시 distributed-tracing-contract 또는 별도 rule로 분리. ## 회고 / Lessons - 빨리 감지하는 신호: 새 ArchUnit rule이 *기존* 합법 코드를 잡으면, rule이 틀렸을 가능성을 먼저 의심하고 위반 대상의 *의도*(여기선 trace id vs resource id)를 확인. - 예방 체크리스트: rule selector는 spec의 "결정 텍스트"(좁은 의도)와 "reference 코드"(넓은 예시)가 다를 때 결정 텍스트를 따른다. id 생성 규칙은 *어떤 id*인지(resource / trace / session / idempotency) 항상 구분한다. - 일반화된 교훈: 식별자 거버넌스 규칙은 "ID 종류"별로 책임 branch가 다르다 — 한 rule이 모든 `UUID.randomUUID()`를 잡으면 cross-domain false positive가 난다. ## Related / 관련 - 관련 branch note: [[raw/branch-notes/feature-resource-identifier-contract]] - 관련 형제 branch: [[raw/branch-notes/feature-boundary-validation-mapping-contract]] (ArchUnit suite 호스팅), [[raw/branch-notes/feature-distributed-tracing-contract]] (trace id 책임) - 파생 blog 글감: [[raw/blog-topics/identifier-governance-rule-scoping-by-id-kind-2026-06-01]]