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>
82 lines
11 KiB
Plaintext
82 lines
11 KiB
Plaintext
Command: printf '%s\n' '--- framework annotations under persistence api ---'; git grep -n -E '@(Component|Configuration|Bean|Conditional|AutoConfiguration|Repository|Entity|Service)' -- 'src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/**/*.java' 'src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/*.java' || true; printf '%s\n' '--- api baseline header/count ---'; sed -n '1,8p' docs/architecture/jpa-api-surface.txt; grep -c 'dev.caskeleton.adapter.outbound.persistence.api' docs/architecture/jpa-api-surface.txt; printf '%s\n' '--- capability enum/composition counts ---'; python3 - <<'PY'
|
|
from pathlib import Path
|
|
import re
|
|
p=Path('src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/capability/JpaCapability.java').read_text()
|
|
inside=p.split('public enum JpaCapability {',1)[1].split('private final String id;',1)[0]
|
|
print('enum=',len(re.findall(r'^\s*[A-Z][A-Z0-9_]*\("',inside,re.M)))
|
|
q=Path('src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java').read_text()
|
|
print('composition=',q.count('CapabilitySupport.'))
|
|
PY
|
|
printf '%s\n' '--- capability report/endpoint path ---'; git grep -n -E 'CapabilitySupport|JpaPlatformReport|JpaPlatformEndpoint|@Endpoint\(id = "jpaplatform"\)' -- 'src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/*.java'; printf '%s\n' '--- retry reason accessor uses in persistence/app-bootstrap ---'; git grep -n '\.reason()' -- 'src/adapter/outbound/persistence-jpa/**' 'src/app-bootstrap/**' || true; printf '%s\n' '--- same simple-name mechanisms elsewhere ---'; git grep -n -E 'class RetryDecision|record RetryDecision|interface CursorCodec|enum SortDirection|enum FailureCategory' -- 'src/adapter/outbound/**/src/main/java/**/*.java' | head -220
|
|
Working directory: /shared/codebase/clean-architecture-backend-template
|
|
Executed at: 2026-08-29T07:48:10Z
|
|
Source revision: a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
Observation boundary: Collects the API package's framework-annotation absence, current public API baseline/count, capability composition count, same-name mechanisms in other bounded contexts, actuator report wiring, and exact retry-reason uses. Same-name classes in other adapters are not asserted to be semantic duplicates by this evidence.
|
|
--- stdout/stderr ---
|
|
--- framework annotations under persistence api ---
|
|
--- api baseline header/count ---
|
|
# JPA persistence leaf public API surface — every public top-level type in src/main/java.
|
|
# A public type in a single-jar leaf is reachable from every adopter's code, so
|
|
# additions are reviewed rather than discovered. `api` is the intended external
|
|
# surface; the rest is implementation that has not been moved under an internal
|
|
# root yet.
|
|
# Update only after review with:
|
|
# ./gradlew :adapter:outbound:persistence-jpa:updateJpaApiSurface -PapproveJpaApiSurfaceChange
|
|
# types: 338
|
|
49
|
|
--- capability enum/composition counts ---
|
|
enum= 16
|
|
composition= 16
|
|
--- capability report/endpoint path ---
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:3:import dev.caskeleton.adapter.outbound.persistence.api.capability.CapabilitySupport;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:54: public List<CapabilitySupport> capabilities() {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:56: CapabilitySupport.stable(JpaCapability.TRANSACTION_RETRY),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:57: CapabilitySupport.stable(JpaCapability.COMPLETION_EVIDENCE),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:58: CapabilitySupport.stable(JpaCapability.KEYSET_PAGINATION),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:59: CapabilitySupport.stable(JpaCapability.BATCH),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:60: CapabilitySupport.stable(JpaCapability.SCHEMA_GATE),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:61: CapabilitySupport.stable(JpaCapability.RUNTIME_ROLE_VERIFICATION),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:62: CapabilitySupport.stable(JpaCapability.OBSERVABILITY),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:63: CapabilitySupport.advanced(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:65: CapabilitySupport.advanced(JpaCapability.POSTGRESQL_WORK_CLAIM, "requires a named queue"),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:66: CapabilitySupport.advanced(JpaCapability.POSTGRESQL_JSONB, "requires a registered path"),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:67: CapabilitySupport.advanced(JpaCapability.POSTGRESQL_ARRAY_RANGE, "requires a JDBC type"),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:68: CapabilitySupport.advanced(JpaCapability.BULK_DML, "requires a registered operation"),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:69: CapabilitySupport.advanced(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:71: CapabilitySupport.advanced(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:73: CapabilitySupport.advanced(JpaCapability.L2_CACHE, "requires an enrolled region catalog"),
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:74: CapabilitySupport.advanced(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:84: public JpaPlatformReport report(DataSource dataSource, String schemaVersion) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java:100: return JpaPlatformReport.sanitized(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformEndpoint.java:20:@Endpoint(id = "jpaplatform")
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformEndpoint.java:21:public class JpaPlatformEndpoint {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformEndpoint.java:23: private final Supplier<JpaPlatformReport> reportSupplier;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformEndpoint.java:25: public JpaPlatformEndpoint(Supplier<JpaPlatformReport> reportSupplier) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformEndpoint.java:31: public JpaPlatformReport platform() {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:3:import dev.caskeleton.adapter.outbound.persistence.api.capability.CapabilitySupport;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:19:public record JpaPlatformReport(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:26: List<CapabilitySupport> capabilities) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:28: public JpaPlatformReport {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:42: public static JpaPlatformReport sanitized(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:49: List<CapabilitySupport> capabilities) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java:50: return new JpaPlatformReport(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:122: public Supplier<JpaPlatformReport> jpaPlatformReportSupplier(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:138: public JpaPlatformEndpoint jpaPlatformEndpoint(Supplier<JpaPlatformReport> reportSupplier) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:139: return new JpaPlatformEndpoint(reportSupplier);
|
|
--- retry reason accessor uses in persistence/app-bootstrap ---
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/notification/platform/JpaSuppressionStore.java:51: entry.tenantId().value(), entry.normalizedTargetHmac(), entry.reason().name())
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/notification/platform/JpaSuppressionStore.java:55: entry.reason().name(),
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/notification/platform/JpaSuppressionStore.java:83: entry.reason().name(),
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/notification/platform/JpaSuppressionStore.java:97: SuppressionReason.valueOf(entity.reason()),
|
|
src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/platform/experimental/ReadAfterWriteRoutingContractTest.java:93: assertThat(decision.reason()).isNotBlank();
|
|
src/adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/transaction/DefaultJpaRetryPolicyTest.java:86: assertThat(decision.reason()).contains("irreversible");
|
|
--- same simple-name mechanisms elsewhere ---
|
|
src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/operations/SortDirection.java:9:public enum SortDirection {
|
|
src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/api/operation/FailureCategory.java:9:public enum FailureCategory {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/error/FailureCategory.java:11:public enum FailureCategory {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/query/CursorCodec.java:10:public interface CursorCodec<C> {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/query/SortDirection.java:9:public enum SortDirection {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/transaction/RetryDecision.java:12:public record RetryDecision(RetryDisposition disposition, Duration delay, String reason) {
|
|
|
|
Exit code: 0
|