Files
llm-wiki/raw/branch-notes/feature-test-taxonomy-fixture-contract.md
T

52 KiB

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-test-taxonomy-fixture-contract branch-note raw feature-test-taxonomy-fixture-contract
ca-skeleton
wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard
wiki/projects/ca-tmpl/sample-fixture-and-adoption
branch
ca-skeleton
test
taxonomy
fixture
2026-05-22 review BR-CA-SKELETON-OPERATIONAL-CONTRACT-042 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-042
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TESTCONTAINERS-001@1
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-TEST-001@1
1 df97c653e6bc2a4b42673993d1881ecd4a683c40c133c115f9f041fef42add59

branch: feature-test-taxonomy-fixture-contract

Layer: raw/branch-notes/ — unit/contract/architecture/slice/integration/smoke 테스트의 책임과 fixture 사용 기준을 정의합니다.

부모 (필수)

ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§29 G-G Test taxonomy · §17/§22 Sample fixture) 의 결정/근거/금지 사항을 정제한다.

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: test level별 fixture가 실행되고 container 사용 정책을 지킨다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-TESTCONTAINERS-001@1 Testcontainers는 persistence/outbound integration test에 사용하고 unit·architecture·contract test에서는 금지한다 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

목표

테스트가 많아도 실패 원인을 구분할 수 없으면 실무 skeleton으로 부족합니다. 이 branch는 어떤 계약을 어떤 테스트 레벨에서 잡을지 고정하고, sample-portfolio과 fixture가 테스트를 오염시키지 않게 합니다.

  • 이슈:
  • PR:

범위

포함 범위

  • unit test 기준.
  • contract test 기준.
  • architecture test 기준.
  • slice test 기준.
  • integration test 기준.
  • smoke test 기준.
  • fixture/test data policy.

제외 범위

  • load/performance test.
  • chaos engineering.
  • external provider E2E test.

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

본 branch의 결정 근거. 상세 비교는 §외부 근거 / 대안 조사 (있다면) 참조.

Source 정당화하는 결정
raw/official-docs/test-taxonomy-testcontainers-official Testcontainers 공식 "real services, no H2" 입장과 정합
raw/official-docs/test-taxonomy-practical-pyramid-fowler Fowler/Cohn pyramid; ca-tmpl 6-level이 contract·architecture·slice를 명시 분리
raw/company-tech-blogs/test-pyramid-vs-trophy-kent-dodds static/integration heavy; React 진영 영향
raw/official-docs/spring-boot-test-slices-webmvctest-datajpatest-official D7 — Spring slice(@WebMvcTest/@DataJpaTest) semantics 및 "여러 slice annotation 혼용 미지원" 공식 정의 (SB-SLICE-C1, SB-SLICE-C2, SB-SLICE-C3, SB-SLICE-C4)
raw/official-docs/governance-archunit-official D2 — ArchUnit이 "Java 코드 architecture(package/class dependency, layer/slice, cyclic)를 plain unit test framework로 검사" 공식 정의 (AU-OFF-C1, AU-OFF-C2)
raw/official-docs/archunit-user-guide D2 — package 의존 규칙 fluent DSL (ARCHUNIT-UG-C4)
raw/official-docs/archunit-conditional-on-property-3-layer-pattern D2 — Building Evolutionary Architectures fitness function 정의 = "아키텍처 특성에 대한 객관적 무결성 평가 mechanism" (AUCP-C5)

외부 근거 / 대안 조사 (2026-05-22 — Group G-G: Test Taxonomy / Fixture)

본 branch의 6 levels (unit/contract/architecture/slice/integration/smoke) + Testcontainers from integration + src/testFixtures + 5min budget 결정에 대한 외부 source.

  • 채택 결정 (6-level taxonomy + Testcontainers integration only):
  • 검토한 대안:
  • 비교 핵심: ca-tmpl 6-level taxonomy는 classic pyramid에 contract·architecture·slice를 명시 분리한 형태. 5min budget + Testcontainers cost가 unit/contract/architecture를 integration과 분리한 핵심 이유. Testcontainers 공식 "real services" 입장이 ca-tmpl integration-only 강제와 정합. Test trophy/Honeycomb은 frontend·SPA 진영이라 backend ca-tmpl과 trade-off 다름.

추가 조사 (2026-06-15 — /branch-spec 자동조사: D2·D7 UNSUPPORTED 해소)

  • D2 (architecture test as level) — ArchUnit 공식 + Building Evolutionary Architectures:
    • 비교한 대안: (1) ArchUnit 전용 architecture-test level, (2) fitness function 일반 메커니즘(jQAssistant/Deptective/custom), (3) 수동 코드 리뷰.
    • 조건부 결론: ca-tmpl 처럼 패키지 경계 = layer 경계인 JVM/Spring Boot 프로젝트 → Alt 1(ArchUnit). 이미 archunit-junit5:1.3.0 의존성 존재(도입비용 0). 복잡한 경계(그래프 탐색 필요) → Alt 2(jQAssistant, 단 GPLv3). 1~2인 단명 프로젝트 → Alt 3(수동, 단 skeleton fork 강제력 없음 → ca-tmpl 부적합).
    • 잔존 갭: "architecture-test를 unit/integration과 동급의 별도 taxonomy level로 정의한 업계 공식 표준은 없음." fitness function 개념이 "architecture test ≠ unit test"임을 book-grade authority로 간접 지지하는 수준. Open Risk(D2)에 명시.
  • D7 (Spring slice test) — Spring Boot 공식 reference:
    • 비교한 대안: (1) Spring test slice(@WebMvcTest/@DataJpaTest), (2) @SpringBootTest 전체 context, (3) MockMvcBuilders.standaloneSetup/순수 mock.
    • 조건부 결론: controller HTTP wire(routing/advice/security) → @WebMvcTest(slice level). JPA query → @DataJpaTest(slice level). 전체 context wire → @SpringBootTest(= integration level). Spring 없는 controller 단위 → standaloneSetup(= unit level). 두 slice annotation 한 클래스 혼용은 Spring 공식이 "not supported"(SB-SLICE-C2) → forbidden 직접 근거.
    • 잔존 갭: "hex use-case slice 와 Spring slice 명시 분리"의 hex 측 외부 근거는 미archive — UNSUPPORTED_IMPL_DECISION 잔존(D7 Open Risk).

TODO

TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / "Test Level Matrix" / "판정 기준" / "테스트 계약" 참조. taxonomy 구분/fixture 사용/test data PII/optional adapter matrix/failure ownership/CI gate mapping 모두 표 또는 결정 라인으로 반영됨. 잔존 TODO 없음.

Work Item Contract

각 TODO는 아래 판정 단위로 재작성되어야 canonical 승급 가능합니다. TODO가 단순히 기준 작성으로 남아 있으면 이 branch는 완료로 보지 않습니다.

field required rule
Decision yes 구현자가 선택해야 하는 기본값
Allowed yes 허용되는 예외와 조건
Forbidden yes 절대 금지되는 구현/문서 상태
Required registry update conditional error/env/header/log/metric/capability 변경 시 필수
Required contract test yes 계약 위반 시 실패해야 하는 테스트
Failure condition yes review/build에서 실패로 판정할 상태
Canonical extraction target yes wiki/projects 승급 위치

진행 중 메모

문서/설계 단계. 코드 구현은 ca-tmpl 측에서 진행 중이며, 본 노트의 일부 결정은 실제 구현과 drift 발생 — §Audit & Findings 참조.

  • 2026-06-15 (/branch-spec): ca-tmpl ground truth 대조 결과, 본 branch 결정 중 architecture-test(D2)·contract-test(D1/D5)·slice(D7)·Testcontainers(D3)·sample 누수 방어(테스트 계약)는 이미 코드에 구현되어 있음(actually-implemented). 단 fixture 배치(D6)·contract 도구(D5)·sample 누수 방어 메커니즘은 결정과 코드가 불일치(§Audit). 노트의 "현재 documented-only 단계" 자기 서술은 stale.

결정 사항

  • 2026-05-22: contract test는 운영 계약 위반을 잡고, integration test는 provider 연동을 잡음.
  • 2026-05-22: architecture test는 CA boundary와 package blueprint 위반을 잡음.
  • 2026-05-22: Testcontainers는 integration test부터 강제. unit/contract/architecture test는 Testcontainers 금지.
  • 2026-05-22: CI time budget 기본값은 unit+contract+architecture 5분 이내, integration matrix는 별도 gate.
  • 2026-05-22: contract test 도구 = (1) envelope/error/log/env shape: JSON snapshot test (approvaltests-java 또는 자체 snapshot) (2) OpenAPI drift: springdoc-openapi 생성 vs checked-in snapshot diff (3) consumer-driven contract는 boundary 외부 통합 시만 도입(현재 skeleton out-of-scope).
  • 2026-05-22: fixture 위치 = Gradle src/testFixtures/java/<feature>/ source set. 명명 = *Fixture.java (정적 factory), *Mother.java는 alias.
  • 2026-05-22: slice test 정의 = Spring slice (@WebMvcTest/@DataJpaTest)는 허용 단 hex slice(use case + port + mapper)와 명시적으로 분리. 동일 메서드에 두 slice annotation 혼용은 forbidden.
  • 2026-05-22: flaky test ownership = test file의 첫 author 또는 가장 최근 maintainer. 14일 quarantine sunset (feature-ci-quality-gates와 cross-link).
  • 2026-05-22: flaky test quarantine 정책 SSOT는 ci-quality-gates-contract(sunset 14일). 본 branch는 flaky 발생 시 quarantine bucket 분리만 명시.
  • 2026-06-19 (구현 정합 — ca-tmpl 코드 작업, 사용자 fork 확정): 노트가 "사용자 정합" 으로 남겨둔 4개 fork 를 확정하고 app-bootstrap test 트리에 구현.
    • (1) D3 / DIR_LEVEL: Testcontainers 를 쓰던 bootstrap/contract[/outbox]/ 5개 test + OutboxContainerTestSupportbootstrap/integration[/outbox]/ 로 재분류 + ..contract..·..architecture.. 패키지가 Testcontainers 에 의존하면 fail 하는 ArchUnit rule TestTaxonomyArchitectureTest.contract_and_architecture_tests_do_not_depend_on_testcontainers(positive-control 로 ..integration.. 에서 발화 증명) 추가 → §테스트 계약 #4 ENFORCED.
    • (2) D6 / FIXTURE_LAYOUT: src/testFixtures 마이그레이션 대신 현행 fixtures/ package 유지 + main classpath 누수 차단 rule CleanArchitectureTest.production_code_does_not_depend_on_test_fixtures(@ArchTest, fixtureleak violation 으로 meta-verify) 추가. 2026-05-22 의 src/testFixtures+*Mother 결정은 superseded — 현 fixture 는 모듈 간 공유가 아니라 source-set 분리 이점이 낮음.
    • (3) SAMPLE_GUARD: sample 누수 방어는 기존 build-time ArchUnit module rule production_code_does_not_depend_on_sample_portfolio 유지 — runtime @ActiveProfiles(prod/staging) ApplicationContext check 는 미채택, §테스트 계약 #3 명세를 build-time 기준으로 갱신(prod/staging yml 신설 없음).
    • (4) D4 / CI: 5분 budget + contract-change/blueprint-change 동반 git-diff gate 는 GitHub Actions 신설 보류(planned) — ca-tmpl 에 CI workflow 부재, CI matrix 는 raw/branch-notes/feature-ci-quality-gates-contract 와 함께 후속.
    • 추가: D7 slice-mixing ban(SB-SLICE-C2) 을 TestTaxonomyArchitectureTest.slice_tests_do_not_mix_two_spring_slice_annotations(@WebMvcTest+@DataJpaTest 한 클래스 금지; over-block guard 포함) 으로 구현. hex-slice 분리는 convention 유지(UNSUPPORTED_IMPL_DECISION).
    • 검증: :app-bootstrap:test --tests '*TestTaxonomyArchitectureTest' 6/6 PASS, --tests '*CleanArchitectureTest' PASS, verifyCleanArchitectureDependencies GREEN, architect-sentinel ready(0 blocking). 변경은 src/test/** 한정 — production·src/build.gradle·module 의존 그래프 무변경. 계획서: ca-tmpl/docs/superpowers/plans/2026-06-19-test-taxonomy-fixture-contract.md.

판정 기준

구분 기준
Decision test taxonomy를 분리해 실패 원인을 즉시 알 수 있게 함
Allowed 작은 프로젝트는 디렉터리를 합치되 test tag/name으로 구분
Forbidden contract violation을 integration test에서만 우연히 발견
Required groups unit, contract, architecture, slice, integration, smoke
Failure condition 어떤 테스트가 어떤 계약을 보호하는지 문서화되지 않으면 실패

Test Level Matrix

level owns Testcontainers
unit pure function/domain rule no
contract response/log/env/error/registry contract no
architecture package/import/capability rules no
slice controller/use case/mapper slice optional no external provider
integration DB/Redis/Kafka/outbound provider yes when provider needed
smoke bootstrap/sample removal/startup optional

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. Decision ID 는 이 branch-note 안에서 안정적으로 유지. 선택 조건 열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면 N/A.

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 contract test는 운영 계약 위반을 잡고, integration test는 provider 연동을 잡음 운영 계약(envelope/error/log/env/registry) shape 위반 검증 → contract test(Testcontainers 없음). 실제 provider 연동(DB/Redis/Kafka/outbound) 검증 → integration test. 계약과 연동을 한 테스트에 섞으면 실패 원인 모호 → 항상 분리 raw/official-docs/test-taxonomy-practical-pyramid-fowler.md#TPP-FOWLER-C2, raw/official-docs/test-taxonomy-practical-pyramid-fowler.md#TPP-FOWLER-C4, raw/official-docs/test-taxonomy-practical-pyramid-fowler.md#TPP-FOWLER-C6 engineering-blog (Fowler/Vocke 정의 + 팀 합의 원칙) Fowler 의 narrow integration 정의는 "test double" 가정 — Testcontainers real-container 와의 일관성은 별도 검증
D2 architecture test는 CA boundary와 package blueprint 위반을 잡음 패키지 경계 = layer 경계인 JVM/Spring Boot → ArchUnit architecture-test(이 결정). 경계가 annotation/runtime 기반이거나 polyglot → fitness function 일반 메커니즘(jQAssistant). 1~2인 단명 프로젝트 → 수동 리뷰. ca-tmpl 은 전자 raw/official-docs/governance-archunit-official.md#AU-OFF-C1, raw/official-docs/governance-archunit-official.md#AU-OFF-C2, raw/official-docs/archunit-user-guide.md#ARCHUNIT-UG-C4, raw/official-docs/archunit-conditional-on-property-3-layer-pattern.md#AUCP-C5 (fitness function 정의) — ca-tmpl 코드 actually-implemented: app-bootstrap/.../architecture/CleanArchitectureTest.java, DisabledAdapterArchitectureTest.java (archunit-junit5:1.3.0, build.gradle:47) official-vendor-doc (ArchUnit) + book-concept (Evolutionary Architectures via AUCP-C5) "architecture-test를 별도 taxonomy level로 정의한 업계 공식 표준은 없음" — fitness function 개념이 unit test와 다른 관심사임을 간접 지지하는 수준. 단 ca-tmpl 코드엔 실제 구현됨 → §Audit D2_NOW_IMPLEMENTED
D3 Testcontainers는 integration test부터 강제. unit/contract/architecture test는 Testcontainers 금지 real service(DB/Redis/Kafka/provider) 필요 → integration test에서 Testcontainers. pure logic/계약 shape/패키지 규칙 → Testcontainers 금지(5min budget·D4 보호). H2 대체는 Testcontainers 공식이 부적합 명시 raw/official-docs/test-taxonomy-testcontainers-official.md#TC-OFFICIAL-C1, raw/official-docs/test-taxonomy-testcontainers-official.md#TC-OFFICIAL-C3, raw/official-docs/test-taxonomy-testcontainers-official.md#TC-OFFICIAL-C5ca-tmpl actually-implemented: testcontainers:postgresql+junit-jupiter (app-bootstrap build.gradle:28-29), @Testcontainers in contract/outbox/* official-vendor-doc (real services + H2 한계) Testcontainers 공식은 integration 권장만, 다른 level 금지는 ca-tmpl 별도 결정 (5분 budget 보호)
D4 CI time budget 기본값은 unit+contract+architecture 5분 이내, integration matrix는 별도 gate unit+contract+architecture 합산 → 5분 gate. integration matrix → 별도 gate(시간 무제한). 5분은 local fast-feedback 목표치이지 측정된 임계값 아님 UNSUPPORTED_DECISION (자료에 5분 정량 기준 부재) team-policy (Testcontainers TC-OFFICIAL-C4 의 "IDE 실행 가능성" 만 간접 지지) 실제 측정으로 5분 임계점 검증 필요 (container start cost 포함). §Claims To Verify 1행
D5 contract test 도구 = JSON snapshot (approvaltests-java) + OpenAPI drift (springdoc) + CDC out-of-scope envelope/error/log/env shape → JSON snapshot. OpenAPI drift → springdoc 생성 vs checked-in diff. boundary 외부 통합 시만 → CDC(현 skeleton out-of-scope) raw/official-docs/test-taxonomy-testcontainers-official.md#TC-OFFICIAL-C1 (Testcontainers 자체 정의는 integration 영역) — contract 도구 자체 근거는 feature-contract-verification-test-suite branch 의 source 가 SSOT(위임) cross-branch-reference 본 branch 의 책임 범위 — 도구 선택 근거는 verification branch 가 owner. DRIFT: 실제 코드는 approvaltests-java 미사용, OpenApiSnapshotTest.java 기반 → §Audit CONTRACT_TOOL_DRIFT
D6 fixture 위치 = Gradle src/testFixtures/java/<feature>/ source set, 명명 *Fixture.java / *Mother.java alias fixture가 여러 test module에서 재사용 → 공유 source set(이 결정). 단일 모듈 한정 → 해당 모듈 test 트리 내 package UNSUPPORTED_DECISION (자료에 src/testFixtures 권장 직접 명시 없음) team-convention (Gradle Java Library plugin 공식 페이지 별도 raw 등록 권고) Gradle 공식 documentation raw source 보강 필요. DRIFT: 실제 코드는 java-test-fixtures 플러그인/src/testFixtures 미적용 — fixtures는 src/test/java/.../fixtures/ package(예: sample-portfolio/.../fixtures/SamplePortfolioFixture.java), *Mother.java 없음 → §Audit FIXTURE_LAYOUT_DRIFT (사용자 정합 필요)
D7 slice test 정의 = Spring slice 허용하되 hex slice 와 명시 분리, 동일 메서드 혼용 forbidden controller HTTP wire(routing/advice/security) → @WebMvcTest. JPA query → @DataJpaTest. 전체 context wire → @SpringBootTest(=integration level). Spring 없는 controller 단위 → standaloneSetup(=unit level). 두 slice annotation 한 클래스 혼용 → forbidden raw/official-docs/spring-boot-test-slices-webmvctest-datajpatest-official.md#SB-SLICE-C1 (slice semantics — 제한된 component scan), raw/official-docs/spring-boot-test-slices-webmvctest-datajpatest-official.md#SB-SLICE-C2 (여러 @…Test 혼용 not supported — 혼용 forbidden 직접 근거), raw/official-docs/spring-boot-test-slices-webmvctest-datajpatest-official.md#SB-SLICE-C3 (@WebMvcTest scan 목록), #SB-SLICE-C4 (@Component 자동 제외) — ca-tmpl actually-implemented: @WebMvcTest in sample-portfolio/.../WorkLogControllerWireTest. @DataJpaTest 미사용(planned). "hex slice 와 명시 분리" 부분은 UNSUPPORTED_IMPL_DECISION 잔존 official-vendor-doc (혼용 금지) + team-convention (hex 분리) "hex slice 와 명시 분리" 결정의 외부 근거 보강 필요 (hexagonal architecture 원전 raw 미등록)
D8 flaky test ownership = test file 첫 author 또는 가장 최근 maintainer, 14일 quarantine sunset flaky 발생 → 본 branch 는 quarantine bucket 분리만. ownership/sunset 정책 자체 → feature-ci-quality-gates-contract 가 SSOT(위임) UNSUPPORTED_DECISION (본 branch 자체에 ownership/sunset 자료 인용 없음 — feature-ci-quality-gates-contractcompany-case-study (Spotify/Google quarantine) 가 SSOT) cross-branch-reference ci-quality-gates-contract 의 company-case-study 는 official best practice 아님

구현 가이드

결정이 "무엇을 할 것인가"라면, 본 §는 "어디에 어떻게 구현되는가"의 사전 명세 — 다음 구현자가 되묻지 않아도 코드를 작성할 수 있는 수준. anchor 는 §2(/branch-spec)에서 대조한 실제 ca-tmpl 코드 경로이며, 코드로 확인 안 된 것은 planned 로 표기. 3-rule: R1 각 cell 은 Decision ID + Supporting Claim 도출 · R2 근거 없는 detail 은 UNSUPPORTED_IMPL_DECISION + trade-off 한 줄 · R3 본 branch 범위 밖은 §Audit 로 이관.

1. Test level → 디렉터리/메커니즘 매핑

Trace: D1 · D2 · D3 · D7 + Test Level Matrix. 등급은 §2 코드 grep 으로 확정.

level 실제 경로/메커니즘 (ca-tmpl) 등급
unit domain-core/src/test/java/.../unit/ + 도메인 per-class 테스트 (Testcontainers 없음) actually-implemented (부분)
contract <module>/src/test/java/.../contract/app-bootstrap(18 classes)·adapter-outbound·adapter-web·shared-contract. D1 운영 계약 shape 검증 actually-implemented
architecture app-bootstrap/.../architecture/CleanArchitectureTest.java(domain_is_pure, value_objects_have_no_public_no_arg_constructor, production_code_does_not_depend_on_sample_portfolio:576), DisabledAdapterArchitectureTest.java. archunit-junit5:1.3.0. D2 actually-implemented
slice @WebMvcTestsample-portfolio/.../WorkLogControllerWireTest·VersioningPrefixTest. @DataJpaTest 없음. D7(SB-SLICE-C1/C3/C4) actually-implemented(@WebMvcTest) / planned(@DataJpaTest)
integration app-bootstrap @Testcontainers (contract/outbox/Outbox*ContractTest). D3(TC-OFFICIAL-C1) actually-implemented
smoke app-bootstrap/.../smoke/ (bootstrap/startup). D1 actually-implemented(부분)
  • UNSUPPORTED_IMPL_DECISION: 6-level 을 디렉터리에 1:1 강제하는 메커니즘(어떤 test가 어떤 level인지 ArchUnit rule/JUnit tag로 고정)은 미정 — 현재는 디렉터리 convention 만 존재. trade-off: convention 은 가볍지만 신규 test가 잘못된 level 에 놓여도 build 가 막지 않음(강제 < 관례). 강제까지 원하면 @Tag + ArchUnit "test class 위치 ↔ tag 일치" rule 추가 필요(planned).
  • integration test 가 ca-tmpl 에서 contract/outbox/ 하위에 위치 — Test Level Matrix 의 level 명과 디렉터리 명이 1:1 아님(outbox integration 이 contract 폴더 안). 명칭 정합은 §Audit 후보(비차단).

2. Fixture 배치 (D6) — 결정 vs 코드 DRIFT

Trace: D6 (UNSUPPORTED_DECISION). §2 코드 대조에서 drift 확정.

  • 결정 명세: src/testFixtures/java/<feature>/ Gradle source set + *Fixture.java/*Mother.java.
  • 실제 코드(actually-implemented): fixtures 는 test source set 내 fixtures/ package (sample-portfolio/.../fixtures/SamplePortfolioFixture.java) + ArchUnit violation fixtures (architecture/violations/.../*Fixture.java). java-test-fixtures 플러그인·src/testFixtures 디렉터리 없음. *Mother.java 없음.
  • UNSUPPORTED_IMPL_DECISION + DRIFT: 결정과 코드가 불일치. 다음 구현자는 결정을 따를지 코드를 따를지 되묻게 됨 → 사용자 정합 필요. 두 옵션의 trade-off:
    • (a) 결정대로 java-test-fixtures 마이그레이션 — fixture 가 main classpath 로 새지 않음을 plugin 이 강제. 비용: source set 분리 + 모든 fixture 이동.
    • (b) 결정을 코드 현실(fixtures/ package)로 갱신 — 가볍지만 누수 차단은 별도 ArchUnit rule(noClasses().that().resideIn("..fixtures..").should().dependOnClassesThat()..., §Claims To Verify 2행)에 의존.
    • 정합 전까지 D6 는 UNSUPPORTED_DECISION 유지. 상세 → §Audit FIXTURE_LAYOUT_DRIFT.
    • RESOLVED (2026-06-19): 옵션 (b) 채택 — fixtures/ package 유지 + ArchUnit 누수 rule production_code_does_not_depend_on_test_fixtures 추가. §결정 사항 2026-06-19 / §Audit.

3. Sample fixture prod 누수 방어 (테스트 계약) — 메커니즘 DRIFT

Trace: §테스트 계약 "sample fixture prod leakage 검사". §2 코드 대조에서 drift 확정.

  • 결정 명세: @ActiveProfiles("prod"|"staging") 테스트의 ApplicationContext 에서 sample package class 0개 + ArchUnit 으로 @ActiveProfiles prod/staging test 의 features.sample import 금지.
  • 실제 코드(actually-implemented): 누수 방어는 build-time ArchUnit rule production_code_does_not_depend_on_sample_portfolio (CleanArchitectureTest.java:576) — production scope ↛ sample-portfolio module 의존 차단. sample 은 features.sample package 가 아니라 sample-portfolio module(test classpath only). application-prod.yml/application-staging.yml 없음.
  • UNSUPPORTED_IMPL_DECISION + DRIFT: 명세 메커니즘(runtime @ActiveProfiles + ApplicationContext bean count)과 실제(build-time module-dependency ArchUnit rule)가 다름. trade-off: build-time module rule 은 compile graph 를 막아 더 이르게 실패하지만 runtime profile-conditional 활성 여부는 검증 못 함; runtime check 는 실제 활성 bean 을 보지만 늦게 실패. 정합 권고 → §Audit SAMPLE_GUARD_MECHANISM_DRIFT.
  • RESOLVED (2026-06-19): build-time module rule 유지로 확정(옵션 b). runtime @ActiveProfiles check·prod/staging yml 미추가 — 위 trade-off 의 "이른 실패 + compile graph 차단" 을 우선. §결정 사항 2026-06-19.

4. Contract 도구 (D5) — 도구 DRIFT

Trace: D5 (cross-branch-reference; 도구 owner 는 feature-contract-verification-test-suite).

  • 결정 명세: JSON snapshot = approvaltests-java(또는 자체) + OpenAPI drift = springdoc 생성 vs checked-in diff.
  • 실제 코드(actually-implemented): approvaltests 의존성 없음. OpenAPI snapshot = sample-portfolio/.../openapi/OpenApiSnapshotTest.java. contract/ 디렉터리는 ArchUnit/custom 기반 contract test.
  • UNSUPPORTED_IMPL_DECISION + DRIFT: 본 branch 는 도구 owner 아님(verification branch 위임) — 도구 결정 정합은 그 branch 가 수행. 본 노트는 drift 만 surface → §Audit CONTRACT_TOOL_DRIFT.

5. CI gate 매핑 (테스트 계약 contract-change

Trace: §테스트 계약 "contract-change 동반 test 검사" · "blueprint-change 동반 architecture test 검사".

  • git diff regex 기반 CI step 2종(registry/owner-branch 변경 ↔ src/test/**/contract/ 변경 동반, blueprint/enforcement 변경 ↔ src/test/**/architecture/ 변경 동반). planned — §2 ground truth 에서 dual-mode CI matrix workflow 미발견, canonical doc 도 "CI matrix 미작성" 명시.
  • UNSUPPORTED_IMPL_DECISION: git diff regex 의 false positive/negative(파일 rename, 신규 registry 파일 추가 시 false miss). trade-off: regex 는 가볍지만 경로 변경에 취약 → §Claims To Verify 6행으로 검증 위임.
  • DEFERRED (2026-06-19, planned 유지): ca-tmpl 에 .github/workflows 부재 — CI gate 신설을 이번 구현에서 보류. 5분 budget 측정·companion-change gate 는 raw/branch-notes/feature-ci-quality-gates-contract 와 함께 후속. 본 branch 의 로컬 강제(§테스트 계약 #3·#4 + slice rule)는 ArchUnit 으로 완료. §결정 사항 2026-06-19.

Audit & Findings

/branch-spec(2026-06-15) ca-tmpl 코드 ground truth 대조에서 발견한 결정↔코드 drift. 사용자 작성 결정 영역이므로 자동 rewrite 하지 않고 정합 권고만 기록. 등급은 §2 직접 grep 으로 확정.

Finding 결정(노트) 코드(ca-tmpl ground truth) 권고
FIXTURE_LAYOUT_DRIFT (D6) src/testFixtures/java/<feature>/ source set + *Fixture.java/*Mother.java java-test-fixtures 플러그인·src/testFixtures 없음. fixtures = src/test/java/.../fixtures/ package (sample-portfolio/.../fixtures/SamplePortfolioFixture.java), architecture/violations/.../*Fixture.java. *Mother.java 없음 RESOLVED (2026-06-19, 옵션 b): 현행 fixtures/ package 유지로 확정 + main-classpath 누수 차단 rule CleanArchitectureTest.production_code_does_not_depend_on_test_fixtures 추가. src/testFixtures 결정 superseded — §결정 사항 2026-06-19
CONTRACT_TOOL_DRIFT (D5) approvaltests-java JSON snapshot + springdoc OpenAPI diff approvaltests 의존성 없음. OpenAPI snapshot = OpenApiSnapshotTest.java. 도구 owner = feature-contract-verification-test-suite 도구 결정 정합은 verification branch 에서; 본 노트는 surface 만
SAMPLE_GUARD_MECHANISM_DRIFT (테스트 계약) @ActiveProfiles("prod"/"staging") + ApplicationContext bean 0개 + features.sample import 금지 build-time ArchUnit production_code_does_not_depend_on_sample_portfolio(CleanArchitectureTest.java:576); sample-portfolio module(≠ features.sample package); prod/staging yml 없음 RESOLVED (2026-06-19, 옵션 b): build-time ArchUnit module rule 유지로 확정 — runtime @ActiveProfiles check 미채택, §테스트 계약 #3 명세를 build-time 기준으로 갱신. §결정 사항 2026-06-19
D2_NOW_IMPLEMENTED (positive) D2 UNSUPPORTED + Claims planned; canonical skeleton-governance-...-scorecard.md "실제 구현 내용: 없음" architecture-test 실제 구현됨(CleanArchitectureTest.java, DisabledAdapterArchitectureTest.java, violation fixtures 까지) canonical project doc 의 "documented-only/없음" 서술이 stale — /ingestactually-implemented 로 갱신 권고
DIR_LEVEL_NAME_DRIFT (D3 / Test Level Matrix) D3: "contract test 는 Testcontainers 금지" + Test Level Matrix 가 contract/integration 을 별개 level 로 분리 contract/outbox/Outbox*ContractTest@Testcontainers 사용(OutboxAppendTransactionalContractTest.java:31) — 실체는 integration-level test 가 contract/ 디렉터리에 mis-filed (D3 와 표면상 충돌하나 본질은 위치/명칭 drift, 계약 위반 아님) RESOLVED (2026-06-19): Task 1 에서 outbox Testcontainers tests 를 bootstrap/integration/outbox/ 로 재분류 완료. contract/ tree 에 Testcontainers 의존 없음 — TestTaxonomyArchitectureTest.contract_level_tests_have_no_testcontainers_dependency() PASS 로 검증됨

엣지·실패·의존

R4 캡처. 정상 경로 외 구현 중 부딪힐 실패/엣지 + 다른 계약 의존을 미리 열거.

  • 실패·엣지 경로:
    • ArchUnit rule typo → false negative(silent pass): 패키지 패턴 오탈자면 위반을 못 잡고 통과. 방어 = 의도적 violation fixture(architecture/violations/.../*Fixture.java)로 rule 이 실제 fail 하는지 메타검증. ca-tmpl 에 이미 존재(actually-implemented). §Claims To Verify 4행.
    • @WebMvcTest + Spring Security → context 적재 비용 증가: security filter chain 스캔으로 slice 속도 이점 감소, 5분 budget(D4) 위협. 방어 = @Import(SecurityConfig) 수동 제어.
    • @DataJpaTest H2 기본값 ↔ Testcontainers real DB 불일치: slice 가 H2, integration 이 Postgres 면 query 동작 차이. 방어 = @AutoConfigureTestDatabase(replace=NONE) (planned@DataJpaTest 미도입).
    • 두 slice annotation 한 클래스 혼용: Spring 공식 "not supported"(SB-SLICE-C2) — context 가 의도와 다르게 작동. 방어 = ArchUnit rule(planned, §Claims To Verify 3행).
    • contract-change CI regex false miss: 파일 rename / 신규 registry 파일이면 동반 test 강제를 우회. §Claims To Verify 6행.
    • fixture 누수: fixture 가 main classpath 로 새면 prod 빌드 오염. D6 drift 로 현재 plugin 강제 부재 → ArchUnit rule 의존(§구현 가이드 2).
    • smoke level 실패: bootstrap context 적재 실패(컨테이너 미기동/포트 충돌) → fail-fast; sample removal 미완 상태로 startup 시 smoke fail. Test Level Matrix 가 smoke Testcontainers 를 optional 로 두어 분기 모호 → 아래 gate 귀속 규칙으로 해소.
  • level → CI gate 귀속 (D4 보강): D4 의 5min gate 는 {unit, contract, architecture} 한정. slice·smoke 중 외부 의존(Testcontainers/real provider)이 있는 것은 integration matrix gate(시간 무제한), 없는 것은 5min gate. 즉 gate 분기 기준은 level 이름이 아니라 외부 의존 유무. (@DataJpaTest H2-only slice = 5min gate, Testcontainers smoke = integration gate.)
  • 다른 계약 의존:

테스트 계약

  • contract-change 동반 test 검사: PR diff에 다음 중 1개라도 변경이 포함되면(ca-tmpl/docs/registries/*.yaml, feature-operational-error-observability-foundation 결정 사항, feature-log-management-contract 결정 사항, feature-env-driven-runtime-configuration 결정 사항) PR diff에 src/test/**/contract/ 디렉터리의 file 변경도 포함되어야 함. 측정 방법: GitHub Actions step git diff --name-only origin/main..HEAD | grep -E "(registries/.*\.yaml|feature-(operational-error|log-management|env-driven).*\.md)" 결과 != empty이고 git diff --name-only origin/main..HEAD | grep "src/test/.*contract/" 결과 == empty이면 fail.
  • blueprint-change 동반 architecture test 검사: PR diff에 feature-skeleton-package-blueprint-contract.md 또는 feature-architecture-enforcement-rules.md 변경이 포함되면 src/test/**/architecture/ 디렉터리의 file 변경도 포함되어야 함. 측정 방법: 동일 git diff regex 조합. 불일치 시 fail.
  • sample fixture prod leakage 검사: production profile(application-prod.yml, application-staging.yml)이 활성된 SpringBootTest 또는 Testcontainers integration test에서 features.sample. package의 class가 ApplicationContext에 등록되거나 fixture로 사용되면 fail. 측정 방법: @ActiveProfiles("prod") 또는 @ActiveProfiles("staging") 테스트 실행 후 ApplicationContext.getBeanNamesForType(...) 결과에서 sample package class 0개여야 함. 또한 ArchUnit으로 @ActiveProfiles value가 prod/staging인 test class는 sample package import 금지. (RESOLVED 2026-06-19: ca-tmpl 채택 메커니즘은 build-time ArchUnit module rule production_code_does_not_depend_on_sample_portfolio 로 확정 — 위 runtime @ActiveProfiles/ApplicationContext bean-count 명세는 미채택. §Audit SAMPLE_GUARD_MECHANISM_DRIFT / §결정 사항 2026-06-19)
  • contract/architecture test가 Testcontainers에 의존하면 실패. (ENFORCED 2026-06-19: TestTaxonomyArchitectureTest.contract_and_architecture_tests_do_not_depend_on_testcontainers..contract../..architecture.. 코퍼스에 위반 없음 + ..integration.. positive-control 로 발화 증명. manual-importer 사용 이유는 @AnalyzeClasses(DoNotIncludeTests) 가 test bytecode 미포함이기 때문.)

검증해야 할 주장

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

Claim Why uncertain How to verify Status
unit+contract+architecture test 합산이 5분 이내 완료 가능 Testcontainers 공식 자료 (TC-OFFICIAL-C4) 는 IDE 실행 가능성만 보장, 시간 budget 정량 보장 없음 CI workflow 에서 unit+contract+architecture job 실행 시간 측정 + 5분 초과 시 알림 needs-confirmation
src/testFixtures/java/<feature>/ source set 이 도메인 분리를 실제로 강제 Gradle source set 자체는 fixture 위치만 강제, 도메인 분리는 별도 ArchUnit rule 필요. DRIFT: 현재 코드는 testFixtures 미사용(fixtures/ package) → 이 Claim 은 결정(b) 채택 시에만 유효 ArchUnit noClasses().that().resideIn("..testFixtures..").should().dependOnClassesThat().resideInAPackage("..features.[^.]+..") 룰 작성 후 위반 검출 planned
@WebMvcTest/@DataJpaTest 와 hex slice 가 한 클래스에서 혼용되지 않음 Spring 공식(SB-SLICE-C2)은 혼용을 "not supported" 로 명시하나 hex slice 와의 분리는 별도 — 혼용 시 context 확장이 의도와 다르게 작동 가능 ArchUnit / custom test 로 @WebMvcTest 또는 @DataJpaTest 가 붙은 class 가 hex slice 구성 요소 (use case interface 등) 와 같은 file 에 없는지 검사 planned
ArchUnit boundary rule 이 ca-tmpl package blueprint 위반을 모두 탐지 ArchUnit DSL 표현력 한계 가능 + rule typo 시 silent false negative 의도적 boundary 위반 코드(violation fixture)를 추가하고 ArchUnit 이 fail 하는지 확인 — ca-tmpl 에 architecture/violations/.../*Fixture.java 이미 존재(actually-implemented) locally-verified(메커니즘 존재) / planned(전수성)
sample-portfolio fixture 가 production scope 에서 제거됨 노트 명세(@ActiveProfiles("prod") ApplicationContext check)와 실제 메커니즘(build-time ArchUnit module rule)이 다름 — §Audit SAMPLE_GUARD_MECHANISM_DRIFT CleanArchitectureTest.production_code_does_not_depend_on_sample_portfolio(L576) 가 production↛sample-portfolio 의존을 차단하는지 확인 — actually-implemented locally-verified
contract-change 동반 test 검사 git diff regex 가 false positive/negative 없음 regex 가 file 경로 변경 (rename) 또는 새 registry 파일 추가 시 false miss 가능 의도적으로 registry yaml 만 수정한 PR 과 src/test/contract 만 수정한 PR 각각 생성 → CI 동작 verify planned

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

/coverage 가 채우는 생성물 — 손으로 유지하지 않는다. governing 문서(governing_docs: wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard §Test taxonomy, wiki/projects/ca-tmpl/sample-fixture-and-adoption §Sample fixture)가 요구하는 관심사를 본 브랜치가 빠짐없이 덮는지의 결과. 기준: rules/coverage-gate.md. 상태: covered-here(이 브랜치 결정) / delegated(다른 owner 브랜치) / missing(아무도 안 맡음 → Blocking).

생성: /coverage(coverage-auditor, 2026-06-15). governing 2종 + sibling 브랜치 + ca-tmpl 코드 대조. 판정: Covered (Blocking 0).

관심사 상태 owner 심각도 근거
6-level test taxonomy 정의 (unit/contract/architecture/slice/integration/smoke) covered-here D1·D2·D7 + Test Level Matrix; ca-tmpl actually-implemented
Testcontainers 적용 범위 (integration부터 강제 / 타 level 금지) covered-here Advisory D3; 단 contract/outbox/Outbox*ContractTest@Testcontainers 사용 → §Audit DIR_LEVEL_NAME_DRIFT
fixture 격리 방법 (source set vs fixtures/ package) covered-here D6(UNSUPPORTED, drift) → §Audit FIXTURE_LAYOUT_DRIFT
5min CI budget 정책 covered-here D4(team-policy) + §Claims 1행
6-level 디렉터리 강제 메커니즘 covered-here (planned) §구현 가이드 1 UNSUPPORTED_IMPL_DECISION + §Claims 2행
sample fixture production 누수 방어 메커니즘 covered-here §테스트 계약 + §구현 가이드 3 → §Audit SAMPLE_GUARD_MECHANISM_DRIFT
flaky test ownership / quarantine 정책 delegated raw/branch-notes/feature-ci-quality-gates-contract D8 위임 (§엣지·§결정 사항 링크; SSOT = sunset 14일)
contract test 도구 선택 (snapshot/OpenAPI) delegated raw/branch-notes/feature-contract-verification-test-suite D5 위임 (§엣지 링크) → §Audit CONTRACT_TOOL_DRIFT
package blueprint / boundary rule 정의 delegated raw/branch-notes/feature-skeleton-package-blueprint-contract · raw/branch-notes/feature-architecture-enforcement-rules D2 위임 (§엣지 링크)
sample fixture 종류 + 12 scenario + 6-field minimum delegated raw/branch-notes/feature-sample-domain-contract-fixture governing sample-fixture-and-adoption.md §Sample fixture SSOT — raw/branch-notes/feature-sample-domain-contract-fixture
sample-off / adoption 절차 (dual-mode CI matrix · adoption checklist) delegated raw/branch-notes/feature-sample-removal-adoption-contract governing §Sample-off SSOT — raw/branch-notes/feature-sample-removal-adoption-contract (§엣지 링크)

마주친 문제

  • OperationalContractRuntimeTest 2건 실패 (pre-existing)

    • 원인: @WebMvcTest Spring context load 실패 (ConversionFailedException, LenientObjectToEnumConverterFactory). 이 branch 변경과 무관 — 해당 파일은 b314a99 (readme refactoring) 이전 커밋에서 유래하며 본 branch 에서 수정하지 않음.
    • 검증(definitive, controller 2026-06-19): git stash push -u 로 본 branch 변경(tracked+untracked) 전부 제거 → working tree == clean HEAD a0534b9 확인 → ./gradlew :app-bootstrap:test --tests '*OperationalContractRuntimeTest' 실행 → clean HEAD 에서도 동일하게 2건 실패(ConversionFailedException / LenientObjectToEnumConverterFactory) → git stash pop 으로 변경 원복. 본 branch 도입 코드에서 재현되므로 pre-existing 확정.
    • root-cause (2026-06-20): application.yml:339client-ip-mode: ${APP_RATE_LIMIT_CLIENT_IP_MODE}기본값 없는 placeholder.env 없는 ./gradlew test 에서 미해석 리터럴이 RateLimitClientIpMode enum 변환 실패 → context load fail. 상세 → raw/errors/webmvctest-slice-configprops-enum-placeholder-no-default-2026-06-20.
    • 해결 (2026-06-20, 사용자 요청으로 본 세션에서 수정 — rate-limit 관심사라 별도 커밋 권장): application.yml 을 레지스트리 선언값대로 ${APP_RATE_LIMIT_CLIENT_IP_MODE:remote-addr-only} 로 갱신. 검증: --tests '*OperationalContractRuntimeTest' PASS, verifyEnvKeys: OK, 전체 :app-bootstrap:test --rerun-tasks 3회 연속 GREEN.
  • TestTaxonomyArchitectureTest 전체 스위트 flaky/vacuous (2026-06-20)

    • 증상: 단독 6/6 PASS 인데 전체 스위트 첫 실행에서 positive-control 3건 간헐 FAIL(코퍼스 빈 채로). clean-check 는 빈 코퍼스에서 silent vacuous-pass 위험.
    • 원인: positive-control 코퍼스가 importPackages(String) static 필드 — 대형 스위트/stale build 에서 빈 코퍼스 반환 가능. 상세 → raw/errors/archunit-importpackages-empty-vacuous-stale-build-2026-06-20.
    • 해결: positive-control/over-block 코퍼스를 importClasses(Class…) (결정적)로 전환 + 슬라이스 fixture public 승격 + 전용 TestcontainersUsingFixture(..taxonomyfixtures..); clean-check 2건은 importPackages 유지하되 non-vacuity 가드(corpus.size()>0) 추가. 검증: 전체 --rerun-tasks 3회 연속 GREEN.

묶음

Phase C2 (ca-implementer) 실 코드 작업 완료 (2026-06-19).

구현 산출물 (2026-06-19 ca-implementer)

Task 1 — Testcontainers 테스트 재분류 (contract/integration/)

파일 작업
bootstrap/contract/DistributedLockProviderContractTest.java 삭제
bootstrap/contract/IdempotencyUniqueScopeContractTest.java 삭제
bootstrap/contract/outbox/Outbox* (4개) 삭제
bootstrap/integration/DistributedLockProviderContractTest.java 생성 (package 변경만)
bootstrap/integration/IdempotencyUniqueScopeContractTest.java 생성 (JavaDoc FQN 참조 수정)
bootstrap/integration/outbox/Outbox* (4개) 생성 (package + 주석 수정)
bootstrap/integration/package-info.java 생성
bootstrap/integration/outbox/package-info.java 생성

Task 2 — TestTaxonomyArchitectureTest.java 생성 (manual-importer pattern)

  • Rule: contract_and_architecture_tests_do_not_depend_on_testcontainers (allowEmptyShould=true)
  • Meta-tests: contract corpus (isFalse, non-vacuity 가드) · architecture corpus (isFalse, non-vacuity 가드) · TestcontainersUsingFixture positive control (isTrue)
  • plain @Test (NOT @AnalyzeClasses) — 이유: @AnalyzeClassesDoNotIncludeTests 로 test bytecode 미포함
  • 하드닝 (2026-06-20): positive-control/over-block 코퍼스를 importClasses(Class…) 결정적 import 로 전환(flaky/vacuous 수정 — §마주친 문제). clean-check 2건만 importPackages + corpus.size()>0 가드. positive-control 용 taxonomyfixtures/TestcontainersUsingFixture.java 신설(..contract../..architecture.. 밖), 슬라이스 fixture public 승격.

Task 3 — slice_tests_do_not_mix_two_spring_slice_annotations rule + fixtures

  • FQN string 참조 패턴 ("org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest" 등) — compile 의존 없음
  • violations/slice/MixedSliceAnnotationsFixture.java (positive control)
  • allowed/slice/SingleSliceWebMvcFixture.java (over-block guard)

Task 4 — CleanArchitectureTest.java@ArchTest 추가 + fixtureleak fixtures

  • @ArchTest static final ArchRule production_code_does_not_depend_on_test_fixtures
  • violations/fixtureleak/LeakyProductionConsumerFixture.java + violations/fixtureleak/fixtures/LeakedTestFixture.java
  • meta-test: TestTaxonomyArchitectureTest.fixture_leak_rule_fires_on_production_depending_on_fixture()CleanArchitectureTest@ArchTest field 를 직접 참조해 evaluate

Task 5 — 검증 결과

Command Result
./gradlew :app-bootstrap:test --tests '*TestTaxonomyArchitectureTest' 6/6 PASS
./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest' PASS
./gradlew verifyCleanArchitectureDependencies BUILD SUCCESSFUL
./gradlew verifyEnvKeys OK (99 keys, 74 required placeholders covered)
./gradlew :app-bootstrap:test (full, --rerun-tasks) 3회 연속 GREEN (2026-06-20, application.yml fix + test 하드닝 후 — 직전 2-fail 은 §마주친 문제에서 해소)

추가 변경 (2026-06-20, 본 세션): application.yml rate-limit default fix(production resource), TestTaxonomyArchitectureTest 하드닝, taxonomyfixtures/TestcontainersUsingFixture 신설, 슬라이스 fixture public 승격.

오류 기록 (본 feature 작업 중 발생)

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

Blog topics (이 작업에서 나온 글감)

관련 일일 노트

  • [[raw/daily-notes/2026-06-19]] — ca-implementer Phase C2 실 코드 작업 완료 일자

완료 후 wiki 추출 대상

  • wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard.md 의 Test taxonomy(§29 G-G) canonical section + wiki/projects/ca-tmpl/sample-fixture-and-adoption.md 의 fixture 누수 방어 section. (구 경로 wiki/projects/ca-skeleton-operational-contract.md 는 현재 cluster 분리됨.)

완료 후 정리

머지/종료 시점에 채움.

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