Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/143-fileserver-control-plane-probes.txt
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

281 lines
21 KiB
Plaintext

Sub-scope 02 (fileserver) control plane + record codec + recovery verifier
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
generatedAt=2026-08-30T01:11:32+00:00
=== OWNED FILES ===
3b5849d179406ffb6158ecd510a8e1854e497480 main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java 1470
b94e783acb752ad603fef2ee6e990af1b8702abb main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodec.java 855
4a43965ba0b17699aa5d0718439f1c73c29922c6 main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentRecoveryVerifier.java 210
a948982e8ab0e192b7d2087091b59f256b2bdef7 test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java 2087
8ad022d5671c15e7b7ed765b1c1e0602eb27646a test/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodecTest.java 924
1b22d273beaa63093ba81574389a687a559de0be test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentCrashRecoveryTest.java 229
main LOC: 2535 total
test LOC: 3240 total
=== 8.1 reachability: who constructs / calls the three types ===
$ git grep -rn 'new LocalPersistentControlPlane\|new FileserverControlRecordCodec\|new LocalPersistentRecoveryVerifier' -- . | grep -v '^Binary'
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodec.java:429: FilePublishReceipt receipt = new FileserverControlRecordCodec().decodeReceiptSnapshot(snapshot);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/FileserverR2Config.java:51: new LocalPersistentControlPlane(attestor, evidence);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:67: new FileserverControlRecordCodec(),
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:81: new FileserverControlRecordCodec(),
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:111: new FileserverControlRecordCodec(),
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:128: new FileserverControlRecordCodec(),
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:139: return new LocalPersistentControlPlane(
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:142: new FileserverControlRecordCodec(),
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:904: return new LocalPersistentControlPlaneException(FailureKind.CONFLICT, message);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:908: return new LocalPersistentControlPlaneException(FailureKind.INTEGRITY, message);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:912: return new LocalPersistentControlPlaneException(FailureKind.INTEGRITY, message, cause);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:916: return new LocalPersistentControlPlaneException(FailureKind.STORAGE, message);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java:920: return new LocalPersistentControlPlaneException(FailureKind.STORAGE, message, cause);
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProvider.java:46: new FileserverControlRecordCodec(),
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProvider.java:47: new LocalPersistentRecoveryVerifier());
adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentRecoveryVerifier.java:27: this(new FileserverControlRecordCodec(), new R2PublishedReferenceCodec());
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/FileserverControlRecordCodecTest.java:32: private final FileserverControlRecordCodec codec = new FileserverControlRecordCodec();
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/FileserverCrashScenarioMain.java:443: new LocalPersistentControlPlane(attestor, evidence),
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:97: .contains(new LocalPersistentControlPlane.R2StoredOperationRecord(writingRecord()));
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:106: .contains(new LocalPersistentControlPlane.R1StoredOperationRecord(published));
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:663: new FileserverControlRecordCodec().encodeOperation(writingRecord()),
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:674: new FileserverControlRecordCodec()
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:697: new FileserverControlRecordCodec()
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:706: new FileserverControlRecordCodec()
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1423: return new LocalPersistentControlPlane.FaultContext(
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1427: new LocalPersistentControlPlane.OperationFaultState(
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1435: return new LocalPersistentControlPlane.FaultContext(kind, FILE_ID, Optional.empty(), boundary);
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1554: ? new FileserverControlRecordCodec()
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1909: return new LocalPersistentControlPlane(attestor, evidence);
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1914: return new LocalPersistentControlPlane(attestor, evidence, faultCallback);
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1927: return new LocalPersistentControlPlane(
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1933: return new LocalPersistentControlPlane(
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:2074: new LocalPersistentControlPlane.SecureRecordCall(topDirectory, shard, relativeFileName));
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProviderTest.java:284: new FileserverControlRecordCodec().decodeReceiptSnapshot(operation.receiptSnapshot()))
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationProviderTest.java:401: return new LocalPersistentControlPlane(attestor, evidence);
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationRecoveryTest.java:386: new FileserverControlRecordCodec()
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationRecoveryTest.java:395: new FileserverControlRecordCodec()
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationRecoveryTest.java:516: FileserverControlRecordCodec codec = new FileserverControlRecordCodec();
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentPublicationRecoveryTest.java:1003: rewriteRecord(target, new FileserverControlRecordCodec().encodeOperation(record));
exit=0
$ git grep -rln 'LocalPersistentControlPlane\|FileserverControlRecordCodec\|LocalPersistentRecoveryVerifier' -- . | grep -v "^adapter/outbound/fileserver/" | head
exit=0
=== 8.2 conditional siblings: the two lock scopes inside one class ===
$ grep -n 'scopedOperationLockKey\|operationLockRootKey +' -A 3 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java | head -20
194: String scopedLockKey = scopedOperationLockKey(token);
195- Set<String> heldTokens = HELD_OPERATION_TOKENS.get();
196- if (heldTokens != null && heldTokens.contains(scopedLockKey)) {
197- storeOperationUpdate(target, record);
--
208: String scopedLockKey = scopedOperationLockKey(token);
209- Path lockPath = operationsDirectory.resolve(token.substring(0, 2)).resolve(token + ".lock");
210- ReentrantLock jvmLock =
211- OPERATION_LOCK_STRIPES[
--
259: return heldTokens != null && heldTokens.contains(scopedOperationLockKey(sha256(operationId)));
260- }
261-
262- boolean operationLockStripeHeldByCurrentThread(String operationId) {
--
264: String scopedLockKey = scopedOperationLockKey(sha256(operationId));
265- return OPERATION_LOCK_STRIPES[
266- Math.floorMod(scopedLockKey.hashCode(), OPERATION_LOCK_STRIPE_COUNT)]
267- .isHeldByCurrentThread();
--
exit=0
$ grep -n 'withImmutableLock' -A 12 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java | head -30
300: withImmutableLock(
301- "manifest:" + manifest.fileId(),
302- () ->
303- storeImmutable(
304- target,
305- codec.encodeManifest(manifest),
306- codec::decodeManifest,
307- manifest,
308- existing -> existing.fileId().equals(manifest.fileId())));
309- }
310-
311- Optional<PrivateFileManifest> findManifest(String fileId) {
312- FileserverControlRecordCodec.requireFileId(fileId);
--
328: withImmutableLock(
329- "reference:" + reference.fileId(),
330- () ->
331- storeImmutable(
332- target,
333- codec.encodeReference(reference),
334- codec::decodeReference,
335- reference,
336- existing -> existing.fileId().equals(reference.fileId())));
337- }
338-
339- Optional<PublishedReferenceRecord> findReference(String fileId) {
340- FileserverControlRecordCodec.requireFileId(fileId);
--
859: private static void withImmutableLock(String key, Runnable action) {
860- ReentrantLock lock =
exit=0
$ grep -n 'IMMUTABLE_LOCK_STRIPES\|OPERATION_LOCK_STRIPES' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java
43: private static final ReentrantLock[] OPERATION_LOCK_STRIPES = createOperationLockStripes();
44: private static final ReentrantLock[] IMMUTABLE_LOCK_STRIPES = createOperationLockStripes();
211: OPERATION_LOCK_STRIPES[
265: return OPERATION_LOCK_STRIPES[
861: IMMUTABLE_LOCK_STRIPES[Math.floorMod(key.hashCode(), OPERATION_LOCK_STRIPE_COUNT)];
exit=0
=== 8.2b which write primitive each path uses (why the lock shapes differ) ===
$ grep -n 'Files.move\|Files.createLink' -B 2 -A 2 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java
436- verifyAttestedIdentity();
437- if (replaceExisting) {
438: Files.move(
439- temporary, target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
440- } else {
441- try {
442: Files.createLink(target, temporary);
443- } catch (FileAlreadyExistsException collision) {
444- verifyAttestedIdentity();
exit=0
=== 8.2c requireOperationLockRootHealthy: write paths vs read paths ===
$ grep -n 'requireOperationLockRootHealthy()' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java
188: requireOperationLockRootHealthy();
213: requireOperationLockRootHealthy();
218: requireOperationLockRootHealthy();
231: requireOperationLockRootHealthy();
298: requireOperationLockRootHealthy();
326: requireOperationLockRootHealthy();
768: private void requireOperationLockRootHealthy() {
exit=0
$ grep -n 'Optional<DurablePublicationRecord> findOperation\|Optional<PrivateFileManifest> findManifest\|Optional<PublishedReferenceRecord> findReference\|Optional<StoredOperationRecord> findStoredOperation' -A 4 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java | grep -n 'requireOperationLockRootHealthy' || echo ' (no health gate on any find* path)'
(no health gate on any find* path)
exit=0
$ grep -n 'poisonedRootBlocksEveryWriteIncludingHeldLockFastPathButAllowsReads' -A 12 adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java
1066: void poisonedRootBlocksEveryWriteIncludingHeldLockFastPathButAllowsReads() throws Exception {
1067- ControlFixture fixture = controlFixture();
1068- LocalPersistentControlPlane healthy = fixture.controlPlane();
1069- healthy.storeOperation(writingRecord());
1070- healthy.storeManifest(manifest());
1071- healthy.storeReference(referenceRecord());
1072-
1073- LocalPersistentControlPlane.OperationLock held = healthy.acquireOperationLock(OPERATION_ID);
1074- RecordingLockLifecycle lifecycle = new RecordingLockLifecycle(true, true);
1075- LocalPersistentControlPlane poisoner = fixture.controlPlane(lifecycle);
1076- ExecutorService executor = Executors.newSingleThreadExecutor();
1077- try {
1078- assertFutureFailureKind(
exit=0
=== 8.3 duplicate mechanism: is POISONED set ever cleared? ===
$ grep -n 'POISONED_OPERATION_LOCK_ROOTS' adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java
46: private static final Set<String> POISONED_OPERATION_LOCK_ROOTS = ConcurrentHashMap.newKeySet();
769: if (POISONED_OPERATION_LOCK_ROOTS.contains(operationLockRootKey)) {
899: POISONED_OPERATION_LOCK_ROOTS.add(operationLockRootKey);
1433: POISONED_OPERATION_LOCK_ROOTS.add(rootKey);
exit=0
$ git grep -rn 'POISONED_OPERATION_LOCK_ROOTS\|poison' -- 'adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver' | head
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1018: ControlFixture poisonedRoot = controlFixture();
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1020: LocalPersistentControlPlane poisoned = poisonedRoot.controlPlane(lifecycle);
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1021: LocalPersistentControlPlane.OperationLock lock = poisoned.acquireOperationLock(OPERATION_ID);
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1024: assertThat(poisoned.operationLockHeldByCurrentThread(OPERATION_ID)).isFalse();
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1025: assertThat(poisoned.operationLockStripeHeldByCurrentThread(OPERATION_ID)).isFalse();
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1035: poisoned.acquireOperationLock(OPERATION_ID)) {
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1036: throw new AssertionError("poisoned root unexpectedly acquired a lock");
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1041: executor.submit(() -> poisoned.storeOperation(writingRecord())));
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1047: poisonedRoot.controlPlane().acquireOperationLock(OPERATION_ID)) {
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java:1048: throw new AssertionError("same-root instance ignored the poison latch");
exit=0
=== 8.3b the R1 fallback path inside decodeStoredOperation ===
$ grep -n 'decodeStoredOperation' -A 20 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlane.java | head -26
286: find(operationPath(operationId), this::decodeStoredOperation);
287- result.ifPresent(
288- record -> {
289- if (!record.operationId().equals(operationId)) {
290- throw integrity("operation control record identity mismatch");
291- }
292- });
293- return result;
294- }
295-
296- void storeManifest(PrivateFileManifest manifest) {
297- Objects.requireNonNull(manifest, "manifest must be non-null");
298- requireOperationLockRootHealthy();
299- Path target = fileRecordPath(manifestsDirectory, manifest.fileId());
300- withImmutableLock(
301- "manifest:" + manifest.fileId(),
302- () ->
303- storeImmutable(
304- target,
305- codec.encodeManifest(manifest),
306- codec::decodeManifest,
--
629: private StoredOperationRecord decodeStoredOperation(byte[] encoded) {
630- try {
631- return new R2StoredOperationRecord(codec.decodeOperation(encoded));
632- } catch (RuntimeException versionTwoFailure) {
exit=0
$ grep -n 'typedOperationLookupDispatchesCanonicalR2AndTerminalR1' -A 8 adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentControlPlaneTest.java
91: void typedOperationLookupDispatchesCanonicalR2AndTerminalR1FromTheSameHashedPath()
92- throws IOException {
93- ControlFixture r2Fixture = controlFixture();
94- r2Fixture.controlPlane().storeOperation(writingRecord());
95-
96- assertThat(r2Fixture.controlPlane().findStoredOperation(OPERATION_ID))
97- .contains(new LocalPersistentControlPlane.R2StoredOperationRecord(writingRecord()));
98-
99- ControlFixture r1Fixture = controlFixture();
exit=0
=== 8.4 doc/claim drift: what README says this layer guarantees ===
$ grep -n 'WRITING -> SEALED\|forced control plane\|Operation-scoped JVM and OS file locks' -A 2 adapter/outbound/fileserver/README.md
30:forces a private stage, and advances the forced control plane through:
31-
32-```text
33:WRITING -> SEALED -> DATA_PUBLISHED -> MANIFEST_PUBLISHED
34- -> REFERENCE_PUBLISHED -> PUBLISHED
35-```
exit=0
$ grep -n 'State {' -A 20 adapter/outbound/fileserver/src/main/java/dev/caskeleton/adapter/outbound/fileserver/DurablePublicationRecord.java | head -30
236: enum State {
237- WRITING(1),
238- SEALED(2),
239- DATA_PUBLISHED(3),
240- MANIFEST_PUBLISHED(4),
241- REFERENCE_PUBLISHED(5),
242- PUBLISHED(6),
243- QUARANTINED(2);
244-
245- private final long minimumRevision;
246-
247- State(long minimumRevision) {
248- this.minimumRevision = minimumRevision;
249- }
250-
251- long minimumRevision() {
252- return minimumRevision;
253- }
254- }
255-}
exit=0
$ grep -n 'crash\|fork' adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentCrashRecoveryTest.java | head -12
39: Path root = temporaryDirectory.resolve("crash-" + boundary.name().toLowerCase(Locale.ROOT));
41: ChildResult crashed = runChild("CRASH", root, boundary.name());
43: assertThat(crashed.exitCode()).isEqualTo(FileserverCrashScenarioMain.CRASH_EXIT_CODE);
44: assertThat(crashed.output()).isEmpty();
108: throw new AssertionError("forked Fileserver scenario exceeded its bounded timeout");
156: throw new AssertionError("forked lock holder exited before its protocol marker");
160: throw new AssertionError("forked lock holder exceeded its bounded marker timeout");
exit=0
$ git ls-files 'adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver' | xargs grep -ln 'FileserverCrashScenarioMain' | head
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/FileserverCrashScenarioMain.java
adapter/outbound/fileserver/src/test/java/dev/caskeleton/adapter/outbound/fileserver/LocalPersistentCrashRecoveryTest.java
exit=0