- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다 - 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5 (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를 techviz 로 만들었다 - 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs 돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다. Concept 이 인용한 코드가 SSOT 에 없어 뺐다 - candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
225 lines
13 KiB
Markdown
225 lines
13 KiB
Markdown
---
|
|
kind: CASE
|
|
slug: a10-f001-readme
|
|
title: 표가 증거로 지목한 시험이 그 표를 반증한다
|
|
topic: caching-and-redis
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: case:a10-f001-readme
|
|
evidenceCapturedOn: 2026-09-02
|
|
body: case-a10-f001-readme.body.md
|
|
assets:
|
|
- key: a10-f001-readme
|
|
file: ../../../final/evidence/rendered/a10-f001-readme.svg
|
|
- key: a10-f001-readme-counts
|
|
file: ../../../final/evidence/rendered/a10-f001-readme-counts.svg
|
|
evidence:
|
|
- ../../../final/evidence/raw/a10-f001-readme.txt
|
|
- ../../../final/evidence/raw/a10-f001-readme-counts.txt
|
|
source:
|
|
- 원본 분석 절은 final/document.md#a10#L121 이다. 등급은 P2 다. 표 네 행 중 셋이 사실과 다르다는 판정, 패키지별 파일과 줄 수, `@Bean` 메서드 일곱, 빌드 파일 주석의 임포트 계수, 그리고 무겁게 보는 세 이유가 그 절에 있다.
|
|
- 그 절은 이 수치를 LOC 라고 적지만 실제로 센 것은 물리 줄 수여서, 여기서는 줄 수라고만 적는다.
|
|
- 표가 둘째 축의 증거로 지목한 시험이 표를 반증한다는 것, 같은 README 의 산문이 세 줄 뒤에서 표와 어긋난다는 것, 다섯 포트 중 세션만 표가 맞다는 것, 일곱째 `@Bean` 이 조건부라는 것, 그리고 주석의 주어절은 맞고 괄호만 틀렸다는 것은 이 기록에서 확인했다.
|
|
---
|
|
|
|
# 표가 증거로 지목한 시험이 그 표를 반증한다
|
|
|
|
리프 README 의 준비도 표와 그 아래 두 문단이 이 리프의 상태를 없음으로 적는다. 표가 둘째 열의 증거로 이름을 대 놓은 시험이 그 빈들이 조립된다고 단언하고, 같은 README 의 산문이 세 줄 뒤에서 같은 기능을 제공한다고 적는다.
|
|
|
|
## 관계
|
|
|
|
- **문서 계약 테스트의 단언 경계 밖에 발견된 드리프트 세 건이 전부 있었다**
|
|
그 테스트가 단언하는 범위 밖에서 문서와 코드가 어긋났다.
|
|
- **README의 세 가지 사실 오류**
|
|
같은 README 에서 확인한 다른 사실 오류다.
|
|
- **산문이 선언한 게이트는 빌드에 있는 게이트가 아니다**
|
|
문서와 빌드를 대조하는 규칙이다.
|
|
|
|
## 문제
|
|
|
|
이 리프의 README 는 준비도 보고를 자기 주제로 삼는다. 세 질문을 합치지 말라고 못 박고, 축마다 증거를 지정한 다음 표를 놓는다.
|
|
|
|
## 결론
|
|
|
|
둘째 축의 증거로 이름을 댄 시험이 RedisSdkAutoConfigurationTest 다. 그 시험이 RedisRuntimeClient 와 RedisRuntimeOwner 를 hasSingleBean 으로 단언한다. 표가 그 둘을 조립되지 않는다고 적은 자리다.
|
|
|
|
같은 README 도 자기와 어긋난다. 표에서 세 줄 뒤 산문이 이 모듈은 Lettuce 연결 수명과 명령 타임아웃과 재연결 재생 차단을 제공한다고 적는다. 표 둘째 행이 없음이라고 적은 바로 그것이다.
|
|
|
|
수를 세면 이렇다.
|
|
|
|
sdk/lettuce/connection 에 아홉 파일 1,473 줄이 있다. RedisTopologyClientFactory 600, RedisRuntimeOwner 316, SentinelFailoverObserver 153, RedisConnectionRegistry 142 줄이다.
|
|
|
|
의미 포트 행은 다섯 이름을 한 칸에 묶는다. 그중 넷은 아홉 파일 2,598 줄로 있고 세션 하나만 표가 맞다. 세션 쪽은 패키지 자체가 없고, 남은 여덟 건은 코드가 아니라 문장과 선택자 값이다.
|
|
|
|
상태 기여자 행도 틀렸다. RedisHealthContributor 88 줄과 RedisCorrectnessRoles 62 줄이 있다.
|
|
|
|
자동 설정에는 @Bean 메서드가 일곱 있다. 여섯은 조건 없이 조립되고, 일곱째 redisRequired 에는 @Conditional 이 붙어 세션·멱등·레이트리밋·리스 중 하나가 Redis 를 고를 때만 생긴다. 조립되는 자리를 못 찾은 것은 게이트웨이와 의미 어댑터다.
|
|
|
|
빌드 파일 주석은 절반만 틀렸다. 주석의 주어는 SDK 이고, sdk 패키지의 어떤 파일도 그 간선들을 임포트하지 않는다. 괄호 안의 일반화가 틀렸다. 메인 소스 전체로 넓히면 애플리케이션 코어를 일곱 파일이, 공유 계약을 세 파일이 임포트한다. 등록된 간선 셋 중 adapter:outbound:support 만 실제로 0 이다.
|
|
|
|
같은 주석은 그 어댑터들이 제거됐다고도 적는다. 위에서 센 파일들이 그것이다. 그리고 간선을 남겨 두는 이유로 든 문장 — 여기서 무언가가 그것에 대해 컴파일되기 때문이 아니라는 것 — 도 뒤집힌다.
|
|
|
|
스무 줄 뒤에 있는 별개 주석 쪽은 맞다. spring-data-redis 와 io.micrometer 임포트는 실제로 0 이다.
|
|
|
|
판정은 P2 다. 코드 결함이 아니라 문서 결함인데 이 저장소 기준으로는 무겁다.
|
|
|
|
첫째, 이 문서는 정직한 준비도 보고를 자기 주제로 삼고, 축마다 증거를 지정하기까지 한다. 그 증거가 문서를 반증한다.
|
|
|
|
둘째, 방향이 이례적이다. 보통의 표류는 없는 것을 있다고 하는데 여기는 있는 것을 없다고 한다. 포크한 쪽은 있는 것을 다시 만들거나, 있는 줄도 모른 채 지나친다.
|
|
|
|
셋째 근거는 자동 설정 안의 문장이다. 이 클래스가 생기기 전까지 설정 검증 메서드에 프로덕션 호출자가 없었다고 적는다.
|
|
|
|
## 검증 환경
|
|
|
|
확인 방식 : 패키지별 파일과 줄 수 계수, @Bean 메서드와 조건 계수, 임포트 계수
|
|
소스 수정 : x
|
|
|
|
## 재현 조건
|
|
|
|
1. README 가 세 축마다 지정한 증거를 읽는다.
|
|
2. 둘째 축의 증거로 지목된 시험이 무엇을 단언하는지 읽는다.
|
|
3. 준비도 표 네 행과 그 아래 두 문단을 읽고, 세 줄 뒤 산문까지 이어 읽는다.
|
|
4. 표가 없다고 적은 자리마다 패키지의 파일과 줄 수를 센다.
|
|
5. 의미 포트 행이 든 다섯 이름과 실제 패키지 이름을 대조하고, 행에 없는 패키지는 합계에서 뺀다.
|
|
6. 세션을 리프 메인 전체에서 문자열로 검색한다.
|
|
7. 자동 설정의 @Bean 메서드를 조건 애너테이션까지 함께 읽는다.
|
|
8. 빌드 파일이 등록한 간선 셋을 각각 임포트하는 파일을 세고, 주석의 주어인 sdk 패키지만으로도 센다.
|
|
9. 스무 줄 뒤의 별개 주석과 그 주장을 확인한다.
|
|
|
|
## 본문
|
|
|
|
<!-- body:start -->
|
|
|
|
README 는 준비도가 서로 다른 세 질문이며 하나로 합치면 안 된다는 문장으로 시작하고, 축마다 무엇을 증거로 삼는지까지 적는다.
|
|
|
|
## 표가 지목한 증거
|
|
|
|
:::evidence key="a10-f001-readme" alt="README 가 준비도 세 축마다 지정한 증거, 준비도 표 네 행, 표 아래 두 문단. 표에서 세 줄 뒤 같은 README 의 산문이 이 모듈이 제공한다고 적는 목록. 그리고 둘째 축의 증거로 지목된 시험이 어떤 빈들을 단언하는지 출력한 터미널 기록." caption="표는 연결 수명과 의미 포트와 상태 기여자를 없음으로 적음 · 세 줄 뒤 산문은 같은 모듈이 Lettuce 연결 수명을 제공한다고 적음 · 표가 증거로 지목한 시험은 RedisRuntimeClient 와 RedisRuntimeOwner 를 hasSingleBean 으로 단언 — 46줄 · exit 0" zoom="true"
|
|
:::
|
|
|
|
```text
|
|
| **Spring composition 구현** | `APP_REDIS_ENABLED=true`에서 실제 bean이 조립된다 | `RedisSdkAutoConfigurationTest` |
|
|
```
|
|
|
|
그 시험이 무엇을 단언하는지 보면 이렇다.
|
|
|
|
```java
|
|
assertThat(context).hasSingleBean(RedisSdkSettings.class);
|
|
...
|
|
assertThat(context).hasSingleBean(RedisRuntimeClient.class);
|
|
...
|
|
assertThat(context).hasSingleBean(RedisRuntimeOwner.class);
|
|
```
|
|
|
|
표는 같은 둘을 조립되지 않는다고 적는다.
|
|
|
|
```text
|
|
| Topology client / connection lifecycle | 없음 | 없음 | 없음 |
|
|
| cache / session / idempotency / rate limit / lease semantic port | 없음 | 없음 | 없음 |
|
|
| role-aware health·readiness contributor | 없음 | 없음 | 없음 |
|
|
```
|
|
|
|
## 같은 README 가 세 줄 뒤에서
|
|
|
|
```text
|
|
모듈은 Lettuce connection lifecycle,
|
|
finite command timeout, reconnect replay 차단, finite request queue/admission, positive/negative
|
|
TTL, absolute soft/hard expiry, deterministic bounded TTL jitter, digest-protected v2 binary
|
|
envelope, HMAC physical key,
|
|
invalidation, closed-catalog
|
|
`EVALSHA -> NOSCRIPT -> SCRIPT LOAD -> digest verify -> EVALSHA` recovery를 제공한다.
|
|
```
|
|
|
|
표 둘째 행이 없음이라고 적은 것을 산문이 제공한다고 적는다. 어긋난 것은 문서 전체가 아니라 표와 그 아래 두 문단이다.
|
|
|
|
## 수를 세면
|
|
|
|
:::evidence key="a10-f001-readme-counts" alt="표가 없다고 적은 자리의 파일 수와 줄 수. 의미 포트 행이 든 다섯 이름 중 구현이 있는 넷의 합계와, 그 행에 이름이 없어 합계에서 뺀 두 패키지. 세션 문자열의 리프 전체 계수. 상태 기여자의 줄 수. 자동 설정의 `@Bean` 메서드 전부와 거기 붙은 조건 애너테이션. 빌드 파일이 등록한 간선 셋과 앞 주석, 그 간선들을 임포트하는 파일 수와 주석의 주어인 sdk 패키지만의 계수, 그리고 스무 줄 뒤의 별개 주석을 출력한 터미널 기록." caption="연결 패키지 9 파일 1,473 줄 · 표가 든 다섯 포트 중 넷이 9 파일 2,598 줄이고 세션만 없음 · @Bean 일곱 중 하나에 @Conditional · 등록 간선 셋 중 둘은 열 파일이 임포트하고 support 만 0 · 주석의 주어인 sdk 패키지만 보면 0 — 58줄 · exit 0" zoom="true"
|
|
:::
|
|
|
|
```text
|
|
# sdk/lettuce/connection : 9 파일 1473 줄
|
|
600 sdk/lettuce/connection/RedisTopologyClientFactory.java
|
|
316 sdk/lettuce/connection/RedisRuntimeOwner.java
|
|
153 sdk/lettuce/connection/SentinelFailoverObserver.java
|
|
142 sdk/lettuce/connection/RedisConnectionRegistry.java
|
|
# 표가 든 다섯 포트 중 구현이 있는 넷
|
|
cache 2 파일 641 줄
|
|
idempotency 2 파일 835 줄
|
|
ratelimit 3 파일 516 줄
|
|
lease 2 파일 606 줄
|
|
합계 9 파일 2598 줄
|
|
# 다섯째 session : 패키지 없음, main 전체에서 session 문자열 8
|
|
# 그 행에 이름이 없어 뺀 패키지 : realtime 591 줄, keyspace 106 줄
|
|
# 상태 기여자 : 88 + 62
|
|
```
|
|
|
|
의미 포트 행은 다섯 이름을 한 칸에 묶는데 그중 하나만 맞다. 세션은 패키지가 없고, 리프 메인 전체에서 그 문자열 여덟 건이 전부 javadoc 산문과 역할 선택자 값이다. `realtime` 과 `keyspace` 는 그 행에 없는 이름이라 합계에서 뺐다.
|
|
|
|
## `@Bean` 은 일곱, 무조건은 여섯
|
|
|
|
```text
|
|
273: @Bean(destroyMethod = "close")
|
|
274- public RedisRuntimeOwner redisRuntimeOwner(RedisRuntimeClient client, RedisSdkSettings settings) {
|
|
297: @Bean(RedisCorrectnessRoles.OPTIONAL_HEALTH_CONTRIBUTOR)
|
|
298- public HealthIndicator redisOptional(RedisRuntimeOwner owner, RedisSdkSettings settings) {
|
|
324: @Bean(RedisCorrectnessRoles.REQUIRED_HEALTH_CONTRIBUTOR)
|
|
325- @Conditional(RedisCorrectnessRoleBound.class)
|
|
326- public HealthIndicator redisRequired(RedisRuntimeOwner owner, RedisSdkSettings settings) {
|
|
```
|
|
|
|
일곱째만 조건부다. 세션·멱등·레이트리밋·리스 중 하나가 Redis 를 고를 때 생긴다. 나머지 여섯은 스위치 하나로 조립된다. 어디서도 조립되지 않는 것은 게이트웨이와 의미 어댑터 둘이다.
|
|
|
|
## 빌드 파일의 의존성 주석
|
|
|
|
```groovy
|
|
// Registered edges the semantic port adapters need. The SDK itself imports nothing from them
|
|
// today (0 imports across main source) — the semantic cache/session/idempotency/rate-limit
|
|
// adapters that did were removed and are restored by Phase E of
|
|
// …
|
|
// because that restoration is the module's stated responsibility, not because anything here
|
|
// compiles against them.
|
|
implementation project(':application-core')
|
|
implementation project(':shared-contract')
|
|
implementation project(':adapter:outbound:support')
|
|
```
|
|
|
|
주어절은 맞다.
|
|
|
|
```text
|
|
dev.caskeleton.application 7 파일
|
|
dev.caskeleton.shared 3 파일
|
|
dev.caskeleton.adapter.outbound.support 0 파일
|
|
# 주석의 주어인 sdk 패키지만 보면 : 0
|
|
```
|
|
|
|
`sdk` 패키지는 세 간선 어디에서도 임포트하지 않는다. 틀린 것은 괄호 안의 일반화다. 메인 소스로 넓히면 열 파일이 임포트하고, 셋 중 `support` 만 주석대로 0 이다.
|
|
|
|
같은 주석이 그 어댑터들은 제거됐다고 적는데, 위에서 센 파일들이 그것이다. 간선을 남겨 두는 이유로 든 문장도 뒤집힌다 — 여기서 무언가가 그것에 대해 컴파일되기 때문이 아니라고 적혀 있는데, 컴파일된다.
|
|
|
|
스무 줄 뒤의 별개 주석은 맞다.
|
|
|
|
```groovy
|
|
// Deliberately absent:
|
|
// org.springframework.data:spring-data-redis — … Zero imports.
|
|
// io.micrometer:micrometer-core — … Zero imports.
|
|
```
|
|
|
|
## 어긋난 방향
|
|
|
|
표가 없다고 적은 자리마다 코드가 있다. 보통의 표류는 반대 방향이다. 이 문서를 읽고 분기하는 쪽은 이미 있는 코드를 다시 구현하거나, 조립되지 않은 채 존재하는 코드의 존재 자체를 모른다.
|
|
|
|
순서를 시사하는 문장이 자동 설정 안에 있다.
|
|
|
|
```java
|
|
* RedisSdkSettings#validate()} the fail-fast its own documentation claims — until this class
|
|
* existed the method had no production caller at all.
|
|
```
|
|
|
|
## 확인하지 못한 것
|
|
|
|
README 가 마지막으로 갱신된 시점과 자동 설정이 추가된 시점을 이력에서 대조하지 않았다. 자동 설정 javadoc 의 문장이 순서를 시사할 뿐이다.
|
|
|
|
<!-- body:end -->
|