Files
document-haness/docs/clean-architecture-backend-template/notes/tech-log-concept-recall-audit.md
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

125 lines
14 KiB
Markdown

# Tech-Log CONCEPT recall audit — cycle 2
> 대상: canonical module SSOT **61편**. 목적은 "이 프로젝트를 이해하려면 알아야 할, 실제로 구현된 메커니즘"을
> CONCEPT 로 회수했는지에 대한 증명이다. `§17 손볼 것` 은 이 pass 의 입력이 아니다 — CONCEPT 는 SSOT 본문의
> 메커니즘 절(모듈 정체·경계, 계약·불변식, 상태 모델, 실행 흐름, 성공/실패, 트랜잭션·동시성·수명주기,
> 설정·활성화, 외부 시스템 상호작용, "확인된 설계(문제 아님)")에서 나온다.
## 방법
1. 61개 SSOT 의 모든 `##`·`###` 헤딩에서 **메커니즘을 이름 짓는 절**만 후보로 남겼다. finding 절(`P1|P2|P3`)과
bookkeeping 절(denominator·완료 조건·coverage ledger·테스트 레인·Source anchors 등)은 제외했다.
2. 상위 절이 이미 같은 메커니즘을 덮는 하위 절은 **MERGED** — 예: `5. idempotency, inbox, outbox` 아래의
`5.1 idempotency`·`5.2 inbox`·`5.3 outbox`.
3. 독립 기록으로 설명할 본문이 부족한 절(정제 후 120자 미만)은 **REJECTED**.
4. quota 는 만들지 않았다. 모듈당 0~60 까지 편차가 있고, 그 편차는 SSOT 의 메커니즘 밀도를 그대로 따른다.
## 전체 수치
| 항목 | 값 |
|---|---:|
| canonical module SSOT | 61 / 61 |
| concept candidate reviewed (메커니즘 절) | **568** |
| EMITTED CONCEPT | **360** |
| MERGED (상위 메커니즘에 흡수) | **138** |
| REJECTED (본문 부족) | **70** |
| 이번 pass 이전 CONCEPT | 26 |
| 최종 CONCEPT | **386** |
| CONCEPT 0건 모듈 | 5 |
## 모듈별
| module | concept candidates reviewed | emitted CONCEPT | merged | rejected | reason / mechanism summary |
|---|---:|---:|---:|---:|---|
| `adapter-inbound-graphql` | 16 | 13 | 0 | 3 | (8.2) 조건 형제 비교 — off 계약의 두 절반 · (8.2) 조건 형제 비교 — 스키마 해시의 생산자와 소비자 · (8.2) 조건 형제 비교 — 연산 정체성을 정하는 두 구현 … |
| `adapter-inbound-grpc` | 1 | 1 | 0 | 0 | (8.3) 중복 메커니즘 — 인증과 예외 처리의 인터셉터 순서 |
| `adapter-inbound-web` | 24 | 19 | 0 | 5 | (8.2) 조건 형제 비교 — 두 자동설정의 게이트 · (8.4) 문서/구현 드리프트 — 모듈 경계 선언과 실제 트리 · (8.1) 도달성 — 신원 모델의 프로덕션 참조 수 … |
| `adapter-inbound-websocket` | 7 | 5 | 0 | 2 | 이 모듈의 형태 — 하나의 leaf, 세 개의 설정 네임스페이 · (8.1) 도달성 — 정책의 실제 적용 지점 · (8.4) 카운트 — `WebSocketFailureCateg … |
| `adapter-outbound-cache-redis` | 13 | 13 | 0 | 0 | 조립의 순서가 클래스 하나에 고정돼 있다 · Confirmed — raw allowlist 기본값은 없는 · Confirmed — "설계상 부재" 주장 6건이 구현·정책 … |
| `adapter-outbound-fileserver` | 8 | 8 | 0 | 0 | Confirmed — 적재 경로는 auto-configurat · Confirmed — codec이 "canonical"을 왕복 · Confirmed — 상태 전이가 인접 행렬이고 termina … |
| `adapter-outbound-httpclient` | 10 | 9 | 1 | 0 | `ClientProfileValidator` — 34개 위반 · `ClientRuntimeRegistry` — 세대 교체가 틈 · `ObjectBody`의 재생 가능성 판정 — 값의 성질이지 … |
| `adapter-outbound-identifier` | 0 | 0 | 0 | 0 | SSOT 본문이 전부 finding 절이다. 유일한 정상 설계 절(가명화기)은 독립 기록으로 낼 만큼의 메커니즘 서술이 없고 키 취급 규칙은 이미 REFERENCE 로 존재한다. |
| `adapter-outbound-messaging` | 4 | 4 | 0 | 0 | 레지스트리가 "닫혀 있다"는 것의 의미 · 봉투 작성이 파서를 거치지 않는다 · 계약이 컴파일되어 닫힌다 … |
| `adapter-outbound-notification` | 10 | 6 | 0 | 4 | "이름 없는 상태"를 없애는 것이 이 sub-scope의 주제 · (8.3) 중복 메커니즘 — 종료 경로 · (8.1) 도달성 — provider가 준 `Retry-Aft … |
| `adapter-outbound-objectstorage` | 9 | 9 | 0 | 0 | Confirmed — "컴파일이 먼저, 생성은 나중"이 실제 · Confirmed — legacy가 세 겹으로 격리돼 있다 · Confirmed — 후보로 본 unguarded split은 … |
| `adapter-outbound-persistence-jpa` | 82 | 58 | 22 | 2 | Sub-scope 02 — API contracts (`api · Capability API — 실행 기능과 지원 등급을 rep · Error API — provider exception을 st … |
| `adapter-outbound-persistence-mongo` | 9 | 9 | 0 | 0 | opt-in은 네 겹이고, 각 겹이 서로 다른 실패를 막는다 · mapping의 나머지는 manifest를 실제로 강제한다 · 실행 scope의 고정된 순서가 이 sub-scope의 중심이 … |
| `adapter-outbound-support` | 9 | 6 | 2 | 1 | 모듈의 정체와 경계 · `FailOpenDependencyLogger`: 진단을 bu · global masking도 이 보장을 복구하지 않는다 … |
| `app-bootstrap` | 7 | 5 | 0 | 2 | (8.3) 중복 메커니즘 — 세 개의 환경 검증기 · — 다섯 어댑터 범위는 런타임 멤버십 레지스트리와 일치한다 ( · (8.4) 카운트 — `.imports` 여섯 줄과 다섯 능력 … |
| `application-core` | 17 | 11 | 6 | 0 | 모듈 경계와 빌드 의존성 · authorization: permission과 object · transaction: framework vocabulary … |
| `domain-core` | 3 | 3 | 0 | 0 | 관찰: 재사용 가능한 도메인 “내용”보다 도메인 모델링 계약을 · Runtime reachability / wiring · Success / failure mechanics |
| `grpc-admin` | 4 | 2 | 0 | 2 | 건강 레지스트리 — 낙관에서 시작하지 않는다 · 배수 순서 |
| `grpc-advanced-bootstrap` | 4 | 3 | 0 | 1 | 능력 15종과 등급 4종 · 게이트가 세 조건을 순서대로 본다 · 승격 게이트 |
| `grpc-advanced-compat` | 2 | 0 | 0 | 2 | 두 절 모두 '무엇을 거절하는가'로 finding 성격이고 독립 메커니즘 서술이 아니다. |
| `grpc-advanced-diagnostics` | 5 | 2 | 0 | 3 | 모듈의 정체 · 두 겹의 게이트 |
| `grpc-advanced-edition` | 1 | 0 | 0 | 1 | 메커니즘 절이 '모듈의 정체' 하나이고, 두 레인의 성격은 `concept:three-sources-of-a-capability-answer` 와 승격 게이트 노드가 덮는다. |
| `grpc-advanced-resilience` | 3 | 2 | 0 | 1 | 헤징 예산 · xDS 시작 가드 |
| `grpc-advanced-streaming` | 2 | 1 | 0 | 1 | 수동 흐름 제어 |
| `grpc-client` | 2 | 0 | 0 | 2 | '세대와 배수' 절이 있으나 본문이 짧다. 그 메커니즘은 `concept:check-then-act-on-atomic-types` 가 가족 수준에서 덮는다. |
| `grpc-codegen` | 4 | 1 | 0 | 3 | 소비자 컴파일 게이트 |
| `grpc-core-api` | 2 | 1 | 0 | 1 | Stable 모듈 목록과 불변식 |
| `grpc-discovery` | 3 | 1 | 0 | 2 | 생성자가 거부하는 것과 검증기가 보고하는 것 |
| `grpc-observability` | 4 | 3 | 1 | 0 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식 |
| `grpc-operation-ledger-jpa` | 4 | 3 | 0 | 1 | 스키마가 계약이다 · 저장 키와 유니크 제약이 같은 행을 가리킨다 · 상태 전이 |
| `grpc-policy` | 4 | 1 | 0 | 3 | 재개 토큰 — 서명하고, 구분자를 봉인한다 |
| `grpc-proto-contract` | 1 | 0 | 0 | 1 | 메커니즘 절이 '모듈의 정체' 하나뿐이고 본문이 짧다. 이 리프의 실제 메커니즘(규칙 엔진과 게이트)은 TOPIC 3·17 의 CONCEPT 와 CASE 가 이미 덮는다. |
| `grpc-server` | 5 | 1 | 0 | 4 | 인터셉터 순서 계약 |
| `grpc-spring-boot-starter` | 2 | 2 | 0 | 0 | 모듈의 정체와 격리 규칙 · 검증기가 담은 규칙 |
| `grpc-testkit` | 2 | 1 | 0 | 1 | 릴리스 게이트 — 문서가 후속이 아니라 차단 사유다 |
| `messaging-admin-api` | 13 | 7 | 5 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-admin-runtime` | 12 | 7 | 4 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-claim-check` | 11 | 7 | 3 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-cloudevents` | 13 | 8 | 5 | 0 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 패키지/컴포넌트 지도 … |
| `messaging-core-api` | 23 | 8 | 15 | 0 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 패키지/컴포넌트 지도 … |
| `messaging-inbox-jdbc-postgresql` | 15 | 7 | 7 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-kafka` | 4 | 2 | 0 | 2 | 소비자 런타임 — 스레드 규율이 설계다 · 커밋은 연속 워터마크로만 전진한다 |
| `messaging-kafka-share-experimental` | 12 | 7 | 4 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-nats-experimental` | 2 | 2 | 0 | 0 | 능력 선언 · 프로파일이 스스로 거부하는 것 |
| `messaging-observability` | 12 | 7 | 4 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-outbox-jdbc-postgresql` | 13 | 6 | 5 | 2 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-policy` | 16 | 9 | 6 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-pulsar-experimental` | 2 | 1 | 0 | 1 | 실패 분류 — 타입 있는 신호만 본다 |
| `messaging-rabbit` | 2 | 2 | 0 | 0 | 소비·정착·죽은 편지의 세 규율 · 자격증명은 연결 시도마다 해석된다 |
| `messaging-reliability-api` | 16 | 7 | 8 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-runtime-core` | 16 | 7 | 8 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-schema-api` | 14 | 7 | 6 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-schema-avro` | 12 | 7 | 4 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-schema-json` | 11 | 7 | 3 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-schema-protobuf` | 9 | 7 | 1 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-security` | 14 | 7 | 6 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-spring-boot-starter` | 3 | 3 | 0 | 0 | 선택은 닫힌 레지스트리이고, 등록과 조립은 다르다 · 설정이 프로파일이 된다 · 종료 순서가 두 수명 주기의 phase 로 표현된다 |
| `messaging-spring-cloud-stream-bridge` | 14 | 6 | 6 | 2 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `messaging-testkit` | 9 | 8 | 1 | 0 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 패키지/컴포넌트 지도 … |
| `messaging-transport-spi` | 13 | 7 | 5 | 1 | 모듈의 정체와 경계 · 의존성과 런타임 배선 · 계약·불변식·상태 모델 … |
| `shared-contract` | 4 | 4 | 0 | 0 | 주요 계약과 불변식 · Permission · Activation and health snapshot … |
| **합계** | **568** | **360** | **138** | **70** | |
## CONCEPT 0건 모듈과 사유
- `adapter-outbound-identifier` — SSOT 본문이 전부 finding 절이다. 유일한 정상 설계 절(가명화기)은 독립 기록으로 낼 만큼의 메커니즘 서술이 없고 키 취급 규칙은 이미 REFERENCE 로 존재한다.
- `grpc-advanced-compat` — 두 절 모두 '무엇을 거절하는가'로 finding 성격이고 독립 메커니즘 서술이 아니다.
- `grpc-advanced-edition` — 메커니즘 절이 '모듈의 정체' 하나이고, 두 레인의 성격은 `concept:three-sources-of-a-capability-answer` 와 승격 게이트 노드가 덮는다.
- `grpc-client` — '세대와 배수' 절이 있으나 본문이 짧다. 그 메커니즘은 `concept:check-then-act-on-atomic-types` 가 가족 수준에서 덮는다.
- `grpc-proto-contract` — 메커니즘 절이 '모듈의 정체' 하나뿐이고 본문이 짧다. 이 리프의 실제 메커니즘(규칙 엔진과 게이트)은 TOPIC 3·17 의 CONCEPT 와 CASE 가 이미 덮는다.
## CONCEPT 와 REFERENCE 를 쌍으로 둔 자리
같은 source 에서 둘 다 나올 수 있다. 이 pass 는 그 둘을 대체 관계로 쓰지 않았다.
| source 메커니즘 | CONCEPT | REFERENCE |
|---|---|---|
| Kafka 연속 워터마크 커밋 | 커밋은 연속 워터마크로만 전진한다 | 완료된 offset 사이에 gap 이 있으면 commit position 을 넘기지 않는다 |
| 자격증명 회전 | 준비 후 교체 후 배수 | 공유 런타임 교체는 준비 → 원자 교체 → 이전 세대 drain 순서로 한다 |
| 원자 타입 위의 갱신 | 검사 후 실행과 비교 후 교체 루프 | `Atomic*` 타입의 존재는 원자성의 증거가 아니다 |
| bounded/unbounded 오버로드 | 두 형태를 나란히 둔 포트 | 두 형태를 나란히 내놓는 포트는 이미 안전하지 않은 쪽을 고른 것이다 |
| 8단계 종료 계약 | 선언된 순서와 실제 종료 경로 | 선언 순서를 단언하는 테스트는 그 순서를 읽는 코드가 있을 때만 게이트다 |
## REFERENCE semantic audit 결과
REFERENCE 105건을 전수 검토했다. 규칙 형태(rule · purpose · scope · exceptions)를 갖추지 못하고
**관측 문장**으로 남아 있던 41건을 다시 썼다. 그 41건의 규칙 문장은 대부분 SSOT 자신이 괄호로 적어 둔 것이고
(40/41), 나머지 1건은 cycle 1 의 규칙이라 누락된 scope·exceptions 만 채웠다.
재작성 후 105 / 105 가 rule-shaped 다. 구체 사건은 규칙 기록에 섞지 않고 `source` 의 finding 이 소유한다.