Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/what-a-gate-does-not-prove/case/case-a-certifying-lane-that-compared-nothing.md
T
DongHyeonkaandClaude Fable 5.1 b25357c48a docs(clean-architecture-backend-template): fold analysis into final and re-select one topic
- 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>
2026-09-07 12:39:20 +09:00

8.7 KiB

kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn assets evidence source
CASE a-certifying-lane-that-compared-nothing "certified"라 불리던 레인이 threshold를 하나도 비교하지 않고 있었다 what-a-gate-does-not-prove clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 case:a-certifying-lane-that-compared-nothing 2026-09-02
key file
a-certifying-lane-that-compared-nothing ../../../final/evidence/rendered/a-certifying-lane-that-compared-nothing.svg
../../../final/evidence/raw/a-certifying-lane-that-compared-nothing.txt
원본 분석 절은 final/document.md#a05 §123 이고, 남은 간격의 판정은 §124–§126 에 있다. `final/document.md#6-6` 이 같은 주석을 이 유형의 정본 수정으로 인용한다. 플래그와 소스셋 이름이 어디에 남아 있는지는 이 기록에 붙은 자산에 있다.

"certified"라 불리던 레인이 threshold를 하나도 비교하지 않고 있었다

성능 레인이 릴리스 게이트에 걸려 있었고, 그 레인의 유일한 임계값 단언은 임계값이 단언되지 않고 있다는 것이었다. 게이트는 기본값이 꺼짐인 불리언 뒤에 있었다.

관계

  • 빠뜨림이 통과가 되는 게이트는 게이트가 아니다 이 레인도 비교할 대상이 없을 때 실패하지 않고 통과로 끝난다.
  • 성능 측정은 릴리스 게이트에 넣지 않는다 이 사례에서 나온 결정이다.
  • strict test lane — 발견하지 못하면 실패하는 레인 발견하지 못하면 실패해야 한다는 레인 규약이다.

문제

레인의 이름은 성능 테스트였고, 설명은 풀과 REQUIRES_NEW 압력을 인증한다고 적혀 있었다.

그 레인은 불리언 하나 뒤에 있었고, 그 불리언은 나타나는 모든 곳에서 기본값이 꺼짐이었다. 빌드 파일에서도, 그것을 명시적으로 꺼짐으로 설정하는 야간 워크플로에서도 그랬다.

따라서 릴리스 게이트는 임계값 단언이 하나뿐인 레인에 의존하고 있었고, 그 하나의 단언은 임계값이 단언되지 않고 있다는 것이었다. 인증됨이라는 말은 어떤 지연이나 처리량 한계도 무엇과도 비교되지 않은 실행을 가리켰다.

결론

레인의 이름이 그것이 실제로 하는 일로 바뀌었다. 지금 이름은 풀 동작 계약 테스트다.

주석은 그 레인이 붙드는 것을 동작 계약 셋으로 적는다 — REQUIRES_NEW 깊이 1 이 동시 스레드당 커넥션 두 개를 요구한다는 것, 포화된 풀이 자기 대기 수를 보고한다는 것, 호출자가 커넥션 없이 진행하는 대신 기다린다는 것.

셋 중 둘에는 실제 단언이 있고 가운데 하나에는 없다. 원본 분석에서 그것은 따로 떼어져 Confirmed P2 로 올라 있다. 이름이 약속한 것과 레인이 관측하는 것의 간격이 완전히 닫히지는 않았다.

불리언 프로퍼티는 이 레인에서 제거됐다. 다만 같은 이름의 플래그가 저장소의 다른 두 성능 레인을 여전히 게이트한다.

검증 환경

OpenJDK : 21.0.12 Gradle : 9.0.0 확인 방식 : build.gradle 의 레인 주석과 등록부 확인, 플래그 이름과 옛 소스셋 이름 전수 검색 소스 수정 : x

재현 조건

  1. persistence-jpa 의 build.gradle 에서 레인 등록부 위의 주석을 읽는다. 옛 이름과 불리언의 기본값이 거기 적혀 있다.
  2. 그 레인이 릴리스 게이트 태스크에 포함되는지 확인한다.
  3. 현재 등록부에 failOnNoDiscoveredTests 와 upToDateWhen 이 설정되어 있는지 확인한다.
  4. performance.assertions.enabled 를 저장소 전체에서 검색해 이 레인 밖의 잔존 위치를 확인한다.
  5. 야간 워크플로가 이 레인을 새 이름으로 부르는지 확인한다.

본문

레인의 이름은 jpaPlatformPerformanceTest 였고 설명은 풀과 REQUIRES_NEW 압력을 인증한다고 적었다. 그 레인은 불리언 하나 뒤에 있었고, 그 불리언은 나타나는 모든 곳에서 기본값이 꺼짐이었다 — 빌드 파일에서도, 그것을 명시적으로 꺼짐으로 설정한 야간 워크플로에서도.

그래서 릴리스 게이트가 의존한 레인의 유일한 임계값 단언은 임계값이 단언되지 않고 있다 는 것이었다.

저장소가 그 이력을 주석에 남겼다

레인 등록부 위의 주석이 이 사건 전체를 기록한다. "certified" 가 가리킨 것은 어떤 지연도 처리량 한계도 무엇과도 비교되지 않은 실행이었다.

주석은 이유까지 적는다 — 프로퍼티 이름을 여기 다시 적지 않는 것은, 주석에 있는 이름이 누군가 다음에 설정해 보려 하는 대상이 되기 때문이다.

이름이 바뀌었고 플래그가 빠졌다

지금 태스크 이름은 jpaPlatformPoolContractTest 이고, 설명은 Hikari 풀과 REQUIRES_NEW 커넥션 동작을 검증한다고 적는다. 등록부에는 failOnNoDiscoveredTests = trueoutputs.upToDateWhen { false } 가 있다 — 발견 0 이 성공이 되지 않고, 이전 실행 결과를 다시 내놓지도 않는다.

릴리스 게이트 태스크가 이 레인을 부르고, 야간 워크플로도 새 이름으로 부른다.

같은 플래그가 다른 두 레인에는 남아 있다

:::evidence key="a-certifying-lane-that-compared-nothing" alt="코드베이스에서 performance.assertions.enabled 와 옛 소스셋 이름을 검색한 출력 20줄. 이 레인의 build.gradle 에서 매치가 0 이고, 같은 플래그가 httpclient 와 mongo 레인에는 남아 있으며, 옛 소스셋 이름이 아홉 곳에 남아 있다는 것이 그 출력에 그대로 보인다." caption="performance.assertions.enabled 잔존 위치 · 옛 소스셋 이름 — 20줄 · exit 0" zoom="true" :::

performance.assertions.enabled 는 이 레인의 build.gradle 에서 매치가 0 이다. 그런데 저장소 밖으로 나가면 그렇지 않다.

  • httpclient/build.gradle — 기본값 false
  • persistence-mongo/build.gradle — 기본값 true
  • httpclient-nightly.yml — 워크플로가 true 로 켠다

이 레인에서 사라진 것이지 저장소에서 사라진 것이 아니다. 같은 형태의 게이트가 두 곳에 더 있고, 그중 하나는 기본값이 꺼짐이다.

이름이 약속한 것과 레인이 관측하는 것의 간격은 아직 남아 있다

주석과 야간 워크플로가 이 레인의 검사 대상을 셋으로 적는다.

  1. REQUIRES_NEW 깊이 1 은 동시 스레드당 커넥션 두 개를 필요로 한다
  2. 포화된 풀은 자기 대기 수를 보고한다
  3. 호출자는 커넥션 없이 진행하는 대신 기다린다

원본 분석이 1 번과 3 번에는 실제 단언이 있고 2 번에는 없다 고 판정한다. pending()saturated() 를 단언하는 곳은 손으로 만든 record 하나뿐이고, 실제 풀에서 대기 수를 읽는 유일한 지점은 포화되지 않은 풀에서 읽은 뒤 대기 수에 대해서는 아무것도 단언하지 않는다.

이 기록의 주제가 "이름이 약속한 것을 아무도 측정하지 않았다" 인데, 새 이름이 약속하는 셋 중 하나도 아직 같은 상태다. 원본 분석은 그것을 별도의 Confirmed P2 로 둔다.

태스크 이름은 바뀌었고 소스셋 이름은 남아 있다

build.gradle 에서 옛 이름이 남은 곳은 아홉 줄이다 — 소스셋 선언 한 줄, 의존성 설정 네 줄, 이력 주석 한 줄, 레인 등록부 두 줄, 그리고 단위 레인이 이 디렉터리를 업투데이트 입력으로 선언하는 한 줄.

마지막 것이 기능적이다. test 태스크가 src/jpaPlatformPerformanceTest/java 를 자기 입력 디렉터리로 읽는다.

소스셋 이름을 유지한 것은 문서에 적힌 결정이다 — docs/jpa/repository-adaptation.md 가 소스셋이 원래 계획의 이름을 지킨다고 적는다. 주석이 다시 적지 않겠다고 한 이름은 프로퍼티 이름이고, 소스셋 이름은 그 대상이 아니다.

진짜 성능 게이트가 요구하는 것

전용 러너와 워밍업과 표본 수와 기록된 임계값이다. 그것이 생기면 별도 레인으로 만드는 것이 맞고, 이 레인의 불리언 뒤가 아니다.

확인하지 못한 것

그 시점 야간 워크플로가 무엇을 실행했는지는 확인 범위 밖이다. 현재 레인 쪽도 돌려 보지 못했다. 실 PostgreSQL 컨테이너가 있어야 한다.

주석과 야간 워크플로가 광고하는 세 성질 중 어느 것에 실제 단언이 있는지는 원본 분석의 판정을 옮긴 것이고, 이 회차에 테스트 본문을 직접 읽어 확인하지는 않았다.