Files
llm-wiki/raw/errors/idempotency-column-definition-base-check-failure-2026-07-15.md
T

6.5 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 / idempotency-column-definition-base-check-failure-2026-07-15 error-note raw
experiment-nplus1-feed-api-replay
ca-skeleton
error
ca-skeleton
architecture
persistence
hibernate
testing
idempotency
2026-07-15 open

error: idempotency-column-definition-base-check-failure-2026-07-15

Layer: raw/errors/ — N+1 replay branch의 최종 check에서 남은 단일 architecture failure를, 랩 기능 실패와 분리해 보존한다. 원본은 raw에 영구 보관한다.

Parent / 부모

증상 / Symptom

  • 에러 메시지 (ArchUnit condition이 만드는 원문):
    Field dev.caskeleton.adapter.outbound.persistence.idempotency.entity.IdempotencyRecordEntity.requestHash pins vendor SQL columnDefinition='char(64)' in adapter:outbound:persistence-jpa; move the physical type to the vendor migration.
    
  • 발생 컨텍스트: lab/nplus1-api-replay의 최종 cd src && ./gradlew check.
  • 발생 시점: 2026-07-15 (최종 검증; 시각은 별도 캡처하지 않음).
  • 발생 환경: local Gradle / app-bootstrapCleanArchitectureTest.
  • 재현 가능 여부: always — 해당 @Column(columnDefinition = "char(64)")가 non-PostgreSQL persistence package에 남아 있는 한.
  • 범위 구분: 이는 L1의 lazy highlights 재현이나 L12의 CQRS-lite read-model 기능 실패가 아니다. final check에서 남은 base architecture failure 하나이며, L1/L12 replay 변경이 이 entity를 수정하거나 도입하지 않았다.

재현 절차 / Reproduction

  1. lab/nplus1-api-replaynplus1-replay-l12 tag에서 cd src && ./gradlew check를 실행한다.
  2. CleanArchitectureTest.PERSISTENCE_RDBMS_ENTITIES_DO_NOT_PIN_VENDOR_COLUMN_DEFINITIONSIdempotencyRecordEntity.requestHash의 non-blank columnDefinition을 검사한다.
  3. 기대 결과: non-PostgreSQL persistence entity에는 vendor SQL columnDefinition 문자열이 없다.
  4. 실제 결과: request_hashcolumnDefinition = "char(64)"가 있어 위 Architecture violation으로 check가 실패한다.

조사 단계 / Investigation log

  • 2026-07-15 — final ./gradlew check의 잔여 failure가 하나뿐임을 raw/branch-notes/experiment-nplus1-feed-api-replayFull check의 기준선 실패 기록으로 확인했다.
  • 2026-07-15 — git show 6f0b0d6:src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/idempotency/entity/IdempotencyRecordEntity.java에서 requestHash@Column(... columnDefinition = "char(64)")를 확인했다.
  • 2026-07-15 — git diff --exit-code 6f0b0d6..nplus1-replay-l12 -- src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/idempotency/entity/IdempotencyRecordEntity.java가 변경 없음으로 끝났다. base와 replay tag의 해당 file blob은 모두 4b0f51783a9db312b09b181c0245734599f7ced7이다.
  • 2026-07-15 — CleanArchitectureTest의 rule은 dev.caskeleton.adapter.outbound.persistence.postgresql.. 밖의 @Column field에 non-blank columnDefinition이 있으면 위 원문을 생성하도록 확인했다. 따라서 failure는 replay의 L1/L12 기능을 대상으로 하지 않는다.

근본 원인 / Root cause

  • 직접 원인: IdempotencyRecordEntity.requestHash가 vendor-neutral persistence package 안에서 @Column(columnDefinition = "char(64)")로 물리 SQL type을 고정했다.
  • 근본 원인: RDBMS base entity의 portable mapping과 PostgreSQL 물리 schema 소유권을 분리하는 architecture rule이 이미 base commit 6f0b0d6의 기존 entity 선언과 충돌한다.
  • 트리거 조건: full checkCleanArchitectureTest를 실행해 non-PostgreSQL package의 모든 @Column field를 검사할 때.

Sources / 근거

  • raw/branch-notes/experiment-nplus1-feed-api-replayFull check의 기준선 실패가 final check의 유일한 잔여 failure와 replay scope 밖이라는 판단을 기록한다.
  • local code evidence: src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.javaPERSISTENCE_RDBMS_ENTITIES_DO_NOT_PIN_VENDOR_COLUMN_DEFINITIONSnotDeclareColumnDefinition() — violation 조건과 원문을 보유한다.
  • local Git evidence: base 6f0b0d6nplus1-replay-l12IdempotencyRecordEntity.java blob SHA가 동일하다. 이는 replay history가 해당 선언을 건드리지 않았다는 근거다.

해결 / Resolution

  • 적용한 조치: replay branch에서는 수정하지 않았다. nplus1-replay-l12가 학습 checkpoint history를 보존해야 하므로, 이 failure의 소유권을 별도 persistence base-fix 작업으로 분리했다.
  • 권고 조치 및 소유권: persistence base owner가 entity의 non-empty columnDefinition을 제거하고, char(64) 물리 type이 PostgreSQL vendor Flyway migration에만 남는지 확인한다. portable @JdbcTypeCode 사용 여부는 기존 mapping/integration test와 함께 검토한다.
  • 검증 방법: base-fix branch에서 cd src && ./gradlew check를 다시 실행하고, idempotency migration 및 persistence integration test로 schema/mapping을 확인한다.
  • 잔여 위험 / 후속 작업: migration이 실제 physical type을 충분히 소유하지 않으면 entity annotation만 제거한 뒤 schema와 runtime mapping이 어긋날 수 있다. base-fix가 완료되기 전에는 replay branch의 full check를 green이라고 주장할 수 없다.

회고 / Lessons

  • 빨리 감지하는 신호: pins vendor SQL columnDefinition= 또는 move the physical type to the vendor migration 메시지가 보이면, 랩 변경 파일부터 추측하지 말고 baseline blob과 replay diff를 먼저 비교한다.
  • 예방 체크리스트 항목 후보: vendor-neutral JPA entity에 @Column(columnDefinition = ...)를 추가하거나 유지할 때는 architecture test와 vendor migration의 schema ownership을 같은 change에서 확인한다.
  • wiki로 끌어올릴 가치가 있는 일반화된 교훈: full-suite failure를 feature regression으로 귀속하기 전에 base/replay diff와 architecture-rule 대상 범위를 대조하는 방법.