The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
103 lines
7.0 KiB
Plaintext
103 lines
7.0 KiB
Plaintext
# 주제: 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 의 판정을 강화한다.
|