From 944a1e348be8c3c5737c68ba412c6ab48c1dce06 Mon Sep 17 00:00:00 2001 From: DongHyeonka Date: Thu, 17 Sep 2026 15:03:36 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20=EB=AC=B8=EC=84=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...6-verification-surface-reduction-design.md | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/docs/superpowers/specs/2026-09-16-verification-surface-reduction-design.md b/docs/superpowers/specs/2026-09-16-verification-surface-reduction-design.md index 13ca45c3..c53ad772 100644 --- a/docs/superpowers/specs/2026-09-16-verification-surface-reduction-design.md +++ b/docs/superpowers/specs/2026-09-16-verification-surface-reduction-design.md @@ -165,3 +165,116 @@ dependency-review, Trivy 스캔, path filter 기반 feature CI, nightly 분리, 따라서 convention 이동은 **해석되는 의존성 집합을 바꾸지 않는 범위**로 제한한다. `ca.spring-config`는 이미 processor를 선언한 leaf만 opt-in한다. 3. 삭제하는 task 이름을 참조하는 workflow/문서/테스트를 같은 변경에서 고친다. + +--- + +# 실행 결과 (2026-09-16) + +## 실제로 한 것 + +### Gradle + +| 파일 | 전 | 후 | +| --- | ---: | ---: | +| `src/build.gradle` | 3,211줄 | 349줄 | +| `src/settings.gradle` | 16줄 | 16줄 (변경 없음) | +| `src/build-logic/src/main/groovy/` | 9 플러그인 | 16 플러그인 | + +루트에서 사라진 것과 간 곳: + +| 대상 | 처리 | +| --- | --- | +| `configure(subprojects)` 306줄 | `ca.java-conventions` + `ca.quality-conventions` + `ca.java-library` / `ca.spring-library` / `ca.spring-config` / `ca.jmh-benchmarks` | +| `verifyCleanArchitectureDependencies`, `verifyApplicationCoreDependencyPurity`, `verifyNoIgnoredSourcePackages` | `ca.architecture` (루트 적용) + `architectureCheck` | +| JPA readiness registry + release gate 685줄 | `gradle/qualification/jpa-qualification.gradle` | +| Messaging evidence 300줄 | `gradle/qualification/messaging-qualification.gradle` | +| `verifyEnvKeys` 280줄 | `gradle/config-contract.gradle`, `:app-bootstrap`이 적용, `configContractCheck` | +| always-fail Messaging 태스크 9개 | 삭제 → `docs/roadmap/messaging-r2.md` | +| `verifyReadmeCommands`, `verifyRunbookReferences`, `verifyDocumentedLeafCount`, `verifyTestSourceSetRegistry`, `verifyDocumentationContracts` | 삭제 | +| `verifyConfigurationPropertiesProcessor` + `blankJavaCommentsAndLiterals` | 삭제 → `ca.spring-config` | +| `verifyOneTypePerFile` | 삭제 → 호출자가 `checkstyleMain`을 직접 부른다 | +| `verifyTrivyignore`, `verifyQuarantineSunset` | 삭제. `flaky-quarantine.yaml`도 삭제 | +| `verifySpotBugsAnalysisFailureContract` | 삭제. 검사기 본체(`spotBugsAnalysisFailures`)는 `ca.quality-conventions`로 이동 | + +`ModuleRegistry`: 필드 집합 정확 일치 → 필수 필드 존재로 완화. self-dependency / 미지의 id / +sample-portfolio edge 검사는 settings에서 `verifyCleanArchitectureDependencies`로 이동. + +Git revision: 없으면 configuration 실패 → `0.0.1-SNAPSHOT` + `sourceRevision='unknown'`. +`verifyReleaseProvenance`가 `releaseCheck`에서만 요구한다. + +### CI + +| 대상 | 처리 | +| --- | --- | +| `.github/ci-gate-matrix.yml` (1,025줄 / 107 gate) | 삭제 | +| `.github/scripts/verify-gate-matrix.sh` (568줄) | 삭제 | +| `.github/scripts/verify-gradle-wrapper.sh` (799줄) | 삭제 → `gradle/actions/setup-gradle`의 기본 wrapper validation | +| 잡마다 반복되던 wrapper-validation 3줄 블록 59개 | composite action 안으로 이동 | +| `_reusable-gradle.yml` | 신규. 단순 Gradle 잡이 호출 | +| `fileserver-release.yml` | `fileserver-certification.yml`로 개명 | +| `docs/ci-cd/boundary.md`, `docs/ci-cd/template-vs-consumer.md` | 신규 | + +### 테스트 + +| 대상 | 전 | 후 | +| --- | ---: | ---: | +| `DeveloperExperienceContractTest` | 1,141줄 (wrapper mutation 24개) | 379줄 | +| `ConditionalTransportQualificationContractTest` | 860줄 (gate matrix 18개) | 94줄 | +| `MessagingCapabilityRegistryContractTest` | 태스크 존재를 요구 | 태스크 부재를 요구 | + +`SampleRemovalSmokeContractTest`의 gate matrix 대조 제거. + +## 리뷰와 다르게 결정한 것 + +1. **`ci-quality-gates.yml`을 `ci.yml`로 개명하지 않았다.** 리뷰 §25는 워크플로 이름 정리를 + 제안했지만, 같은 절에서 "중요한 것은 workflow 개수가 아니라 공통 setup을 복사하지 않는 것"이라고 + 했다. 개명은 문서·테스트 20여 곳을 건드리고 얻는 것이 이름뿐이다. `fileserver-release.yml`만 + 개명했다 — 그건 이름이 틀렸기 때문이다(릴리스하지 않는다). +2. **`ca.spring-config`는 opt-in이다.** 리뷰 §14는 convention이 자동으로 processor를 넣는 그림을 + 보여 주지만, 모든 configuration이 STRICT로 락되어 있어서 지금 선언하지 않은 leaf에 넣으면 락이 + 깨진다. 지금 선언한 15개 leaf가 명시적으로 적용한다. +3. **`integrationCheck`를 `ci`에 넣지 않았다.** 리뷰 §10의 계층은 `ci = check + architectureCheck + + integrationCheck`지만, 이 저장소의 통합 레인 상당수는 컨테이너 런타임이 필요하고 이미 + `integration-main.yml`(main push)과 nightly로 분리돼 있다. PR 게이트에 Docker를 요구하면 리뷰가 + 비판한 "로컬에서 돌릴 수 없는 check"가 된다. +4. **`verifyRuntimeModuleMembership`은 단순화하지 않았다.** 리뷰는 "현재보다 중복"이라 봤지만, + 현재 구현은 선언된 멤버십이 아니라 **해석된 runtime closure**를 비교한다 — 다른 검증이 답하지 + 않는 질문이다. 중복이었던 85줄은 이미 이전 작업에서 제거돼 있었다. +5. **`springDependencyManagement`를 1.1.6 → 1.1.7로 올렸다.** 리뷰에 없는 항목이다. build-logic이 + 같은 플러그인을 적용해야 하는데, 루트는 Spring Boot 플러그인 때문에 이미 1.1.7로 해석하고 + 있었다(`buildEnvironment`가 `1.1.6 -> 1.1.7`로 표시). 카탈로그가 아무도 해석하지 않는 버전을 + 적고 있었고, 그대로 두면 convention plugin과 leaf가 서로 다른 버전을 쓰게 된다. + +## 검증 + +```text +./gradlew -p build-logic test BUILD SUCCESSFUL (56 tests) +./gradlew verifyDependencyLocks BUILD SUCCESSFUL (62 leaf, 락 변화 없음) +./gradlew architectureCheck BUILD SUCCESSFUL +./gradlew configContractCheck BUILD SUCCESSFUL +./gradlew ci releaseCheck integrationCheck --dry-run BUILD SUCCESSFUL +./gradlew check --continue :sample-portfolio:test 3건만 실패 (아래) +./gradlew :app-bootstrap:test BUILD SUCCESSFUL +./gradlew :app-bootstrap:functionalTest BUILD SUCCESSFUL +python3 -c "yaml.safe_load(...)" workflow 20개 + composite action 파싱 OK +``` + +락 파일이 한 줄도 바뀌지 않았다는 것이 convention 이동의 핵심 근거다 — 해석되는 의존성 집합이 +그대로라는 뜻이다. + +## 이번 작업으로 드러난 기존 결함 + +셋 다 HEAD(d00c762)에서 동일하게 재현되며, 이번 변경이 원인이 아니다. + +1. **`:sample-portfolio:test` 3건 실패.** `JpaLiveEventReplayAdapter`가 `@Repository`인데 생성자 + 3번째 파라미터 `java.time.Duration`을 만족시킬 빈이 없다. 샘플의 `@ComponentScan("dev.caskeleton")` + 이 이 어댑터를 집어오고, `app-bootstrap`은 이 타입을 아예 참조하지 않는다. retention을 어디서 + 받을지(typed settings)는 설계 결정이라 이번 빌드 리팩터링에서 건드리지 않았다. **미해결.** +2. **`:adapter:outbound:messaging:verifyJsonSchemaRuntimeGraph` — 한 번도 통과한 적 없음.** + `libs.*` 카탈로그 accessor(Provider)를 `String`으로 받는 클로저에 넘겨서 실행 즉시 + `MissingMethodException`으로 죽었다. `check`가 이 태스크에 의존했지만 항상 앞선 실패가 먼저 + 빌드를 멈췄다. 고쳤고, 고치자 진짜 문제가 드러났다 — 카탈로그는 `jackson-core:3.0.2`를 적는데 + Jackson BOM은 3.1.5로 해석한다. 버전 고정은 현재 상태 검증이므로 **모듈 존재** 검사로 바꿨다. +3. **`BuildVerificationPurityContractTest` 5건 실패.** public path snapshot의 입력이 + `src/.env`에서 커밋된 `config/security.yml`로 옮겨졌는데(`src/.env*`는 gitignore라 CI 체크아웃에 + 없다) 픽스처는 계속 `.env`를 썼다. 스크립트가 맞고 테스트가 이전 계약을 설명하고 있었다. 고쳤다.