Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/assembly-ownership/case/case-observation-downgraded-by-the-composition.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, body, assets, evidence, source
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn body assets evidence source
CASE observation-downgraded-by-the-composition 관측을 필수 생성자 인자로 만든 수정을 조립이 6인자 생성자로 되돌렸다 assembly-ownership clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 case:observation-downgraded-by-the-composition 2026-09-01 case-observation-downgraded-by-the-composition.body.md
key file
observation-downgraded-by-the-composition ../../../final/evidence/rendered/observation-downgraded-by-the-composition.svg
../../../final/evidence/raw/observation-downgraded-by-the-composition.txt
../../../final/evidence/raw/tl-messaging-observation-noop.txt
원본 분석 절은 final/document.md#5-2 · analysis/19 §5.1 이다.

관측을 필수 생성자 인자로 만든 수정을 조립이 6인자 생성자로 되돌렸다

발행기는 관측 구현을 필수 인자로 요구하는 생성자를 갖고 있다. 자동설정이 관측 인자가 없는 짧은 생성자를 부르고, 그 생성자는 no-op 관측으로 위임한다. 출하 배포에서 메시징 관측은 아무것도 기록하지 않는다.

관계

  • @Bean이 있다는 것은 조립 증거가 아니다 타입이 요구하는 것과 조립이 넘기는 것이 다를 수 있다는 사례다.
  • 조립 결함을 판정하려면 조립하는 쪽을 먼저 읽어야 한다 발행기만 읽으면 관측이 필수로 보인다.
  • outbox가 둘이고, 출하되는 것은 messaging 플랫폼 쪽이 아니다 같은 조립 지점에서 나온 다른 공백이다.

문제

DefaultMessagePublisher 는 생성자가 둘이다.

7인자 : 관측 인자가 없고, NO_OBSERVATION 으로 위임한다 8인자 : 관측을 받고 Objects.requireNonNull 로 검사한다

8인자 쪽 javadoc 은 그것이 모든 결과를 기록하는 발행기라고 적는다. 7인자 쪽은 주입 가능한 시계를 위한 것이라고 적는다.

NO_OBSERVATION 은 필드 javadoc 이 그 성격을 밝힌다. 메트릭을 배선하지 않은 배포를 위한 no-op 관측이다. 여섯 개 기록 메서드가 전부 빈 본문이다.

결론

자동설정이 6인자 호출을 한다.

MessagingCoreAutoConfiguration 의 messagingPublisher 빈은 여섯 개 협력자만 받아 6인자 생성자를 호출한다. 그 생성자는 다시 7인자로, 7인자는 8인자로 NO_OBSERVATION 을 넣어 위임한다.

결과적으로 출하 배포의 발행기는 발행도, 전달도, 정산도, 백로그도, 진단도 기록하지 않는다. 관측 인터페이스는 존재하고 구현체도 존재하지만 그 사이를 잇는 조립이 없다.

이 실패의 성격은 조용하다. 빈은 생성되고 발행은 정상 동작하며 로그에도 신호가 없다. no-op 구현이 명시적으로 존재하기 때문에 널 참조도 예외도 나지 않는다. 관측이 꺼진 것과 관측이 배선되지 않은 것이 런타임에서 구별되지 않는다.

@ConditionalOnMissingBean 이 붙어 있으므로 애플리케이션이 자기 MessagePublisher 빈을 등록하면 이 자동설정은 물러난다. 그러나 이 저장소의 출하 컴포지션은 그렇게 하지 않는다.

검증 환경

OpenJDK : 21.0.12 Gradle : 9.0.0 Spring Boot : 4.0.8 확인 방식 : 정적 도달성 확인. 애플리케이션을 부팅하지 않았다 소스 수정 : x

재현 조건

원문은 final/evidence/raw/tl-messaging-observation-noop.txt 에 있다.

  1. DefaultMessagePublisher 의 생성자 두 개와 NO_OBSERVATION 필드를 읽는다.
  2. 6인자 호출이 7인자로, 7인자가 8인자로 위임하며 관측 자리에 NO_OBSERVATION 이 들어가는 경로를 확인한다.
  3. MessagingCoreAutoConfiguration 의 messagingPublisher 빈이 몇 개의 인자로 생성자를 부르는지 확인한다.

본문

관측을 선택적 데코레이터가 아니라 필수 생성자 인자로 만든 수정이 runtime-core에 있고 그 javadoc이 "an unobserved publish path is how 'the dashboards were empty during the incident' happens"로 이유를 적는다.

관측을 필수 인자로 만든 수정

:::evidence key="observation-downgraded-by-the-composition" alt="분석 문서 final/document.md 에서 이 기록의 근거 절을 그대로 잘라낸 18줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md 발췌 — 18줄" zoom="true" :::

조립이 그 수정을 되돌린다

자동설정은 6인자 생성자를 골라 NO_OBSERVATION(다섯 메서드 전부 빈 본문)을 주입하고, 방출자 넷은 main 참조 0이며 등록되는 것은 협력자 둘뿐이다.

같은 경로가 예외 메시지를 의도적으로 버린다

둘이 합쳐지면 진단 흔적이 남지 않는다.

확인하지 못한 것

애플리케이션을 부팅해 액추에이터에서 messaging 메트릭 시리즈의 부재를 관측하지 않았다. 부팅 한 번이면 확증된다.