5.4 KiB
5.4 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 / contract-registry-reference-row-universal-column-false-fail-2026-06-20 | error-note | raw |
|
|
|
2026-06-20 | resolved |
error: contract-registry-reference-row-universal-column-false-fail-2026-06-20
Layer:
raw/errors/— schema-owner gate 구현 중 발견한, 모든 row 에 universal column 을 요구하는 naive 게이트의 false-FAIL 함정.
Parent / 부모
- raw/branch-notes/feature-contract-registry-governance — 본 branch 의 schema governance 게이트(
ContractRegistrySchemaGovernanceTest) 구현(Phase C2, 2026-06-20)에서 발견.
증상 / Symptom
- 발생 컨텍스트:
feature-contract-registry-governance의 schema-owner 게이트를 구현하기 위해, "모든 registry row 는 universal-3 column(owner_branch/compatibility_impact/required_test)을 가져야 한다"(branch-note §구현 가이드 §1/§2, grep "7/7")를 그대로 테스트로 옮기려 했다. - 사전 검사(테스트 작성 전 row 수 vs column 수 대조):
secrets-classification rows(name)=15 owner_branch=15 compat=10 req_test=10 (그 외 6 registry: rows == compat == req_test 로 일치) - 즉
secrets-classification.yaml의 15 row 중 5개가compatibility_impact/required_test를 보유하지 않는다. 모든 row 에 universal-3 를 요구하는 게이트는 이 5 row 에서 hard FAIL 한다(실제 데이터는 정상인데 게이트가 틀린 false-positive). - 재현 가능 여부:
always(게이트가 reference-row 면제를 모르면 항상)
재현 절차 / Reproduction
- branch-note §1/§2 의 "universal-3 column 7/7 필수" 를 곧이곧대로 옮겨, 모든 registry 의 모든 row 에 대해
compatibility_impact ∈ legal-enumANDrequired_test != blank를 단언하는 테스트를 작성. - 로컬에 seed 된
docs/registries/*.yaml로 실행. secrets-classification.yaml의 Tier-1 public-config 5 row 에서compatibility_impact/required_test부재로 단언 실패.
조사 단계 / Investigation log
- 2026-06-20 — 사전 검사에서
secrets compat=10 != rows=15불일치 포착. 테스트를 쓰기 전이라 false-FAIL 을 코드로 만들기 전에 차단됨(= "데이터로 먼저 검증" 의 효용). - 2026-06-20 —
secrets-classification.yaml전문 확인. 해당 5 row 는 헤더 L17# - public-config 항목은 env-keys.yaml에서 직접 정의되며 본 파일에는 reference row만 둔다가 규정한 reference row 였다(APP_PROFILE / APP_NAME / SERVER_PORT / SPRING_PROFILES_ACTIVE / OTEL_EXPORTER_OTLP_ENDPOINT). 각 row 는reference: env-keys.yaml#<KEY>를 갖고 contract column 은 의도적으로 생략. - 2026-06-20 —
grep -cE "^ reference:" docs/registries/*.yaml로 reference row 가 secrets 전용(5건)임을 확인(나머지 6 registry 0건). 면제 메커니즘이 secrets 한정임을 데이터로 확정.
근본 원인 / Root cause
- branch-note 의 "universal-3 column 7/7 필수" 요약은 full row 기준이었고, as-built schema 에는 문서화된 예외 — reference row — 가 존재한다. reference row 는 자기 식별자(
name)와 위임 포인터(owner_branch,reference)만 갖고,compatibility_impact/required_test의 authoritative 값은reference가 가리키는 registry(여기선env-keys.yaml)에 있다. 한 곳에만 contract column 을 두는 single-source 위임 이므로, 면제는 누락이 아니라 설계다.
해결 / Resolution
- 게이트를 두 단계로 분리:
- 모든 row(reference 포함): identity column(error=
code/mdc=key/그 외=name) +owner_branch필수. - full row 만(=
reference:키 부재):compatibility_impact ∈ {none, additive, behavior-change, breaking}+required_test != blank. - reference row 만(=
reference:키 보유):referencetarget 이 non-blank 인지 검증(면제를 명시적·검증 가능하게 — "그냥 빠뜨린 것" 과 "위임" 을 구분).
- 모든 row(reference 포함): identity column(error=
isReferenceRow(row) = row.containsKey("reference")단일 술어로 분기.- 결과: 6 tests green(skipped=0). 음성 변이(headers row 에 illegal
compatibility_impact: BOGUS_ILLEGAL주입)로every_full_row_declares_compatibility_impact_within_the_legal_enum()FAIL 확인 후 원복.
교훈 / Lessons
- 요약(grep "7/7")을 곧이곧대로 단언으로 옮기지 말 것 — 요약은 보통 happy-path(full row) 기준이고, as-built 에는 파일 헤더 주석에만 적힌 예외가 있다. 테스트 작성 전 row 수 vs column 수 대조(데이터 검증)가 false-FAIL 을 코드화하기 전에 잡아준다.
- 면제는 "검증 가능하게" 모델링 — reference row 를 그냥 skip 하지 않고,
referencetarget 보유를 별도 단언으로 강제하면 "위임" 과 "단순 누락" 이 구분된다. - gitignore 된 seed 데이터(
/docs) 위에서 도는 테스트는 부재 시 SKIP(=Assumptions), 존재 시 위반 FAIL 의 이중 모드를 따른다(기존 registry drift 테스트 패턴과 동일). 관련: raw/errors/ca-gitignored-seed-divergence-at-rebase.