Files
llm-wiki/raw/errors/spring-boot-four-jackson-three-migration-2026-06-30.md
T

25 KiB

title, source_type, status, related_branches, related_projects, tags, created, status_label
title source_type status related_branches related_projects tags created status_label
error / spring-boot-four-jackson-three-migration-2026-06-30 error-note raw
ca-skeleton-operational-contract
error
ca-tmpl
runtime
spring-boot
json
testing
distributed-lock
2026-06-30 resolved

error: spring-boot-four-jackson-three-migration-2026-06-30

Layer: raw/errors/ — Spring Boot 4 / Jackson 3 / Testcontainers 2 / Spring Integration 7 migration 중 발생한 실패 묶음의 트러블슈팅 기록.

Parent / 부모

증상 / Symptom

  • 에러 메시지 (원문 그대로):
    Property 'server.error.include-stacktrace' is Deprecated: Use 'spring.web.error.include-stacktrace' instead.vscode-spring-boot(YAML_DEPRECATED_ERROR)
    
  • 에러 메시지 (원문 그대로):
    server.error.include-stacktrace -> spring.web.error.include-stacktrace
    Default: never
    Deprecated!
    When to include the "trace" attribute.
    
  • 에러 메시지 (원문 그대로):
    MethodName must match pattern '^[a-z][a-zA-Z0-9]*$'
    
  • 에러 메시지 (원문 그대로):
    ConstantName must match pattern
    NeedBraces
    StaticVariableName
    
  • 에러 메시지 (원문 그대로):
    The method asText() from the type JsonNode is deprecatedJava(67108967)
    String tools.jackson.databind.JsonNode.asText()
    Deprecated. Use asString() instead.
    Source: jackson-databind-3.0.2.jar
    
  • 에러 메시지 (원문 그대로):
    Execution failed for task ':adapter-web:spotlessJavaCheck'.
    The following files had format violations:
    Run './gradlew spotlessApply' to fix all violations.
    
  • 에러 메시지 (원문 그대로):
    Execution failed for task ':app-bootstrap:compileTestJava'.
    bad class file: /home/donghyeon/workspace/ca-tmpl/src/app-bootstrap/build/classes/java/test/dev/caskeleton/bootstrap/integration/outbox/OutboxContainerTestSupport.class
    unable to access file: java.nio.file.NoSuchFileException
    Please remove or make sure it appears in the correct subdirectory of the classpath.
    
  • 에러 메시지 (원문 그대로):
    H S SECUJDES: Unsafe Jackson deserialization configuration used in
    dev.caskeleton.bootstrap.architecture.violations.boundary.DefaultTypingFixture.unsafe()
    SpotBugs ended with exit code 1
    
  • 에러 메시지 (원문 그대로):
    java.lang.Error: Failed Approval
    Approved: .../EnvelopeContractTest.successEnvelopeShape.approved.txt
    Received: .../EnvelopeContractTest.successEnvelopeShape.received.txt
    
  • 경고 메시지 (원문 그대로):
    Assigning String value 'high' to property of enum type 'com.github.spotbugs.snom.Confidence'.
    This behavior has been deprecated. This will fail with an error in Gradle 10.
    
  • 경고 메시지 (원문 그대로):
    Invocation of Task.project at execution time has been deprecated.
    This will fail with an error in Gradle 10.
    
  • 경고 메시지 (요약):
    MissingJavadocMethodCheck 310
    MissingJavadocTypeCheck 34
    
  • CI 실패 메시지 후보 (workflow 원문):
    A governed contract baseline changed but the PR lacks the
    'intent:breaking-change-approved' label.
    
  • 서버 시작 실패 메시지 (원문 발췌):
    Caused by: org.flywaydb.core.api.exception.FlywayValidateException:
    Validate failed: Migrations have failed validation
    Migration checksum mismatch for migration version 4
    -> Applied to database : 1718831886
    -> Resolved locally    : -37693890
    Either revert the changes to the migration, or run repair to update the schema history.
    
  • 서버 시작 실패 메시지 (local bootRun):
    Failed to bind properties under 'spring.profiles.active' to java.util.Set<java.lang.String>
    Value: "${SPRING_PROFILES_ACTIVE}"
    Profile '${SPRING_PROFILES_ACTIVE}' must contain a letter, digit or allowed char
    
  • 서버 시작 실패 메시지 (local bootRun):
    Could not initialize Logback logging from classpath:logback-spring.xml
    Could not resolve placeholder 'APP_NAME' in value "${APP_NAME}"
    
  • 서버 시작 실패 메시지 (사용자 신규 로그):
    org.flywaydb.core.api.FlywayException: Found more than one migration with version 4
    Offenders:
    -> .../adapter-persistence-postgresql-0.0.1+3a300d89ec30.jar!/db/migration/postgresql/V4__int_lock.sql
    -> .../adapter-persistence-postgresql/build/resources/main/db/migration/postgresql/V4__int_lock.sql
    
  • 발생 컨텍스트: Spring Boot 4 dependency set에서 Gradle compile/test/check 및 VSCode Spring Boot YAML validation 실행.
  • 발생 시점: 2026-06-30
  • 발생 환경: local
  • 재현 가능 여부: always

재현 절차 / Reproduction

  1. Spring Boot 4 / Spring Framework 7 / Jackson 3 dependency set으로 프로젝트를 refresh한다.
  2. src/app-bootstrap/src/test/resources/application-test.yml 또는 application yml에서 deprecated server.error.include-stacktrace key를 유지한다.
  3. VSCode Spring Boot YAML validation 또는 Gradle test/check를 실행한다.
  4. 기대 결과: 설정 key, compile surface, tests가 현 dependency set과 일치한다.
  5. 실제 결과: deprecated YAML warning/error, moved package compile errors, Jackson runtime test failures, JDBC lock schema/API mismatch, Checkstyle method naming failures가 발생한다.

조사 단계 / Investigation log

  • 2026-06-30 — rg -n "server\\.error\\.include" 실행 → repository config에 deprecated key가 남아 있음을 확인.
  • 2026-06-30 — Spring Boot 4.0.0 jar metadata에서 replacement 확인 → spring.web.error.include-stacktracespring.web.error.include-message로 이동.
  • 2026-06-30 — focused adapter-web/app-bootstrap/sample tests 실행 → Jackson 3 tools.jackson.* API와 local JsonNullable module 필요 확인.
  • 2026-06-30 — Spring Integration 7 source/API 확인 → JdbcLockRegistry TTL constructor와 DistributedLock.tryLock(wait, ttl) path 필요 확인.
  • 2026-06-30 — ./gradlew test --continue 실행 → 전체 test suite 통과 확인.
  • 2026-06-30 — ./gradlew check 실행 → architecture/env checks는 통과했으나 Checkstyle/Spotless 단계에서 test method naming 위반으로 실패 확인.
  • 2026-07-01 — rg -n "\\.asText\\(" src 실행 → adapter-web auth 테스트 2개 파일에서 Jackson 3 deprecated call 확인.
  • 2026-07-01 — adapter-web auth focused tests 실행 → asString() 전환 후 테스트 통과 확인.
  • 2026-07-01 — ./gradlew check --continue 실행 → blocking failures가 adapter-web, app-bootstrap, sample-portfolio Spotless format drift였음을 확인.
  • 2026-07-01 — ./gradlew spotlessApply 실행 → formatter-owned import order / google-java-format drift 정리.
  • 2026-07-01 — ./gradlew check 재실행 → app-bootstrap:compileTestJava가 stale OutboxContainerTestSupport.class 경로를 참조하며 실패.
  • 2026-07-01 — ./gradlew :app-bootstrap:cleanTest :app-bootstrap:compileTestJava 실행 → stale test output 제거 후 재컴파일 성공.
  • 2026-07-01 — Checkstyle XML report를 집계 → MethodName, ConstantName, NeedBraces, StaticVariableName error entries가 test source에 남아 있음을 확인.
  • 2026-07-01 — test method/constant bulk rename 및 one-line if brace cleanup 실행 → ./gradlew checkstyleTest checkstyleSampleOffTest --continue 후 XML parser total_errors=0 확인.
  • 2026-07-01 — ApprovalTests failed path 확인 → PackageSettings.UseApprovalSubdirectory exact field convention을 lowerCamelCase로 바꾸면 approved snapshot directory lookup이 깨짐을 확인.
  • 2026-07-01 — SpotBugs SECUJDES output 확인 → architecture negative fixture가 의도적으로 unsafe Jackson call을 포함해 false-positive처럼 출력됨을 확인.
  • 2026-07-01 — ApprovalTests snapshot filename을 lowerCamelCase method name과 맞추고, exact field/negative fixture만 targeted suppression/filter 적용.
  • 2026-07-01 — ./gradlew build --warning-mode all 실행 → Gradle 10 deprecation 후보가 SpotBugs enum coercion과 task action project lookup 2건임을 확인.
  • 2026-07-01 — Checkstyle XML report 집계 → 남은 warning이 MissingJavadocMethodCheck 310건, MissingJavadocTypeCheck 34건뿐임을 확인.
  • 2026-07-01 — SpotBugs reportLevel을 enum value로 넘기고 verifyCleanArchitectureDependencies lookup을 rootProject.project(...)로 변경.
  • 2026-07-01 — default Checkstyle에서 Javadoc warning-tier modules를 제거 → Checkstyle XML warning/error total 0 확인.
  • 2026-07-01 — CI quality-gates workflow 검토 → PR 전용 breaking-change-approval gate가 .approved.txt filename-only rename도 label-required로 볼 수 있음을 확인.
  • 2026-07-01 — old/new ApprovalTests approved snapshot SHA 비교 → 세 snapshot 모두 내용 동일, 파일명만 변경됨을 확인.
  • 2026-07-01 — .github/scripts/verify-breaking-change-approval.sh 추가 → R100 identical-content rename은 통과, content change는 label 없으면 실패하도록 분리.
  • 2026-07-01 — temp git repo에서 no-change / identical rename / content change without label / content change with label path 검증.
  • 2026-07-01 — ./gradlew check, ./gradlew build 실행 → 둘 다 success.
  • 2026-07-01 — 사용자 서버 startup log 확인 → 실제 root cause는 후속 BeanCreationException이 아니라 마지막 Caused by의 Flyway V4 checksum mismatch임을 확인.
  • 2026-07-01 — git show b3bd7fa:.../V4__int_lock.sql 확인 → 기존 V4에는 EXPIRED_AFTER가 없고 최근 커밋에서 V4에 컬럼을 직접 추가했음을 확인.
  • 2026-07-01 — FlywayMigrationCompatibilityContractTest 추가 → old V4가 이미 적용된 PostgreSQL DB에 current V4/V5 migration set을 적용하는 시나리오를 재현.
  • 2026-07-01 — V4__int_lock.sql에서 EXPIRED_AFTER를 제거하고 V5__int_lock_expired_after.sql을 추가 → focused migration compatibility test 통과.
  • 2026-07-01 — 순수 bootRun 실행 → profile placeholder literal binding failure 확인.
  • 2026-07-01 — spring.profiles.activelocal fallback과 EnvProfileMatrixContractTest 회귀 테스트 추가 → focused test 통과.
  • 2026-07-01 — 순수 bootRun 재실행 → logback early placeholder failure 확인.
  • 2026-07-01 — logback-spring.xml springProperty source를 direct env key로 변경하고 StructuredLogFieldContractTest 회귀 테스트 추가 → focused test 통과.
  • 2026-07-01 — .env를 process env로 명시 주입한 bootRun 실행 → 서버가 Started CaSkeletonApplication까지 도달하고 기존 DB에 V5 migration이 적용됨을 확인.
  • 2026-07-01 — Gradle bootRunsrc/.env를 Java process env로 주입하도록 변경 → 순수 timeout 60s ./gradlew :app-bootstrap:bootRun --no-daemon --stacktraceStarted CaSkeletonApplication까지 도달.
  • 2026-07-01 — ./gradlew check verifyPublicPathSnapshot --no-daemon --stacktrace 재실행 → success.
  • 2026-07-01 — 사용자 신규 startup log 확인 → root cause가 이전 checksum mismatch가 아니라 stale adapter-persistence-postgresql JAR와 current resources의 Flyway migration duplicate version임을 확인.
  • 2026-07-01 — find src/adapter-persistence-postgresql/build/libs -name 'adapter-persistence-postgresql-*.jar' 실행 → 0.0.1+3a300d89ec30.jar 포함 다수의 old git-revision JAR가 남아 있음을 확인.
  • 2026-07-01 — verifyNoStaleTraceableJars를 먼저 추가하고 실행 → 10개 module의 stale traceable JAR를 감지하며 실패해 검증이 실제 문제를 잡는 것을 확인.
  • 2026-07-01 — cleanStaleTraceableJars, verifyNoStaleTraceableJars, Jar/BootJar 실행 전 stale archive cleanup을 추가하고 check에 연결.
  • 2026-07-01 — ./gradlew verifyNoStaleTraceableJars --no-daemon --stacktrace 재실행 → stale archive 105개 삭제 후 success.
  • 2026-07-01 — find src -path '*/build/libs/*.jar' 실행 → 각 module에 current git-revision archive만 남은 것을 확인.
  • 2026-07-01 — timeout 45s ./gradlew :app-bootstrap:bootRun --no-daemon --stacktrace 실행 → Flyway duplicate 오류 없이 Started CaSkeletonApplication까지 도달.
  • 2026-07-01 — ./gradlew check verifyPublicPathSnapshot --no-daemon --stacktrace 재실행 → new stale-jar gate 포함 success.

근본 원인 / Root cause

  • 직접 원인: Spring Boot 4 / Spring Framework 7 / Jackson 3 / Testcontainers 2 / Spring Integration 7에서 package, module, configuration key, serializer API, lock schema/API가 변경되었는데 기존 코드와 설정이 Boot 3/Jackson 2 계열 surface에 남아 있었다.
  • 근본 원인: patch upgrade와 달리 major upgrade는 compiler output뿐 아니라 runtime auto-configuration metadata, test-slice module split, third-party module compatibility까지 함께 바뀐다.
  • 추가 원인: warning-only static-analysis task라도 rule severity가 error면 Gradle 출력에 error처럼 보이는 로그가 남는다. 이 경우 ignoreFailures 정책은 exit code만 완화하고 리포트의 severity를 바꾸지 않는다.
  • 추가 원인: Gradle warning은 default mode에서 요약만 보이고 실제 제거 지점은 --warning-mode all에서만 드러난다. Checkstyle Javadoc warning은 meaningful documentation 없이 대량 주석을 강제하는 baseline이라 기본 build signal로 적합하지 않았다.
  • 추가 원인: CI breaking-change approval gate가 content diff가 아니라 path glob 중심으로 governed snapshot 변경을 판단해, 동일 내용 rename도 breaking change로 오탐할 수 있었다.
  • 추가 원인: 적용된 Flyway versioned migration인 V4__int_lock.sql에 Spring Integration 7용 EXPIRED_AFTER 컬럼을 직접 추가해 기존 DB의 flyway_schema_history checksum과 소스 checksum이 달라졌다.
  • 추가 원인: Boot 4 early profile/logging initialization은 spring-dotenv.env를 Spring Environment에 넣기 전에 실행될 수 있어, required placeholder가 literal 또는 unresolved 상태로 실패했다.
  • 추가 원인: Gradle bootRun은 working directory만 src로 바꿨고, .env 값을 Java process environment로 직접 주입하지는 않았다.
  • 추가 원인: traceable artifact 이름에 git revision이 포함되는데 build/libs에 old revision JAR가 누적되었다. IDE/runtime classpath가 stale JAR와 current build/resources/main을 함께 잡으면 Flyway가 동일 versioned migration을 두 번 발견한다.
  • 트리거 조건: Boot 4 dependency set refresh 후 Gradle compile/test/check 및 IDE YAML validation 실행.

Sources / 근거 (해결 근거가 된 자료, 최소 1개+ 권장)

해결 / Resolution

  • 적용한 조치:
    • Boot 4 moved package imports와 split module dependencies를 갱신했다.
    • Jackson 3 tools.jackson.* API로 production/test code를 전환했다.
    • Jackson 2 기반 nullable module 대신 local Jackson 3 JsonNullable serializer/deserializer module을 구성했다.
    • Testcontainers PostgreSQL package를 Testcontainers 2 module namespace로 갱신했다.
    • Spring Integration 7 JDBC lock schema에 EXPIRED_AFTER를 추가하고 TTL-aware lock API를 사용했다.
    • server.error.include-stacktrace/messagespring.web.error.include-stacktrace/message로 이전하고 env registry를 갱신했다.
    • Jackson 3.0.2에서 deprecated 된 JsonNode.asText() 테스트 assertion을 asString()으로 변경했다.
    • spotlessApply로 formatter-owned drift를 정리했다.
    • :app-bootstrap:cleanTest :app-bootstrap:compileTestJava로 stale test compile output을 재생성했다.
    • test method snake_case를 lowerCamelCase로, static constant를 UPPER_SNAKE_CASE로 정리했다.
    • Checkstyle NeedBraces 위반이 남은 single-line if에 braces를 추가했다.
    • ApprovalTests approved snapshot 파일명을 새 lowerCamelCase method name과 맞췄다.
    • ApprovalTests reflection convention인 UseApprovalSubdirectory만 file-scoped Checkstyle exception으로 문서화했다.
    • architecture negative fixture의 SECUJDESDefaultTypingFixture.java source에 한정해 SpotBugs exclude했다.
    • SpotBugs Gradle reportLevel은 문자열 coercion 대신 com.github.spotbugs.snom.Confidence.valueOf('HIGH')를 사용했다.
    • verifyCleanArchitectureDependencies task action 내부 project lookup은 rootProject.project(...)로 변경했다.
    • Checkstyle default ruleset에서 MissingJavadocType, MissingJavadocMethod, NonEmptyAtclauseDescription warning-tier modules를 제거했다.
    • breaking-change approval workflow inline shell을 .github/scripts/verify-breaking-change-approval.sh로 분리하고, git diff --name-status --find-renames=100% 기반으로 identical-content rename을 통과시켰다.
    • 이미 적용된 V4__int_lock.sql을 원래 checksum으로 되돌리고 V5__int_lock_expired_after.sql 전진 migration으로 EXPIRED_AFTER를 추가했다.
    • 기존 V4가 적용된 DB도 repair 없이 V5로 올라가는 Testcontainers 회귀 테스트를 추가했다.
    • spring.profiles.activelocal fallback을 추가하고 early profile binding 계약 테스트를 추가했다.
    • logback-spring.xml의 early properties를 application.yml 경유가 아니라 direct env key + default로 읽게 바꿨다.
    • Gradle bootRunsrc/.env를 Java process env로 주입하되 이미 export된 env를 덮어쓰지 않게 했다.
    • cleanStaleTraceableJarsverifyNoStaleTraceableJars를 추가해 old git-revision JAR를 삭제하고 남아 있으면 검증 실패하도록 했다.
    • verifyNoStaleTraceableJars를 기본 check에 연결했다.
    • 모든 Jar/BootJar 계열 archive task 실행 전에 같은 archive base/classifier의 old git-revision JAR를 삭제하게 했다.
  • 검증 방법:
    • ./gradlew test --continue success.
    • ./gradlew verifyCleanArchitectureDependencies verifyEnvKeys verifyPublicPathSnapshot success.
    • ./gradlew checkstyleTest checkstyleSampleOffTest --continue success and Checkstyle XML total_errors=0.
    • ./gradlew checkstyleMain checkstyleTest checkstyleSampleOffTest --continue success and Checkstyle XML total warning/error 0.
    • ./gradlew :app-bootstrap:spotbugsTest :app-bootstrap:spotbugsSampleOffTest success without SECUJDES output.
    • ./gradlew build --warning-mode all success without Gradle deprecation output.
    • ./gradlew check verifyPublicPathSnapshot --no-daemon --stacktrace success.
    • ./gradlew :app-bootstrap:sampleOffTest verifyCleanArchitectureDependencies --no-daemon --stacktrace success.
    • bash .github/scripts/verify-gate-matrix.sh && bash .github/scripts/verify-supply-chain-contract.sh && bash .github/scripts/test-supply-chain-scripts.sh success.
    • temp git repo script test success for breaking-change approval paths.
    • ./gradlew check success.
    • ./gradlew build success.
    • ./gradlew :app-bootstrap:test --tests dev.caskeleton.bootstrap.integration.FlywayMigrationCompatibilityContractTest --no-daemon --stacktrace success.
    • ./gradlew :app-bootstrap:test --tests dev.caskeleton.bootstrap.contract.EnvProfileMatrixContractTest --no-daemon --stacktrace success.
    • ./gradlew :app-bootstrap:test --tests dev.caskeleton.bootstrap.contract.StructuredLogFieldContractTest --no-daemon --stacktrace success.
    • timeout 60s ./gradlew :app-bootstrap:bootRun --no-daemon --stacktrace → process는 timeout 124로 종료했지만 로그에서 Started CaSkeletonApplication 및 Readiness ACCEPTING_TRAFFIC 확인.
    • ./gradlew check verifyPublicPathSnapshot --no-daemon --stacktrace success.
    • ./gradlew verifyNoStaleTraceableJars --no-daemon --stacktrace → stale traceable JAR 삭제 후 success.
    • find src -path '*/build/libs/*.jar' → old git-revision JAR 제거 확인.
    • timeout 45s ./gradlew :app-bootstrap:bootRun --no-daemon --stacktrace → process는 timeout 124로 종료했지만 로그에서 Flyway validate/migrate와 Started CaSkeletonApplication 확인.
    • ./gradlew check verifyPublicPathSnapshot --no-daemon --stacktrace success, verifyNoStaleTraceableJars 포함.
    • rg -n "server\\.error\\.include|spring\\.jackson\\.generator|SPRING_JACKSON_GEN_WRITE_BIGDECIMAL_AS_PLAIN" .로 deprecated/removed keys 제거 확인.
    • rg -n "\\.asText\\(" src no matches.
    • ./gradlew :adapter-web:test --tests 'dev.caskeleton.adapter.web.auth.EnvelopeAccessDeniedHandlerTest' --tests 'dev.caskeleton.adapter.web.auth.EnvelopeAuthenticationEntryPointTest' success.
  • 잔여 위험 / 후속 작업:
    • 기본 빌드의 Javadoc warning은 제거했지만, public API documentation 자체가 완료된 것은 아니다.
    • tracing fallback은 local test contract를 유지하기 위한 최소 bean 구성이다. 운영 exporter 구성은 별도 작업으로 분리해야 한다.
    • 대규모 test method rename으로 외부 IDE run configuration이나 문서가 old snake_case method name을 직접 참조하면 갱신이 필요하다.
    • remote Gitea CI 로그는 로컬에 gh가 없고 GitHub remote가 아니어서 직접 조회하지 못했다. remote runner 재실행으로 최종 확인 필요.
    • 누군가 잘못된 V4 내용으로 flyway repair를 이미 실행한 DB는 이번 V4 원복 후 반대 방향 checksum mismatch가 날 수 있다. 해당 경우에는 DB별 schema history 확인 후 별도 repair/backout 절차가 필요하다.
    • .env parser는 단순 KEY=value 형식만 처리한다. quoted value, escaped newline, export KEY=value가 필요하면 확장해야 한다.
    • IDE run configuration이 삭제된 old JAR absolute path를 직접 고정하고 있다면 IDE classpath refresh가 필요하다. Gradle check와 archive task는 stale JAR를 다시 만들지 않도록 막지만 IDE 설정 자체의 old path 참조까지 수정하지는 않는다.

회고 / Lessons

  • 빨리 감지하는 신호:
    • Boot major upgrade 후 YAML_DEPRECATED_ERROR, tools.jackson/com.fasterxml 혼재, JsonNode.asText() deprecation, NoSuchMethod/schema mismatch, Testcontainers package missing이 함께 보이면 단순 import fix가 아니라 migration surface 전체를 점검해야 한다.
  • 예방 체크리스트 항목 후보:
    • Boot metadata replacement grep.
    • Jackson 2 module compatibility audit.
    • Testcontainers module namespace audit.
    • Spring Integration schema/API diff audit.
    • test --continuecheck를 분리해 test pass와 style gate failure를 별도 보고.
    • Spotless failure가 보이면 수동 import/order patch보다 spotlessApply로 formatter-owned 영역을 정규화.
    • bad class file + NoSuchFileException 조합은 stale Gradle test output 가능성이 크므로 해당 source set clean 후 재컴파일.
    • ApprovalTests PackageSettings처럼 reflection convention을 쓰는 도구 설정은 일반 naming cleanup 전에 exact symbol contract인지 먼저 확인한다.
    • warning-only 정적분석 task라도 developer-facing error log를 줄이려면 XML severity entry를 0으로 만드는 별도 검증이 필요하다.
    • Gradle deprecation은 --warning-mode all을 정기적으로 돌려 실제 Gradle 10 failure 후보를 조기에 제거한다.
    • Javadoc은 대량 기계 주석으로 해결하지 말고, 공개 API 문서화 정책과 범위를 별도 작업으로 잡는 편이 낫다.
    • Contract snapshot 게이트는 파일 경로 변경과 내용 변경을 분리해야 한다. ApprovalTests method rename은 filename drift를 만들지만 wire contract drift를 뜻하지 않는다.
    • Flyway versioned migration은 한 번 적용되면 코드 리뷰에서도 immutable artifact로 취급해야 한다. schema drift는 새 version migration으로만 전진시킨다.
    • Boot major upgrade 후 local bootRun 검증은 compiler/test와 별개로 필요하다. profile/logging은 application context보다 먼저 실패할 수 있다.
    • .env를 working directory에 두는 것과 process env에 주입하는 것은 다르다. early initialization 경로는 process env 또는 inline default가 더 안전하다.
    • git revision을 archive name에 포함하는 build에서는 build/libs 누적 산출물도 runtime 위험이 될 수 있다. IDE classpath가 Gradle classpath와 다르게 움직일 수 있으므로 stale artifact cleanup과 검증을 빌드에 포함해야 한다.
  • wiki로 끌어올릴 가치가 있는 일반화된 교훈:
    • Major framework migration은 "compile surface", "runtime metadata", "test slice auto-config", "third-party module compatibility", "registry/env contract"를 별도 축으로 검증한다.
    • Static-analysis noise cleanup은 "진짜 코드 스타일 위반", "도구 convention", "negative fixture"를 분리해야 한다.
  • 관련 작업 식별자: chore-spring-boot-four-migration (별도 branch-note 없음)
  • 선행 patch upgrade 작업 식별자: chore-spring-boot-patch-upgrade (별도 branch-note 없음)