- 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>
5.3 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 | the-same-rotation-defect-closed-once-and-reproduced | 같은 자격 증명 회전 결함이 한 가족에서 닫히고 다른 가족에서 재현됐다 | learning-transfer-between-families | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:the-same-rotation-defect-closed-once-and-reproduced | 2026-09-01 | case-the-same-rotation-defect-closed-once-and-reproduced.body.md |
|
|
|
같은 자격 증명 회전 결함이 한 가족에서 닫히고 다른 가족에서 재현됐다
messaging 가족이 동기화 없는 읽기-갱신 회전 결함을 닫고 그 이력을 계약 테스트에 남겼다. gRPC 가족의 회전 매니저는 AtomicReference 를 평범한 홀더로 쓰며 같은 형태를 반복하고, 그 javadoc 은 경합의 존재를 이미 알고 있다.
관계
- Atomic 타입의 존재는 원자성의 증거가 아니다 이 사례가 그 규칙의 대표 형태다.
- 레지스트리로 표현된 규칙은 전이되고 CI로 표현된 규칙은 전이되지 않는다 같은 저장소 안에서 학습이 전이되지 않은 사례다.
- 두 번째 플랫폼이 첫 번째의 bridge 부재는 막고 게이트 배선은 옮기지 않았다 같은 두 가족 사이의 전이 패턴을 다룬다.
문제
messaging 가족의 자격 증명 런타임 레지스트리는 예전에 동기화 없이 읽고 가져오고 넣고 지웠다.
그 결함을 계약 테스트의 javadoc 이 사후 기록으로 남긴다. 같은 자격 증명을 회전시키는 두 호출자가 둘 다 같은 옛 런타임을 읽고 둘 다 교체본을 가져왔다. 하나의 교체본이 한 번도 정리되지 않은 채 맵에서 버려졌다. 아무도 소유하지 않는 비밀이 메모리에 남은 것이다. 그리고 진 쪽이 이긴 쪽이 아직 쓰고 있는 자료를 지울 수 있었다.
결함은 닫혔고 이력은 남았다.
결론
gRPC 가족의 회전 매니저가 같은 형태를 반복한다.
그 클래스는 AtomicReference 를 필드로 갖는다. 그러나 원자적 갱신 연산을 한 번도 쓰지 않는다.
get 으로 읽고 set 으로 쓴다 compareAndSet 사용 0 updateAndGet 사용 0 synchronized 사용 0
읽은 값으로 다음 상태를 만들어 쓰는 지점이 여럿이다. 상태를 관측하고 그 관측값으로 새 상태를 구성해 설정하는 형태다. 두 회전자가 동시에 들어오면 나중 쓰기가 앞선 쓰기를 덮는다.
그리고 같은 파일의 javadoc 이 그 경합을 이미 이름으로 부른다. 회전자가 둘 겹치는 것이 그 상황의 통상적인 이유라고 적혀 있다.
정책 리프의 테스트 열여섯 개 중 동시성을 다루는 것이 없다.
두 가족이 같은 저장소 안에 있고, 앞선 결함의 이력이 코드 주석으로 남아 있는데도 전이되지 않았다.
검증 환경
OpenJDK : 21.0.12 확인 방식 : 두 구현의 코드 비교와 연산 계수 소스 수정 : x
재현 조건
원문은 final/evidence/raw/tl-rotation-defect-reproduced.txt 에 있다.
- messaging 자격 증명 계약 테스트의 javadoc 에서 닫힌 결함의 서술을 읽는다.
- gRPC 회전 매니저에서 AtomicReference 의 사용 지점을 열거한다.
- 같은 파일에서 compareAndSet 과 updateAndGet 과 synchronized 를 센다. 셋 다 0 이다.
- 그 파일의 javadoc 에서 경합을 언급하는 문장을 찾는다.
- 정책 리프의 테스트 중 동시성을 다루는 것을 센다.
본문
messaging이 get → fetch → put → clear를 동기화 없이 하던 결함을 닫고 이력을 계약 테스트 javadoc에 남겼다 — "one replacement was dropped from the map without ever being cleared — a secret left in memory that nothing owns."
messaging 이 닫고 남긴 이력
:::evidence key="the-same-rotation-defect-closed-once-and-reproduced" alt="분석 문서 final/document.md 에서 이 기록의 근거 절을 그대로 잘라낸 18줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md 발췌 — 18줄" zoom="true" :::
gRPC 쪽은 CAS 를 한 번도 쓰지 않는다
회전 매니저는 AtomicReference를 쓰면서 compareAndSet을 한 번도 쓰지 않고 get()→set()으로만 다룬다(synchronized도 0). javadoc이 그 경합의 존재를 이미 알고 있다 — "the usual reason for one is two rotators racing".
테스트 열여섯 중 동시성을 다루는 것이 없다
grpc-policy 쪽이다.
확인하지 못한 것
경합을 재현하는 동시성 테스트를 작성하지 않았다. 이 기록은 코드 형태와 앞선 사례의 대조에 근거한다.
gRPC 블록은 어떤 배포에도 포함되지 않으므로 이 경합이 프로덕션에서 일어날 수 있는 상태는 아니다.