- 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.9 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-a06-f026 | 커버리지 gate 둘이 나란히 있고, 하나는 발화할 수 없다 | multitenancy-isolation | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:analysis-finding-a06-f026 | 2026-09-01 | case-analysis-finding-a06-f026.body.md |
|
|
|
커버리지 gate 둘이 나란히 있고, 하나는 발화할 수 없다
계약 묶음의 javadoc 은 실패한 계약과 한 번도 돌지 않은 계약을 구분한다고 적는다. 구현에서 실행 집합이 전체와 항상 같으므로 누락 항목이 어떤 입력으로도 생성되지 않는다. 같은 테스트킷에 옳게 구현된 형제가 있다.
관계
- 빠뜨림이 통과가 되는 게이트는 게이트가 아니다 이 사례가 그 규칙의 형태다.
- 아무것도 발견하지 못한 레인은 성공이 아니라 실패여야 한다 같은 원칙의 레인 판이다.
- 중복 장치를 찾으면 어느 쪽이 조립됐는지 먼저 확인한다 형제 구현과 비교하는 방법이다.
문제
계약 묶음의 javadoc 이 존재 이유를 적는다.
보고서는 실패한 계약과 한 번도 돌지 않은 계약을 구분한다. 절반이 건너뛰어졌기 때문에 실패 없음을 보고하는 묶음은 아무것도 인증하지 않는 초록 빌드의 전형이므로, 누락된 계약은 여기서 실패다.
결론
구현이 그 구분을 만들 수 없다.
루프가 실행 집합을 무조건 채운다. 각 계약을 실행 집합에 넣고 그다음 검사를 수행한다.
그러므로 실행 집합은 전체 집합과 언제나 같고, 누락 집합은 언제나 비며, 실행되지 않음 항목은 어떤 입력으로도 생성되지 않는다.
인증 여부를 판정하는 조건도 마찬가지로 항상 참이다.
조건부 형제가 같은 테스트킷 안에 있다. 카오스 게이트의 보고 메서드는 같은 일을 옳게 한다. 실행 집합이 명시적 기록 호출로만 채워지는 맵이고, 누락은 전체에서 기록되지 않은 것을 뺀 것이다.
그리고 그 형제의 테스트가 그것을 증명한다. 열세 시나리오 중 하나만 기록하고 나머지가 실행되지 않음으로 나타나는지 단언한다.
계약 묶음의 대응 테스트는 그렇게 하지 않는다. 모든 계약에 통과를 주고 나서 실행 집합이 전부를 담는지 단언한다. 구조상 항상 참인 것을 단언하는 것이다.
판정은 두 인증 레인의 커버리지 주장이 무효라는 것이다.
수정은 형제를 따르면 된다. 실행 메서드가 실행할 계약 집합을 인자로 받거나, 실제로 호출된 것만 실행 집합에 넣는 것이다.
검증 환경
OpenJDK : 21.0.12 확인 방식 : 구현 코드 확인과 형제 구현 비교 소스 수정 : x
재현 조건
원문은 final/evidence/raw/138 계열에 있다.
- 계약 묶음의 javadoc 을 읽는다.
- 보고 메서드의 루프에서 실행 집합이 어떻게 채워지는지 확인한다.
- 누락 집합이 어떻게 계산되는지 확인한다.
- 카오스 게이트의 같은 메서드와 비교한다.
- 두 테스트가 각각 무엇을 단언하는지 비교한다.
본문
MongoStableContractSuite의 javadoc이 존재 이유를 적는다.
The report distinguishes a failed contract from a contract that never ran. A suite that reports "no failures" because half of it was skipped is exactly the shape of green build that certifies nothing, so a missing contract is a failure here.
suite javadoc 이 적은 존재 이유
:::evidence key="analysis-finding-a06-f026" alt="분석 문서 final/document.md#a06 에서 이 기록의 근거 절을 그대로 잘라낸 15줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md#a06 발췌 — 15줄" zoom="true" :::
구현은 그 구분을 만들 수 없다
Set<MongoReplicaSetContract> executed = new LinkedHashSet<>();
for (MongoReplicaSetContract contract : MongoReplicaSetContract.all()) {
executed.add(contract); // ← 루프가 무조건 채운다
if (!contractRunner.test(contract)) { failures.add(...); }
}
Set<MongoReplicaSetContract> missing = new LinkedHashSet<>(MongoReplicaSetContract.all());
missing.removeAll(executed); // ← 항상 비어 있다
missing.forEach(contract -> failures.add(... + " (not executed)"));
executed는 all()과 언제나 같으므로 missing은 언제나 비고, (not executed) 항목은 어떤 입력으로도 생성되지 않는다. certified()의 executed.containsAll(all())(78행)도 항상 참이다. 두 인증 lane(7.0/8.0)의 커버리지 주장이 무효다. P2.
조건부 형제가 같은 testkit 안에 있다
MongoChaosGate.report()는 같은 일을 옳게 한다 — executed는 명시적 record(scenario, passed) 호출로만 채워지는 map이고, missing은 all()에서 기록되지 않은 것을 뺀 것이다. 그 test가 그것을 증명한다: aScenarioThatNeverRanIsAFailureRatherThanASilence는 13개 시나리오 중 하나만 기록하고 나머지가 (not executed)로 나타나는지 단언한다. 수정은 형제를 따르면 된다 — run(...)이 실행할 contract 집합을 인자로 받거나, runner가 실제로 호출된 것만 executed에 넣는 것.
확인하지 못한 것
계약 하나를 실제로 건너뛰게 만들어 보고서가 여전히 깨끗한지 재현하지 않았다. 코드 구조상 그 결과가 나온다.