--- kind: CASE slug: a-certifying-lane-that-compared-nothing title: "certified"라 불리던 레인이 threshold를 하나도 비교하지 않고 있었다 topic: what-a-gate-does-not-prove project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: case:a-certifying-lane-that-compared-nothing evidenceCapturedOn: 2026-09-02 assets: - key: a-certifying-lane-that-compared-nothing file: ../../../final/evidence/rendered/a-certifying-lane-that-compared-nothing.svg evidence: - ../../../final/evidence/raw/a-certifying-lane-that-compared-nothing.txt source: - 원본 분석 절은 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 = true` 와 `outputs.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 컨테이너가 있어야 한다. 주석과 야간 워크플로가 광고하는 세 성질 중 어느 것에 실제 단언이 있는지는 원본 분석의 판정을 옮긴 것이고, 이 회차에 테스트 본문을 직접 읽어 확인하지는 않았다.