Files
document-haness/docs/clean-architecture-backend-template/final/evidence/meta/a06-f016-flamingock-probe.json
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

15 lines
7.0 KiB
JSON

{
"assetKey": "a06-f016-flamingock-probe",
"kind": "terminal",
"command": "set -e\nD=$(mktemp -d)\ntrap 'rm -rf \"$D\"' EXIT\n\ncat > \"$D/FlamingockFenceProbe.java\" <<'JAVA'\nimport dev.caskeleton.adapter.outbound.mongo.security.admin.MongoAdminAuthorization;\nimport dev.caskeleton.adapter.outbound.mongo.security.admin.MongoAdminGateway;\nimport dev.caskeleton.adapter.outbound.mongo.security.admin.MongoAdminOperation;\nimport dev.caskeleton.adapter.outbound.mongo.security.admin.MongoAdminRuntimeGuard;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigration;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationChecksum;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationContext;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationId;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationLedger;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationLock;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationPostcondition;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationPrecondition;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationResult;\nimport dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationRunner;\nimport dev.caskeleton.adapter.outbound.mongo.migration.flamingock.FlamingockLockAdapter;\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneOffset;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\n\npublic final class FlamingockFenceProbe {\n\n private static final MongoMigrationId ID = new MongoMigrationId(\"20260829-001\");\n\n public static void main(String[] args) {\n FlamingockLockAdapter flamingock =\n new FlamingockLockAdapter(() -> true, extension -> {}, () -> {});\n System.out.println(\"FlamingockLockAdapter.held() = \" + flamingock.held());\n System.out.println(\"FlamingockLockAdapter.fence() = \" + flamingock.fence()\n + \" (UNFENCED = \" + MongoMigrationLock.UNFENCED + \")\");\n System.out.println();\n\n MongoMigrationRunner runner = new MongoMigrationRunner(new EmptyLedger());\n System.out.println(\"[검사가 마이그레이션을 보기 전에 걸린다]\");\n apply(\"마이그레이션 0건\", runner, List.of(), flamingock);\n apply(\"재개 불가 1건\", runner, List.of(nonResumable()), flamingock);\n System.out.println();\n\n System.out.println(\"[같은 마이그레이션, 펜스가 있는 리스]\");\n apply(\"재개 불가 1건\", runner, List.of(nonResumable()), new FencedLock(7L));\n System.exit(0);\n }\n\n private static void apply(\n String what, MongoMigrationRunner runner, List<MongoMigration> migrations,\n MongoMigrationLock lock) {\n try {\n List<MongoMigrationResult> results = runner.apply(migrations, lock, template());\n System.out.println(\" \" + what + \" -> 실행, 결과 \" + results.size() + \"건\"\n + (results.isEmpty() ? \"\" : \" \" + results.get(0).status()));\n } catch (RuntimeException refused) {\n System.out.println(\" \" + what + \" -> 거절, \" + refused.getClass().getSimpleName());\n System.out.println(\" \" + refused.getMessage().split(\" \\\\[\")[0]);\n }\n }\n\n /** Completed in one call, so it never produces a checkpoint: not a resumable migration. */\n private static MongoMigration nonResumable() {\n return new MongoMigration() {\n @Override\n public MongoMigrationId id() {\n return ID;\n }\n\n @Override\n public MongoMigrationChecksum checksum() {\n return new MongoMigrationChecksum(\"abc\");\n }\n\n @Override\n public MongoMigrationPrecondition precondition() {\n return context -> true;\n }\n\n @Override\n public MongoMigrationResult execute(MongoMigrationContext context) {\n return MongoMigrationResult.completed(1L);\n }\n\n @Override\n public MongoMigrationPostcondition postcondition() {\n return (context, result) -> true;\n }\n };\n }\n\n private static MongoMigrationContext template() {\n MongoAdminGateway gateway =\n new MongoAdminGateway(\n new MongoAdminRuntimeGuard(true, \"app-credential\", \"migration-credential\"),\n MongoAdminAuthorization.routine(Set.of(MongoAdminOperation.APPLY_MIGRATION)),\n record -> {},\n Clock.fixed(Instant.EPOCH, ZoneOffset.UTC));\n return MongoMigrationContext.unleased(\n ID, gateway, null, 100, Duration.ZERO, Duration.ofMinutes(1), false, \"release-engineer\");\n }\n\n private static final class FencedLock implements MongoMigrationLock {\n\n private final long fence;\n\n private FencedLock(long fence) {\n this.fence = fence;\n }\n\n @Override\n public boolean held() {\n return true;\n }\n\n @Override\n public long fence() {\n return fence;\n }\n\n @Override\n public void refresh(Duration extension) {}\n\n @Override\n public void close() {}\n }\n\n private static final class EmptyLedger implements MongoMigrationLedger {\n\n @Override\n public Optional<AppliedMigration> find(MongoMigrationId migrationId) {\n return Optional.empty();\n }\n\n @Override\n public void recordApplied(\n MongoMigrationId migrationId, MongoMigrationChecksum checksum, String operator,\n Instant appliedAt, long fence) {}\n\n @Override\n public Optional<dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationCheckpoint>\n findCheckpoint(MongoMigrationId migrationId) {\n return Optional.empty();\n }\n\n @Override\n public void saveCheckpoint(\n dev.caskeleton.adapter.outbound.mongo.migration.MongoMigrationCheckpoint checkpoint,\n long fence) {}\n }\n}\nJAVA\n\nCACHE=/root/.gradle/caches/modules-2/files-2.1\nLOCK=src/adapter/outbound/persistence-mongo/gradle.lockfile\nCP=src/adapter/outbound/persistence-mongo/build/classes/java/main\nwhile IFS= read -r line; do\n coord=${line%%=*}; confs=${line#*=}\n case \",$confs,\" in *\",testRuntimeClasspath,\"*) ;; *) continue ;; esac\n g=${coord%%:*}; r=${coord#*:}; n=${r%%:*}; v=${r##*:}\n jar=$(find \"$CACHE/$g/$n/$v\" -name '*.jar' ! -name '*sources*' ! -name '*javadoc*' 2>/dev/null | head -1)\n [ -n \"$jar\" ] && CP=\"$CP:$jar\"\ndone < <(grep -E '^[a-zA-Z0-9._-]+:[^=]+=' \"$LOCK\")\n\njavac -encoding UTF-8 -cp \"$CP\" -d \"$D\" \"$D/FlamingockFenceProbe.java\"\njava -Dstdout.encoding=UTF-8 -cp \"$D:$CP\" FlamingockFenceProbe 2>&1 \\\n | grep -vE '^[0-9]{2}:[0-9]{2}:[0-9]{2}[.][0-9]{3} ' ",
"cwd": "/shared/codebase/clean-architecture-backend-template",
"exitCode": 0,
"executedAt": "2026-09-02T07:44:36+00:00",
"sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916",
"raw": "evidence/raw/a06-f016-flamingock-probe.txt",
"svg": "evidence/rendered/a06-f016-flamingock-probe.svg",
"rawSha256": "2e858aaef023f1711122a8d67e9da6c74795abb9bab32d5fc7b57fdc8298ce70",
"lines": 11,
"redaction": "none — 밀폐 탐침 실행 출력, 자격증명 없음"
}