Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/file-transfer-and-storage/case/case-analysis-finding-a09-f001.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.6 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 analysis-finding-a09-f001 production 판정이 두 개의 리터럴 프로파일 이름에 걸려 있다 file-transfer-and-storage clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 case:analysis-finding-a09-f001 2026-09-01 case-analysis-finding-a09-f001.body.md
key file
analysis-finding-a09-f001 ../../../final/evidence/rendered/analysis-finding-a09-f001.svg
../../../final/evidence/raw/analysis-finding-a09-f001.txt
원본 분석 절은 analysis/09-adapter-outbound-objectstorage.md#L106 이다.

production 판정이 두 개의 리터럴 프로파일 이름에 걸려 있다

개발용 제공자를 운영에서 쓰지 말라는 금지가 문서에 있고 그것을 강제하는 코드는 한 곳이다. 그 코드는 거부 검사인데 판정 근거가 이름 두 개의 허용 목록이다. 다른 이름을 쓰는 분기는 검사를 통과한다.

관계

  • 거부 검사의 근거를 허용 목록으로 두면 목록 밖이 통과한다 이 사례가 그 규칙의 형태다.
  • 사라진 가드가 문서에만 남았고 그 부재는 이미 승인된 결정이다 같은 계열의 강제 수단 사례다.
  • 발행 rename만 경로 기반이고 그것을 지키는 것은 모듈 자신이 근사에 불과하다고 적은 사전검사다 도달성이 형상에 달린 다른 사례다.

문제

리프 지침 문서의 금지 목록에 개발용 제공자를 운영에서 쓰는 것이 있다.

그것을 강제하는 코드가 어디 있는지 찾았다.

결론

한 곳이다.

활성 프로파일 목록을 소문자로 만들고, 그중 하나가 짧은 운영 이름이거나 긴 운영 이름과 같은지 본다.

이 저장소가 짧은 이름의 프로파일 설정 파일을 싣고 있으므로 현재 형상에서는 맞는다.

그리고 같은 방식으로 운영을 판정하는 리프는 이것 하나뿐이다. 저장소 전체가 공유하는 운영 판별 장치가 없다.

문제는 방향이다.

이것은 거부 검사인데 판정 근거가 허용 목록 두 개다.

지역이나 환경을 이름에 붙이거나 축약형이나 다른 낱말을 쓰는 분기는 이 검사를 통과한다. 그리고 개발용 제공자가 운영에서 조용히 선택된다.

그 제공자는 README 가 현재 경로 전용 개발 제공자라고 적은 것이다.

실패는 시작 시점이 아니라 데이터가 로컬 디스크에 쌓인 뒤에 드러난다.

판정은 P3 다. 이 저장소 형상에서는 도달하지 않는다.

기록하는 이유는 셋이다. 지침 문서가 금지 항목으로 명시했고, 강제 수단이 문자열 둘이며, 분기가 프로파일 이름을 바꾸는 것은 평범한 일이다.

수정은 운영 판별을 뒤집는 것이다. 이름을 묻는 대신 개발용 제공자를 허용한다는 명시적 설정을 요구하는 형태다. 이름이 아니라 의도를 묻는 것이다.

검증 환경

Spring Boot : 4.0.8 확인 방식 : 강제 코드 전수 검색과 저장소 전체 운영 판별 장치 확인 소스 수정 : x

재현 조건

원문은 final/evidence/raw/150 계열에 있다.

  1. 지침 문서의 금지 목록을 읽는다.
  2. 그 금지를 강제하는 코드를 저장소에서 찾는다.
  3. 판정 조건이 무엇과 비교하는지 확인한다.
  4. 같은 방식으로 운영을 판정하는 다른 리프가 있는지 센다.
  5. 개발용 제공자의 README 서술을 확인한다.

본문

CLAUDE.md의 Forbidden 목록에 "local-dev in production"이 있고, 그것을 강제하는 코드는 이것 하나다.

private boolean productionProfileActive() {
  return activeProfiles.stream()
      .map(profile -> profile.toLowerCase(Locale.ROOT))
      .anyMatch(profile -> profile.equals("prod") || profile.equals("production"));
}

금지를 강제하는 코드 한 곳

:::evidence key="analysis-finding-a09-f001" alt="분석 문서 analysis/09-adapter-outbound-objectstorage.md 에서 이 기록의 근거 절을 그대로 잘라낸 15줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="analysis/09-adapter-outbound-objectstorage.md 발췌 — 15줄" zoom="true" :::

현재 형상에서는 맞는다

이 저장소가 application-prod.yml을 싣고 있다. 그리고 150-... §8.2c에서 확인했듯 같은 방식으로 production을 판정하는 leaf는 이것 하나뿐이다 — 저장소 전체가 공유하는 production 판별 장치가 없다.

문제는 방향이다

이것은 거부 검사인데 판정 근거가 허용 목록 두 개다. prd, production-eu, live, prod-apac 같은 이름을 쓰는 fork는 이 검사를 통과하고, filesystem-local-dev가 production에서 조용히 선택된다 — 그 provider는 README가 "R1-only development provider"라고 적은 것이다. 실패는 startup이 아니라 데이터가 로컬 디스크에 쌓인 뒤에 드러난다.

기록하는 세 이유

(a) CLAUDE.md가 금지 항목으로 명시했고 (b) 강제 수단이 두 문자열이며 (c) fork가 프로파일 이름을 바꾸는 것은 평범한 일이다. 수정은 production 판별을 명시적 설정(예: app.object-storage.allow-local-dev=true를 요구)으로 뒤집는 것 — 이름이 아니라 의도를 묻는 형태다. P3.

확인하지 못한 것

목록 밖 이름의 프로파일로 실제로 띄워 개발용 제공자가 선택되는지 재현하지 않았다. 조건식상 그 결과가 나온다.