# 주제: Stable/Advanced 경계를 지킨다고 선언된 세 주체 중 어느 것도 # 카탈로그를 레지스트리와 대조하지 않는다 # revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 # severity: P2 # ---- 선언 ---- # GrpcStableModuleCatalog.java:6-17 (클래스 javadoc) # "The Stable plan fixes its module list as a Global Constraint so that "this capability is # Stable" is a fact with one owner instead of a property of whatever happens to be on a classpath. # This repository's module registry (src/config/architecture/modules.json) is the SSOT for # which Gradle projects exist; this catalog is the SSOT for which of them the Stable contract # covers, and **GrpcStableModuleCatalogTest holds the two together.**" # # GrpcStableBuildInvariant.java:5-11 # "These are asserted from Java as well as from Gradle on purpose. The registry gate # (verifyCleanArchitectureDependencies) is the one that fails a build, and it is the authority; # this class is what a runtime component calls when it is handed a dependency set it did not # compile against." # ---- 측정 1: 테스트는 modules.json 을 읽지 않는다 ---- # GrpcStableModuleCatalogTest.java 전문 60줄, 5개 테스트: # stableModuleSetIsExactAndAdvancedIsExcluded -> 하드코딩 4개 이름 contains + advanced 제외 # stableAndAdvancedAreDisjoint -> 두 상수 집합의 교집합 없음 # stableModuleMayNotDependOnAdvanced -> requireNoAdvancedDependency 가 던짐 # stableOnlyDependenciesPass -> 안 던짐 # advancedModuleIsNotGovernedByTheStableRule -> advanced 는 규칙 밖 # # import 목록: java.util.Set, org.junit..., assertj 뿐. # **파일·경로·JSON 을 읽는 코드가 없다.** # => "holds the two together" 는 성립하지 않는다. # modules.json 에 grpc 리프가 추가·제거·개명되어도 이 카탈로그는 알지 못한다. # 두 상수 집합(STABLE 12 + ADVANCED 6 = 18)이 현재 레지스트리와 일치하는 것은 # 누군가 손으로 맞춰 두었기 때문이다. # ---- 측정 2: Gradle 게이트는 Stable/Advanced 를 모른다 ---- # build-logic/src/main/groovy/ca.architecture-registry.settings.gradle:19-23 이 # 저장소의 레지스트리 게이트 3종을 열거한다: # verifyCleanArchitectureDependencies — "fails when a declared project has no entry or an entry # no project" (+ 선언 edge ⊇ 해소 edge) # verifyRuntimeModuleMembership — "compares the resolved runtime closure against the # declared memberships" # verifyDocumentedLeafCount — "fails any document that states a count the registry # disagrees with" # ModuleRegistry.groovy:27-31 의 필드 집합: # ['id','gradle_path','source_path','allowed_dependencies','runtime_memberships'] # => 레지스트리 스키마에 Stable/Advanced 개념이 없다. 세 게이트 중 어느 것도 그 분할을 모른다. # javadoc 이 "the authority" 라고 부른 게이트는 **선언 edge 적합성**을 강제하지 # Stable≠Advanced 를 강제하지 않는다. # 현재 그 분할이 성립하는 것은 allowed_dependencies 를 쓴 사람이 지켰기 때문이다 # (EVD-325 표: Stable 리프 12개 중 advanced 를 의존하는 것이 없다). # ---- 측정 3: 런타임 검사는 실제로 배선되어 있다 ---- # command: git grep -n "requireNoAdvancedDependency" -- src # GrpcStableBuildInvariant.java:113 (정의) # GrpcAdvancedModuleGuard.java:76 (grpc-advanced-bootstrap, 프로덕션) # GrpcPlatformStartupValidator.java:176 (grpc-spring-boot-starter, 프로덕션) # GrpcStableModuleCatalogTest.java:39,50,57 (테스트) # => 이 셋 중 유일하게 실제로 도는 검사다. 다만 **호출자가 넘긴 의존 집합**을 볼 뿐이고, # 그 집합이 레지스트리와 일치하는지는 검사하지 않는다. # ---- 판정 ---- # 세 주체가 각각 다른 것을 검사한다: # 테스트 : 두 하드코딩 상수 집합이 서로소인가 (항상 참, 손으로 그렇게 썼으므로) # Gradle 게이트 : 선언 edge 와 해소 edge 가 맞는가 (Stable/Advanced 무관) # 런타임 불변식 : 넘겨받은 집합에 advanced 가 섞였는가 (호출자가 정직할 때만 유효) # **카탈로그와 레지스트리를 대조하는 주체가 없다.** # 이것은 messaging-testkit 의 BrokerFailureMatrix javadoc 과 같은 형태다 — # "That rule is enforced by a test rather than documented" 인데 그 테스트가 규칙을 강제하지 않는다. # ================= 정정 (grpc-spring-boot-starter 분석 중 발견) ================= # 위 "측정 2" 의 판정이 과했다. Stable 리프가 advanced 를 의존하는 것은 **실제로 막힌다**. # # (a) modules.json 의 grpc-spring-boot-starter allowed_dependencies 가 advanced id 를 하나도 # 담지 않는다(EVD-325 표). build.gradle 에 advanced project 의존을 추가하면 해소 edge 가 # 선언 집합에 없게 되어 verifyCleanArchitectureDependencies 가 실패한다. # => 게이트는 분할을 "모르지만", 레지스트리 내용을 통해 결과적으로 강제한다. # # (b) GrpcPlatformStartupValidatorTest:245-257 이 **실제 build.gradle 파일을 읽는다**: # @DisplayName("the auto-configuration is registered and reaches no Advanced module") # // matching on the prose would fail on the sentence stating the rule, so: # assertThat(read(Path.of("build.gradle"))).doesNotContain("project(':grpc-advanced"); # => 좁지만 실제 저장소 내용을 검사하는 테스트가 있다. # # (c) GrpcPlatformStartupValidatorTest:215-222 이 requireNoAdvancedDependency 를 기동 시나리오로 # 단언한다. # # grpc-spring-boot-starter/build.gradle:4-7 의 주장 — # "That is not a comment — the registry's allowed_dependencies for this leaf omits every advanced # id, verifyCleanArchitectureDependencies enforces it, and GrpcPlatformStartupValidatorTest # asserts the same rule from the Java side." # — 세 주장이 전부 확인된다. # # 남는 정확한 결함은 하나로 좁혀진다: # **GrpcStableModuleCatalog 의 STABLE/ADVANCED 이름 목록(12+6)이 modules.json 과 대조되지 않는다.** # 리프가 추가·개명·제거되어도 카탈로그는 알지 못한다. GrpcStableModuleCatalogTest 는 JSON 을 읽지 않는다. # 이것은 "Stable 이 advanced 를 의존하는가" 와는 다른 질문이며, 그 질문만 답이 없다. # ============================================================================== # ---- 부수 확인: grpc 18개의 빈 멤버십은 검증된 상태다 ---- # verifyRuntimeModuleMembership 이 "resolved runtime closure against the declared memberships" 를 # 비교하므로, 18개 리프의 runtime_memberships:[] 는 레지스트리 실수가 아니라 # **게이트가 확인한 사실**이다. EVD-325 의 판정을 강화한다.