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>
135 lines
10 KiB
Markdown
135 lines
10 KiB
Markdown
---
|
|
kind: CASE
|
|
slug: a19-f003-messaging-reliability-api
|
|
title: messaging-reliability-api는 main 13파일 · 817 LOC에 테스트가 0개다
|
|
topic: messaging-and-outbox
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: case:a19-f003-messaging-reliability-api
|
|
evidenceCapturedOn: 2026-09-04
|
|
body: case-a19-f003-messaging-reliability-api.body.md
|
|
assets:
|
|
- key: a19-f003-messaging-reliability-api
|
|
file: ../../../final/evidence/rendered/a19-f003-messaging-reliability-api.svg
|
|
evidence:
|
|
- ../../../final/evidence/raw/a19-f003-messaging-reliability-api.txt
|
|
source:
|
|
- 원본 분석 절은 analysis/19-messaging-platform.md#L325 이다.
|
|
---
|
|
|
|
# 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
|
|
|
|
## 재현 조건
|
|
|
|
1. 이 하위 범위의 리프 넷을 나열하고 각각의 src 아래 디렉터리를 읽는다.
|
|
2. 리프마다 main 과 test 파일 수, 그리고 main 원시 줄 수를 센다.
|
|
3. 그 줄 수를 공백과 주석과 코드로 나눈다.
|
|
4. 테스트 디렉터리가 없는 리프의 타입을 전부 나열하고 선언 형태와 줄 수를 확인한다.
|
|
5. 두 열거형의 메서드 수를 세고, 전이 규칙이 실제로 선언된 자리를 찾는다.
|
|
6. 같은 리프의 다른 열거형이 값에 규칙을 실었는지 확인한다.
|
|
7. 원문이 지목한 구현 리프 이름이 실재하는지 확인하고, 같은 문서의 표가 적은 실제 이름과 계수를 읽는다.
|
|
8. 두 열거형의 test 참조를 셀 때 자바독과 문자열 리터럴을 먼저 걷어낸다.
|
|
9. 열세 타입 각각에 대해 test 참조와 자기 파일 밖 main 참조를 센다.
|
|
|
|
## 본문
|
|
|
|
<!-- body:start -->
|
|
|
|
`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 개다. 모듈이 아니라 빌드 산출물이 남은 자리로 보고 계수에서 뺐다.
|
|
|
|
<!-- body:end -->
|