Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/verification-path-coverage/case/case-messaging-nats-experimental-f01.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

5.0 KiB

kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source, module, priority
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn assets evidence source module priority
CASE messaging-nats-experimental-f01 deduplicatedPublish 를 무조건 참으로 선언하는데 실제 중복 제거는 프로파일에 창이 있을 때만 일어난다 verification-path-coverage clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 case:messaging-nats-experimental-f01 2026-09-01
key file
messaging-nats-experimental-f01 ../../../final/evidence/rendered/messaging-nats-experimental-f01.svg
key file
messaging-nats-experimental-f01-diagram ../../../final/assets/diagrams/messaging-nats-experimental-f01.svg
../../../final/evidence/raw/messaging-nats-experimental-f01.txt
원본 분석 절은 analysis/messaging/messaging-nats-experimental.md#L146 이다.
messaging-nats-experimental P2

deduplicatedPublish 를 무조건 참으로 선언하는데 실제 중복 제거는 프로파일에 창이 있을 때만 일어난다

검증기의 capabilities() 도 같은 값을 돌려준다. 그런데 중복 제거 식별자는 프로파일에 창이 있을 때만 만들어진다.

문제

검증기의 capabilities() 도 같은 값을 돌려준다.

그런데 중복 제거 식별자는 프로파일에 창이 있을 때만 만들어진다.

결론

NatsJetStreamProfile.deduplicationWindow 는 Optional 이고, 비어 있는 것이 정상 상태다 — 프로파일 생성자도 검증기도 창을 요구하지 않는다.

창이 없으면 Nats-Msg-Id 가 실리지 않고 서버는 중복을 제거하지 않는다.

즉 능력 선언이 프로파일과 무관하게 참이다.

이 저장소에서 능력 열두 개 중 부재가 예외를 만드는 유일한 것이 deduplicatedPublish 다(DefaultMessagePublisher:250).

나머지는 읽히지 않거나 분기에 쓰인다.

그러므로 이 플래그의 과대 선언은 다른 어느 플래그의 과대 선언보다 직접적이다 — 창 없는 목적지가 그 가드를 통과한다.

클래스 javadoc: "when the profile enables one" 이 정확히 능력이 담지 않은 조건이다.

창이 없는 목적지에서 모호를 재시도하면 스트림에 같은 메시지가 두 번 들어간다.

검증 환경

OpenJDK : 21.0.12 java -version 으로 확인 Gradle : 9.0.0 src/gradle/wrapper/gradle-wrapper.properties 의 distributionUrl 로 확인 확인 방식 : NatsJetStreamProfile 참조 17건 검색과 능력 상수 대비 중복 제거 식별자 생성 조건 확인 소스 수정 : x

재현 조건

원문은 analysis/messaging/messaging-nats-experimental.md#L146 에 있다.

본문

능력은 상수이고 검증기의 capabilities() 도 같은 값을 돌려준다. 그런데 중복 제거 식별자는 프로파일에 창이 있을 때만 만들어진다.

선언과 실제가 갈리는 조건

:::evidence key="messaging-nats-experimental-f01-diagram" alt="창 없는 프로파일이 능력은 참과 가드 통과를 지나 중복 저장으로 이어진다" caption="선언과 실제가 갈리는 조건" zoom="false" :::

NatsJetStreamProfile.deduplicationWindowOptional<Duration> 이고, 비어 있는 것이 정상 상태다 — 프로파일 생성자도 검증기도 창을 요구하지 않는다. 창이 없으면 Nats-Msg-Id 가 실리지 않고 서버는 중복을 제거하지 않는다.

NatsJetStreamProfile 참조 위치

:::evidence key="messaging-nats-experimental-f01" alt="코드베이스에서 NatsJetStreamProfile 를 검색한 출력 17줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="NatsJetStreamProfile 코드베이스 검색 — 17줄 · exit 0" zoom="true" :::

이 플래그의 과대 선언이 가장 직접적이다

능력 열두 개 중 부재가 예외를 만드는 유일한 것이 deduplicatedPublish 다(DefaultMessagePublisher:250). 나머지는 읽히지 않거나 분기에 쓰인다. 그러므로 창 없는 목적지가 그 가드를 통과한다. 클래스 javadoc 의 "when the profile enables one" 이 정확히 능력이 담지 않은 조건이고, 창이 없는 목적지에서 모호를 재시도하면 스트림에 같은 메시지가 두 번 들어간다.

모순이 테스트로 고정되어 있다

NatsAdapterContractTest 안에서 같은 빈 창 프로파일(confirming(Optional.empty()))에 대해 둘 다 통과한다. 우연히 남은 것이 아니라는 뜻이고, 수정할 때 함께 고쳐야 할 지점이 어디인지도 이 두 개가 알려 준다.

수정

능력을 프로파일에서 파생시킨다. NatsJetStreamProfile.durable(...) 는 창을 2분으로 채워 주지만 호출자가 없고, 정규 생성자는 빈 창을 정상값으로 받는다(§4).

확인하지 못한 것

중복 제거 창이 없는 프로파일로 모호 재발행을 재현하지 않았다. 실제 JetStream 서버를 띄우지 않았다 — 클라이언트 브리지를 싣지 않는 리프다.