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>
111 lines
4.5 KiB
Markdown
111 lines
4.5 KiB
Markdown
---
|
|
kind: CASE
|
|
slug: analysis-finding-a19-f018
|
|
title: claim-check는 starter에 배선 코드가 한 줄도 없다
|
|
topic: messaging-and-outbox
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: case:analysis-finding-a19-f018
|
|
evidenceCapturedOn: 2026-09-01
|
|
body: case-analysis-finding-a19-f018.body.md
|
|
assets:
|
|
- key: analysis-finding-a19-f018
|
|
file: ../../../final/evidence/rendered/analysis-finding-a19-f018.svg
|
|
evidence:
|
|
- ../../../final/evidence/raw/analysis-finding-a19-f018.txt
|
|
source:
|
|
- 원본 분석 절은 analysis/19-messaging-platform.md#L926 이다.
|
|
---
|
|
|
|
# claim-check는 starter에 배선 코드가 한 줄도 없다
|
|
|
|
출하 리프의 두 진입 타입이 주 참조 0 건이고 신뢰성 자동 설정에 그 이름이 아예 나오지 않는다. 프로파일은 임계값을 선언할 수 있고 검증도 받는데 그것을 수행하는 코드가 조립되지 않는다.
|
|
|
|
## 관계
|
|
|
|
- **상호운용 규격 leaf는 출하되고 starter의 의존이며 소비자가 없다**
|
|
같은 가족의 같은 형태다.
|
|
- **두 개의 outbox 중 하나만 조립되어 있다**
|
|
같은 계열의 조립 문제다.
|
|
- **조용한 잘못된 성공이 아니라 시끄러운 실패다**
|
|
판정을 낮춘 이유다.
|
|
|
|
## 문제
|
|
|
|
청구 확인 리프가 출하된다. 주 파일 여섯에 사백여 줄이다.
|
|
|
|
바깥에서 들어오는 경로가 있는지 확인했다.
|
|
|
|
## 결론
|
|
|
|
없다.
|
|
|
|
발행자와 해석기의 주 참조가 0 건이고, 신뢰성 자동 설정에 이 이름의 문자열이 등장하지 않는다.
|
|
|
|
무결성 가드와 정책과 저장소는 리프 내부에서 서로를 참조한다. 그러므로 리프는 내부적으로 일관되다.
|
|
|
|
다만 바깥에서 들어오는 경로가 없다.
|
|
|
|
목적지 프로파일 검증기는 이 기능을 알고 있다.
|
|
|
|
임계값이 최대 크기보다 크면 거부한다.
|
|
|
|
즉 프로파일은 임계값을 선언할 수 있고 검증도 받는데, 그 임계값을 넘는 적재물에 대해 이 기능을 수행하는 코드가 조립되지 않는다.
|
|
|
|
임계값은 설정 가능하고 효과는 없다.
|
|
|
|
같은 가족의 발신함 사례보다 낮은 등급으로 두는 이유가 있다.
|
|
|
|
이 기능은 부재 시 동작이 명확하다.
|
|
|
|
적재물이 그대로 전송되고, 크기 한도에 걸리면 전용 예외로 명시적으로 실패한다.
|
|
|
|
조용한 잘못된 성공이 아니라 시끄러운 실패다.
|
|
|
|
판정은 P3 다.
|
|
|
|
## 검증 환경
|
|
|
|
확인 방식 : 참조 계수와 자동 설정 문자열 검색
|
|
소스 수정 : x
|
|
|
|
## 재현 조건
|
|
|
|
원문은 final/evidence/raw/252 계열에 있다.
|
|
|
|
1. 리프의 주 파일과 줄 수를 센다.
|
|
2. 두 진입 타입의 주 참조를 센다.
|
|
3. 신뢰성 자동 설정에서 이 이름을 검색한다.
|
|
4. 리프 내부의 상호 참조를 확인한다.
|
|
5. 목적지 프로파일 검증기의 관련 규칙을 확인한다.
|
|
|
|
## 본문
|
|
|
|
<!-- body:start -->
|
|
|
|
`messaging-claim-check`(6 main, 418 LOC, **출하**)의 `ClaimCheckPublisher`·`ClaimCheckResolver`는 main 참조 0건이고, `MessagingReliabilityAutoConfiguration`에 `ClaimCheck` 문자열이 등장하지 않는다.
|
|
|
|
## ClaimCheckPublisher 참조 위치
|
|
|
|
:::evidence key="analysis-finding-a19-f018" alt="코드베이스에서 ClaimCheckPublisher 를 검색한 출력 2줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="ClaimCheckPublisher 코드베이스 검색 — 2줄 · exit 0" zoom="true"
|
|
:::
|
|
|
|
## leaf는 내부적으로 일관되고 바깥 경로가 없다
|
|
|
|
`ClaimCheckIntegrityGuard`·`ClaimCheckPolicy`·`ClaimCheckStore`는 leaf 내부에서 서로를 참조한다.
|
|
|
|
## 임계값은 설정 가능하고 효과는 없다
|
|
|
|
`DestinationProfileValidator`는 claim check를 알고 있다 — `profile.payload().claimCheckThresholdBytes() > profile.payload().maxBytes()`를 거부한다. 즉 프로파일은 claim check 임계값을 선언할 수 있고 검증도 받지만, 그 임계값을 넘는 payload에 대해 claim check를 수행하는 코드가 조립되지 않는다.
|
|
|
|
## P3으로 두는 이유
|
|
|
|
claim check는 outbox와 달리 **부재 시 동작이 명확**하다 — payload가 그대로 전송되고, 크기 한도(`BoundedByteSink`, §4.1)에 걸리면 `MessageTooLargeException`으로 명시적으로 실패한다. 조용한 잘못된 성공이 아니라 시끄러운 실패다.
|
|
|
|
## 확인하지 못한 것
|
|
|
|
임계값을 넘는 적재물을 보내 그대로 전송되는 것을 재현하지 않았다. 조립 부재상 그 결과가 나온다.
|
|
|
|
<!-- body:end -->
|