Files
llm-wiki/raw/branch-notes/feature-static-analysis-quality-contract.md
T

42 KiB
Raw Blame History

title, source_type, status, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, contract_packet_sha256
title source_type status branch parent_branch related_projects governing_docs tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet contract_packet_sha256
branch / feature-static-analysis-quality-contract branch-note raw feature-static-analysis-quality-contract
ca-skeleton
ca-tmpl
wiki/projects/ca-tmpl/devops-ci-supply-chain-dx
branch
ca-skeleton
ci
static-analysis
build
2026-06-15 review BR-CA-SKELETON-OPERATIONAL-CONTRACT-059 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-059
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1
WI-CA-SKELETON-OPERATIONAL-CONTRACT-028
WI-CA-SKELETON-OPERATIONAL-CONTRACT-029
WI-CA-SKELETON-OPERATIONAL-CONTRACT-018
1 0c95c259df15379beb8e37dc590b41edb18028dd131f37b90fd59959d8d99163

branch: feature-static-analysis-quality-contract

Layer: raw/branch-notes/ — 단일 브랜치의 TODO·결정·진행 기록. 머지/종료 후 verified 결과는 /ingestwiki/projects/에 추출. 원본은 raw에 영구 보관. status_label: in-progress | review | merged | abandoned 계층 표기: "root branch" 라는 별도 개념은 없음. project 의 직접 자식 branch 는 parent_branch:비워두고 related_projects 만 채움. 다른 branch 의 자식이면 parent_branch: <부모 branch 이름> 명시 + ## Parent 섹션의 부모 wikilink 필수.

부모 (필수)

이 branch 가 어느 작업 묶음에 속하는지. 모든 branch 는 예외 없이 upward link 보유.

Project 의 직접 자식 branch (parent_branch: 비어있음):

  • raw/project-notes/ca-skeleton-operational-contract — ca-tmpl 운영 계약 canonical SSOT. 본 branch 는 §35-E 신규 branch 권고 우선순위 #2 (Implementation Coverage Checklist C 영역 L2051: "Static analysis / code quality baseline — tool 선택 + 룰셋") 의 전개.

선택 (인접 sibling — 경계 확정용, 본 branch 가 침범하지 않음):

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: static analysis 도구·threshold·CI failure mapping과 fixture가 명시된다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1 build tool은 Gradle Groovy DSL이다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1 test framework는 JUnit 5다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

ca-tmpl skeleton 의 정적 분석 / 코드 품질 baseline어떤 정적 분석 도구를 채택하고 어떤 룰셋을 적용할지 를 결정한다. 부모 §35-E 우선순위 #2 ("코드 작성 본격화 직전" 박는 architecture-blocking 결정).

  • 무엇을 막는가: (1) 도구·룰셋이 모듈마다 제각각이라 위치 판정 불가, (2) formatter 와 style linter 가 같은 규칙을 중복 강제해 CI 가 무한 reformat 루프에 빠짐, (3) 코드 수준 보안 anti-pattern(SQL injection·weak crypto 등)이 빌드에서 새어나감, (4) 빈 (toolchain) gate 로 인해 lint gate 가 실제로 아무 도구도 실행하지 않음.
  • ci-quality-gates 와의 분담: 그 branch 는 threshold (어느 위반이 release-blocking 인가) + gate 순서 owner. 본 branch 는 tool 선택 + 룰셋 + Gradle wiring. 본 branch 가 ci-quality-gates 의 format / lint gate row 의 (toolchain) 공석(literal gate-list feature-ci-quality-gates-contract.md:194; 동 노트의 ownership 매트릭스 :184 는 이미 본 branch 를 owner 로 기재)을 채우는 producer.
  • 이슈: (ca-tmpl repo — 미생성)
  • PR: (미생성)

범위

포함 범위

  • 정적 분석 도구 선택 (formatter / style linter / bytecode bug finder / code-level security / compile-time checker / aggregate platform 채택 여부) — D1~D7
  • 각 도구의 룰셋 내용 + config 파일 위치 (config/checkstyle/checkstyle.xml, config/spotbugs/exclude.xml 등)
  • Gradle plugin wiring (plugin id + 버전 + 모듈 전체 적용 메커니즘 + ./gradlew check 집계) — D8/D9
  • 도구별 위반의 blocking vs warning 채널 라우팅 (정책 은 ci-quality-gates 소유 → consume)
  • suppression / baseline 규약 (정적 분석 도구 한정 — Trivy suppression 은 ci-quality-gates 소유)

제외 범위

의도적으로 제외 — sibling branch 소유 (CLAUDE.md §11 OUT_OF_BRANCH_SCOPE). 면접에서 "이건 본 branch 범위 밖" 답변 근거.

근거 (필수, 최소 1개+)

이 branch의 구현·설계 결정의 근거가 되는 외부 자료. 공식 문서·대기업 기술 블로그·강의 등 raw 자료를 인용. 같은 자료가 여러 결정의 근거면 결정 표시와 함께 여러 번 등장 가능.

Source 정당화하는 결정
raw/official-docs/errorprone-gradle-plugin-readme D5 — net.ltgt.errorprone 채택, Java 21에서 JDK 16+ 자동 forking + JVM args 주입 근거 (C3, C4)
raw/official-docs/sonarqube-server-versus-cloud D7 — SonarQube(Server든 Cloud든) 기본 미채택 근거. Server는 self-managed 서버 설치 필요, Cloud는 외부 SaaS — 둘 다 zero-external-service 원칙과 충돌.
raw/official-docs/checkstyle-google-style-reference D2 — Checkstyle naming(TypeName/MethodName)/Javadoc(MissingJavadocType/MissingJavadocMethod)/formatting(Indentation/LineLength/Whitespace) 모듈 분류 + google_checks.xml 기준 config 확인
raw/official-docs/spotless-gradle-plugin-readme D1/D9 — Spotless Gradle plugin(com.diffplug.spotless) 채택 + spotlessCheck(CI 검증) vs spotlessApply(자동수정) task 분리 + googleJavaFormat step 사용 + Gradle 7.3 / JRE 17 최소 요건 확인
raw/official-docs/spotbugs-gradle-plugin-docs D3/D4/D9 — SpotBugs Gradle Plugin 채택, spotbugsPlugins 로 FindSecBugs 연동, ./gradlew check 자동 집계 (C1~C5)
raw/official-docs/find-sec-bugs-official D4 — FindSecBugs(SpotBugs 보안 플러그인) 채택. 144개 취약점 유형·826+ API 시그니처 탐지, OWASP Top 10/CWE 연계, Maven/IDE/CI 통합 공식 확인.
raw/official-docs/google-java-format-readme D1 — google-java-format 공식 scope(formatting 전용, naming 등 미포함), Java 21 최소 버전 요건, zero-configurability 설계 결정, JDK 16+ --add-exports JVM flag 요건 원문 확인.

근거 자료가 raw에 아직 없다면 먼저 raw-source-template 또는 lecture-note-template 으로 raw에 등록한 뒤 여기서 링크.

TODO

각 항목 옆에 증거 등급 표기: actually-implemented | locally-verified | prod-verified | documented-only | planned | needs-confirmation

  • Spotless + google-java-format Gradle wiring (subprojects {} + spotlessCheck/spotlessApply) — 등급: locally-verified (8.6.0 + GJF 1.35.0, spotlessApply 로 654 파일 일괄 포맷, spotlessCheck green)
  • Checkstyle custom minimal ruleset (config/checkstyle/checkstyle.xml + suppressions) — 등급: locally-verified (13.5.0; naming/logical error-tier, formatting/import-order 모듈 제거, Javadoc warning-tier, log/SELF 관용구 보정)
  • SpotBugs + FindSecBugs wiring (config/spotbugs/exclude.xml) — 등급: locally-verified (6.5.6/core 4.10.2 + FSB 1.14.0; reportLevel='high'; commons-lang3 BOM 충돌 해소 후 분석 정상; CSRF false-positive exclude)
  • ErrorProne wiring (net.ltgt.errorprone + error_prone_core) — 등급: locally-verified (5.1.0 + core 2.49.0; main 무오류, test 4건 실수정 후 compileJava/compileTestJava green)
  • Gradle 9.0.0 + Java 21 에서 4개 도구 plugin 버전 호환 smoke 검증 (./gradlew check) — 등급: locally-verified (./gradlew check BUILD SUCCESSFUL, 10모듈 도구+테스트+Testcontainers; gate-bites 음성테스트 확인)
  • (선택) SonarQube opt-in 문서 (docs/optional/sonarqube-integration.md) — 등급: documented-only (작성 완료; 단 /docs 는 gitignore 라 로컬 전용 — 커밋 비포함)
  • 머지 시 ci-quality-gates format / lint gate row (toolchain)feature-static-analysis-quality-contract 충원 (역참조 전파) — 등급: planned (merge-time follow-up — 본 구현 범위 밖)

진행 중 메모

  • ca-tmpl 은 정적 분석 도구가 전무한 greenfield (Explore 확인: spotless/checkstyle/spotbugs/errorprone/pmd/sonar/jacoco 0). 본 branch 는 신규 도입(마이그레이션 아님).
  • 실제 stack: Java 21 / Gradle 9.0.0 / Spring Boot 3.5.15 (project §34 는 3.5.14 기재 — 경미한 drift, §Audit 참조). 모든 plugin 버전 선택이 Gradle 9.0.0 기준 → 호환은 §Claims To Verify 로 실측.
  • 도구 선택 철학: §34 single-stack minimalism + §2 무외부의존 → 로컬·infra-free·비중복 도구만. 중복 도구(PMD)·외부 서비스(Sonar)는 기본 배제.

결정 사항

추후 면접/회고에서 "왜 이렇게 했나" 답할 근거. 대안과 함께 기록. 상세 매핑은 ↓ Decision Evidence Map.

  • 2026-06-15: D1 formatter = Spotless 8.6.0 + google-java-format 1.35.0 / 이유: 결정론적 zero-config 포맷 + spotlessApply 자동수정 / 대안: palantir-java-format(Spotless API 호환 위험), Eclipse JDT(custom XML overhead), Checkstyle-only(자동수정 없음) / 근거: raw/official-docs/google-java-format-readme, raw/official-docs/spotless-gradle-plugin-readme
  • 2026-06-15: D2 style linter = Checkstyle 13.5.0 (custom minimal ruleset) / 이유: formatter 가 못 하는 naming·Javadoc·logical 강제, formatting 모듈은 formatter 와 중복이라 suppress / 대안: google_checks.xml 그대로(포맷 충돌 #6527), sun_checks.xml(obsolete) / 근거: raw/official-docs/checkstyle-google-style-reference, raw/official-docs/google-java-format-readme
  • 2026-06-15: D3 bytecode bug finder = SpotBugs 6.5.6 (core 4.10.2) / 이유: 바이트코드 데이터플로우 null/resource/equals 버그 탐지 / 대안: 미채택 시 ErrorProne 단독 / 근거: raw/official-docs/spotbugs-gradle-plugin-docs
  • 2026-06-15: D4 code-level security = FindSecBugs 1.14.0 (SpotBugs plugin) / 이유: SQL injection·weak crypto 등 코드 수준 보안 anti-pattern 탐지(타 도구 미커버), CVE 스캔과 구분 / 대안: 전문 SAST 위임 / 근거: raw/official-docs/find-sec-bugs-official
  • 2026-06-15: D5 compile-time checker = ErrorProne (net.ltgt.errorprone 5.1.0 + core 2.49.0) / 이유: 컴파일 타임 correctness/swapped-arg/MissingOverride 즉시 강제 / 대안: 빌드 속도 제약 시 생략 / 근거: raw/official-docs/errorprone-gradle-plugin-readme
  • 2026-06-15: D6 PMD 미채택 / 이유: SpotBugs+ErrorProne 과 중복 크고 domain-less skeleton 에서 복잡도/CPD 가치 낮음·보안 미커버 / 대안: 복잡도 계약 요구 시 재검토 / 근거: 비교 합성(외부 vendor "미사용" 권고 부재 — UNSUPPORTED_DECISION)
  • 2026-06-15: D7 SonarQube 미채택(기본 skip) + optional opt-in / 이유: Server/Cloud 모두 외부 서비스 전제 → §2 무외부의존 위반; 로컬 plugin 으로 ./gradlew check 완결 / 대안: 조직이 Sonar 서버 보유 시 opt-in profile / 근거: raw/official-docs/sonarqube-server-versus-cloud
  • 2026-06-15: D8 Gradle wiring = 기존 루트 subprojects {} 확장 / 이유: ca-tmpl 현행 build.gradle 이 이미 subprojects {} 사용 → 일관성 / 대안: build-logic convention plugin(모듈 급증 시) / 근거: ca-tmpl src/build.gradle:15-52 ground truth (UNSUPPORTED_IMPL_DECISION — 메커니즘 선택은 임의 trade-off)
  • 2026-06-15: D9 ./gradlew check 단일 집계 + blocking; ci-quality-gates (toolchain) 충원 / 이유: 각 plugin 이 check 에 자동 연결, lint gate 가 실제 도구 실행 / 대안: 별도 task 수동 호출 / 근거: raw/official-docs/spotless-gradle-plugin-readme, raw/official-docs/spotbugs-gradle-plugin-docs + cross raw/branch-notes/feature-ci-quality-gates-contract D1/D4

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시한다. Decision ID 는 이 branch-note 안에서 안정적으로 유지한다. 예: D1, D2. Supporting Claimsraw/<category>/<slug>.md#C1 형식으로 연결한다.

선택 조건 열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면 N/A.

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 formatter = Spotless 8.6.0 + google-java-format 1.35.0 결정론적 포맷 + 100-char 수용 가능 → 이 결정 / 120-char 팀 표준이면 palantir(단 Spotless API 호환 확인 필수) raw/official-docs/google-java-format-readme.md#GJF-README-C2, raw/official-docs/google-java-format-readme.md#GJF-README-C3, raw/official-docs/spotless-gradle-plugin-readme.md#SPOTLESS-GRADLE-C4, raw/official-docs/spotless-gradle-plugin-readme.md#SPOTLESS-GRADLE-C5 official-vendor-doc google-java-format 1.35.0 + Spotless 8.6.0 의 Gradle 9.0.0 무결 동작 미검증(docs는 Gradle 7.3+/JRE17+ 최소만) → Claims To Verify
D2 style linter = Checkstyle 13.5.0 (custom minimal ruleset: naming+Javadoc+logical, formatting 모듈 suppress) naming/Javadoc 강제가 skeleton 계약 범위 → 이 결정 / pure formatting 만이면 Checkstyle 생략(D1 단독) raw/official-docs/checkstyle-google-style-reference.md#C2, raw/official-docs/checkstyle-google-style-reference.md#C3, raw/official-docs/checkstyle-google-style-reference.md#C4, raw/official-docs/checkstyle-google-style-reference.md#C1, raw/official-docs/google-java-format-readme.md#GJF-README-C1 official-vendor-doc google_checks.xml 직접 사용 시 formatter 충돌(#6527); importOrder↔CustomImportOrder 동기화 누락 시 CI 무한 reformat 루프
D3 bytecode bug finder = SpotBugs 6.5.6 (toolVersion core 4.10.2) 항상(baseline) raw/official-docs/spotbugs-gradle-plugin-docs.md#SPOTBUGS-GRADLE-C1, raw/official-docs/spotbugs-gradle-plugin-docs.md#SPOTBUGS-GRADLE-C3, raw/official-docs/spotbugs-gradle-plugin-docs.md#SPOTBUGS-GRADLE-C5 official-vendor-doc docs는 "Gradle v7.0+"만 명시(Gradle 9.0.0 직접 미언급) → plugin 6.5.6 의 Gradle 9 동작 실측 필요
D4 code-level security = FindSecBugs 1.14.0 (spotbugsPlugins) 코드 수준 OWASP 보안을 CI 에서 잡을 때 → 이 결정 / 전문 SAST 완전 위임 시 생략 가능 raw/official-docs/find-sec-bugs-official.md#C1, raw/official-docs/find-sec-bugs-official.md#C2, raw/official-docs/find-sec-bugs-official.md#C5, raw/official-docs/spotbugs-gradle-plugin-docs.md#SPOTBUGS-GRADLE-C4 official-vendor-doc FSB docs는 Gradle 통합 직접 미명시(C4=Maven/IDE만) → spotbugsPlugins 경유 Gradle 적용 실측 필요; CVE 스캔(sibling)과 경계 유지
D5 compile-time checker = ErrorProne (net.ltgt.errorprone 5.1.0 + error_prone_core 2.49.0) correctness/null 즉시 강제 필요 → 이 결정 / 빌드 속도 절대 제약이면 생략(SpotBugs 단독) raw/official-docs/errorprone-gradle-plugin-readme.md#C3, raw/official-docs/errorprone-gradle-plugin-readme.md#C4, raw/official-docs/errorprone-gradle-plugin-readme.md#C2, raw/official-docs/errorprone-gradle-plugin-readme.md#C1 official-vendor-doc README는 min Gradle 6.8 만 명시; plugin 5.1.0 + core 2.49.0 의 Gradle 9.0.0 fork compiler 정상 동작 실측 필요
D6 PMD 미채택 SpotBugs+ErrorProne 기채택 + domain-less skeleton → 제외 / 복잡도·CPD 가 계약 요구되면 재검토 (없음 — 비교 합성, vendor "미사용" 권고 부재) research-synthesisUNSUPPORTED_DECISION (외부 근거 없는 임의 trade-off: 중복성·skeleton 규모 판단) PMD CPD/복잡도 메트릭이 나중에 필요해지면 재평가
D7 SonarQube 미채택(기본 skip) + optional opt-in 문서 skeleton zero-external-service 원칙 고수 → skip / 조직이 Sonar 서버 보유 시 opt-in profile raw/official-docs/sonarqube-server-versus-cloud.md#C1, raw/official-docs/sonarqube-server-versus-cloud.md#C2 (+ project §2/§34 무외부의존 연결 논리) official-vendor-doc(배포모델) + project-ssot Sonar Gradle 9 + 9-module classpath drop 위험(opt-in 활성화 시); SonarJava 고유 dataflow 룰 일부 미커버
D8 Gradle wiring = 기존 루트 subprojects {} 블록 확장 (신규 build-logic convention plugin 미도입) ca-tmpl 현행 build.gradle 이 이미 subprojects {} + tasks.named('check') 집계 사용 → 일관성 / 모듈 급증 시 convention plugin 재검토 ca-tmpl ground truth src/build.gradle:15-52 (subprojects {} apply 패턴 + tasks.named('check') 집계) ground-truth-codeUNSUPPORTED_IMPL_DECISION (메커니즘 선택은 임의 trade-off; convention plugin 이 Gradle 9 에선 더 idiomatic) 빌드 복잡도 증가 시 convention plugin 마이그레이션 부담
D9 ./gradlew check 단일 집계 + blocking; ci-quality-gates (toolchain) 공석 충원 항상 raw/official-docs/spotless-gradle-plugin-readme.md#SPOTLESS-GRADLE-C3, raw/official-docs/spotbugs-gradle-plugin-docs.md#SPOTBUGS-GRADLE-C1 (+ cross raw/branch-notes/feature-ci-quality-gates-contract D1/D4) official-vendor-doc + cross-contract 최종 blocking/warning 정책 값 은 ci-quality-gates 소유 → 본 branch 는 채널 라우팅만, 정책 변경 시 재평가

구현 가이드

결정 (Decisions) 이 "무엇 을 할 것인가" 라면, 본 §는 "어디에 어떻게 구현될 것인가" 의 사전 명세 — 문서가 모호해서 구현자가 임의로 정해야 했던 결정 카탈로그. 작성 목표는 다음 구현자가 되묻지 않아도 코드를 작성할 수 있는 수준.

본 §는 일률적 anchor list 를 강제하지 않는다. branch 마다 구현 내용·범위가 다르므로 sub-section 은 이 branch 의 결정과 근거에서 도출되는 것만 작성. 어떤 branch 는 error mapping 표 + 정적 강제 카탈로그, 어떤 branch 는 migration 단계 + wiring, 어떤 branch 는 sequence + state machine. 형식 예시는 raw/branch-notes/feature-boundary-validation-mapping-contract 의 §구현 가이드 참조.

3-rule meta principle (필수 준수):

  1. R1. Reference 필수 — 각 sub-section / row / cell 은 본 branch 의 Decision ID (예: D1, D2) + 그 결정의 Supporting Claim ID (예: RAW-SLUG-C1) 를 reference. 근거 없는 결정 금지 — 모든 구현 detail 은 결정 + 근거의 도출 이어야 함.
  2. R2. UNSUPPORTED_IMPL_DECISION 명시 — 근거 raw 가 원칙 만 권고하고 detail (메커니즘 선택 / 클래스/rule 명명 / glob 패턴 / algorithm / factory API 모양 등) 은 권고하지 않는 cell 은 UNSUPPORTED_IMPL_DECISION 라벨 + 사용자 trade-off 근거 한 줄. 이게 근거 있는 결정 vs 사용자 임의 trade-off 의 경계.
  3. R3. OUT_OF_BRANCH_SCOPE 정제 — 본 branch 결정 범위 밖 cell 은 §구현 가이드에 남기지 않음. 별도 branch 또는 canonical SSOT 로 이관 (이관 history 는 별도 § "Audit & Findings" 등에 보존). 도메인 특화 detail (ca-tmpl skeleton 범위 밖) 도 동일하게 정제.

각 sub-section 의 권장 헤더 패턴:

### N. <sub-section 제목>

> **Trace**: <In-scope row 들 + Decision ID + Supporting Claim ID 의 매핑 (한 줄/한 단락)>
>
> - **UNSUPPORTED_IMPL_DECISION**: <근거 없는 사용자 임의 결정 항목들 + 각각의 trade-off 근거 한 줄>

<표 또는 명확한 구조 — 자유 텍스트 = 모호함 = 되묻기 원인>

1. Gradle plugin 적용 (루트 build.gradle + 기존 subprojects 블록)

Trace: D1(GJF-README-C2/C3,SPOTLESS-GRADLE-C4) · D3(SPOTBUGS-GRADLE-C3) · D4(SPOTBUGS-GRADLE-C4) · D5(errorprone-...#C3/C4/C5) · D8(ca-tmpl src/build.gradle:15-52). project §34 apply false 패턴 상속.

  • UNSUPPORTED_IMPL_DECISION: plugin 버전 핀(8.6.0 / 6.5.6 / 5.1.0) + effort='max' / reportLevel='high' 는 docs 가 원칙만 제시하고 skeleton-specific 값은 권고 없음 → 사용자 trade-off(엄격도↑ vs 빌드시간/false-positive↑). 기본값('default')도 기능상 유효.
// 루트 build.gradle plugins 블록 (apply false — 기존 §34 패턴)
plugins {
    id 'com.diffplug.spotless'   version '8.6.0' apply false   // D1
    id 'com.github.spotbugs'      version '6.5.6' apply false   // D3
    id 'net.ltgt.errorprone'      version '5.1.0' apply false   // D5
}

// 기존 subprojects {} (src/build.gradle:15-52)에 추가 — D8
subprojects {
    apply plugin: 'com.diffplug.spotless'
    apply plugin: 'checkstyle'                 // Gradle 내장 — plugins{} 선언 불요 (D2)
    apply plugin: 'com.github.spotbugs'
    apply plugin: 'net.ltgt.errorprone'

    spotless { java {                          // D1
        googleJavaFormat('1.35.0')
        importOrder()
        removeUnusedImports()
    } }

    checkstyle {                               // D2
        toolVersion = '13.5.0'                 // ※ Gradle 기본 toolVersion 은 구버전 → 명시 필수
        configFile = rootProject.file('config/checkstyle/checkstyle.xml')
        configDirectory = rootProject.file('config/checkstyle')
        ignoreFailures = false
        maxWarnings = 0
    }

    spotbugs {                                 // D3
        toolVersion = '4.10.2'
        excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
        // effort / reportLevel: UNSUPPORTED_IMPL_DECISION (위 참조)
    }

    dependencies {
        spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.14.0'  // D4
        errorprone 'com.google.errorprone:error_prone_core:2.49.0'            // D5
    }

    tasks.withType(JavaCompile).configureEach {
        options.errorprone { disableWarningsInGeneratedCode = true }          // D5 (errorprone-...#C5)
    }
}

ErrorProne Java 21 JVM args 수동 설정 금지 (errorprone-...#C4): plugin 5.1.0 은 JDK 16+ 감지 시 forking compiler + 필요한 --add-exports/--add-opens 를 자동 주입한다. org.gradle.jvmargs 에 수동 추가 시 중복/충돌. 단 Gradle daemon 자체가 Java 21 toolchain 으로 컴파일하는지만 확인.

2. Config 파일 레이아웃

Trace: D2(checkstyle config) · D3/D4(spotbugs exclude). 본 branch 의 결정 산출물 위치.

  • UNSUPPORTED_IMPL_DECISION: config/<tool>/ 경로는 Gradle Checkstyle 관행 차용 — SpotBugs docs 는 자동탐색 없음. 다른 경로도 기능 동등(사용자 trade-off: 관행 일관성 vs 자유).
config/
  checkstyle/
    checkstyle.xml                 ← KEEP: naming + Javadoc + logical 모듈만 (CS-C2/C3)
    checkstyle-suppressions.xml    ← SUPPRESS: formatter 소유 모듈 (CS-C4) — §3 카탈로그
  spotbugs/
    exclude.xml                    ← SpotBugs + FindSecBugs false-positive exclude filter

3. Checkstyle ruleset 카탈로그 (KEEP vs SUPPRESS)

Trace: D2 + checkstyle-...#C2/C3/C4/C5 + GJF-README-C1(formatter scope 는 formatting 한정, naming 미강제 → Checkstyle 잔존 이유). formatter(D1)와 중복 모듈을 suppress 해야 무한 reformat 루프(§엣지) 방지.

  • UNSUPPORTED_IMPL_DECISION: KEEP/SUPPRESS 각 모듈의 세부 파라미터(예: LineLength 100 vs MissingJavadocMethodscope/test 예외)는 docs 가 모듈 존재만 확인하고 값은 미권고 → 사용자 trade-off. 아래는 권고 기본선.
분류 모듈(예) 처리 근거
naming TypeName, MethodName, ConstantName, ParameterName, LocalVariableName, LambdaParameterName KEEP (blocking) CS-C2, CS-C5
Javadoc MissingJavadocType, MissingJavadocMethod, NonEmptyAtclauseDescription KEEP (main: blocking, test: warning) CS-C3
logical/design NeedBraces, FallThrough, EmptyCatchBlock, OneStatementPerLine, MissingSwitchDefault KEEP google_checks.xml(CS-C1)
formatting Indentation, LineLength, WhitespaceAround, LeftCurly/RightCurly, SeparatorWrap, OperatorWrap, EmptyLineSeparator SUPPRESS (formatter 소유) CS-C4 (#6527 충돌)
import order CustomImportOrder SUPPRESS (Spotless importOrder() 단독 소유) D1 + SPOTLESS-GRADLE-C1 (spotless{} 포매터 step 구성)

4. 위반 → blocking

Trace: D9 + cross raw/branch-notes/feature-ci-quality-gates-contract D1(contract violation=blocking)/D4(warning-only 경계). 본 branch 는 라우팅만; 최종 정책 은 ci-quality-gates 소유.

  • UNSUPPORTED_IMPL_DECISION: 아래 채널 배정은 ci-quality-gates 정책의 예상 적용 — 그 branch 가 최종 확정. test source set warning 시작 여부는 사용자 trade-off.
도구 task 채널 비고
spotlessCheck (포맷 diff) blocking CI 는 spotlessApply 절대 실행 금지(파일 mutate) — spotlessCheck
checkstyleMain blocking (ignoreFailures=false, maxWarnings=0) naming/Javadoc 위반 = skeleton 계약 위반
checkstyleTest warning 시작 → 추후 승급 테스트 헬퍼 Javadoc 예외
compileJava (ErrorProne) blocking (컴파일 오류) 별도 설정 불요
spotbugsMain (+ FindSecBugs) blocking (high priority) reportLevel/severity 정책은 ci-quality-gates

5. SonarQube opt-in (기본 미적용)

Trace: D7 + sonarqube-...#C1/C2(Server/Cloud 모두 외부 서비스). 기본 build.gradle 에 Sonar plugin 미포함.

  • UNSUPPORTED_IMPL_DECISION: opt-in 제공 형식(주석 build.gradle vs 별도 docs/optional/)은 docs 무관 사용자 선택. 아래는 권고.
docs/optional/sonarqube-integration.md   ← Sonar 서버 보유 팀용 opt-in 가이드 (plugin id org.sonarqube + host.url/token)

기본 ./gradlew check 는 Sonar 분석을 포함하지 않으며 외부 연결 없이 완결된다(D7).

엣지·실패·의존

R4(깊이 게이트) 캡처용. 정상 경로 외에 구현 중 부딪힐 실패/엣지/다른 계약 의존을 미리 열거. 없으면 "해당 없음" 명시(공란 금지).

  • 실패·엣지 경로:
    • formatter ↔ linter 충돌: google_checks.xml 직접 사용 시 Indentation/LineLength 등 formatter 가 고친 코드를 Checkstyle 이 reject → CI 무한 reformat. 기대 동작: custom ruleset 이 formatter 소유 모듈 suppress(D2 / CS-C4 / §구현 가이드 §3).
    • import order 동기화: Spotless importOrder() ↔ Checkstyle CustomImportOrder 불일치 → 영구 CI 루프. 기대 동작: Checkstyle 에서 import-order 검사 제거(Spotless 단독 소유).
    • 생성 코드 false positive: MapStruct/Lombok 생성물에 ErrorProne 경고 → disableWarningsInGeneratedCode=true(errorprone-...#C5).
    • Gradle 9 + Java 21 plugin 호환: 4개 plugin 버전이 Gradle 9.0.0 에서 미검증 → 빌드 실패 가능. 기대 동작: smoke 검증 후 버전 핀(§Claims To Verify).
    • FSB false positive: taint 분석 inter-procedural 한계 → config/spotbugs/exclude.xml 로 관리.
  • 다른 계약 의존:
    • raw/branch-notes/feature-ci-quality-gates-contract D1(contract violation=blocking) + D4(warning-only 경계)에 의존 — 본 branch 는 도구 위반을 그 정책 채널로 라우팅만. 그 정책 변경 시 본 branch 의 blocking 매핑 재평가. 역방향: 그 branch 의 ownership 매트릭스(:184/§Coverage :287)는 이미 (toolchain)→본 branch 로 매핑됨; literal gate-list row :194(toolchain) token 잔존(cosmetic) — 본 branch 머지 시 정합.
    • raw/branch-notes/feature-build-release-supply-chain-contract D8(Gradle dependency-locking)에 의존 — 도구 JAR 버전이 gradle/locks/*.lockfile 에 포함되어야 함(./gradlew dependencies --write-locks). 본 branch 는 버전 값만 정하고 locking 메커니즘은 그 branch 소유.
    • raw/branch-notes/feature-architecture-enforcement-rules — ArchUnit suite 는 그 branch 소유. 본 branch 는 ArchUnit rule 추가 안 함(OOS).

검증해야 할 주장

공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다. 구현 전/중/후에 실제로 검증해야 하는 주장을 분리한다.

Claim Why uncertain How to verify Status
Spotless 8.6.0 + google-java-format 1.35.0 이 Gradle 9.0.0 + Java 21 에서 무결 동작 docs는 Gradle 7.3+/JRE17+ 최소만 명시, Gradle 9 직접 미검증 ./gradlew spotlessCheck 실행 후 오류 0 locally-verifiedspotlessApply 654파일 포맷 후 spotlessCheck green (2026-06-20)
SpotBugs plugin 6.5.6(core 4.10.2) + FindSecBugs 1.14.0 이 Gradle 9.0.0 에서 분석 성공 docs는 "Gradle v7.0+"만 명시(SPOTBUGS-GRADLE-C5); FSB는 Gradle 통합 직접 미언급(find-sec-bugs-...#C4) ./gradlew check → spotbugsMain 리포트 생성 + FSB 룰 동작 확인 locally-verified — 단 Boot BOM 이 commons-lang3 를 3.17.0 으로 강등 → SpotBugs 4.10.2 가 org.apache.commons.lang3.Strings(3.18.0+) 부재로 crash. ext['commons-lang3.version']='3.20.0' override 로 해소(force 는 dependency-management 가 덮어써 무효). FSB 동작 확인(SPRING_CSRF_PROTECTION_DISABLED 탐지). 상세: raw/errors/spotbugs-commons-lang3-bom-downgrade-noclassdef-2026-06-20
ErrorProne plugin 5.1.0 + core 2.49.0 이 Gradle 9.0.0 + Java 21 fork compiler 정상 README는 min Gradle 6.8 만 명시; 5.1.0 의 Gradle 9 호환 실측 필요 ./gradlew compileJava 오류 없이 통과 + ErrorProne 룰 적용 확인 locally-verified — main 무오류; test 4건(CheckReturnValue×3, DoubleBraceInitialization×1) 실수정 후 compileJava/compileTestJava green
custom checkstyle.xml + suppressions 가 formatter 와 충돌 없이 동작(무한 reformat 루프 없음) google_checks.xml 직접 사용은 #6527 충돌 — custom suppress 완전성 미검증 ./gradlew spotlessApply && ./gradlew checkstyleMain 연속 실행 시 위반 0 locally-verified — formatting/import-order 모듈 제거; spotlessApplycheckstyleMain error 0(naming/logical), Javadoc 만 warning
./gradlew check 가 4개 도구 task 를 모두 집계 + 위반 시 non-zero exit 각 plugin 이 check 에 자동 연결되나 조합 동작 미검증 의도적 위반 fixture 주입 후 ./gradlew check exit code ≠ 0 확인 locally-verified:module:check dry-run 에 4개 도구 task 집계 확인; 의도적 위반(나쁜 포맷 + Bad_Method_Name) 주입 시 spotlessCheck/checkstyleMain BUILD FAILED 확인 후 원복
Sonar opt-in 구성이 Gradle 9.0.0 + 9-module 에서 classpath drop 없이 분석 sonar-scanner-gradle 7.0 공지가 "complex multi-module → major drop" 경고 opt-in 활성화 후 ./gradlew sonar 이슈 수 비교 planned — 기본 미적용(opt-in 문서만), 본 branch 미검증

Audit & Findings

ground-truth(ca-tmpl 실제 코드/registry) 대조에서 발견한 drift. 본 branch 결정 영역 밖 항목은 정합 권고만 (자동 rewrite 금지). 비차단.

  • GREENFIELD: ca-tmpl 에 정적 분석 도구 전무(Explore 확인: settings.gradle 9-module 어디에도 spotless/checkstyle/spotbugs/errorprone/pmd/sonar/jacoco 없음). 본 branch = 신규 도입(마이그레이션 아님).
  • STACK_DRIFT (비차단): project §34 Stack Matrix = Spring Boot 3.5.14, 실제 ca-tmpl/src/build.gradle:2 = 3.5.15. 정적 분석 도구는 Boot 버전 비의존이라 본 결정 무영향. project §34 갱신 권고.
  • GRADLE_VERSION (검증 대상화): ca-tmpl gradle/wrapper/gradle-wrapper.properties = Gradle 9.0.0. project §34 는 "Gradle Groovy DSL"만 명시(버전 무기재). 본 branch 의 모든 plugin 버전이 9.0.0 기준 → §Claims To Verify 로 실측.
  • MODULE_LIST_STALE (비차단): ca-tmpl 실제 모듈 9개(settings.gradle): app-bootstrap · domain-core · application-core · adapter-web · adapter-persistence · adapter-outbound · adapter-identifier · shared-contract · sample-portfolio. project §25 Blocking Defaults 의 package layout 목록은 adapter-identifier 미포함(부분 stale). 본 branch 의 subprojects {} 는 9개 전체에 적용되므로 영향 없음.
  • CI_TOOLCHAIN_VACANCY (대부분 이미 정합): ci-quality-gates 노트는 ownership 매트릭스(:184) + Sources(:254) + Coverage(:287) + Audit(:297)에서 이미 (toolchain)feature-static-analysis-quality-contract 를 owner 로 기재함. 잔존: literal gate-list row feature-ci-quality-gates-contract.md:194| format / lint | true | (toolchain) | token 만 미정합(cosmetic). 본 branch 머지 시 그 row 정합 권고(역참조 비차단 전파). → §TODO 에 항목화.

AS-BUILT 편차 (2026-06-20 구현 실측 — §구현 가이드 대비)

spec §구현 가이드 의 사전 명세 대비, 실제 ca-tmpl(Gradle 9.0.0 / Java 21 / Boot 3.5.15 / 10모듈)에서 green 을 위해 조정한 항목. 사용자 승인된 전략(Javadoc warning-tier)과 환경 강제(commons-lang3) 구분.

  • plugin 버전: spec 핀(8.6.0 / 6.5.6 / 5.1.0) 그대로 사용 — Gradle Plugin Portal 에서 resolve 확인. config 파일은 rootProject = src/ 이므로 src/config/ 에 배치(spec §2 의 config/ = rootProject 상대).
  • SpotBugs (env 강제): ext['commons-lang3.version']='3.20.0' 추가 — spec 미기재. Boot BOM 이 도구 classpath 의 commons-lang3 를 3.17.0 으로 강등시켜 4.10.2 가 crash(§마주친 문제). 또 reportLevel='high' 적용(§1 이 제시한 strictness lever) — medium tier 78건 중 38건이 EI_EXPOSE_REP/REP2(DI 협력자 방어복사 노이즈)라 high-confidence 만 blocking. SPRING_CSRF_PROTECTION_DISABLED(stateless JWT API 의 의도된 설정) 3건은 *SecurityConfig 한정 exclude.xml suppress.
  • Checkstyle (사용자 승인 전략 + 관용구 보정): §4 는 checkstyleMain Javadoc 을 blocking 으로 규정하나, 기존 코드 327건(Method 293 + Type 34) 누락 → 사용자 결정으로 Javadoc 규칙을 warning-tier(severity=warning, maxWarnings=∞)로 도입(추후 blocking 승급). naming/logical 은 error-tier 유지. 관용구 false-positive 보정: ConstantNamelog/logger 허용(Logger 는 Google §5.2.4 상 비-상수), 타입파라미터 패턴 ^[A-Z][A-Z0-9]*$ 로 F-bounded SELF 허용. checkstyleTest·spotbugsTestignoreFailures=true(§4 test-source warning trade-off).
  • 코드 실수정(behavior-preserving): NeedBraces 13(중괄호 추가) + MissingSwitchDefault 1(UpdateWorkLogUseCase 방어 default) + ErrorProne test 4(catchThrowableOfTypeassertThatThrownBy ×3, double-brace init→static factory ×1). spotlessApply 로 654 파일 일괄 포맷(google-java-format 2-space).
  • SonarQube 문서: docs/optional/sonarqube-integration.md 작성. 단 ca-tmpl /docs.gitignore → 로컬 전용(registries/snapshot 과 동일 관행), 커밋에는 비포함.

관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)

/coverage 가 채우는 생성물 — 손으로 유지하지 않는다. governing 문서(frontmatter governing_docs)가 요구하는 관심사를 이 브랜치가 빠짐없이 덮는지의 결과. 기준: rules/coverage-gate.md. 상태: covered-here(이 브랜치 결정) / delegated(다른 owner 브랜치) / missing(아무도 안 맡음 → Blocking).

관심사 상태 owner 심각도 근거
<governing doc 의 관심사> covered-here D
<관심사> delegated feature- OK/Should-fix §Audit 위임 링크
<관심사> missing (없음) 🔴 Blocking governing doc § 요구, 결정 없음

마주친 문제

짧은 메모만. 깊이 있는 트러블슈팅은 raw/errors/ 로 분리하고 아래 Cluster에 연결.

  • 2026-06-20 — SpotBugs 4.10.2 분석 worker crash (NoClassDefFoundError: org.apache.commons.lang3.Strings). Boot BOM 이 commons-lang3 를 모든 configuration(도구 spotbugs 포함)에서 3.17.0 으로 강등 → SpotBugs 가 요구하는 3.20.0 의 Strings(3.18.0+) 부재. resolutionStrategy.force 무효(dependency-management 가 우선), ext['commons-lang3.version']='3.20.0' 로 해소. 전말: raw/errors/spotbugs-commons-lang3-bom-downgrade-noclassdef-2026-06-20.
  • 2026-06-20 — spec 의 plugin 버전 핀은 Maven Central 구현-artifact 경로엔 404 였으나 Gradle Plugin Portal 에는 전부 존재(SpotBugs 6.5.6 / ErrorProne 5.1.0 marker 확인). plugins{} 는 portal 에서 resolve 하므로 spec 버전 그대로 사용.

묶음 (이 branch에서 파생된 자료)

이 branch는 단일 노트가 아니라 작업 묶음의 entry point. 이 branch에서 파생된 모든 raw 노트를 카테고리별로 명시. 자식 노트가 forward link만 박아도 Obsidian backlink로 자동 발견되지만, 읽기 흐름과 분류를 위해 hub가 명시적으로 그룹화한다.

Sub-branches (세부 작업)

  • 해당 없음 (단일 branch — 세부 분해 없음).

근거 자료 (이 branch 결정 근거 — official-docs, 본 branch 가 hub)

오류 기록 (이 branch 작업 중 발생)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

강의 (이 작업을 위해 학습한 강의)

  • 해당 없음.

job-posting tie-ins (이 작업에서 파생된 글감)

관련 일일 노트

이 브랜치를 작업한 날짜들. 양방향 nav 유지.

  • 해당 없음 (2026-06-15 daily 노트 미생성).

완료 후 정리

머지/종료 시점에 채움. /ingest가 이 섹션을 기준으로 wiki/projects/에 추출.

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경: (로컬/dev/staging/prod 어디까지 검증됐는지)
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목:
    • locally-verified 항목:
    • prod-verified 항목:
  • 추출하지 않을 항목 (planned / documented-only / abandoned):