Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/analysis-finding-a06-f014.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

193 lines
12 KiB
Plaintext

# 매니페스트가 선언하는 것
MongoIndexManifest.java:11 /**
MongoIndexManifest.java:12 * One declared index, with everything a diff or a review needs (design §18).
MongoIndexManifest.java:13 *
MongoIndexManifest.java:14 * <p>Two fields carry most of the weight. {@code expectedUsage} names the operations the index
MongoIndexManifest.java:15 * exists for, which is what makes "is this index still needed" answerable without guessing from
MongoIndexManifest.java:16 * production statistics. {@code metadataOwnership} says who created it, which is what keeps drift
MongoIndexManifest.java:17 * cleanup from proposing to drop an encryption or search index it did not declare.
MongoIndexManifest.java:18 *
MongoIndexManifest.java:19 * <p>Key order is preserved because it is part of the index's identity, not a presentation detail.
MongoIndexManifest.java:20 */
MongoIndexManifest.java:21 public record MongoIndexManifest(
MongoIndexManifest.java:22 String name,
MongoIndexManifest.java:23 List<MongoIndexKey> keys,
MongoIndexManifest.java:24 boolean unique,
MongoIndexManifest.java:25 boolean sparse,
MongoIndexManifest.java:26 boolean hidden,
MongoIndexManifest.java:27 boolean deprecated,
MongoIndexManifest.java:28 String partialFilterExpression,
MongoIndexManifest.java:29 String collationProfile,
MongoIndexManifest.java:30 Duration expireAfter,
MongoIndexManifest.java:31 String wildcardProjection,
MongoIndexManifest.java:32 boolean shardKeySupport,
MongoIndexManifest.java:33 Set<String> expectedUsage,
MongoIndexManifest.java:34 String owner,
MongoIndexManifest.java:35 MongoMetadataOwnership metadataOwnership) {
MongoIndexManifest.java:36
MongoIndexManifest.java:37 public MongoIndexManifest {
MongoIndexManifest.java:38 Objects.requireNonNull(name, "name");
MongoIndexManifest.java:39 Objects.requireNonNull(keys, "keys");
MongoIndexManifest.java:40 Objects.requireNonNull(partialFilterExpression, "partialFilterExpression");
MongoIndexManifest.java:41 Objects.requireNonNull(collationProfile, "collationProfile");
MongoIndexManifest.java:42 Objects.requireNonNull(wildcardProjection, "wildcardProjection");
MongoIndexManifest.java:43 Objects.requireNonNull(expectedUsage, "expectedUsage");
MongoIndexManifest.java:44 Objects.requireNonNull(owner, "owner");
MongoIndexManifest.java:45 Objects.requireNonNull(metadataOwnership, "metadataOwnership");
# 비교용 뷰가 나르는 것
MongoIndexDescriptorView.java:6 /**
MongoIndexDescriptorView.java:7 * An index as it actually exists on the server (design §18).
MongoIndexDescriptorView.java:8 *
MongoIndexDescriptorView.java:9 * <p>Read through the D4 admin client and reduced to the fields a diff can compare. Ownership is
MongoIndexDescriptorView.java:10 * inferred here rather than trusted from the manifest, because the whole purpose of the diff is to
MongoIndexDescriptorView.java:11 * find indexes the manifest does not know about — and some of those belong to encryption or search
MongoIndexDescriptorView.java:12 * and must never be proposed for deletion.
MongoIndexDescriptorView.java:13 */
MongoIndexDescriptorView.java:14 public record MongoIndexDescriptorView(
MongoIndexDescriptorView.java:15 String collection,
MongoIndexDescriptorView.java:16 String name,
MongoIndexDescriptorView.java:17 String keySignature,
MongoIndexDescriptorView.java:18 boolean unique,
MongoIndexDescriptorView.java:19 boolean hidden,
MongoIndexDescriptorView.java:20 MongoMetadataOwnership metadataOwnership) {
# 비교 엔진이 실제로 견주는 것
MongoIndexDiffEngine.java:25 /** Compares one collection's declared indexes with the observed ones. */
MongoIndexDiffEngine.java:26 public MongoIndexDiff compare(
MongoIndexDiffEngine.java:27 MongoCollectionManifest manifest, Collection<MongoIndexDescriptorView> observed) {
MongoIndexDiffEngine.java:28 Objects.requireNonNull(manifest, "manifest");
MongoIndexDiffEngine.java:29 Objects.requireNonNull(observed, "observed");
MongoIndexDiffEngine.java:30
MongoIndexDiffEngine.java:31 Map<String, MongoIndexDescriptorView> observedByName = new LinkedHashMap<>();
MongoIndexDiffEngine.java:32 for (MongoIndexDescriptorView view : observed) {
MongoIndexDiffEngine.java:33 observedByName.put(view.name(), view);
MongoIndexDiffEngine.java:34 }
MongoIndexDiffEngine.java:35
MongoIndexDiffEngine.java:36 List<String> create = new ArrayList<>();
MongoIndexDiffEngine.java:37 List<String> change = new ArrayList<>();
MongoIndexDiffEngine.java:38 List<String> hide = new ArrayList<>();
MongoIndexDiffEngine.java:39 List<String> dropCandidates = new ArrayList<>();
MongoIndexDiffEngine.java:40
MongoIndexDiffEngine.java:41 for (MongoIndexManifest declared : manifest.indexes()) {
MongoIndexDiffEngine.java:42 MongoIndexDescriptorView actual = observedByName.get(declared.name());
MongoIndexDiffEngine.java:43 if (actual == null) {
MongoIndexDiffEngine.java:44 if (!declared.deprecated()) {
MongoIndexDiffEngine.java:45 create.add(qualify(manifest, declared.name()));
MongoIndexDiffEngine.java:46 }
MongoIndexDiffEngine.java:47 continue;
MongoIndexDiffEngine.java:48 }
MongoIndexDiffEngine.java:49 if (!actual.keySignature().equals(declared.keySignature())
MongoIndexDiffEngine.java:50 || actual.unique() != declared.unique()) {
MongoIndexDiffEngine.java:51 // Same name, different definition: MongoDB will not silently re-create it, so a rebuild has
MongoIndexDiffEngine.java:52 // to be planned rather than discovered when a query starts scanning.
MongoIndexDiffEngine.java:53 change.add(qualify(manifest, declared.name()));
MongoIndexDiffEngine.java:54 }
MongoIndexDiffEngine.java:55 if (declared.hidden() && !actual.hidden()) {
MongoIndexDiffEngine.java:56 hide.add(qualify(manifest, declared.name()));
MongoIndexDiffEngine.java:57 }
MongoIndexDiffEngine.java:58 }
MongoIndexDiffEngine.java:59
MongoIndexDiffEngine.java:60 for (MongoIndexDescriptorView actual : observedByName.values()) {
MongoIndexDiffEngine.java:61 if (!actual.metadataOwnership().droppableByApplicationDrift()) {
MongoIndexDiffEngine.java:62 continue;
MongoIndexDiffEngine.java:63 }
MongoIndexDiffEngine.java:64 if (manifest.index(actual.name()).isEmpty()) {
MongoIndexDiffEngine.java:65 dropCandidates.add(qualify(manifest, actual.name()));
MongoIndexDiffEngine.java:66 }
MongoIndexDiffEngine.java:67 }
MongoIndexDiffEngine.java:68
MongoIndexDiffEngine.java:69 create.sort(String::compareTo);
MongoIndexDiffEngine.java:70 change.sort(String::compareTo);
한 줄에서 declared 값과 actual 값을 견주는 줄 : 3 개
MongoIndexDiffEngine.java:49 if (!actual.keySignature().equals(declared.keySignature())
MongoIndexDiffEngine.java:50 || actual.unique() != declared.unique()) {
MongoIndexDiffEngine.java:55 if (declared.hidden() && !actual.hidden()) {
[참고] 그 반복문에서 declared 나 actual 이 나오는 줄 전부 :
MongoIndexDiffEngine.java:42 MongoIndexDescriptorView actual = observedByName.get(declared.name());
MongoIndexDiffEngine.java:44 if (!declared.deprecated()) {
MongoIndexDiffEngine.java:45 create.add(qualify(manifest, declared.name()));
MongoIndexDiffEngine.java:49 if (!actual.keySignature().equals(declared.keySignature())
MongoIndexDiffEngine.java:50 || actual.unique() != declared.unique()) {
MongoIndexDiffEngine.java:53 change.add(qualify(manifest, declared.name()));
MongoIndexDiffEngine.java:55 if (declared.hidden() && !actual.hidden()) {
MongoIndexDiffEngine.java:56 hide.add(qualify(manifest, declared.name()));
# 뷰에 없어서 견줄 수 없는 요소
매니페스트 요소 : 14 개
뷰 요소 : 6 개
각 요소가 뷰에 있는가 :
name 뷰에 있음
keys 뷰에 없음
unique 뷰에 있음
sparse 뷰에 없음
hidden 뷰에 있음
deprecated 뷰에 없음
partialFilterExpression 뷰에 없음
collationProfile 뷰에 없음
expireAfter 뷰에 없음
wildcardProjection 뷰에 없음
shardKeySupport 뷰에 없음
expectedUsage 뷰에 없음
owner 뷰에 없음
metadataOwnership 뷰에 있음
[자기검증] 매니페스트 요소가 14 개가 아니면 실패 : 14 확인
# 빈 보고서가 무엇으로 읽히는가
MongoIndexDiff.java:1 package dev.caskeleton.adapter.outbound.mongo.schema.index;
MongoIndexDiff.java:2
MongoIndexDiff.java:3 import java.util.List;
MongoIndexDiff.java:4 import java.util.Objects;
MongoIndexDiff.java:5
MongoIndexDiff.java:6 /**
MongoIndexDiff.java:7 * The difference between declared and observed indexes (design §18).
MongoIndexDiff.java:8 *
MongoIndexDiff.java:9 * <p>Every list is sorted so the diff is byte-identical for the same inputs. A CI artifact that
MongoIndexDiff.java:10 * reorders between runs cannot be diffed against the previous run, which is most of what an index
MongoIndexDiff.java:11 * drift report is for.
MongoIndexDiff.java:12 *
MongoIndexDiff.java:13 * <p>{@code dropCandidates} is named for what it is: a proposal that still has to pass deprecation,
MongoIndexDiff.java:14 * hiding, observation and approval before anything is dropped.
MongoIndexDiff.java:15 */
MongoIndexDiff.java:16 public record MongoIndexDiff(
MongoIndexDiff.java:17 List<String> create, List<String> change, List<String> hide, List<String> dropCandidates) {
MongoIndexDiff.java:18
MongoIndexDiff.java:19 public MongoIndexDiff {
MongoIndexDiff.java:20 Objects.requireNonNull(create, "create");
MongoIndexDiff.java:21 Objects.requireNonNull(change, "change");
MongoIndexDiff.java:22 Objects.requireNonNull(hide, "hide");
MongoIndexDiff.java:23 Objects.requireNonNull(dropCandidates, "dropCandidates");
MongoIndexDiff.java:24 create = List.copyOf(create);
MongoIndexDiff.java:25 change = List.copyOf(change);
MongoIndexDiff.java:26 hide = List.copyOf(hide);
MongoIndexDiff.java:27 dropCandidates = List.copyOf(dropCandidates);
MongoIndexDiff.java:28 }
MongoIndexDiff.java:29
MongoIndexDiff.java:30 /** A diff with no differences. */
MongoIndexDiff.java:31 public static MongoIndexDiff empty() {
MongoIndexDiff.java:32 return new MongoIndexDiff(List.of(), List.of(), List.of(), List.of());
MongoIndexDiff.java:33 }
MongoIndexDiff.java:34
MongoIndexDiff.java:35 /** True when declared and observed state already agree. */
MongoIndexDiff.java:36 public boolean isClean() {
MongoIndexDiff.java:37 return create.isEmpty() && change.isEmpty() && hide.isEmpty() && dropCandidates.isEmpty();
MongoIndexDiff.java:38 }
MongoIndexDiff.java:39
MongoIndexDiff.java:40 /** A stable, line-oriented rendering suitable for a CI artifact. */
MongoIndexDiff.java:41 public String render() {
MongoIndexDiff.java:42 StringBuilder report = new StringBuilder();
MongoIndexDiff.java:43 appendSection(report, "create", create);
MongoIndexDiff.java:44 appendSection(report, "change", change);
MongoIndexDiff.java:45 appendSection(report, "hide", hide);
MongoIndexDiff.java:46 appendSection(report, "drop-candidate", dropCandidates);
MongoIndexDiff.java:47 return report.toString();
MongoIndexDiff.java:48 }
MongoIndexDiff.java:49
MongoIndexDiffEngine 이 main 에 나오는 줄 : 1 개
MongoIndexDiffEngine.java:23 public final class MongoIndexDiffEngine {
[대조] 시험에서 그 엔진의 compare 를 부르는 줄 : 4 개
MongoIndexDiffEngineTest.java:30 MongoIndexDiff diff = engine.compare(manifest, observed);
MongoIndexDiffEngineTest.java:42 MongoIndexDiff diff = engine.compare(applicationManifest(), observed);
MongoIndexDiffEngineTest.java:49 MongoIndexDiff diff = engine.compare(applicationManifest(), List.of());
MongoIndexDiffEngineTest.java:61 MongoIndexDiff diff = engine.compare(applicationManifest(), observed);