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>
209 lines
18 KiB
Plaintext
209 lines
18 KiB
Plaintext
Sub-scope 03 (fileserver) publication - provider / adapter / journal / attestor / binding
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
generatedAt=2026-08-30T01:19:02+00:00
|
|
|
|
=== OWNED FILES (19 main + 7 test) ===
|
|
c0ab08838529d6c1306aa74a4bcc342c67e131ad main/LocalPersistentPublicationProvider.java 896
|
|
471fe5a3c3431341e1e2a04df322129a38e71209 main/LocalFilePublicationAdapter.java 437
|
|
4cb369601458728aa95a3622ed67bcaeda0a9c85 main/RoutingFilePublicationAdapter.java 42
|
|
54233811ca6321c8f4d930e1d8992ea857cdde11 main/FilePublicationProvider.java 15
|
|
8b5f37749b3f01cc0dff9141ec319a8c8475134f main/LocalFilePublicationPolicy.java 25
|
|
b3f87f2cfbb778f4cde623a73ab2ecf764cce869 main/FilePublicationCanonicalDigests.java 201
|
|
129025a5b1de77098d60e3ee1d73a6d6d27d9f11 main/FilePublishRequestFingerprint.java 77
|
|
4289cbadde46c952b6d670fd0db1a77761f01803 main/DurablePublicationRecord.java 255
|
|
6061c91898c44220e24799ee0e2919c5bc986fbe main/PublishedReferenceRecord.java 48
|
|
a722a598a4913154c7f86f6f21bdd27f91bda96d main/R2PublishedReferenceCodec.java 79
|
|
3e8ddfe2536e32c78397d3606648690c31d42247 main/LocalPublicationJournal.java 294
|
|
a88c8957e6c5554fe46246d1184088225f828403 main/LocalPublicationJournalCodec.java 266
|
|
91795acbb44b33fc101403b9f1cc9d7d51dbaa27 main/LocalPublicationJournalRecord.java 145
|
|
fcc75af5de670326e0dcdd7045c3cece2540c0da main/LocalPublicationJournalException.java 15
|
|
ddeda2bbff614ef6eada17c6ce704cb6513d7d1e main/LocalPersistentRootAttestor.java 773
|
|
45347a6246fbbf6ce190bc254182b07d23a5a666 main/LocalPersistentRootEvidence.java 41
|
|
25527a723854d0aa5fc998a9ad2a20a1990f2d50 main/PrivateFileManifest.java 77
|
|
b121a7092f0f7edf537895f90adfdd805eb76e38 main/CompiledFileDestination.java 198
|
|
d6a89051f27b3ec02bd7940128ec935d7efac011 main/FileserverBindingCompiler.java 227
|
|
0b94b8585fb66dd609a4a1a9a81a18d728ee8202 test/LocalPersistentPublicationProviderTest.java 511
|
|
9400ea3df6f94194259b8defd7561d2f984bf241 test/LocalPersistentPublicationRecoveryTest.java 1121
|
|
f5895b81e9088db8a44133349bb98907ea0b0d9f test/LocalFilePublicationAdapterTest.java 235
|
|
2d2ed6023366c2f8bc382c3216dcef529f9173e9 test/LocalFilePublicationRecoveryTest.java 280
|
|
a13d78681d3d80651209f659d52499c3588df68a test/LocalPublicationJournalTest.java 147
|
|
a2c215e229a9490e36d491b8c6884f4806fad7c0 test/LocalPersistentRootAttestorTest.java 769
|
|
c5ad051249d1ab27e701c987169ef25cc210cc8e test/FileserverBindingCompilerTest.java 969
|
|
|
|
=== 8.1 reachability: which of the 19 escape the leaf? ===
|
|
$ git grep -rln 'LocalPersistentPublicationProvider\|LocalFilePublicationAdapter\|RoutingFilePublicationAdapter\|LocalPersistentRootAttestor\|FileserverBindingCompiler\|DurablePublicationRecord\|PrivateFileManifest\|PublishedReferenceRecord\|LocalPublicationJournal' -- . | grep -v "^adapter/outbound/fileserver/"
|
|
exit=1
|
|
|
|
$ grep -n 'public\|^final class\|^record\|^interface' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FilePublicationProvider.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/CompiledFileDestination.java | head
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:3:import dev.caskeleton.application.filepublication.FileDestinationId;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:4:import dev.caskeleton.application.filepublication.FilePublicationException;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:5:import dev.caskeleton.application.filepublication.FilePublicationPort;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:6:import dev.caskeleton.application.filepublication.FilePublishReceipt;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:7:import dev.caskeleton.application.filepublication.FilePublishRequest;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:8:import dev.caskeleton.application.filepublication.TabularRowProducer;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:13:final class RoutingFilePublicationAdapter implements FilePublicationPort {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:25: public FilePublishReceipt publish(FilePublishRequest request, TabularRowProducer producer) {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:27: throw invalidRequest("file publication request must be non-null");
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/RoutingFilePublicationAdapter.java:30: throw invalidRequest("file publication producer must be non-null");
|
|
exit=0
|
|
|
|
=== 8.2 R1 journal vs R2 control plane: the same job at two rigor levels ===
|
|
--- (a) decoding strictness
|
|
$ grep -n 'new String(bytes, StandardCharsets.UTF_8)\|onMalformedInput' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalCodec.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodec.java
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalCodec.java:82: .onMalformedInput(CodingErrorAction.REPORT)
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalCodec.java:156: input = new String(bytes, StandardCharsets.UTF_8);
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodec.java:846: .onMalformedInput(CodingErrorAction.REPORT)
|
|
exit=0
|
|
|
|
$ grep -n 'static LocalPublicationJournalRecord decode\|decodeCanonical' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalCodec.java
|
|
53: static LocalPublicationJournalRecord decode(byte[] bytes) {
|
|
78: static LocalPublicationJournalRecord decodeCanonical(byte[] bytes) {
|
|
exit=0
|
|
|
|
$ git grep -n 'LocalPublicationJournalCodec.decode' -- 'adapter/outbound/fileserver/src/main'
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:634: LocalPublicationJournalRecord r1 = LocalPublicationJournalCodec.decodeCanonical(encoded);
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java:52: LocalPublicationJournalCodec.decode(Files.readAllBytes(record));
|
|
exit=0
|
|
|
|
--- (b) control-character escapes: R1 escapes them, R2 forbids them
|
|
$ grep -n "case 'b', 'f', 'n', 'r', 't'" -A 2 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodec.java
|
|
786: case 'b', 'f', 'n', 'r', 't' ->
|
|
787- throw new IllegalArgumentException("control characters are forbidden");
|
|
788- default -> throw new IllegalArgumentException("invalid JSON escape");
|
|
exit=0
|
|
|
|
$ grep -n "case 'b' ->" -A 6 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalCodec.java
|
|
214: case 'b' -> value.append('\b');
|
|
215- case 'f' -> value.append('\f');
|
|
216- case 'n' -> value.append('\n');
|
|
217- case 'r' -> value.append('\r');
|
|
218- case 't' -> value.append('\t');
|
|
219- case 'u' -> value.append(unicode());
|
|
220- default -> throw new IllegalArgumentException("invalid escape");
|
|
exit=0
|
|
|
|
--- (c) POSIX permission enforcement
|
|
$ grep -n 'UnsupportedOperationException ignored' -B 4 -A 2 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java
|
|
191- Set.of(
|
|
192- PosixFilePermission.OWNER_READ,
|
|
193- PosixFilePermission.OWNER_WRITE,
|
|
194- PosixFilePermission.OWNER_EXECUTE));
|
|
195: } catch (UnsupportedOperationException ignored) {
|
|
196- // Deployment qualification owns non-POSIX permission evidence.
|
|
197- }
|
|
--
|
|
200- private static void restrictFile(Path path) throws IOException {
|
|
201- try {
|
|
202- Files.setPosixFilePermissions(
|
|
203- path, Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));
|
|
204: } catch (UnsupportedOperationException ignored) {
|
|
205- // Deployment qualification owns non-POSIX permission evidence.
|
|
206- }
|
|
exit=0
|
|
|
|
$ grep -n 'must have exact private mode 0700\|PRIVATE_DIRECTORY_PERMISSIONS.equals' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentRootAttestor.java
|
|
404: if (!PRIVATE_DIRECTORY_PERMISSIONS.equals(attributes.permissions())) {
|
|
405: throw failure("internal directory must have exact private mode 0700: " + directory);
|
|
exit=0
|
|
|
|
--- (d) filesystem access primitive
|
|
$ grep -c 'SecureDirectoryStream' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:17
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java:0
|
|
exit=0
|
|
|
|
$ grep -n 'Files.exists\|Files.readAllBytes\|Files.isRegularFile' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java
|
|
43: if (!Files.exists(record, LinkOption.NOFOLLOW_LINKS)) {
|
|
47: if (!Files.isRegularFile(record, LinkOption.NOFOLLOW_LINKS)
|
|
52: LocalPublicationJournalCodec.decode(Files.readAllBytes(record));
|
|
73: if (Files.exists(lockPath, LinkOption.NOFOLLOW_LINKS)
|
|
74: && !Files.isRegularFile(lockPath, LinkOption.NOFOLLOW_LINKS)) {
|
|
175: if (Files.exists(directory, LinkOption.NOFOLLOW_LINKS)) {
|
|
exit=0
|
|
|
|
=== 8.2b where the two meet: the R2 control plane reading an R1 journal ===
|
|
$ grep -n 'LocalPublicationJournalCodec.decodeCanonical' -B 6 -A 6 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java
|
|
628-
|
|
629- private StoredOperationRecord decodeStoredOperation(byte[] encoded) {
|
|
630- try {
|
|
631- return new R2StoredOperationRecord(codec.decodeOperation(encoded));
|
|
632- } catch (RuntimeException versionTwoFailure) {
|
|
633- try {
|
|
634: LocalPublicationJournalRecord r1 = LocalPublicationJournalCodec.decodeCanonical(encoded);
|
|
635- if (r1.state() != LocalPublicationJournalRecord.State.PUBLISHED) {
|
|
636- throw new IllegalArgumentException(
|
|
637- "R1 compatibility operation must be terminal PUBLISHED");
|
|
638- }
|
|
639- return new R1StoredOperationRecord(r1);
|
|
640- } catch (RuntimeException versionOneFailure) {
|
|
exit=0
|
|
|
|
=== 8.3 duplicate mechanism: two reference formats, two lock implementations ===
|
|
$ grep -n 'filepub:' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProvider.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalFilePublicationAdapter.java
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProvider.java:310: "filepub:" + request.destinationId().value() + ":" + operationToken),
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalFilePublicationAdapter.java:243: "filepub:" + policy.destinationId().value() + ":" + operationToken),
|
|
exit=0
|
|
|
|
$ grep -n 'VERSION = ' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/R2PublishedReferenceCodec.java
|
|
14: private static final String VERSION = "fsr1";
|
|
exit=0
|
|
|
|
$ grep -n 'class OperationLock' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:1377: static final class OperationLock implements AutoCloseable {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java:252: static final class OperationLock implements AutoCloseable {
|
|
exit=0
|
|
|
|
$ grep -n 'Semaphore\[\]\|ReentrantLock\[\]' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java:29: private static final Semaphore[] JVM_LOCK_STRIPES = createLockStripes();
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java:233: private static Semaphore[] createLockStripes() {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournal.java:234: Semaphore[] locks = new Semaphore[JVM_LOCK_STRIPE_COUNT];
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:43: private static final ReentrantLock[] OPERATION_LOCK_STRIPES = createOperationLockStripes();
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:44: private static final ReentrantLock[] IMMUTABLE_LOCK_STRIPES = createOperationLockStripes();
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:870: private static ReentrantLock[] createOperationLockStripes() {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:871: ReentrantLock[] stripes = new ReentrantLock[OPERATION_LOCK_STRIPE_COUNT];
|
|
exit=0
|
|
|
|
=== 8.4 doc claims about R1 restore and guarantee non-promotion ===
|
|
$ grep -n 'PROCESS_LOCAL_SYNC' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProvider.java adapter/outbound/fileserver/README.md adapter/outbound/fileserver/CLAUDE.md
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProvider.java:323: DurabilityGuarantee.PROCESS_LOCAL_SYNC,
|
|
adapter/outbound/fileserver/README.md:111:matching root-level artifact, R2 may restore its original `PROCESS_LOCAL_SYNC` receipt read-only.
|
|
adapter/outbound/fileserver/CLAUDE.md:53: `PROCESS_LOCAL_SYNC`; R2 writes schema v2 only.
|
|
exit=0
|
|
|
|
$ grep -n 'never writes schema v1\|never promotes' adapter/outbound/fileserver/README.md
|
|
112:It never writes schema v1, creates an R2 manifest/reference for that artifact, or promotes its
|
|
exit=0
|
|
|
|
$ grep -n 'CURRENT_SCHEMA_VERSION' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/DurablePublicationRecord.java adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalRecord.java
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/DurablePublicationRecord.java:34: static final int CURRENT_SCHEMA_VERSION = 2;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/DurablePublicationRecord.java:37: if (schemaVersion != CURRENT_SCHEMA_VERSION) {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalRecord.java:22: static final int CURRENT_SCHEMA_VERSION = 1;
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalRecord.java:25: if (schemaVersion != CURRENT_SCHEMA_VERSION) {
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalRecord.java:60: CURRENT_SCHEMA_VERSION,
|
|
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPublicationJournalRecord.java:86: CURRENT_SCHEMA_VERSION,
|
|
exit=0
|
|
|
|
$ grep -n 'routeToken(String effectivePolicyDigest)' -A 5 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FilePublicationCanonicalDigests.java
|
|
108: static String routeToken(String effectivePolicyDigest) {
|
|
109- String validated =
|
|
110- FileserverR2Validation.requireSha256("effectivePolicyDigest", effectivePolicyDigest);
|
|
111- return "r" + validated.substring(0, 31);
|
|
112- }
|
|
113-
|
|
exit=0
|
|
|
|
$ grep -n 'deriveUniqueRouteTokens' -A 4 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverBindingCompiler.java | head -12
|
|
89: Map<FileDestinationId, String> routeTokens = deriveUniqueRouteTokens(policyDigests);
|
|
90- compiled.forEach(
|
|
91- (destinationId, destination) -> {
|
|
92- if (!destination.routeToken().equals(routeTokens.get(destinationId))) {
|
|
93- throw new IllegalStateException("compiled route token differs from route registry");
|
|
--
|
|
99: static Map<FileDestinationId, String> deriveUniqueRouteTokens(
|
|
100- Map<FileDestinationId, String> policyDigests) {
|
|
101- Objects.requireNonNull(policyDigests, "policyDigests must be non-null");
|
|
102- Map<String, FileDestinationId> routeOwners = new LinkedHashMap<>();
|
|
103- Map<FileDestinationId, String> routeTokens = new LinkedHashMap<>();
|
|
exit=0
|
|
|