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>
115 lines
14 KiB
Plaintext
115 lines
14 KiB
Plaintext
# revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
|
|
## A. this leaf has no test source set at all
|
|
main
|
|
|
|
## B. thirteen public types, files referencing them outside the owning leaf (qualified name)
|
|
OutboxRepository 7
|
|
OutboxRecord 13
|
|
OutboxStatus 7
|
|
OutboxLease 6
|
|
OutboxTransitionResult 6
|
|
OutboxCanonicalMetadata 8
|
|
InboxRepository 6
|
|
InboxRecord 0
|
|
InboxResult 2
|
|
ClaimCheckReference 6
|
|
IdempotentMessageHandler 1
|
|
TransactionalMessageAction 1
|
|
ReliableMessagePublisher 0
|
|
|
|
## C. the two with no consumer
|
|
ReliableMessagePublisher NONE
|
|
InboxRecord NONE
|
|
|
|
## D. implementors of the four ports
|
|
src/messaging/messaging-inbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/inbox/JdbcInboxRepository.java:30:public final class JdbcInboxRepository implements InboxRepository {
|
|
src/messaging/messaging-inbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/inbox/TransactionalInboxHandler.java:31:public final class TransactionalInboxHandler<T> implements IdempotentMessageHandler<T> {
|
|
src/messaging/messaging-inbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/inbox/IdempotentConsumerTest.java:91:final class InMemoryInbox implements InboxRepository {
|
|
src/messaging/messaging-inbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/inbox/InboxOperationsTest.java:24: private static final class InMemoryInbox implements InboxRepository {
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/outbox/JdbcOutboxRepository.java:48:public final class JdbcOutboxRepository implements OutboxRepository {
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxOperationsTest.java:23: private static final class RecordingRepository implements OutboxRepository {
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxRelayTest.java:223:final class InMemoryOutboxRepository implements OutboxRepository {
|
|
src/messaging/messaging-spring-boot-starter/src/test/java/dev/caskeleton/messaging/autoconfigure/MessagingOutboxRelayLifecycleTest.java:109: static final class CountingOutboxRepository implements OutboxRepository {
|
|
|
|
## E. OutboxRepository carries two generations of the same five transitions
|
|
22: void append(OutboxRecord record);
|
|
67: void markPublished(MessageId messageId, Instant now);
|
|
74: OutboxTransitionResult markPublished(OutboxLease lease, Instant now);
|
|
85: void markAmbiguous(MessageId messageId, String failureCode, Instant now);
|
|
88: OutboxTransitionResult markAmbiguous(OutboxLease lease, String failureCode, Instant now);
|
|
91: OutboxTransitionResult markAmbiguous(
|
|
100: OutboxTransitionResult markExhausted(OutboxLease lease, String reason, Instant now);
|
|
109: void markFailed(MessageId messageId, String failureCode, Instant now);
|
|
112: OutboxTransitionResult markFailed(OutboxLease lease, String failureCode, Instant now);
|
|
119: void releaseLease(MessageId messageId);
|
|
122: OutboxTransitionResult releaseLease(OutboxLease lease);
|
|
138: int purgePublishedBefore(Instant publishedBefore);
|
|
151: int purgePublishedBefore(Instant publishedBefore, int limit);
|
|
|
|
## F. the older generation is called deprecated in prose but is not annotated
|
|
43: * inspection paths and is deprecated for the relay's use.
|
|
--- any @Deprecated in the leaf?
|
|
exit=1 (1 = none)
|
|
|
|
## G. which generation the messaging relay actually calls
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/outbox/OutboxRelay.java:158: repository.claimBatch(owner, batchSize, leaseDuration, now, scheduler.maxAttempts());
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/outbox/OutboxRelay.java:171: if (repository.markPublished(lease, now) == OutboxTransitionResult.APPLIED) {
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/outbox/OutboxRelay.java:189: .map(reason -> repository.markExhausted(lease, reason, now))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/outbox/OutboxRelay.java:192: repository.markAmbiguous(
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/outbox/OutboxRelay.java:205: if (repository.markFailed(
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:92: List<OutboxRecord> leased = repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:111: List<OutboxRecord> first = repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:112: List<OutboxRecord> second = repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:121: repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:124: repository.leaseBatch(10, Duration.ofSeconds(30), NOW.plusSeconds(31));
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:133: repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:135: repository.markAmbiguous(record.messageId(), "CONFIRM_TIMEOUT", NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:139: assertThat(repository.leaseBatch(10, Duration.ofSeconds(30), NOW))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:148: repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:150: repository.markPublished(record.messageId(), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:154: assertThat(repository.leaseBatch(10, Duration.ofSeconds(30), NOW.plusSeconds(60))).isEmpty();
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:161: repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:163: repository.markFailed(record.messageId(), "INVALID_TOPIC", NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:165: assertThat(repository.leaseBatch(10, Duration.ofSeconds(30), NOW.plusSeconds(60))).isEmpty();
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:200: repository.markPublished(published.messageId(), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:321: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:326: repository.claimBatch("relay-b", 10, Duration.ofSeconds(30), NOW.plusSeconds(31));
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:331: assertThat(repository.markPublished(second.get(0), NOW.plusSeconds(32)))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:335: assertThat(repository.markAmbiguous(first.get(0), "CONFIRM_TIMEOUT", NOW.plusSeconds(40)))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:347: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW).get(0);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:349: assertThat(repository.markPublished(lease, NOW))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:351: assertThat(repository.markPublished(lease, NOW))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:364: repository.claimBatch("relay-a", 1, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:366: repository.claimBatch("relay-b", 1, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:379: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW).get(0).token();
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:381: repository.claimBatch("relay-b", 10, Duration.ofSeconds(30), NOW.plusSeconds(31)).get(0);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:392: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW, 10).get(0);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:394: repository.markAmbiguous(lease, "CONFIRM_TIMEOUT", NOW, NOW.plusSeconds(120));
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:396: assertThat(repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW.plusSeconds(1), 10))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:402: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW.plusSeconds(121), 10))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:414: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), clock, 3).get(0);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:415: repository.markAmbiguous(lease, "CONFIRM_TIMEOUT", clock, clock);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:419: assertThat(repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), clock, 3))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:429: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW, 10).get(0);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:431: repository.markExhausted(lease, "budget spent without a confirmation", NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:437: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW.plusSeconds(600), 10))
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:446: repository.claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW, 10).get(0);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:447: repository.markAmbiguous(first, "CONFIRM_TIMEOUT", NOW, NOW.plusSeconds(60));
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:451: .claimBatch("relay-a", 10, Duration.ofSeconds(30), NOW.plusSeconds(61), 10)
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxPostgresIT.java:453: repository.markPublished(second, NOW.plusSeconds(62));
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxRelayTest.java:127: assertThat(repository.leaseBatch(10, Duration.ofSeconds(30), NOW)).isEmpty();
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxRelayTest.java:134: List<OutboxRecord> first = repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxRelayTest.java:135: List<OutboxRecord> second = repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxRelayTest.java:144: repository.leaseBatch(10, Duration.ofSeconds(30), NOW);
|
|
src/messaging/messaging-outbox-jdbc-postgresql/src/test/java/dev/caskeleton/messaging/outbox/OutboxRelayTest.java:147: repository.leaseBatch(10, Duration.ofSeconds(30), NOW.plusSeconds(31));
|
|
|
|
## H. OutboxStatus.FAILED means the opposite of the legacy application enum
|
|
237: "APPLICATION_DOES_NOT_DEPEND_ON_THE_MESSAGING_PLATFORM: the application owns its "
|
|
238- + "publish port and outbox model; a bridge adapter translates, and the two "
|
|
239- + "outbox status models mean opposite things under the same names")
|
|
240- .allowEmptyShould(true);
|
|
241-
|
|
242- /**
|
|
243- * The two notification models must not learn about each other.
|