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>
15 lines
4.7 KiB
JSON
15 lines
4.7 KiB
JSON
{
|
|
"assetKey": "a14-f018-webplatformstartupvalidator-run",
|
|
"kind": "terminal",
|
|
"command": "set -e\nset -o pipefail\nD=$(mktemp -d); trap 'rm -rf \"$D\"' EXIT\nC=/shared/codebase/clean-architecture-backend-template\nM=$C/src/adapter/inbound/web\nCACHE=/root/.gradle/caches/modules-2/files-2.1\njava -version 2>&1 | grep version\ncp=\"\"\nwhile IFS= read -r line; do\n coord=${line%%=*}; confs=${line#*=}\n case \",$confs,\" in *\",testRuntimeClasspath,\"*) ;; *) continue ;; esac\n g=${coord%%:*}; rest=${coord#*:}; n=${rest%%:*}; v=${rest##*:}\n jar=$(find \"$CACHE/$g/$n/$v\" -name '*.jar' ! -name '*sources*' ! -name '*javadoc*' 2>/dev/null | head -1) || true\n [ -n \"$jar\" ] && cp=\"$cp:$jar\"\ndone < <(grep -E '^[a-zA-Z0-9._-]+:[^=]+=' \"$M/gradle.lockfile\")\nSIB=$(find \"$C/src\" -path '*/build/libs/*+21234e38cdb9*.jar' ! -name '*-testkit.jar' | sort | tr '\\n' ':')\n\ncat > \"$D/ValidatorProbe.java\" <<'JAVA'\nimport dev.caskeleton.adapter.inbound.web.admin.platform.WebPlatformSnapshot;\nimport dev.caskeleton.adapter.inbound.web.admin.platform.WebPlatformStartupValidator;\nimport java.util.List;\nimport java.util.Map;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n/** 검증기를 직접 돌려 보고, 출하 조립이 그것을 빈으로 갖는지 본다. */\npublic final class ValidatorProbe {\n\n /** 출하 루트가 이 리프에 대해 거는 것과 같은 컴포넌트 스캔. CaSkeletonApplication:44. */\n @Configuration(proxyBeanMethods = false)\n @ComponentScan(basePackages = \"dev.caskeleton.adapter.inbound.web.admin\")\n static class ShippingScan {}\n\n /** 시험이 쓰는 것과 같은 모양의 스냅숏. 통제 목록만 갈아 끼운다. */\n private static WebPlatformSnapshot snapshot(Map<String, Boolean> controls) {\n return new WebPlatformSnapshot(\n \"servlet\",\n List.of(1),\n List.of(\"VALIDATION_FAILED\", \"INTERNAL_ERROR\"),\n Map.of(\"standard\", \"8MiB body\"),\n Map.of(\"global-write\", \"32 concurrent\"),\n List.of(\"sensitive\", \"revalidated\"),\n controls);\n }\n\n public static void main(String[] args) {\n var validator = new WebPlatformStartupValidator(List.of(\"rate-limit\", \"budget\", \"problem-catalog\"));\n\n System.out.println();\n System.out.println(\"[선언된 통제 셋 중 하나가 배선되지 않은 스냅숏을 넣는다]\");\n var missing = snapshot(Map.of(\"rate-limit\", true, \"budget\", true, \"problem-catalog\", false));\n System.out.printf(\" 스냅숏이 보고하는 미설치 통제 : %s%n\", missing.uninstalledControls());\n try {\n validator.validate(missing);\n System.out.println(\" 결과 : 통과\");\n } catch (RuntimeException refused) {\n System.out.println(\" 결과 : \" + refused.getClass().getSimpleName());\n System.out.println(\" \" + refused.getMessage());\n }\n\n System.out.println();\n System.out.println(\"[셋 다 배선된 스냅숏을 넣는다]\");\n var complete = snapshot(Map.of(\"rate-limit\", true, \"budget\", true, \"problem-catalog\", true));\n validator.validate(complete);\n System.out.println(\" 결과 : 통과\");\n\n System.out.println();\n System.out.println(\"[출하 루트와 같은 스캔을 admin 패키지에 걸어 본다]\");\n try (var context = new AnnotationConfigApplicationContext(ShippingScan.class)) {\n System.out.printf(\n \" 올라온 WebPlatformStartupValidator 빈 : %d 개%n\",\n context.getBeanNamesForType(WebPlatformStartupValidator.class).length);\n System.out.printf(\n \" 올라온 WebPlatformSnapshot 빈 : %d 개%n\",\n context.getBeanNamesForType(WebPlatformSnapshot.class).length);\n System.out.println(\" 스캔이 집어 갈 스테레오타입이 두 클래스에 없다.\");\n }\n }\n}\nJAVA\njavac -encoding UTF-8 -cp \"$SIB$cp\" -d \"$D/out\" \"$D/ValidatorProbe.java\" 2>&1 | head -8\nprintf '%s\\n' '<configuration><root level=\"OFF\"/></configuration>' > \"$D/out/logback.xml\"\njava -Dstdout.encoding=UTF-8 -cp \"$D/out:$SIB$cp\" ValidatorProbe 2>&1 | grep -vE '^[0-9]{4}-|^\\s+at |WARN|INFO'\n",
|
|
"cwd": "/shared/codebase/clean-architecture-backend-template/src",
|
|
"exitCode": 0,
|
|
"executedAt": "2026-09-03T08:09:07+00:00",
|
|
"sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916",
|
|
"raw": "evidence/raw/a14-f018-webplatformstartupvalidator-run.txt",
|
|
"svg": "evidence/rendered/a14-f018-webplatformstartupvalidator-run.svg",
|
|
"rawSha256": "614c3ee7eefb7cfdb9dcacc3d12928b1e9d78083fa49ecd25bea0fda553d177f",
|
|
"lines": 14,
|
|
"redaction": "코드베이스 측정과 실행 결과로 교체"
|
|
}
|