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>
66 lines
3.1 KiB
Plaintext
66 lines
3.1 KiB
Plaintext
# 리프가 선언하는 export 목록
|
|
135: private static final Set<String> EXPORTED_PACKAGES =
|
|
136- Set.of(
|
|
137- // The contracts other leaves are meant to speak.
|
|
138- "api",
|
|
139- // Capability configuration facades, each assembling its own capability's internals.
|
|
140- "notification.configuration",
|
|
141- // Cross-cutting seams a composition root legitimately wires.
|
|
142- "transaction",
|
|
143- "security",
|
|
144- "observation",
|
|
145- "migration",
|
|
146- "hibernate",
|
|
147- "fileserver",
|
|
148- "failure",
|
|
149- "config");
|
|
|
|
# 컴포지션 루트의 소비자 규칙이 같은 목록을 다시 적는다
|
|
* implementation types by name — every store, every repository, the record mapper — which made
|
|
* each of them a cross-leaf source contract: moving one to another package, or reducing its
|
|
* visibility, broke this module's compile. The notification wiring is a facade the leaf owns now,
|
|
* and this keeps the surface from re-growing one convenient import at a time.
|
|
*
|
|
* <p>The list is the leaf's export allowlist, mirrored here because this is the consumer side of
|
|
* the same boundary. {@code JpaModuleBoundaryTest} owns the definition.
|
|
*/
|
|
@ArchTest
|
|
private static final java.util.Set<String> EXPORTED =
|
|
java.util.Set.of(
|
|
"api",
|
|
"notification.configuration",
|
|
"transaction",
|
|
"security",
|
|
"observation",
|
|
"migration",
|
|
"hibernate",
|
|
"fileserver",
|
|
"failure",
|
|
"config",
|
|
// The two vendor entry points. A vendor configuration imports the core JPA
|
|
// config rather than the reverse, so there is no single internal entry the
|
|
// composition root could gate instead — inverting the import to make one
|
|
// produced a package cycle. Admitting exactly these two, and no other
|
|
// vendor
|
|
// internals, is the narrower price.
|
|
"postgresql",
|
|
"h2");
|
|
|
|
# 두 집합의 차이
|
|
# 리프 10개 / 루트 12개
|
|
# 루트에만 있는 것: ['h2', 'postgresql']
|
|
# 리프에만 있는 것: []
|
|
|
|
# 사본은 정본을 이름으로 적는다
|
|
1118: * the same boundary. {@code JpaModuleBoundaryTest} owns the definition.
|
|
# app-bootstrap 에서 그 정본 클래스를 언급하는 줄: 1
|
|
# 선언 파일 밖에서 EXPORTED_PACKAGES 를 참조하는 자바 코드: 0
|
|
|
|
# 리프의 export 목록을 쓰는 두 시험이 무엇을 보는가
|
|
380: @DisplayName("the export list names only packages that exist")
|
|
381- void theExportListNamesOnlyPackagesThatExist() {
|
|
382- java.nio.file.Path root = sourceRoot().resolve(ROOT.replace('.', '/'));
|
|
396: @DisplayName("every exported package is one the catalog governs")
|
|
397- void everyExportedPackageIsGoverned() {
|
|
398- Set<String> ungoverned = new TreeSet<>();
|