Files
document-haness/docs/clean-architecture-backend-template/final/evidence/rendered/a05-f014-collection-fetch-pagination-lane.svg
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
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>
2026-09-04 22:51:59 +09:00

93 lines
15 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1580" viewBox="0 0 1200 1580" role="img">
<title>terminal evidence</title>
<desc>Terminal-style rendering generated from retained command output. Sensitive-looking values are redacted in the visual asset.</desc>
<rect x="1" y="1" width="1198" height="1578" rx="14" fill="#0d1117" stroke="#30363d"/>
<rect x="1" y="1" width="1198" height="44" rx="14" fill="#161b22"/>
<rect x="1" y="30" width="1198" height="14" fill="#161b22"/>
<circle cx="24" cy="22" r="6" fill="#ff5f57"/>
<circle cx="44" cy="22" r="6" fill="#febc2e"/>
<circle cx="64" cy="22" r="6" fill="#28c840"/>
<text x="92" y="27" fill="#8b949e" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">terminal evidence</text>
<text x="24" y="68" fill="#c9d1d9" font-size="15" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">$ echo &#x27;# 릴리스 레지스트리가 이 게이트에 붙인 생산자 태스크&#x27;
grep -n -A3 &#x27;&quot;collection-fetch-pagination&quot;&#x27; src/config/jpa</tspan><tspan x="24" dy="22">/release-registry.json
echo -n &#x27;# blocking 이 참인 게이트 / 거짓인 게이트: &#x27;
printf &#x27;%s / %s\n&#x27; &quot;$(grep -c &#x27;&quot;blocking&quot;</tspan><tspan x="24" dy="22">: true&#x27; src/config/jpa/release-registry.json)&quot; \
&quot;$(grep -c &#x27;&quot;blocking&quot;: false&#x27; src/config/jpa/releas</tspan><tspan x="24" dy="22">e-registry.json)&quot;
M=src/adapter/outbound/persistence-jpa/src/testkit/java/dev/caskeleton/adapter/outbound/persistence/te</tspan><tspan x="24" dy="22">stkit/release/JpaReleaseManifest.java
echo -n &#x27;# 매니페스트 파서가 blocking 을 읽는 줄: &#x27;
grep -c &#x27;blocking&#x27; &quot;$M&quot;
echo</tspan><tspan x="24" dy="22"> -n &#x27;# 게이트 검증기가 blocking 을 읽는 줄: &#x27;
sed -n &#x27;1046,1090p&#x27; src/build.gradle | grep -c &#x27;blocking&#x27;
echo
echo &#x27;# </tspan><tspan x="24" dy="22">그 태스크와 게이트 테스트의 태그&#x27;
grep -n -A3 &quot;registerJpaPlatformLane(&quot; src/adapter/outbound/persistence-jpa/build.grad</tspan><tspan x="24" dy="22">le | grep -E &quot;jpaPlatform|&#x27;jpa-&quot;
grep -n &#x27;includeTags tag&#x27; src/adapter/outbound/persistence-jpa/build.gradle
grep -n &#x27;@T</tspan><tspan x="24" dy="22">ag&#x27; src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/</tspan><tspan x="24" dy="22">platform/HibernateCollectionFetchPaginationContractTest.java
echo -n &#x27;# jpa-queryplan 태그를 단 클래스: &#x27;
grep -rl &#x27;@T</tspan><tspan x="24" dy="22">ag(&quot;jpa-queryplan&quot;)&#x27; --include=*.java --exclude-dir=build src | sed &#x27;s|.*/||&#x27;
echo
echo &#x27;# 그 불일치를 지나가게 하는 검</tspan><tspan x="24" dy="22">증기가 무엇을 보는가&#x27;
sed -n &#x27;1058,1078p&#x27; src/build.gradle | grep &#x27;violations &lt;&lt;&#x27; | sed &#x27;s/^ */ /&#x27;
echo &#x27;# 레지스트리</tspan><tspan x="24" dy="22">를 읽는 단위 테스트의 게이트 단언&#x27;
grep -n -A3 &#x27;for (String gate : JpaReleaseGate.required())&#x27; \
src/adapter/outbound/</tspan><tspan x="24" dy="22">persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/testkit/release/../JpaReleaseManifestTest.java</tspan><tspan x="24" dy="22"> 2&gt;/dev/null \
|| grep -n -A3 &#x27;for (String gate : JpaReleaseGate.required())&#x27; \
src/adapter/outbound/persistence-jpa</tspan><tspan x="24" dy="22">/src/test/java/dev/caskeleton/adapter/outbound/persistence/testkit/JpaReleaseManifestTest.java
echo
echo &#x27;# 그래도 그 </tspan><tspan x="24" dy="22">테스트는 다른 레인으로 돈다&#x27;
grep -rn &#x27;jpaPlatformContractTest&#x27; .github/workflows/*.yml | sed &#x27;s|.*/||&#x27; | cut -c1-90
gre</tspan><tspan x="24" dy="22">p -n &#x27;dependsOn jpaPlatformContractTest&#x27; src/adapter/outbound/persistence-jpa/build.gradle</tspan></text>
<text x="24" y="464" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">cwd: /shared/codebase/clean-architecture-backend-template</tspan></text>
<text x="24" y="486" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">time: 2026-09-02T04:06:45+00:00 · exit 0</tspan></text>
<line x1="24" y1="500" x2="1176" y2="500" stroke="#30363d"/>
<text x="24" y="540" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 릴리스 레지스트리가 이 게이트에 붙인 생산자 태스크</tspan></text>
<text x="24" y="562" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">56: &quot;name&quot;: &quot;collection-fetch-pagination&quot;,</tspan></text>
<text x="24" y="584" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">57- &quot;task&quot;: &quot;:adapter:outbound:persistence-jpa:jpaPlatformQueryPlanTest&quot;,</tspan></text>
<text x="24" y="606" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">58- &quot;blocking&quot;: true</tspan></text>
<text x="24" y="628" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">59- }</tspan></text>
<text x="24" y="650" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># blocking 이 참인 게이트 / 거짓인 게이트: 6 / 0</tspan></text>
<text x="24" y="672" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 매니페스트 파서가 blocking 을 읽는 줄: 0</tspan></text>
<text x="24" y="694" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 게이트 검증기가 blocking 을 읽는 줄: 0</tspan></text>
<text x="24" y="716" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="738" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 태스크와 게이트 테스트의 태그</tspan></text>
<text x="24" y="760" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">250:def jpaPlatformContractTest = registerJpaPlatformLane(</tspan></text>
<text x="24" y="782" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">251- &#x27;jpaPlatformContractTest&#x27;,</tspan></text>
<text x="24" y="804" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">252- &#x27;jpa-contract&#x27;,</tspan></text>
<text x="24" y="826" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">254:def jpaPlatformMigrationTest = registerJpaPlatformLane(</tspan></text>
<text x="24" y="848" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">255- &#x27;jpaPlatformMigrationTest&#x27;,</tspan></text>
<text x="24" y="870" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">256- &#x27;jpa-migration&#x27;,</tspan></text>
<text x="24" y="892" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">258:def jpaPlatformFailureTest = registerJpaPlatformLane(</tspan></text>
<text x="24" y="914" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">259- &#x27;jpaPlatformFailureTest&#x27;,</tspan></text>
<text x="24" y="936" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">260- &#x27;jpa-failure&#x27;,</tspan></text>
<text x="24" y="958" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">262:def jpaPlatformQueryPlanTest = registerJpaPlatformLane(</tspan></text>
<text x="24" y="980" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">263- &#x27;jpaPlatformQueryPlanTest&#x27;,</tspan></text>
<text x="24" y="1002" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">264- &#x27;jpa-queryplan&#x27;,</tspan></text>
<text x="24" y="1024" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">266:def jpaPlatformSecurityTest = registerJpaPlatformLane(</tspan></text>
<text x="24" y="1046" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">267- &#x27;jpaPlatformSecurityTest&#x27;,</tspan></text>
<text x="24" y="1068" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">268- &#x27;jpa-security&#x27;,</tspan></text>
<text x="24" y="1090" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">238: includeTags tag</tspan></text>
<text x="24" y="1112" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">26:@Tag(&quot;jpa-contract&quot;)</tspan></text>
<text x="24" y="1134" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># jpa-queryplan 태그를 단 클래스: PostgreSqlQueryPlanContractTest.java</tspan></text>
<text x="24" y="1156" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1178" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 불일치를 지나가게 하는 검증기가 무엇을 보는가</tspan></text>
<text x="24" y="1200" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> violations &lt;&lt; &quot;${name}: gate task must be an absolute Gradle path, was &#x27;${path}&#x27;&quot;</tspan></text>
<text x="24" y="1222" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> violations &lt;&lt; &quot;${name}: no project at &#x27;${projectPath}&#x27; for gate task &#x27;${path}&#x27;&quot;</tspan></text>
<text x="24" y="1244" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> violations &lt;&lt; &quot;${name}: no task &#x27;${taskName}&#x27; in &#x27;${projectPath}&#x27;&quot;</tspan></text>
<text x="24" y="1266" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> violations &lt;&lt; &quot;${name}: &#x27;${path}&#x27; is not a Test task, so it produces no JUnit evidence&quot;</tspan></text>
<text x="24" y="1288" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 레지스트리를 읽는 단위 테스트의 게이트 단언</tspan></text>
<text x="24" y="1310" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">45: for (String gate : JpaReleaseGate.required()) {</tspan></text>
<text x="24" y="1332" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">46- assertThat(manifest.taskFor(gate))</tspan></text>
<text x="24" y="1354" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">47- .as(&quot;gate %s must name the task that produces its evidence&quot;, gate)</tspan></text>
<text x="24" y="1376" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">48- .startsWith(&quot;:&quot;);</tspan></text>
<text x="24" y="1398" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
<text x="24" y="1420" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그래도 그 테스트는 다른 레인으로 돈다</tspan></text>
<text x="24" y="1442" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">jpa-nightly.yml:49: :adapter:outbound:persistence-jpa:jpaPlatformContractTest</tspan></text>
<text x="24" y="1464" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">jpa-pr.yml:86: :adapter:outbound:persistence-jpa:jpaPlatformContractTest</tspan></text>
<text x="24" y="1486" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">gradlew :adapter:outbound:persistence-jpa:jpaPlatformContractTest --console=plain</tspan></text>
<text x="24" y="1508" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">gradlew :adapter:outbound:persistence-jpa:jpaPlatformContractTest :adapter:outbound:persis</tspan></text>
<text x="24" y="1530" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">304: dependsOn jpaPlatformContractTest</tspan></text>
</svg>