Files
llm-wiki/raw/branch-notes/feature-implementation-readiness-scorecard.md
T

366 lines
44 KiB
Markdown

---
title: branch / feature-implementation-readiness-scorecard
source_type: branch-note
status: raw
id: BR-CA-SKELETON-OPERATIONAL-CONTRACT-043
kind: project-work-item
project: ca-skeleton-operational-contract
work_item: WI-CA-SKELETON-OPERATIONAL-CONTRACT-043
inherits: [DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1]
refines: []
overrides: []
depends_on: []
contract_packet: 1
branch: feature-implementation-readiness-scorecard
parent_branch:
related_projects: [ca-skeleton]
governing_docs: [wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard]
tags: [branch, ca-skeleton, readiness, scorecard, quality-gate, multi-module]
created: 2026-05-22
target_merge:
status_label: in-progress
contract_packet_sha256: e252546bb4c59f376e3cbf19938076de6880c5e01703fe37525ea1aea80a8c03
---
# branch: feature-implementation-readiness-scorecard
> Layer: `raw/branch-notes/` — skeleton이 실제 도메인을 받을 준비가 됐는지 binary readiness gate로 판정합니다.
<!-- section-id: branch-parent -->
## 부모 (필수)
- **Parent project (canonical SSOT)**: [[raw/project-notes/ca-skeleton-operational-contract]]
> ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 readiness scorecard 영역을 multi-module Clean Architecture 기준으로 정제한다.
<!-- GENERATED: branch-contract:start -->
<!-- section-id: branch-contract-packet -->
## 브랜치 계약 패킷
- **생성 시 프로젝트 개정**: `1`
- **패킷 스키마**: `contract_packet: 1`
- **완료 조건**: readiness 각 항목이 binary evidence link로 판정된다
<!-- section-id: inherited-project-decisions -->
### 상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1` | 신규 환경의 default 진입 명령은 ./gradlew bootstrap이다 | bootstrap을 포함한 skeleton readiness를 binary evidence로 판정한다 | [[raw/project-notes/ca-skeleton-operational-contract]] |
<!-- section-id: branch-local-decisions -->
### 브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | readiness를 binary gate로 판정한다 | `local` | [[raw/project-notes/ca-skeleton-operational-contract]] | `proposed` |
| D2 | 미통과 항목이 있으면 canonical 승급을 차단한다 | `local` | [[raw/project-notes/ca-skeleton-operational-contract]] | `proposed` |
| D3 | 자동 계산기와 별개로 수동 evidence mapping을 요구한다 | `local` | [[raw/project-notes/ca-skeleton-operational-contract]] | `proposed` |
| D4 | 모든 readiness area가 통과해야 최종 pass한다 | `local` | [[raw/project-notes/ca-skeleton-operational-contract]] | `proposed` |
| D5 | real-domain dry-run evidence는 onboarding owner를 소비한다 | `local` | [[raw/project-notes/ca-skeleton-operational-contract]] | `proposed` |
| D6 | sample-off readiness는 sample-removal evidence를 소비한다 | `local` | [[raw/project-notes/ca-skeleton-operational-contract]] | `proposed` |
<!-- section-id: declared-overrides -->
### 선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|---|---|---|---|
없음.
<!-- GENERATED: branch-contract:end -->
<!-- section-id: branch-goal -->
## 목표
문서가 많아질수록 “좋아 보임”과 “바로 구현 가능함”이 섞입니다. 이 branch는 skeleton이 실제 도메인을 받아도 되는지 판정하는 최종 점검표를 제공합니다. Phase C2 기본값이 Gradle multi-module로 바뀌었으므로 readiness도 단일 package slice가 아니라 module boundary, architecture rule, onboarding checklist, sample-off smoke를 함께 봐야 합니다.
- 이슈:
- PR:
<!-- section-id: branch-scope -->
## 범위
### 포함 범위
- binary readiness scorecard.
- branch canonical 승급 기준.
- multi-module architecture enforcement evidence.
- sample-portfolio 검증 기준.
- sample-off 검증 기준.
- real domain onboarding dry-run 검증 기준.
### 제외 범위
- 실제 점수 자동 계산기 구현.
- project management dashboard.
- business-specific acceptance criteria.
- 새 도메인 module slice 정의 중복 작성. 해당 SSOT는 `feature-domain-feature-onboarding-contract`.
## 근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
| [[raw/official-docs/scorecard-aws-well-architected]] | 질문 기반 HRI flag와 지속 개선형 review 모델 비교 |
| [[raw/official-docs/scorecard-opentelemetry-maturity]] | signal stability/lifecycle 모델 비교 |
| [[raw/official-docs/scorecard-cis-benchmarks-slsa]] | CIS/SLSA의 점진적 maturity scoring 비교 |
| [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] | scorecard 구조 영역의 module blueprint SSOT |
| [[raw/branch-notes/feature-architecture-enforcement-rules]] | architecture boundary pass/fail evidence owner |
| [[raw/branch-notes/feature-domain-feature-onboarding-contract]] | real-domain dry-run checklist SSOT |
| [[raw/branch-notes/feature-sample-removal-adoption-contract]] | sample-off smoke와 sample runtime isolation verification owner |
## TODO
각 항목 옆에 증거 등급 표기: `actually-implemented` | `locally-verified` | `prod-verified` | `documented-only` | `planned` | `needs-confirmation`
- [x] binary readiness model 정의 — 등급: `documented-only`
- [x] 15 area evidence owner mapping 정의 — 등급: `documented-only`
- [x] real-domain dry-run SSOT를 onboarding branch로 확정 — 등급: `documented-only`
- [x] scorecard evidence table에 실제 file path / test name 채우기 — 등급: `actually-implemented`
- [x] ca-tmpl repo에서 readiness gate 자동/수동 검증 실행 및 결과 기록 — 등급: `locally-verified` (Gradle + shell gates 통과, hosted CI/provenance는 `needs-confirmation`)
- [x] scorecard owner slug 3건 drift 정정 반영 확인 (§Audit A1) — 등급: `locally-verified`
## 진행 중 메모
- 2026-05-28: 기존 단일 package dry-run 표기는 폐기한다. scorecard는 `feature-domain-feature-onboarding-contract`의 New Domain Module Slice + Read/Write Difference Table을 consume only 한다.
- 본 branch는 readiness 판정 책임자이지 도메인 onboarding checklist 작성자가 아니다.
- 2026-06-15 (`/branch-spec`): governing_docs 지정 + Decision Evidence Map `선택 조건` 열 + §구현 가이드 + §엣지·실패·의존 추가. scorecard owner slug 3건 drift 정정(§Audit A1), adapter-identifier 모듈 누락(§Audit A2), area 표 16행 vs 선언 15 불일치(§Audit A3) surface. 기존 본문은 verbatim 보존.
- 2026-06-26 (implementation): `Readiness Scorecard`에 실제 file path/test name evidence column을 추가했다. 16행 drift는 `오류`+`예외``오류/예외`로 합쳐 15 area로 reconcile했고, `adapter-identifier` dry-run row를 추가했다. shell-only CI matrix/supply-chain scripts와 Gradle `verifyCleanArchitectureDependencies`, `check verifyPublicPathSnapshot`, `:app-bootstrap:sampleOffTest`를 로컬에서 통과 확인했다.
## 결정 사항
- 2026-05-22: readiness pass는 문서 완성도가 아니라 contract 강제력과 도메인 적용 가능성으로 판정. / 이유: 보기 좋은 문서와 구현 가능한 skeleton을 분리 / 검토한 대안: maturity 점수식 / 근거: [[raw/official-docs/scorecard-aws-well-architected]]
- 2026-05-22: scorecard 미통과 항목이 있으면 canonical 승급하지 않음. / 이유: 미검증 계약을 canonical 사실로 승급하지 않기 위함 / 검토한 대안: known issue로 승급 / 근거: project decision
- 2026-05-22: 자동 계산기는 optional이지만 수동 산식과 branch evidence mapping은 필수. / 이유: 자동화 전에도 재현 가능한 판정이 필요 / 검토한 대안: 구현 후 자동화만 인정 / 근거: [[raw/official-docs/scorecard-cis-benchmarks-slsa]]
- 2026-05-22: readiness pass는 15개 area가 각각 Pass일 때만 부여한다. / 이유: 하나의 회귀가 skeleton adoption 실패로 이어질 수 있음 / 검토한 대안: 부분 점수 누적 / 근거: project decision
- 2026-05-28: area #15의 real-domain dry-run evidence는 onboarding branch의 New Domain Module Slice + Read/Write Difference Table 통과로 판정한다. / 이유: checklist SSOT 충돌 방지 / 검토한 대안: scorecard 내부 checklist 유지 / 근거: [[raw/branch-notes/feature-domain-feature-onboarding-contract]]
## 결정-근거 매핑
> 각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시한다.
> `선택 조건` 열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면 N/A.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | readiness pass = contract 강제력 + 도메인 적용 가능성 binary gate | 판정 목적이 *skeleton 도입 go/no-go* 단일 결정이면 binary gate. 지속 운영 품질을 시계열로 추적해야 하면 maturity score(AWS WAR/OTel/SLSA 류) — governing doc §27: scorecard 는 *도입 gate 한정*, 운영 SLO·코드 품질 maturity 도구 아님 | `raw/official-docs/scorecard-aws-well-architected.md#SC-AWS-WAR-C2`, `raw/official-docs/scorecard-opentelemetry-maturity.md#SC-OTEL-C1` | `official-vendor-doc comparison + project-decision` | 외부 모델은 지속 개선/maturity tracking에 가깝고 ca-tmpl binary gate를 직접 권장하지 않음 |
| D2 | 미통과 항목이 있으면 canonical 승급하지 않음 | 미검증 계약을 canonical 사실로 올리면 안 될 때(기본) 차단. 후속 추적이 보장된 known-issue 프로세스가 있으면 조건부 승급 — ca-tmpl 엔 그런 추적 프로세스 부재 → 차단 채택 | `raw/official-docs/scorecard-aws-well-architected.md#SC-AWS-WAR-C4` | `official-vendor-doc comparison + project-decision` | HRI flag와 release-blocking gate의 의미가 다름 |
| D3 | 자동 계산기는 optional, 수동 evidence mapping은 필수 | 자동화 전에도 *재현 가능한 판정*이 필요하면 manual evidence 필수. 자동 계산기가 구현·검증되면 추가 인정하되, manual table 부재 시 자동만으로는 불인정 | `raw/official-docs/scorecard-cis-benchmarks-slsa.md#SC-CIS-C1` | `official-standard comparison` | scorecard CI step / badge / branch↔area 자동검증은 아직 `planned` |
| D4 | 15 area 모두 Pass일 때만 readiness pass | 한 영역 회귀가 skeleton adoption 실패로 직결되는 *전체 도입 gate* 용도이면 all-pass. 부분 진척 자체가 의미 있는 maturity 추적이면 부분 점수 누적 — 본 용도는 전자 | `raw/branch-notes/feature-contract-verification-test-suite.md`, `raw/branch-notes/feature-ci-quality-gates-contract.md` | `project-decision (consume: owner-branch Decision)` | hosted CI 결과는 별도 확인 필요 |
| D5 | real-domain dry-run checklist는 onboarding branch를 consume | checklist SSOT 가 onboarding branch 에 이미 있으면 consume-only(중복 작성 금지). onboarding branch 부재 시에만 내부 checklist — 현재 존재하므로 consume | `raw/branch-notes/feature-domain-feature-onboarding-contract.md`, `raw/branch-notes/feature-skeleton-package-blueprint-contract.md` | `project-decision (consume: owner-branch Decision)` | onboarding branch가 변경되면 scorecard area #15도 함께 갱신 필요 |
| D6 | sample-off readiness는 sample-removal branch evidence를 consume | sample runtime isolation owner branch 가 별도로 있으면 그 evidence consume. owner 부재 시에만 내부 정의 — 현재 sample-removal branch가 owner | `raw/branch-notes/feature-sample-removal-adoption-contract.md` | `project-decision (consume: owner-branch Decision)` | GitHub-hosted CI run은 아직 확인되지 않음 |
## 구현 가이드
> *결정 (Decisions)* 이 "*무엇* 을 할 것인가" 라면, 본 §는 "*어디에 어떻게* 판정·운영될 것인가" 의 사전 명세. 본 branch 의 산출물은 코드가 아니라 **markdown gate artifact + 수동 판정 절차**다. 구체 표는 바로 뒤의 `Readiness Scorecard` · `Dry-Run Evidence` · `Manual Score Formula` 가 SSOT 로 보유한다.
>
> **3-rule meta principle**: 각 sub-section 은 본 branch 의 Decision ID + Supporting Claim 을 reference(R1). 근거 없는 detail 은 `UNSUPPORTED_IMPL_DECISION` 라벨(R2). 본 branch 결정 범위 밖 cell 은 §Audit 으로 이관(R3).
### 1. Readiness gate artifact & 수동 판정 메커니즘
> **Trace**: D1(binary gate) + D2(미통과 시 승급 차단) + D3(수동 필수·자동 optional) + D4(15-area all-pass). Supporting: `SC-AWS-WAR-C2/C4`, `SC-CIS-C1`, `SC-OTEL-C1`.
>
> - **UNSUPPORTED_IMPL_DECISION**: ① scorecard artifact 의 *물리적 위치* — 현재 본 branch-note 의 `Readiness Scorecard` 표가 SSOT(별도 파일/badge 미작성). 근거 raw 는 "binary gate 가 있어야 한다"만 권고, *어디에 둘지*는 임의 → trade-off: 자동화 전 단계에서 markdown 한 곳에 두는 편이 review·diff 가능. ② "Unknown = Not ready" 의 *Unknown 정의*(evidence cell 공란 또는 owner branch 미존재) — governing doc 미권고, 본 branch 운영 정의.
- **판정 단위**: area 별 `Pass` / `Fail` / `Unknown`. area Pass ⇔ 해당 owner branch 의 `required evidence`가 (a) 존재하고 (b) green. 하나라도 `Fail` 또는 `Unknown` ⇒ readiness `Not ready` (부분 점수 대체 금지 — D4).
- **승급 게이트(D2)**: readiness `Not ready` 인 area 의 owner branch 는 canonical(`wiki/projects/`) 승급 금지. known-issue 우회 없음.
- **자동화(D3)**: scorecard CI step / badge / branch↔area 매핑 자동검증은 `planned` — 미작성. manual evidence table은 file path/test name까지 채웠고, shell-only matrix/supply-chain gate 및 Gradle local gate는 통과했다. 단 hosted CI/provenance 결과는 `needs-confirmation`.
### 2. Area → owner-branch evidence 매핑
> **Trace**: D4(15-area) + D5/D6(consume owner evidence). 각 area 는 sibling branch 1개를 evidence owner 로 지목(governing doc §27: 1:1 branch evidence). 구체 표 = `Readiness Scorecard`.
>
> - **UNSUPPORTED_IMPL_DECISION**: 각 area 의 `required evidence` 종류(어떤 test class / arch rule 이 "Pass" 증거로 카운트되는가)는 owner branch 의 결정 영역에서 도출되나, *15-area 분류 partition 자체*(어떤 관심사를 어느 area 로 묶는가)는 governing doc 이 "15 area" 만 권고하고 enumerate 하지 않음 → 본 branch 의 설계 선택. §Audit A3(16행 vs 15)은 2026-06-26에 `오류/예외` 병합으로 해소했다.
> - **drift 정정(§Audit A1)**: owner slug 3건이 실제 sibling branch 명과 불일치하여 `Readiness Scorecard` 에서 정정함: `feature-env-driven-configuration-contract` → `feature-env-driven-runtime-configuration`, `feature-outbound-http-client-contract` → `feature-outbound-http-client-baseline`, `feature-persistence-failure-contract` → `feature-persistence-failure-baseline`.
### 3. Real-domain dry-run evidence (consume-only)
> **Trace**: D5 — onboarding branch 의 New Domain Module Slice + Read/Write Difference Table 을 consume. 본 branch 는 module row 별 evidence 의 *존재* 만 게이트하고, checklist 내용은 재작성하지 않음(중복 금지, §범위 Out of scope). 구체 표 = `Dry-Run Evidence`.
>
> - **UNSUPPORTED_IMPL_DECISION**: 없음(consume SSOT). module row 집합은 ca-tmpl `src/<module>/` ground truth 에 정합. 기존 누락이던 `adapter-identifier` row는 2026-06-26에 추가했다.
### 4. Sample-off readiness (consume-only)
> **Trace**: D6 — sample-removal branch evidence consume. sample-off smoke = CI 의 sample-on/sample-off 두 profile job. 구체 계약 = `테스트 계약`.
>
> - **UNSUPPORTED_IMPL_DECISION**: 없음(consume owner). sample-off CI job과 gate matrix row는 `.github/workflows/ci-quality-gates.yml` 및 `.github/ci-gate-matrix.yml`에 존재한다. 본 branch는 hosted run 결과가 아니라 evidence 존재와 local gate 결과만 consume한다.
## Readiness Scorecard
| area | pass condition | primary evidence owner | required evidence | actual file path / test name | status |
|---|---|---|---|---|---|
| 구조 | Gradle multi-module blueprint와 dependency direction이 일치 | `feature-skeleton-package-blueprint-contract`, `feature-architecture-enforcement-rules` | Gradle dependency rule + ArchUnit test | `src/build.gradle` `verifyCleanArchitectureDependencies`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java` rules `domain_is_pure`, `application_does_not_depend_on_adapters_or_transport`, `web_adapter_does_not_depend_on_persistence_or_outbound_adapters`, `persistence_adapter_does_not_depend_on_web_or_outbound_adapters`, `identifier_adapter_does_not_depend_on_other_adapters_or_bootstrap`, `production_code_does_not_depend_on_sample_portfolio` | `locally-verified` |
| 응답 | 성공/실패 응답이 envelope와 OpenAPI snapshot을 따른다 | `feature-api-contract-baseline` | response contract test | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/EnvelopeContractTest.java` `success_envelope_shape`, `error_envelope_shape_with_validation_details`, `error_envelope_shape_retryable_transient`; `src/sample-portfolio/src/test/java/dev/caskeleton/sample/portfolio/api/OpenApiSnapshotTest.java` `api_docs_are_generated_and_describe_the_worklogs_contract` | `locally-verified` |
| 오류/예외 | error registry 기반 mapping이 강제되고 raw exception이 adapter-web까지 새지 않는다 | `feature-operational-error-observability-foundation` | error mapping + exception leakage test | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/ErrorCodeRegistryMappingTest.java` `every_enum_code_present_in_the_registry_matches_its_http_status`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/BusinessRuleValidationContractTest.java` `no_client_safe_message_leaks_sql_constraint_or_internals`; `src/adapter-web/src/test/java/dev/caskeleton/adapter/web/error/TransportErrorHandlingTest.java` | `locally-verified` |
| 경계 | request/application/domain/response/filter mapper 경계가 우회되지 않는다 | `feature-boundary-validation-mapping-contract` | boundary bypass test | `CleanArchitectureTest` rules `controllers_do_not_return_domain_or_entity_types`, `application_methods_do_not_accept_web_dtos`, `request_dtos_do_not_escape_web_adapter`, `response_dtos_do_not_escape_web_adapter`, `validation_constraints_stay_at_web_boundary`, `filter_config_settings_do_not_depend_on_application_or_domain`; `BusinessRuleValidationContractTest` category/transport leakage checks | `locally-verified` |
| 로그 | 필수 field와 금지 field가 테스트된다 | `feature-log-management-contract` | log capture test | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/StructuredLogFieldContractTest.java` `structured_appender_emits_only_registered_snake_case_fields`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/logging/SecretMaskingMessageConverterTest.java`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/logging/LogMaskingPatternsTest.java` | `locally-verified` |
| trace | inbound/outbound/async/message trace가 연결된다 | `feature-distributed-tracing-contract` | propagation contract test | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/DistributedTracingContractTest.java` `meta_traceId_is_non_null_when_trace_id_on_mdc`, `response_meta_traceId_component_exists_and_is_non_null_when_populated`, `traceparent_header_row_matches_code_contract`, `tracing_sampling_rate_gauge_registry_contract`; `src/adapter-outbound/src/test/java/dev/caskeleton/adapter/outbound/http/TraceContextPropagationInterceptorTest.java` | `locally-verified` |
| env | profile별 env matrix와 fail-fast가 있다 | `feature-env-driven-runtime-configuration` | startup smoke test | `src/build.gradle` `verifyEnvKeys`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/EnvProfileMatrixContractTest.java` `prod_unsafe_toggles_ship_disabled_in_env`, `prod_unsafe_toggles_carry_prod_must_be_false_constraint`, `profile_selector_is_spring_profiles_active_only`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/startup/StartupSafetyValidatorTest.java` | `locally-verified` |
| repo | use case capability와 persistence/outbound capability가 매칭된다 | `feature-application-port-usecase-contract`, `feature-repository-access-permission-contract` | architecture/contract test | `CleanArchitectureTest` rules `inbound_port_implementations_declare_capability`, `read_only_use_cases_do_not_call_repository_write_methods`, `bulk_write_capability_requires_write_repository_access`, `use_case_capability_matches_transaction_port_boundary`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/RepositoryAccessCapabilityRegistryTest.java` `registry_capability_names_match_the_as_built_model_one_to_one` | `locally-verified` |
| adapter | dependency failure가 같은 언어로 분류된다 | `feature-outbound-http-client-baseline`, `feature-persistence-failure-baseline` | adapter failure mapping test | `src/adapter-persistence-rdbms/src/test/java/dev/caskeleton/adapter/persistence/rdbms/error/PersistenceFailureMappingContractTest.java` `every_matrix_sqlstate_classifies_to_its_contracted_code`, `transient_lock_and_integrity_violation_stay_distinct`; `src/adapter-outbound/src/test/java/dev/caskeleton/adapter/outbound/http/OutboundHttpClientTest.java`; `src/adapter-outbound/src/test/java/dev/caskeleton/adapter/outbound/http/OutboundHttpResilienceTest.java` | `locally-verified` |
| domain | `domain-core`가 framework-neutral하다 | `feature-domain-modeling-guardrails` | forbidden import test | `CleanArchitectureTest` rules `domain_is_pure`, `domain_has_no_logger`, `value_objects_have_no_public_no_arg_constructor`, `aggregate_root_setters_are_not_public`, `domain_events_are_records`, `domain_events_are_transport_free`, `domain_entities_do_not_carry_audit_fields`; `src/domain-core/src/test/java/dev/caskeleton/domain/sample/WorkLogInvariantTest.java` | `locally-verified` |
| sample | `sample-portfolio`은 fixture/reference로 유지되고 production runtime에서 비활성화 가능하다 | `feature-sample-domain-contract-fixture`, `feature-sample-removal-adoption-contract` | sample matrix + sample-off smoke | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/sample/SampleRemovalSmokeContractTest.java` `production_modules_reference_sample_only_as_test_fixture_dependency`, `sample_off_source_set_and_task_are_declared`, `sample_off_ci_job_is_release_blocking`, `sample_class_is_absent_from_the_sample_off_test_classpath`; `.github/workflows/ci-quality-gates.yml` job `sample-off`; `.github/ci-gate-matrix.yml` gate `sample-off-build` | `locally-verified`; hosted CI `needs-confirmation` |
| CI | contract violation이 release-blocking이다 | `feature-ci-quality-gates-contract` | CI gate | `.github/workflows/ci-quality-gates.yml` jobs `quality-gates`, `sample-off`, `gate-matrix-lint`, `breaking-change-approval`, `quarantine`, `release-gate`; `.github/scripts/verify-gate-matrix.sh`; `.github/scripts/verify-supply-chain-contract.sh`; `.github/scripts/test-supply-chain-scripts.sh` | `locally-verified`; hosted CI `needs-confirmation` |
| 운영 | alert/runbook/metric/log/trace가 연결된다 | `feature-operational-runbook-contract` | runbook mapping | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/RunbookCoverageContractTest.java` `every_mandatory_error_code_is_covered_by_at_least_one_runbook`, `all_runbook_links_resolve_to_existing_files`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/MetricsAlertingContractTest.java` required-test and metric registry contract checks | `locally-verified` |
| 보안 | token/PII/secret/body가 노출되지 않는다 | `feature-security-operational-baseline` | privacy/log leakage test | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/PiiTokenBodyForbiddenContractTest.java` `masking_removes_every_enumerated_secret_shape`, `captured_log_line_carries_no_unmasked_secret`, `request_body_capture_is_disabled_by_default`; `src/build.gradle` `verifyPublicPathSnapshot`; `docs/security/public-path-snapshot.txt` | `locally-verified` |
| adoption | 실제 도메인 dry-run이 module checklist를 통과한다 | `feature-domain-feature-onboarding-contract` | New Domain Module Slice + Read/Write Difference Table evidence | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/DomainFeatureOnboardingContractTest.java` `read_only_onboarding_slice_has_minimum_contract_and_no_write_artifacts`, `write_onboarding_slice_has_minimum_contract_and_static_rules_pass`; onboarding fixture files under `src/*/src/test/java/dev/caskeleton/onboarding/**`; migration `src/adapter-persistence-postgresql/src/test/resources/db/migration/postgresql/V9000__feature_onboarding_contract.sql` | `locally-verified` |
> **owner slug 정정 확인 (2026-06-26, §Audit A1)**: `env` 행 owner 는 `feature-env-driven-runtime-configuration`, `adapter` 행 owner 는 `feature-outbound-http-client-baseline` 및 `feature-persistence-failure-baseline`으로 정정돼 있으며, 관련 branch-note 파일 존재를 로컬 대조로 확인했다.
> **count 정정 (§Audit A3)**: 기존 별도 행 `오류`와 `예외`를 `오류/예외` 단일 area로 병합해 D4·Manual Score Formula의 15 area 선언과 reconcile했다.
Readiness framing은 binary pass/fail입니다. 하나라도 Fail 또는 Unknown이면 `Not ready`입니다. 부분 점수로 대체하지 않습니다. 로컬 evidence 기준으로 15 area는 `Pass`입니다. hosted CI/provenance와 scorecard 자동화는 별도 `needs-confirmation`/`planned`으로 남깁니다.
## Dry-Run Evidence
| onboarding row | required evidence | actual file path / test name | status |
|---|---|---|---|
| `domain-core` | model/value object/domain rule file path + forbidden import test | `src/domain-core/src/test/java/dev/caskeleton/onboarding/domain/FeatureAggregate.java`, `FeatureAggregateId.java`, `FeatureAggregateCreated.java`; `CleanArchitectureTest.domain_is_pure`; `DomainFeatureOnboardingContractTest.write_onboarding_slice_has_minimum_contract_and_static_rules_pass` | `locally-verified` |
| `application-core` | inbound use case + outbound port + transaction/capability contract test | `src/application-core/src/test/java/dev/caskeleton/onboarding/application/ListFeatureAggregatesUseCase.java`, `CreateFeatureAggregateUseCase.java`, `FeatureAggregateSummaryQueryPort.java`, `FeatureAggregateWritePort.java`; `CleanArchitectureTest.use_case_capability_matches_transaction_port_boundary` | `locally-verified` |
| `adapter-web` | request/response DTO + mapper + controller contract test | onboarding web fixture files under `src/adapter-web/src/test/java/dev/caskeleton/onboarding/adapter/web/**`; `CleanArchitectureTest.controllers_do_not_return_domain_or_entity_types`; `CleanArchitectureTest.application_methods_do_not_accept_web_dtos` | `locally-verified` |
| `adapter-persistence-rdbms` | persistence adapter + mapper + failure mapping test | onboarding persistence fixture files under `src/adapter-persistence-rdbms/src/test/java/dev/caskeleton/onboarding/adapter/persistence/**`; `PersistenceFailureMappingContractTest.every_matrix_sqlstate_classifies_to_its_contracted_code` | `locally-verified` |
| `adapter-persistence-postgresql` | vendor SQL state / migration evidence | `src/adapter-persistence-postgresql/src/test/java/dev/caskeleton/adapter/persistence/postgresql/PostgreSqlSqlStateErrorMappingTest.java`; `src/adapter-persistence-postgresql/src/test/resources/db/migration/postgresql/V9000__feature_onboarding_contract.sql` | `locally-verified` |
| `adapter-outbound` | external dependency adapter + timeout/retry/error mapping test when needed | `src/adapter-outbound/src/test/java/dev/caskeleton/adapter/outbound/http/OutboundHttpClientTest.java`, `OutboundHttpTimeoutEnforcerTest.java`, `OutboundHttpResilienceTest.java`, `FailOpenDependencyLoggerTest.java` | `locally-verified` |
| `adapter-identifier` | non-IO identifier capability and onboarding id factory evidence | `src/adapter-identifier/src/test/java/dev/caskeleton/adapter/identifier/UlidCodecTest.java`; `src/adapter-identifier/src/test/java/dev/caskeleton/adapter/identifier/HmacUserPrincipalPseudonymizerTest.java`; onboarding `FeatureAggregateIdFactory` fixture under `src/adapter-identifier/src/test/java/dev/caskeleton/onboarding/**` | `locally-verified` |
| `shared-contract` | skeleton-wide contract only; no business/domain concept | `CleanArchitectureTest.shared_contract_contains_only_operational_contract_packages`; `src/shared-contract/src/test/java/dev/caskeleton/shared/contract/EnvelopeTest.java`; `src/shared-contract/src/test/java/dev/caskeleton/shared/contract/OperationalErrorTest.java` | `locally-verified` |
| `app-bootstrap` | wiring/profile/startup smoke | `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/settings/BootstrapSettingsTest.java`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/startup/StartupSafetyValidatorTest.java`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/OperationalContractRuntimeTest.java`; `src/build.gradle` task `sampleOffTest` | `locally-verified` |
| `sample-portfolio` | fixture module 유지 + no production runtime dependency + sample-off smoke | `src/sample-portfolio/src/test/java/dev/caskeleton/sample/portfolio/SampleApplicationContextTest.java`; `src/sample-portfolio/src/test/java/dev/caskeleton/sample/portfolio/api/OpenApiSnapshotTest.java`; `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/sample/SampleRemovalSmokeContractTest.java` | `locally-verified`; hosted CI `needs-confirmation` |
> **§Audit A2 resolved (2026-06-26)**: `adapter-identifier` 모듈(owner: `feature-resource-identifier-contract`) row를 추가했다. 현재 표는 ca-tmpl runtime/test fixture module 집합을 10개 row로 추적한다.
## Manual Score Formula
```text
Readiness = Pass only if every area is Pass.
any Fail = Not ready.
any Unknown = Not ready.
automation missing is allowed only if manual evidence table is complete.
Unknown = required evidence cell 공란 OR owner branch 미존재 OR required evidence 의 구성요소(file path AND test name) 중 하나라도 누락(부분 기입). 부분 기입 = Unknown, Pass 아님.
```
## 엣지·실패·의존
> R4(깊이 게이트) 캡처용. readiness 판정은 본질적으로 *consume gate* 이므로 실패·의존이 대부분 cross-branch 다.
- **실패·엣지 경로**:
- **owner branch 미존재/오타** — area 의 owner slug 가 실제 branch 와 불일치하면 evidence 추적 불가 → 해당 area `Unknown` → readiness `Not ready`. (실제 발생: §Audit A1 3건 — 정정 완료. 재발 방지는 §테스트 계약의 registry-test mapping grep 으로 일부 포착.)
- **area partition drift 재발** — 2026-06-26에는 `오류/예외` 병합으로 15 area와 산식을 맞췄다. 향후 영역을 나누거나 합칠 때 D4·Manual Score Formula·Coverage row를 함께 갱신하지 않으면 readiness denominator가 다시 모호해진다.
- **모듈 집합 drift 재발** — 2026-06-26에는 `adapter-identifier` row를 추가했다. onboarding SSOT 가 module 을 추가/제거하면 `Dry-Run Evidence` 행이 다시 어긋날 수 있으므로 dry-run area 평가 시 `src/<module>/` 와 표 row 를 대조해야 한다.
- **hosted evidence 공백** — local Gradle/shell gates는 통과했지만 hosted CI/provenance artifact 확인 전에는 CI 운영 증거를 `prod-verified`로 올리지 않는다.
- **다른 계약 의존** (consume-only — 본 branch 는 아래 owner 의 evidence 를 *판정에 인용*만 하고 재정의하지 않음. 표기: `owner-branch (owner Decision) ← 본 branch Decision`):
- [[raw/branch-notes/feature-domain-feature-onboarding-contract]] (그 branch D1 module slice / D3 read-only / D4 write feature / D7: dry-run checklist SSOT 결정) ← 본 branch D5 — area `adoption` + `Dry-Run Evidence` 의 SSOT. 변경 시 본 branch area #15·dry-run 표 동반 갱신.
- [[raw/branch-notes/feature-sample-removal-adoption-contract]] (그 branch D1 production import 금지 / D2 sample-off core contract test / D3 dual-mode 검증) ← 본 branch D6 — area `sample` 의 sample-off smoke / runtime isolation evidence owner.
- [[raw/branch-notes/feature-ci-quality-gates-contract]] (그 branch D1 release-blocking / D3 drift gate) + [[raw/branch-notes/feature-contract-verification-test-suite]] (그 branch D2 release-blocking / D6 11-gate) ← 본 branch D4 — area `CI`. governing doc 의 Verification 축은 이 branch 들이 owner(본 branch 는 delegated, §Coverage).
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] (그 branch D1 multi-module 구조 / D4 adapter inbound·outbound 분리) + [[raw/branch-notes/feature-architecture-enforcement-rules]] (그 branch D1 CA 경계 archtest / D2 package rule) — area `구조` 의 module blueprint + boundary pass/fail evidence owner.
- registry SSOT: ca-tmpl `docs/registries/*.yaml``required_test` 행 (§테스트 계약) — 7개 registry 의 row 가 실제 test class FQN 으로 매칭되는지가 area 다수의 evidence 전제.
## 검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| sample-portfolio contract test가 release-blocking scenario를 cover한다 | local file/test evidence와 Gradle sample-off는 확인했지만 hosted CI는 미확인 | `SampleRemovalSmokeContractTest``.github/workflows/ci-quality-gates.yml` `sample-off` job 대조 후 GitHub Actions hosted result 확인 | `locally-verified`; hosted CI `needs-confirmation` |
| sample-off smoke가 sample-on / sample-off 두 profile 모두에서 green | local sample-off는 확인했지만 hosted profile matrix 결과는 미확인 | `.github/scripts/verify-gate-matrix.sh` + `./gradlew :app-bootstrap:sampleOffTest` + GitHub Actions hosted result | `locally-verified`; hosted CI `needs-confirmation` |
| New Domain Module Slice의 모든 row에 evidence가 채워진다 | onboarding owner branch의 향후 변경 가능 | `Dry-Run Evidence` 섹션 row별 file path/test name 존재와 `DomainFeatureOnboardingContractTest` 포함 Gradle check | `locally-verified` |
| 7개 yaml registry의 모든 row `required_test` 값이 실제 test class FQN으로 매칭된다 | hosted CI는 미확인 | `ContractRegistrySchemaGovernanceTest` required-test mapping checks와 `./gradlew check` | `locally-verified`; hosted CI `needs-confirmation` |
| owner branch 각각이 canonical promotion artifact를 만족한다 | owner branch 파일 존재는 확인했지만 각 owner의 canonical promotion deep audit은 범위 밖 | branch별 Decision Evidence Map / contract test / architecture rule / adoption note 존재 검사 | `documented-only`; owner deep audit `needs-confirmation` |
| 15 area Readiness Scorecard의 evidence cell이 모두 채워진다 | manual table은 본 branch가 요구하는 artifact | scorecard 표의 `actual file path / test name` column에 15 area 모두 file path 또는 test name 존재 | `actually-implemented` |
| AWS WAR / SLSA / OTel 외부 모델과 ca-tmpl 15 area가 혼동되지 않는다 | 외부 taxonomy와 ca-tmpl taxonomy 단위가 다름 | comparison matrix에서 external model은 보조 근거로만 표시 | `documented-only` |
| area 14 evidence cell에 SLSA provenance가 실제 검증 가능한 형태로 들어간다 | shell scripts는 검증했지만 hosted provenance artifact는 미확인 | `.github/scripts/verify-supply-chain-contract.sh`, `.github/scripts/test-supply-chain-scripts.sh`, hosted artifact/provenance 확인 | shell scripts `locally-verified`; hosted provenance `needs-confirmation` |
| Readiness Scorecard area 개수와 산식 선언이 일치한다 | 기존 §Audit A3 불일치 | `Readiness Scorecard` 표 body 15행과 Manual Score Formula의 all-pass denominator 대조 | `locally-verified` |
| Readiness Scorecard owner slug 가 모두 실재 branch 다 | §Audit A1 3건 정정 후 재발 가능 | owner column slug를 `raw/branch-notes/<slug>.md` 파일 존재와 대조 | `locally-verified` |
## 테스트 계약
- sample-portfolio contract test 누락: release-blocking scenario가 `sample-portfolio` module의 contract test class로 존재해야 함. 불일치 시 readiness=Fail.
- sample-off smoke 누락: CI workflow 또는 동등한 local gate에 sample-on / sample-off 두 profile 검증이 있어야 함. sample-off job에서 production runtime이 sample bean에 의존하면 fail.
- real domain dry-run 누락: `feature-domain-feature-onboarding-contract`의 New Domain Module Slice + Read/Write Difference Table row별 evidence가 비어 있으면 fail.
- registry-test mapping 누락: 7개 yaml registry 파일의 모든 row에서 `required_test` field가 실제 test class FQN으로 매칭되어야 함.
- canonical promotion 미통과: owner branch마다 Decision Evidence Map / contract test mapping / architecture rule mapping / runbook/log/metric mapping / adoption note / out-of-scope note가 있어야 함.
- 수동 evidence 부재: Readiness Scorecard 표의 evidence가 file path 또는 test name으로 채워져야 함. 빈 cell이 있으면 fail.
## Audit & Findings
> ca-tmpl ground truth(`src/`, `docs/registries/`, sibling branch slugs) 대조에서 발견한 drift. 사용자 결정 영역은 자동 rewrite 하지 않고 정합 권고만(슬러그 오타 정정은 broken reference 이므로 적용 + 기록).
| ID | finding | 종류 | 조치 |
|---|---|---|---|
| A1 | Readiness Scorecard owner slug 3건이 실재 branch 와 불일치: `feature-env-driven-configuration-contract``feature-env-driven-runtime-configuration`, `feature-outbound-http-client-contract``feature-outbound-http-client-baseline`, `feature-persistence-failure-contract``feature-persistence-failure-baseline` | `STALE_OWNER` (broken reference) | **RESOLVED 2026-06-26**. `Readiness Scorecard` owner column은 corrected slug만 보유하고, 파일 존재를 로컬 대조했다. |
| A2 | `adapter-identifier` 모듈(owner: `feature-resource-identifier-contract`)이 ca-tmpl `src/` 에 실재하나 기존 `Dry-Run Evidence` 표(8행)에 누락 — src 모듈 9개 vs 표 8행 | `MODULE_DRIFT` | **RESOLVED 2026-06-26**. `adapter-identifier` row를 추가하고 `UlidCodecTest`, `HmacUserPrincipalPseudonymizerTest`, onboarding id factory evidence를 연결했다. |
| A3 | 기존 `Readiness Scorecard` 표 16행 vs D4·Manual Score Formula·governing doc §27 의 "15 area" 선언 불일치 | `COUNT_DRIFT` | **RESOLVED 2026-06-26**. `오류` + `예외``오류/예외` 단일 area로 병합해 표 body 15행으로 reconcile했다. |
## 관심사 커버리지 (coverage-auditor 자동 생성)
> `/coverage` (coverage-auditor) 산출 — governing doc `wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard` 가 요구하는 관심사 대비 본 브랜치 완전성. 기준: `rules/coverage-gate.md`. **Verdict: Covered (Blocking 0)**. 본 branch 는 governance 4축 중 **Scorecard(§27) 축 owner**, 나머지 3축은 delegated.
| 관심사 | 상태 | owner | 심각도 | 근거 |
|--------|------|-------|--------|------|
| [Scorecard §27] binary pass/fail gate (maturity 점수 X) | covered-here | — | — | D1; governing doc §27 |
| [Scorecard §27] 도입 gate 한정 scope (운영 SLO·코드품질 도구 아님) | covered-here | — | — | D1 선택 조건 + §구현 가이드 §1 |
| [Scorecard §27] 15 area 전체 Pass 시에만 readiness pass | covered-here | — | — | D4; Manual Score Formula |
| [Scorecard §27] 1:1 branch evidence 매핑 | covered-here | — | — | D4·D5·D6; §구현 가이드 §2 |
| [Scorecard §27] 미통과 area owner branch 는 canonical 승급 금지 | covered-here | — | — | D2; §구현 가이드 §1 |
| [Scorecard §27] 수동 evidence mapping 필수 (자동 계산기 optional) | covered-here | — | — | D3; §구현 가이드 §1 |
| [Scorecard §27] scorecard CI step / badge / 자동 매핑 검증 (planned) | covered-here | — | — | D3; §구현 가이드 §1 (`planned` 명시), manual table evidence는 2026-06-26 채움 |
| [Scorecard §27] real-domain dry-run evidence = onboarding consume | covered-here | — | — | D5; `adoption` area + §구현 가이드 §3 |
| [Scorecard §27] sample-off readiness = sample-removal consume | covered-here | — | — | D6; `sample` area + §구현 가이드 §4 |
| [Scorecard §27] area row 표 16행 vs 선언 15 reconcile | covered-here | — | OK | §Audit A3 resolved 2026-06-26 (`오류/예외` 병합, 표 body 15행) |
| [Registry §21] markdown SSOT + YAML generated constants + 7 yaml | delegated | [[raw/branch-notes/feature-contract-registry-governance]] | OK | governing doc §21 owner; Registry 축은 본 branch 범위 밖 |
| [Verification §12] 11 release-blocking gate + JSON snapshot 검증 | delegated | [[raw/branch-notes/feature-contract-verification-test-suite]] | OK | governing doc §12 owner; §엣지·실패·의존 D4 consume + §Coverage 위임 명시 |
| [Test taxonomy §29 G-G] 6 level + Testcontainers/testFixtures/5min budget | delegated | [[raw/branch-notes/feature-test-taxonomy-fixture-contract]] | OK | governing doc §29 G-G owner; Test taxonomy 축은 본 branch 범위 밖 |
> coverage-auditor finding(2026-06-15): Blocking 0 → **Covered**. 3축 delegation 위임 링크를 본 §에 명시해 UNLINKED_DELEGATION(Should-fix) 해소. area count(16 vs 15)는 2026-06-26에 `오류/예외` 병합으로 해소했다. local Gradle/shell gate 기준 15 area evidence는 통과했으며, hosted CI/provenance는 `prod-verified`로 승격하지 않는다.
## 마주친 문제
- 2026-06-26: sandbox 안에서 `./gradlew verifyCleanArchitectureDependencies`를 실행하면 `~/.gradle/wrapper/dists/.../gradle-9.0.0-bin.zip.lck` lock write가 막혀 실패했다. 이후 권한 상승 실행에서 `verifyCleanArchitectureDependencies`, `check verifyPublicPathSnapshot`, `:app-bootstrap:sampleOffTest`가 모두 통과했다. 재현/해결 메모는 [[raw/errors/gradle-wrapper-sandbox-lock-readiness-scorecard-2026-06-26]].
- 2026-06-26: Gradle `check verifyPublicPathSnapshot`는 exit 0이지만 Error Prone/Gradle deprecation warnings가 출력됐다. 현재 build 실패 조건은 아니며 이 branch의 scorecard 문서 범위 밖이다.
- 2026-06-26: shell-only 검증은 완료했다. `.github/scripts/verify-gate-matrix.sh`, `.github/scripts/verify-supply-chain-contract.sh`, `.github/scripts/test-supply-chain-scripts.sh` 모두 exit 0.
## 묶음 (이 branch에서 파생된 자료)
<!-- GENERATED: sources:start -->
- [[raw/official-docs/registry-adr-official]]
- [[raw/official-docs/scorecard-aws-well-architected]]
- [[raw/official-docs/scorecard-cis-benchmarks-slsa]]
- [[raw/official-docs/scorecard-opentelemetry-maturity]]
<!-- GENERATED: sources:end -->
<!-- GENERATED: blog-topics:start -->
- [[raw/blog-topics/binary-readiness-scorecard-clean-architecture-skeleton-2026-07-02]]
<!-- GENERATED: blog-topics:end -->
### Sub-branches (세부 작업)
- (없음 — 현재 leaf branch)
### 오류 기록 (이 branch 작업 중 발생)
- [[raw/errors/gradle-wrapper-sandbox-lock-readiness-scorecard-2026-06-26]]
### 면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- (없음 — 이번 scorecard evidence 갱신에서 추출할 별도 면접 질문 없음)
### 강의 (이 작업을 위해 학습한 강의)
- (없음)
### job-posting tie-ins (이 작업에서 파생된 글감)
- (없음 — 이번 scorecard evidence 갱신에서 추출할 별도 글감 없음)
## 관련 일일 노트
- [[raw/daily-notes/2026-05-28]]
## 완료 후 정리
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경:
- **wiki 추출 대상** (verified만, `wiki/projects/`로만 추출):
- `actually-implemented` 항목: `Readiness Scorecard` 15-area evidence table file path/test name 채움; `Dry-Run Evidence` module row evidence 채움; §Audit A2/A3 resolved 기록.
- `locally-verified` 항목: `./gradlew verifyCleanArchitectureDependencies`, `./gradlew check verifyPublicPathSnapshot`, `./gradlew :app-bootstrap:sampleOffTest`; `.github/scripts/verify-gate-matrix.sh`, `.github/scripts/verify-supply-chain-contract.sh`, `.github/scripts/test-supply-chain-scripts.sh`; §Audit A1 owner slug existence 대조.
- `prod-verified` 항목: 없음.
- **추출하지 않을 항목** (planned / documented-only / abandoned):
- hosted CI/provenance 결과는 `needs-confirmation`.
- scorecard CI step / badge / 자동 매핑 검증은 `planned`.
- readiness scorecard policy 문서화 항목은 canonical 추출 요청 전까지 raw branch-note에 유지.