Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/_meta/editorial/editorial-exceptions.json
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

185 lines
13 KiB
JSON

{
"schemaVersion": 1,
"project": "clean-architecture-backend-template",
"reviewedAt": "2026-09-01T15:43:48Z",
"note": "검토를 마치고 유지하기로 한 editorial finding 의 원장이다. 감사 도구는 여기 있는 항목을 ACCEPTED 로, 없는 항목을 UNREVIEWED 로 보고한다. 제목이 바뀌면 titleSha256 이 어긋나 그 항목은 다시 UNREVIEWED 가 된다 — 한 번 승인했다고 영원히 넘어가지 않는다. 제목을 다시 써서 60자 아래로 내려간 항목은 가리킬 발견이 없으므로 여기서 지운다 — 낡은 항목은 tools/editorial_quality/detect_stale_exceptions.py 가 찾는다.",
"criteria": {
"PROTECTED_IDENTIFIER": "길이가 보호 대상 식별자(코드 심볼 · 설정 키 · SQL 구문 · 고유명)에서 온다",
"PAIRED_CONTRAST": "사건 자체가 두 사실의 대비이고, 한쪽을 빼면 사건이 사라진다",
"ENUMERATION_IS_THE_EVENT": "열거된 항목 자체가 관측의 실질이다",
"TECHNICAL_QUALIFIER": "수치나 위치 같은 기술적 한정어가 결함의 규모·범위를 정한다"
},
"exceptions": {
"LONG_TITLE": {
"a-digest-that-covered-who-but-not-what": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "덮은 것과 덮지 않은 것의 대비가 digest 결함의 정의다.",
"path": "case/case-a-digest-that-covered-who-but-not-what.md",
"title": "transition digest가 \"누가·언제\"만 덮고 \"무엇\"을 덮지 않아 다른 전이를 같다고 보고했다",
"titleSha256": "b3fc797d1c1ba2153d91cef24a0b120b215f9caf2e85976967196d585a711629"
},
"a-five-second-string-that-broke-every-prod-deploy": {
"status": "ACCEPTED",
"category": "PROTECTED_IDENTIFIER",
"reason": "connection-timeout: 5s 는 설정 키와 값 그대로다. 그 문자열이 사건의 원인이다.",
"path": "case/case-a-five-second-string-that-broke-every-prod-deploy.md",
"title": "connection-timeout: 5s가 모든 prod 배포를 시작 실패시켰고 local만 통과했다",
"titleSha256": "b3e9857acb4647200bc420b861507cf22389bf9b05b5eed35a905afe15ef6e54"
},
"a16-f004-graphqloperationnamepolicy": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "배선된 쪽과 미배선 쪽 중 정책 타입을 쓰는 것이 미배선 쪽이라는 역전이 사건이다.",
"path": "case/case-a16-f004-graphqloperationnamepolicy.md",
"title": "연산 이름 정책의 두 구현 중 하나만 배선되고, 미배선 쪽만 GraphQlOperationNamePolicy를 쓴다",
"titleSha256": "d72780971c6a7742d779b1b6df1600edd6ee83b8c14f4059b987a983bd8175c3"
},
"a17-f002-stomp": {
"status": "ACCEPTED",
"category": "ENUMERATION_IS_THE_EVENT",
"reason": "연결 티켓·origin 정책·메시지 권한·연결 예산 네 통제의 열거가 실질이고, 뒤 절이 그중 일부의 예외를 정한다.",
"path": "case/case-a17-f002-stomp.md",
"title": "연결 티켓·origin 정책·메시지 권한·연결 예산이 요청 경로 밖이고, 그중 일부는 STOMP 어댑터가 다른 방식으로 대체한다",
"titleSha256": "19246d62702500370586a97fd1bb90dce46e5c277ee3498773f1433e3233c5f7"
},
"a19-f003-messaging-reliability-api": {
"status": "ACCEPTED",
"category": "TECHNICAL_QUALIFIER",
"reason": "main 13파일 · 817 LOC · 테스트 0개 라는 세 수치의 비율이 관측 자체다. 수치를 빼면 남는 것이 없다.",
"path": "case/case-a19-f003-messaging-reliability-api.md",
"title": "messaging-reliability-api는 main 13파일 · 817 LOC에 테스트가 0개다",
"titleSha256": "d94de5ec6f540c39653aa918da71f98fe4975b8609140889143911fb76f4ff50"
},
"analysis-finding-a06-f027": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "실제로 차단하는 것과 없는 것의 대비가 검증 지형 관측 자체다.",
"path": "case/case-analysis-finding-a06-f027.md",
"title": "release gate가 실제로 차단하는 것은 hermetic test 3개이고, mongo용 CI workflow는 없다",
"titleSha256": "1e576f89ecf30db51c9b63a612d7fc3588fd631531fbcc5362818874fb7463f7"
},
"analysis-finding-a08-f004": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "경로 기반이라는 것과 그것을 지키는 사전검사가 스스로 근사라고 적었다는 인용의 대비다.",
"path": "case/case-analysis-finding-a08-f004.md",
"title": "발행 rename만 경로 기반이고, 그것을 지키는 것은 이 모듈이 \"근사에 불과하다\"고 적은 사전검사다",
"titleSha256": "ed49f9e7783938fc6810385172713197c4c3aa4f51405125e2fa5346dca44f32"
},
"analysis-finding-a13-f010": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "FCM 만 규칙 밖이라는 것과 그 FCM 이 두 계약 집합 어디에도 없다는 것이 함께여야 사각지대가 성립한다.",
"path": "case/case-analysis-finding-a13-f010.md",
"title": "FCM만 \"커밋 후 응답 손실 = ambiguous\" 규칙 밖에 있고, 그 FCM이 두 계약 집합 어디에도 없다",
"titleSha256": "4b12e9c90a97c8df82f6ccc5fa6336cabf14618675e78b1e187d94ca18cf0eac"
},
"analysis-finding-a16-f001": {
"status": "ACCEPTED",
"category": "ENUMERATION_IS_THE_EVENT",
"reason": "스키마 조립·계약 정체성·해시 사슬 셋이 통째로 미배선이라는 열거가 규모를 정하고, 액추에이터 엔드포인트가 네 번째다.",
"path": "case/case-analysis-finding-a16-f001.md",
"title": "스키마 조립·계약 정체성·해시 사슬이 통째로 미배선이고, 그것을 발행할 액추에이터 엔드포인트도 등록되지 않는다",
"titleSha256": "e5f6e1f12deaa7f333a81801998a0ed09245ce00dbfaac04b4b7e76249456d58"
},
"autoconfiguration-in-name-only": {
"status": "ACCEPTED",
"category": "TECHNICAL_QUALIFIER",
"reason": "세 클래스라는 수와 capability 리포트에 Stable 로 올랐다는 결과가 사건의 두 축이다.",
"path": "case/case-autoconfiguration-in-name-only.md",
"title": "이름만 AutoConfiguration이던 세 클래스가 capability 리포트에 Stable로 올라 있었다",
"titleSha256": "fed765b2bcafabffa436bbb66b658d38be4889bf0a29428fe3ce577666a01a42"
},
"conditionalonbean-evaluated-at-parse-time": {
"status": "ACCEPTED",
"category": "PROTECTED_IDENTIFIER",
"reason": "@ConditionalOnBean(DataSource.class) 는 애너테이션 표기 그대로가 원인이다. 인자 타입까지가 조건이다.",
"path": "case/case-conditionalonbean-evaluated-at-parse-time.md",
"title": "@ConditionalOnBean(DataSource.class)가 클래스 파싱 시점에 평가되어 여덟 빈이 사라졌다",
"titleSha256": "2f89d628a8e05f3943701661fc17a44b77d6b2a131943fb5a11a5927b7ece67e"
},
"grpc-proto-contract-f01": {
"status": "ACCEPTED",
"category": "PROTECTED_IDENTIFIER",
"reason": "reserved 2 to 5; 는 오탐을 만드는 원문 구문이고 RESERVED_HISTORY 는 위반 코드다. 둘 다 그대로여야 재현된다.",
"path": "case/case-grpc-proto-contract-f01.md",
"title": "reserved 2 to 5; 범위가 개별 숫자로만 수집되어 RESERVED_HISTORY 오탐이 된다",
"titleSha256": "ddb7fe8063fa09028571f1a8647c86b29e73bfc042bcabfaf7c013e4c6d6a2f0"
},
"messaging-inbox-jdbc-postgresql-f01": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "구현돼 있다는 것과 호출되지 않는다는 것의 대비이고, 뒤 절이 그 결과다.",
"path": "case/case-messaging-inbox-jdbc-postgresql-f01.md",
"title": "bounded purge가 구현돼 있고 호출되지 않아, cleanup이 스스로 막겠다고 한 장애를 일으킨다",
"titleSha256": "11e1b5262a9f7739bdd6872a67886b4874d00c121ee2d004d71ae40408d303ab"
},
"messaging-nats-experimental-f01": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "무조건 참인 선언과 창이 있을 때만 일어나는 실제 동작의 대비다. 조건절을 빼면 결함이 성립하지 않는다.",
"path": "case/case-messaging-nats-experimental-f01.md",
"title": "deduplicatedPublish 를 무조건 참으로 선언하는데 실제 중복 제거는 프로파일에 창이 있을 때만 일어난다",
"titleSha256": "d88fd462e81989a10308e98413fc5c0496662ce130606e4d25a947cbacc397a9"
},
"messaging-rabbit-f04": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "능력 상수가 참이라는 것과 그 지연을 제공할 토폴로지가 없다는 것의 대비다.",
"path": "case/case-messaging-rabbit-f04.md",
"title": "능력 상수의 delayedDelivery 가 무조건 참이고, 그 지연을 제공할 토폴로지는 조립되지 않는다",
"titleSha256": "2ff213b705421e39147bad47dbcf8b3ed0dc22fa76daa1227fa62787041e7c34"
},
"messaging-reliability-api-f08": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "두 오버로드를 나란히 노출한다는 것과 호출자가 무제한 쪽을 골랐다는 것이 원인과 결과다.",
"path": "case/case-messaging-reliability-api-f08.md",
"title": "포트가 bounded/unbounded purge 두 오버로드를 나란히 노출하고, 호출자가 무제한 쪽을 고른다",
"titleSha256": "d569175440aa856b591bd4e607f2830320fe877691c9dfc2660888afd53f4af7"
},
"messaging-spring-boot-starter-f02": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "아무도 공급하지 않는 빈 뒤에 있다는 것과 사슬이 자기 클래스 안을 가리킨다는 것이 함께여야 자기참조 구조가 드러난다.",
"path": "case/case-messaging-spring-boot-starter-f02.md",
"title": "출고되는 신뢰성 체인 전체가 아무도 공급하지 않는 빈 뒤에 있고, 그 사슬이 자기 클래스 안을 가리킨다",
"titleSha256": "3c751db7f8344dd35c7f13610b20a384e88e53c6b1d7eab162787773ca881192"
},
"readme-said-no-beans-there-are-eight": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "README 인용과 실제 bean 여덟이 대비 자체다. 한쪽만 남기면 사건이 사라진다.",
"path": "case/case-readme-said-no-beans-there-are-eight.md",
"title": "README가 \"노출된 setting도 bean도 없다\"고 적은 능력에 production bean 여덟이 있다",
"titleSha256": "c1f78904149820c311d1b1882827d808eb0e282e305606062f69dd5f93710f00"
},
"the-public-surface-contract-test-lives-outside-the-family": {
"status": "ACCEPTED",
"category": "PROTECTED_IDENTIFIER",
"reason": "MessagingPublicSurfaceContractTest 한 이름이 제목의 절반이고, app-bootstrap 이 실제 소재다.",
"path": "case/case-the-public-surface-contract-test-lives-outside-the-family.md",
"title": "MessagingPublicSurfaceContractTest가 가족 밖(app-bootstrap)에 있다",
"titleSha256": "fcf1375b7b32bea7173dcb0ab7d9e407e0c8a58cef56a12575dedaad420828d1"
},
"the-transport-and-the-validator-answer-differently": {
"status": "ACCEPTED",
"category": "PAIRED_CONTRAST",
"reason": "두 쪽이 다르게 답한다는 것과 런타임이 쓰는 쪽이 틀렸다는 것이 함께 있어야 심각도가 정해진다.",
"path": "case/case-the-transport-and-the-validator-answer-differently.md",
"title": "같은 어댑터의 능력을 전송과 검증기가 다르게 답하고, 런타임이 쓰는 쪽이 record 의 의미와 어긋난다",
"titleSha256": "092faa5727dcae07b8486a17ddb1f6ff64c1141f33fedac9085641bd3e0edb74"
},
"trust-policy-lives-in-nginx-not-in-the-code": {
"status": "ACCEPTED",
"category": "TECHNICAL_QUALIFIER",
"reason": "421 LOC 이 배선되지 않은 정책의 규모이고, Nginx 라는 실제 판정 위치가 대비의 반대쪽이다.",
"path": "case/case-trust-policy-lives-in-nginx-not-in-the-code.md",
"title": "forwarded 헤더 신뢰 판정이 Nginx에만 있고 Java 정책 421 LOC은 배선되지 않았다",
"titleSha256": "1d2ef0398997a68c91b2712b2a55af15b2cf2a25f5720e6cfdbc01e092950a14"
}
}
}
}