Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/state-machines-and-ownership/concept/concept-adapter-outbound-cache-redis-c10.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

3.8 KiB

kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source, module
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn assets evidence source module
CONCEPT adapter-outbound-cache-redis-c10 뒤 단계일수록 비싸도록 검증 순서를 고정했다 state-machines-and-ownership clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 concept:adapter-outbound-cache-redis-c10 2026-09-01
key file
adapter-outbound-cache-redis-c10 ../../../final/evidence/rendered/adapter-outbound-cache-redis-c10.svg
key file
adapter-outbound-cache-redis-c10-diagram ../../../final/assets/diagrams/adapter-outbound-cache-redis-c10.svg
../../../final/evidence/raw/adapter-outbound-cache-redis-c10.txt
원본 분석 절은 analysis/10-adapter-outbound-cache-redis.md#L560 이다.
adapter-outbound-cache-redis

뒤 단계일수록 비싸도록 검증 순서를 고정했다

CommandPolicyGuard의 javadoc이 순서와 이유를 적는다 — 각 단계가 다음 단계보다 싸므로 명백히 부적격한 명령은 인코딩도 전송도 하기 전에 거절된다.

본문

javadoc이 순서와 그 이유를 적는다 — "Validation order is fixed and each step is cheaper than the one after it, so an obviously inadmissible command is refused before anything is encoded or sent."

capability → risk/permit provenance → namespace → slot → request budget
  → connection lane → timeout/retry → invocation → reply budget → translation → telemetry

고정된 검증 순서

:::evidence key="adapter-outbound-cache-redis-c10-diagram" alt="capability 와 위험 등급과 namespace 와 slot 과 요청 예산이 왼쪽에서 오른쪽으로 이어지는 구조" caption="고정된 검증 순서" zoom="false" :::

각 단계가 구체적이다. requireReachableBLOCKED거나 access == NONE이면 거부하고 R3/R4를 애플리케이션 경로에서 배제한다. requireCapability는 명령의 최소 버전을 프로브된 서버 버전과 대조한다. requireNamespace는 모든 키의 네임스페이스를 확인하고 렌더까지 수행한다. requireSameSlot은 Cluster에서 두 개 이상 슬롯이면 RedisCrossSlotException서버를 부르기 전에 던진다. effectiveTimeout은 블로킹 명령이 유한한 server block을 선언하지 않으면 거부하고, 설정 상한을 넘으면 거부하며, 통과하면 BLOCKING_MARGIN(2초)을 더한다.

CommandPolicyGuard 참조 위치

:::evidence key="adapter-outbound-cache-redis-c10" alt="코드베이스에서 CommandPolicyGuard 를 검색한 출력 26줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="CommandPolicyGuard 코드베이스 검색 — 26줄 · exit 0" zoom="true" :::

죽은 중복을 지운 기록

validateReply(...)가 있었고 아무도 부르지 않았다.

"Two mechanisms for one rule, with the more visible one dead, is worse than one: a reader finds the guard's method, assumes replies are bounded during admission, and writes an operation that never bounds its own. Admission cannot do this job anyway. The guard runs before the command is sent, so the only reply size available to it is the estimate the request declared. The authority has to sit where the bytes actually arrive."

발화하지 못하던 조건을 떼어낸 기록

다중 키 permit 검사가 advanced permit 검사와 한 조건으로 접혀 있었고, "둘 다 없음"이 위에서 이미 던지므로 다중 키 절은 도달 불가였다 — "set algebra over any number of keys was admitted on an advanced permit alone." 지금은 request.keys().size() > 1 && request.multiKeyPermit().isEmpty()가 독립 조건이다. test rejectsAMultiKeyCommandCarryingOnlyAnAdvancedPermitaSingleKeyAdvancedCommandStillNeedsNoMultiKeyPermit가 양쪽을 고정한다.