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>
114 lines
6.4 KiB
Plaintext
114 lines
6.4 KiB
Plaintext
Sub-scope 12 negative-space probes: lane claims, release-gate membership, reachability
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
executedAt=2026-08-29T14:41:21+00:00
|
|
cwd=/shared/codebase/clean-architecture-backend-template/src
|
|
observation boundary: tracked build/registry/workflow/doc files at this revision.
|
|
|
|
=== A. release registry gate names and tasks ===
|
|
$ python3 -c "import json;d=json.load(open(\"config/jpa/release-registry.json\"));print(len(d[\"gates\"]));[print(g[\"name\"],g[\"task\"],g[\"blocking\"]) for g in d[\"gates\"]]"
|
|
6
|
|
postgresql-contract :adapter:outbound:persistence-jpa:jpaPlatformContractTest True
|
|
completion-unknown-no-retry :adapter:outbound:persistence-jpa:jpaPlatformFailureTest True
|
|
osiv-disabled :app-bootstrap:test True
|
|
flyway-validate :adapter:outbound:persistence-jpa:jpaPlatformMigrationTest True
|
|
runtime-role-no-ddl :adapter:outbound:persistence-jpa:jpaPlatformSecurityTest True
|
|
collection-fetch-pagination :adapter:outbound:persistence-jpa:jpaPlatformQueryPlanTest True
|
|
exit=0
|
|
|
|
=== B. is the pool lane a registered gate? ===
|
|
$ grep -n -i pool config/jpa/release-registry.json
|
|
exit=1
|
|
|
|
$ grep -n -i pool ../docs/jpa/support-matrix.md
|
|
exit=1
|
|
|
|
$ grep -n -i pool adapter/outbound/persistence-jpa/src/testkit/java/dev/caskeleton/adapter/outbound/persistence/testkit/release/JpaReleaseGate.java
|
|
exit=1
|
|
|
|
=== C. where the pool lane is wired ===
|
|
$ grep -n jpaPlatformPoolContractTest adapter/outbound/persistence-jpa/build.gradle
|
|
287:def jpaPlatformPoolContractTest = tasks.register('jpaPlatformPoolContractTest', Test) {
|
|
309: dependsOn jpaPlatformPoolContractTest
|
|
exit=0
|
|
|
|
$ grep -rn jpaPlatformPoolContractTest ../.github/workflows
|
|
../.github/workflows/jpa-nightly.yml:132: :adapter:outbound:persistence-jpa:jpaPlatformPoolContractTest
|
|
exit=0
|
|
|
|
$ grep -n -A10 "register..jpaPlatformReleaseGate" adapter/outbound/persistence-jpa/build.gradle
|
|
300:tasks.register('jpaPlatformReleaseGate') {
|
|
301- group = 'verification'
|
|
302- description = 'Runs every JPA platform lane required for a release (design §41).'
|
|
303- dependsOn tasks.named('test')
|
|
304- dependsOn jpaPlatformContractTest
|
|
305- dependsOn jpaPlatformMigrationTest
|
|
306- dependsOn jpaPlatformFailureTest
|
|
307- dependsOn jpaPlatformQueryPlanTest
|
|
308- dependsOn jpaPlatformSecurityTest
|
|
309- dependsOn jpaPlatformPoolContractTest
|
|
310-}
|
|
exit=0
|
|
|
|
=== D. what the lane files actually assert ===
|
|
$ grep -n "assertThat\|assertThatThrownBy\|@DisplayName" adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest/java/dev/caskeleton/adapter/outbound/persistence/platform/pool/PoolPressureContractTest.java
|
|
3:import static org.assertj.core.api.Assertions.assertThat;
|
|
27: @DisplayName("pending count and acquire latency are reported together")
|
|
31: assertThat(measurement.pending()).isEqualTo(3);
|
|
32: assertThat(measurement.acquireLatency()).isEqualTo(Duration.ofMillis(80));
|
|
33: assertThat(measurement.total()).isEqualTo(6);
|
|
34: assertThat(measurement.saturated()).isTrue();
|
|
38: @DisplayName("a REQUIRES_NEW depth of one needs two connections per concurrent thread")
|
|
45: assertThat(required)
|
|
exit=0
|
|
|
|
$ grep -n "assertThat\|assertThatThrownBy\|@DisplayName" adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest/java/dev/caskeleton/adapter/outbound/persistence/platform/pool/HikariPoolSaturationContractTest.java
|
|
3:import static org.assertj.core.api.Assertions.assertThat;
|
|
4:import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
51: @DisplayName("a saturated pool fails within its acquisition timeout")
|
|
61: assertThatThrownBy(pool::getConnection).isInstanceOf(SQLException.class);
|
|
64: assertThat(waited)
|
|
76: @DisplayName("releasing a connection lets the next caller through")
|
|
84: assertThat(third.isValid(1)).isTrue();
|
|
91: @DisplayName("the measurement reports what the pool is actually doing")
|
|
103: assertThat(measurement.active()).isEqualTo(1);
|
|
104: assertThat(measurement.total()).isGreaterThanOrEqualTo(1);
|
|
105: assertThat(held.isValid(1)).isTrue();
|
|
exit=0
|
|
|
|
$ grep -n "assertThat\|assertThatThrownBy\|@DisplayName" adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest/java/dev/caskeleton/adapter/outbound/persistence/platform/pool/RequiresNewPoolPressureContractTest.java
|
|
3:import static org.assertj.core.api.Assertions.assertThat;
|
|
4:import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
44: @DisplayName("a pool of one deadlocks the moment an inner transaction is needed")
|
|
50: assertThatThrownBy(pool::getConnection)
|
|
60: @DisplayName("a pool of two serves the same nesting")
|
|
68: assertThat(inner.isValid(1)).isTrue();
|
|
69: assertThat(inner).isNotSameAs(outer);
|
|
79: @DisplayName("the sizing rule matches the observed requirement")
|
|
86: assertThat(required)
|
|
exit=0
|
|
|
|
=== E. does any lane assertion read a non-zero pending count from a real pool? ===
|
|
$ grep -rn "getThreadsAwaitingConnection\|pending()\|saturated()" adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest
|
|
adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest/java/dev/caskeleton/adapter/outbound/persistence/platform/pool/HikariPoolSaturationContractTest.java:100: bean.getThreadsAwaitingConnection(),
|
|
adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest/java/dev/caskeleton/adapter/outbound/persistence/platform/pool/PoolPressureContractTest.java:31: assertThat(measurement.pending()).isEqualTo(3);
|
|
adapter/outbound/persistence-jpa/src/jpaPlatformPerformanceTest/java/dev/caskeleton/adapter/outbound/persistence/platform/pool/PoolPressureContractTest.java:34: assertThat(measurement.saturated()).isTrue();
|
|
exit=0
|
|
|
|
=== F. nightly workflow claim text ===
|
|
$ sed -n 122,135p ../.github/workflows/jpa-nightly.yml
|
|
- name: Verify pool saturation and REQUIRES_NEW connection behaviour
|
|
working-directory: src
|
|
# A behaviour contract, not a measurement. This step used to switch assertions off with an
|
|
# explicit property and call the result a certification, so the only threshold it ever
|
|
# asserted was that thresholds were not being asserted. What
|
|
# it checks now — that REQUIRES_NEW needs two connections per concurrent thread, that a
|
|
# saturated pool reports its pending count, that a caller waits rather than proceeding
|
|
# without a connection — is true on any runner, so there is nothing to switch off.
|
|
run: >-
|
|
./gradlew
|
|
:adapter:outbound:persistence-jpa:jpaPlatformPoolContractTest
|
|
--no-daemon
|
|
--stacktrace
|
|
exit=0
|
|
|