4.3 KiB
4.3 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-no-uuid-random-trace-id-false-positive-2026-06-01 | error-note | raw |
|
|
|
2026-06-01 | 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_controllerrule이 resource id 생성이 아닌 correlation/trace id 생성까지 잡는 false positive를 냈다. - raw/project-notes/ca-skeleton-operational-contract — ca-tmpl ArchUnit guardrail의 scope 정밀도 이슈다.
증상 / Symptom
- 에러 메시지 (원문 그대로):
Rule 'D5/D17 no_uuid_random_in_controller: ...' was violated (1 times): Method <dev.caskeleton.adapter.web.filter.RequestLoggingFilter.doFilterInternal(...)> calls method <java.util.UUID.randomUUID()> 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
no_uuid_random_in_controller를noClasses().that().resideInAnyPackage("..adapter.web..", "..application..")로 작성.cd src && ./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest'실행.- 기대 결과: resource id 생성만 차단.
- 실제 결과:
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