docs(clean-architecture-backend-template): 제1부가 채택한 것만 글감으로 남기고 다시 고른다

글감 1,001개 중 제1부(§3~§11) 앵커를 하나라도 가진 것은 112개뿐이었다. 나머지 889개는
제2부 모듈 분석 65편의 절 제목에서 나온 것이고, 그것이 재판정이 필요했던 이유다.

  주제      44 → 16   (43개가 독자 질문 없이 있었다. 지금은 전부 있다)
  글감   1,001 → 123  (제1부 앵커 112 + 제1부가 채택했는데 비어 있던 자리 11)
  후보      965 → 1,088 · PENDING 905 → 0
  error   3,042 → 0

내려온 889개는 후보 대장에 KEEP_IN_SSOT 로 남는다 — 버린 것이 아니라 분석에 남기고 독립
기록으로 만들지 않기로 한 것이다. 그 글감을 받치던 기록 파일 828개는 지웠다. 계약이 정본이고,
파일이 남아 있다는 이유로 계약에서 뺀 주제가 되살아나면 안 된다. 이력에는 그대로 있다 —
git checkout a0ca2bb -- <경로>.

제1부가 채택했는데 글감이 없던 자리 열하나를 채웠다: mongo high-water mark 가 재전달 이벤트를
삼킨 P1, admin plane 이 가드만 켜고 서비스는 켜지 않은 것과 그 짝인 결정, 실패 어휘 세 층과
SQLState 매트릭스 병합 규칙, 부하 아래에서만 새는 admission 경계, 발행 증거와 완료 판정의
분리, keyset·JSONB 결정 둘.

Concept 17개에 basis-version 을 채우고, 계약 제목과 기록 제목이 갈라져 있던 23건을 기록 쪽에
맞췄다. candidateScope 에 excludedAnchorPattern 을 적어 제2부 앵커만 가진 글감이 다시 올라올
수 없게 한다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-09-07 15:02:25 +09:00
co-authored by Claude Opus 5
parent a0ca2bb72a
commit 1f04117bbf
851 changed files with 5498 additions and 90638 deletions
@@ -1,96 +0,0 @@
---
kind: CASE
slug: the-same-repository-bound-a-decision-once-and-not-the-other-time
title: 같은 저장소가 "결정을 그 결정이 판정한 대상에 묶는 것"을 한 번은 맞게, 한 번은 틀리게 썼다
topic: duplicate-mechanisms
project: clean-architecture-backend-template
status: 게시 전
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
rootTreeNode: case:the-same-repository-bound-a-decision-once-and-not-the-other-time
evidenceCapturedOn: 2026-09-01
assets:
- key: the-same-repository-bound-a-decision-once-and-not-the-other-time
file: ../../../final/evidence/rendered/the-same-repository-bound-a-decision-once-and-not-the-other-time.svg
evidence:
- ../../../final/evidence/raw/the-same-repository-bound-a-decision-once-and-not-the-other-time.txt
source:
- 원본 분석 절은 final/document.md#a20-grpc-codegen §17.4 · final/document.md#a20-grpc-advanced-bootstrap(확인된 설계) 이다.
---
# 같은 저장소가 "결정을 그 결정이 판정한 대상에 묶는 것"을 한 번은 맞게, 한 번은 틀리게 썼다
두 리프가 판정과 기록을 두 호출로 나눈다. 한쪽은 결정이 자기가 밟고 선 상태를 들고 있어 적용 시점에 대조하고, 다른 쪽은 결정이 무엇을 판정했는지 들고 있지 않아 짝이 어긋날 수 있다.
## 관계
- **중복 장치를 찾으면 어느 쪽이 조립됐는지 먼저 확인한다**
같은 형태의 장치가 둘일 때 쓰는 규칙이다.
- **같은 자격 증명 회전 결함이 한 가족에서 닫히고 다른 가족에서 재현됐다**
같은 저장소가 같은 형태를 두 번 다르게 쓴 다른 사례다.
- **검증기는 발행이 아니라 주입이 강제다**
판정이 실제로 걸리는 지점을 묻는 계열의 규칙이다.
## 문제
판정과 기록을 나누면 그 사이를 무엇이 묶는지가 문제가 된다.
스키마 산출물 발행자는 후보와 소비자 픽스처 목록을 받아 발행 가능 여부를 결정으로 돌려준다. 그리고 그 결정을 들고 다시 오면 이력에 기록한다. 발행 결정은 허용 여부와 차단 사유 목록으로 되어 있다.
승격 지원 매트릭스도 같은 형태다. 승격 게이트가 증거와 시작 등급과 목표 등급을 받아 결정을 돌려주고, 매트릭스가 그 결정을 받아 적용한다.
## 결론
한쪽만 짝을 확인한다.
승격 매트릭스는 결정의 시작 등급이 현재 등급과 다르면 던진다. 예외 메시지가 그 이유를 적는다. 두 승격이 경합했거나 하나가 재생된 경우라는 것이다. 결정이 자기가 밟고 선 상태를 들고 있고 적용 시점에 그것을 대조한다.
스키마 발행자는 결정이 허용인지만 본다. 그 결정이 지금 발행하려는 후보를 판정한 것인지 확인하지 않는다. 발행 결정 객체가 허용 여부와 차단 사유만 갖고 있어서 확인할 재료도 없다.
그래서 무해한 후보를 평가한 결정으로 다른 후보를 발행할 수 있다. 그 후보는 어떤 소비자 픽스처와도 대조되지 않고, 이미 발행된 버전인지도 확인되지 않은 채 이력에 들어간다. 이 클래스가 존재하는 이유인 두 규칙, 즉 소비자 컴파일 게이트와 릴리스 버전 불변성이 인자 짝 하나로 무력해진다.
테스트의 차이도 같다. 발행자 테스트는 평가와 발행을 한 줄에 겹쳐 써서 규율을 지킨다. 그 규율을 코드가 강제하지 않는다. 매트릭스 쪽에는 어긋난 짝을 넣어 거부를 확인하는 테스트가 따로 있다.
이 저장소는 올바른 형태를 알고 있고 한 곳에서 쓰지 않았다.
## 검증 환경
OpenJDK : 21.0.12
Gradle : 9.0.0
확인 방식 : 두 적용 메서드의 본문 대조와 결정 객체의 성분 확인
소스 수정 : x
## 재현 조건
1. 스키마 발행자의 평가 메서드와 발행 메서드가 각각 무엇을 검사하는지 적는다.
2. 발행 결정 객체의 성분을 나열한다.
3. 승격 매트릭스의 적용 메서드가 결정의 어떤 성분을 현재 상태와 대조하는지 확인한다.
4. 두 테스트가 각각 짝을 어떻게 맞추는지 확인한다.
## 본문
<!-- body:start -->
두 리프가 같은 문제를 푼다 — 판정과 기록이 두 호출로 나뉠 때 그 사이를 무엇이 묶는가.
## PublishDecision 참조 위치
:::evidence key="the-same-repository-bound-a-decision-once-and-not-the-other-time" alt="코드베이스에서 PublishDecision 를 검색한 출력 4줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="PublishDecision 코드베이스 검색 — 4줄 · exit 0" zoom="true"
:::
## 묶지 않은 쪽
`GrpcSchemaArtifactPublisher.publish(candidate, decision)``decision.allowed()` 만 보고 기록한다. `PublishDecision``(boolean, List<String>)` 뿐이라 자기가 무엇을 판정했는지 들고 있지 않으므로, A 를 평가한 결정으로 B 를 발행할 수 있고 그러면 소비자 컴파일 게이트와 릴리스 버전 불변성을 둘 다 우회한다. 이 클래스가 존재하는 이유인 두 규칙이 인자 짝 하나로 무력해진다.
## 묶은 쪽
`GrpcAdvancedSupportMatrix.apply(decision)` 는 결정의 `from` 이 현재 등급과 다르면 던지고, 그 이유를 "두 승격이 경합했거나 하나가 재생된 경우" 라고 적는다. 결정이 자기가 밟고 선 상태를 들고 있고 적용 시점에 대조하는 형태다.
## 두 테스트의 차이도 같다
전자의 테스트는 `publish(artifact, evaluate(artifact, …))` 로 한 줄에서 짝을 맞춰 규율을 지키지만 코드가 그것을 강제하지 않고, 후자는 어긋난 짝을 넣는 테스트가 따로 있다.
## 확인하지 못한 것
어긋난 짝을 실제로 실행해 보지 않았다. 판정은 발행 메서드 본문에 대조 코드가 없다는 것에 근거한다.
<!-- body:end -->