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>
10 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, body, assets, evidence, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | evidenceCapturedOn | body | assets | evidence | source | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CASE | a19-f003-messaging-reliability-api | messaging-reliability-api는 main 13파일 · 817 LOC에 테스트가 0개다 | messaging-and-outbox | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:a19-f003-messaging-reliability-api | 2026-09-04 | case-a19-f003-messaging-reliability-api.body.md |
|
|
|
messaging-reliability-api는 main 13파일 · 817 LOC에 테스트가 0개다
네 리프 중 messaging-reliability-api 만 src 아래에 main 디렉터리만 있다. 담긴 것은 outbox 와 inbox 계약 타입 열셋인데, 그중 넷은 어느 시험도 이름을 대지 않는다.
관계
- outbox 가 둘이고, 출하되는 것은 messaging 플랫폼 쪽이 아니다
이 리프가 선언한
OutboxRepository를 구현하는 것은 저쪽이 다루는 스택이고, 출하되는 outbox 는application-core의 별도 포트를 쓴다. - 소비자가 없는 fixture 셋 저쪽은 세 타입을 참조하는 소스가 test 와 testFixtures 양쪽에서 0 이고, 여기는 리프에 test 소스 세트 자체가 없다.
- 계약만 담는 leaf도 계약의 거절 조건은 자기 레인에서 검증한다
이 리프에
test디렉터리가 없어서, 레코드 생성자가 거는 검증과 열거형이 든 술어가 이 리프의 레인에서는 한 번도 실행되지 않는다.
문제
이 하위 범위에 리프가 넷 있다.
각 리프에 어떤 소스 세트가 있고 파일이 몇인지, 그리고 시험이 없는 리프의 타입을 무엇이 참조하는지 셌다.
결론
테스트 디렉터리가 있는 리프가 셋, 없는 리프가 하나다.
형제 셋은 각각 test 파일을 8, 4, 4 개 갖는다. messaging-reliability-api 만 0 이고, 그 리프에는 test 디렉터리 자체가 없다.
제목의 817 은 원시 줄 수다. 그중 415 줄이 자바독이고 남는 코드가 323 줄이다.
열세 타입은 레코드 다섯, 인터페이스 다섯, 열거형 셋이다. 큰 것은 OutboxCanonicalMetadata(158줄)와 OutboxRepository(152줄)와 OutboxRecord(140줄)다.
상태 전이를 담는다고 알려진 두 열거형은 메서드가 0 개다. OutboxStatus 와 OutboxTransitionResult 는 전이의 어휘를 정의할 뿐이고, 규칙은 OutboxRepository 의 자바독 계약과 그것을 강제하는 JDBC 구현에 있다. 규칙을 값으로 든 것은 InboxResult 뿐이다.
참조는 다른 리프에 있다. 자바독과 문자열 리터럴을 걷어낸 뒤 세면 OutboxStatus 쪽이 여섯 파일, OutboxTransitionResult 쪽이 네 파일이다.
그렇다고 열세 타입이 모두 시험된다고 읽으면 안 된다. 넷은 test 참조가 0 이고, InboxRecord 와 ReliableMessagePublisher 는 자기 파일 밖 main 참조도 0 이다.
판정은 P3 이고 원문과 같다.
검증 환경
확인 방식 : 리프별 소스 세트와 파일·줄 수 계수, 817 줄의 분해, 열세 타입의 선언 형태와 메서드 수, 전이 규칙이 적힌 자리 추적, 자바독을 걷어낸 뒤의 참조 재계수 소스 수정 : x
재현 조건
- 이 하위 범위의 리프 넷을 나열하고 각각의 src 아래 디렉터리를 읽는다.
- 리프마다 main 과 test 파일 수, 그리고 main 원시 줄 수를 센다.
- 그 줄 수를 공백과 주석과 코드로 나눈다.
- 테스트 디렉터리가 없는 리프의 타입을 전부 나열하고 선언 형태와 줄 수를 확인한다.
- 두 열거형의 메서드 수를 세고, 전이 규칙이 실제로 선언된 자리를 찾는다.
- 같은 리프의 다른 열거형이 값에 규칙을 실었는지 확인한다.
- 원문이 지목한 구현 리프 이름이 실재하는지 확인하고, 같은 문서의 표가 적은 실제 이름과 계수를 읽는다.
- 두 열거형의 test 참조를 셀 때 자바독과 문자열 리터럴을 먼저 걷어낸다.
- 열세 타입 각각에 대해 test 참조와 자기 파일 밖 main 참조를 센다.
본문
messaging 플랫폼의 첫 하위 범위에 리프가 넷 있다. 셋은 자기 test 디렉터리를 갖고 하나는 갖지 않는다.
네 리프의 소스 세트와 817 줄의 내역
:::evidence key="a19-f003-messaging-reliability-api" alt="저장소 루트에서 돌린 정적 검색 출력 70줄. 네 리프의 main·test 파일 수와 main 줄 수와 소스 세트가 먼저 나오는데 messaging-reliability-api 만 소스 세트가 main 하나다. 이어서 그 817 줄이 공백 79 · 주석 415 · 코드 323 으로 갈리고, 열세 타입이 선언 형태와 줄 수로 나열된다. 그다음 InboxResult 만 isSafeToSettle 이라는 메서드를 갖고 OutboxStatus 와 OutboxTransitionResult 의 메서드 수가 0 이며, 전이 규칙이 OutboxRepository 의 자바독에 적혀 있다는 것이 보인다. 원문 §3.6 이 지목한 두 리프 이름은 src 디렉터리가 없고 같은 문서의 표가 적은 실제 이름 셋의 계수가 이어진다. jpa 쌍은 modules.json 등재 0 건 git 추적 파일 0 개다. 끝으로 주석과 문자열을 제거하고 단어 경계로 다시 센 두 열거형의 test 참조가 파일별 횟수와 소속 리프까지 나오고, 열세 타입 중 test 참조가 0 인 넷이 보인다." caption="네 리프의 소스 세트 · 817 줄의 내역 · 열세 타입과 메서드 수 · 실제 구현 리프 이름 · 재계수한 참조와 참조 0 인 넷 — 70줄 · exit 0" zoom="true" :::
messaging-core-api 는 main 85 에 test 8, messaging-transport-spi 는 13 에 4, messaging-runtime-core 는 6 에 4 다. messaging-reliability-api 만 main 13 에 test 0 이고, 그 리프의 src 아래에는 main 디렉터리 하나만 있다.
main 줄 수 817 은 원시 줄 수다. 갈라 보면 공백 79, 주석 415, 코드 323 이다. 절반이 자바독이라 제목의 817 LOC 를 구현 규모로 읽으면 두 배 넘게 과장된다.
열세 타입이 무엇인가
레코드가 다섯이다. OutboxCanonicalMetadata(158줄), OutboxRecord(140줄), ClaimCheckReference(50줄), OutboxLease(42줄), InboxRecord(27줄).
인터페이스가 다섯이다. OutboxRepository(152줄), InboxRepository(53줄), IdempotentMessageHandler(33줄), TransactionalMessageAction(29줄), ReliableMessagePublisher(27줄).
열거형이 셋이다. InboxResult(45줄), OutboxStatus(37줄), OutboxTransitionResult(24줄).
두 열거형은 규칙이 아니라 어휘다
OutboxStatus 와 OutboxTransitionResult 는 메서드가 0 개다. 상수와 자바독뿐이고 전이를 판정하는 코드가 없다.
규칙이 선언된 자리는 OutboxRepository 의 자바독이다. :70 이 확정된 발행 기록을 이 임차가 아직 그 행을 소유할 때만 한다고 적고, :72 가 다른 릴레이가 가져갔으면 STALE_LEASE 를 돌려준다고 적으며, :87 이 모호한 결과에 같은 조건을 건다. 강제하는 것은 JDBC 구현의 SQL 이다.
이 리프에서 실행 가능한 규칙을 가진 열거형은 InboxResult 하나다. :42 의 isSafeToSettle() 이 CLAIMED_ELSEWHERE 에서 정산하면 효과가 사라진다는 것을 값으로 들고 있다.
계약 타입은 다른 리프의 시험이 참조한다
주석과 문자열을 제거하고 단어 경계로 다시 세면 OutboxStatus 를 참조하는 test 는 여섯 파일이고 전부 messaging-outbox-jdbc-postgresql 안에 있다. 가장 많이 쓰는 것은 OutboxRelayTest(18회)와 OutboxPostgresIT(8회)다.
OutboxTransitionResult 는 네 파일이다. OutboxRelayTest(19회), OutboxOperationsTest(11회), MessagingOutboxRelayLifecycleTest(7회), OutboxPostgresIT(4회)이고 마지막 하나만 다른 리프다.
다만 열세 중 넷은 test 참조가 0 이다. IdempotentMessageHandler, InboxRecord, ReliableMessagePublisher, TransactionalMessageAction 이고, 그중 InboxRecord 와 ReliableMessagePublisher 는 자기 파일 밖 main 참조도 0 이다.
그래서 이 리프의 계약이 전부 시험된다는 뜻은 아니다. 시험되는 타입은 다른 리프에서 시험되고, 시험되지 않는 타입이 넷 있다.
원문과 갈리는 자리
원문 §3.6 은 구현 쪽 확인을 다음 범위로 넘기면서 messaging-outbox-jdbc 와 messaging-inbox-jdbc 를 지목했다. 그 이름의 src 디렉터리는 없다.
다만 이것은 미확인이 아니라 축약 표기다. 같은 문서의 리프 표가 messaging-outbox-jdbc-postgresql, messaging-inbox-jdbc-postgresql, messaging-claim-check 를 실제 이름으로 싣고 있다. 세 리프 모두 자기 시험을 갖는다 — 각각 main 13 에 test 8, main 6 에 test 4, main 6 에 test 3 이다. 원문의 표는 리소스를 포함한 다른 기준으로 세어 수치가 다르다.
원문이 OutboxTransitionResult 와 OutboxStatus 를 "상태 전이 규칙을 담을 수 있는 타입" 이라고 조심스럽게 적은 것도 그대로 옳다. 둘 다 메서드가 없어서 담을 수 있을 뿐 담고 있지는 않다.
확인하지 못한 것
두 열거형에 전이 로직이 없다는 것은 메서드 계수와 본문 읽기로 판정했다. OutboxRepository 의 자바독 계약을 JDBC 구현이 실제로 어떻게 강제하는지는 SQL 을 열어 보지 않았다.
참조 계수는 파일 수와 등장 횟수다. 어느 시험이 무엇을 단언하는지까지는 들어가지 않았다.
두 열거형에 전이 로직이 없다는 것은 메서드 계수와 본문 읽기로 판정했다. OutboxRepository 의 자바독 계약을 JDBC 구현이 실제로 어떻게 강제하는지는 SQL 을 열어 보지 않았다.
messaging-outbox-jpa 와 messaging-inbox-jpa 디렉터리는 modules.json 등재가 0 건이고 git 이 추적하는 파일도 0 개다. 모듈이 아니라 빌드 산출물이 남은 자리로 보고 계수에서 뺐다.