Skip to content

test(F-INT-001): 계약 enum ≡ web 유니온을 값으로 대조한다 — 한 enum 만 대조되고 있었다 (#597) - #626

Open
hd0rable wants to merge 1 commit into
mainfrom
feat/web-union-enum-mirror-597
Open

hd0rable wants to merge 1 commit into
mainfrom
feat/web-union-enum-mirror-597

Conversation

@hd0rable

Copy link
Copy Markdown
Member

#597 입니다. #594 가 머지돼서 선행이 풀렸습니다.

무엇이 비어 있었나

ApiError.code       핸들러 · openapi · CLAUDE.md · 유니온 · 문면 표 · 명세 §9   여섯 벌
나머지 enum          openapi · types.ts 유니온                                 ❗0 벌

WebTypesMirrorContractTest필드 이름만 봅니다. 계약 enum 에 값이 하나 늘고 유니온이 안 따라와도 아무것도 안 울었습니다.

#594(운영 콘솔)와 #596(추출 카드)이 서로를 알고 있어서 이번엔 사람이 맞췄습니다. 다음 카드가 생기는 날에는 두 변경이 겹치지 않을 수 있습니다.

갈리면 화면이 값으로 분기하는 자리가 조용히 기본 갈래로 떨어집니다 — 운영 콘솔이면 카드 하나가 이름 없이 그려지고, 하필 그 카드가 지금 문제인 카드일 수 있습니다(#316 과 같은 모양).

❗짝을 손으로 적지 않습니다 — 값 집합으로 찾습니다

「어느 enum 이 어느 유니온과 짝인가」를 목록으로 두면 그 목록이 새 사본이 되고 늘릴 때 같이 안 고쳐집니다(#586SOURCES 에서 밟은 자리입니다).

유니온의 값 집합 == 어느 계약 enum 의 값 집합 인가
  → 같으면 화면이 그 값들을 안다는 뜻이다
  → 계약이 값을 하나 더하면 어느 enum 과도 안 맞아서 빨개진다

인라인 유니온(OpsComponent.id 는 이름 없는 유니온입니다)까지 보려면 이름으로는 짝을 못 짓습니다. 그래서 이쪽은 값 집합으로 짓고, 이름 대조는 기존 테스트가 계속 맡습니다. 두 파일에 상호 참조를 적었습니다.

contracts/ 전체를 읽습니다

RiskItem.importance  "required" | "recommended"        risk_item.schema.json
RiskItem.status      "extracted" | "extraction_failed"  risk_item.schema.json

openapi.yaml 만 보면 이 둘이 짝 없는 유니온으로 잡혀 맞는 코드가 빨개집니다. 역검증 ⓓ 가 그것입니다.

❗반대 방향은 안 봅니다

계약 enum 28 개 · 유니온으로 온 것 22 개
안 온 여섯: ageBand · amountBand · experienceLevel · …
            → 화면이 string 으로 받는다. 값으로 분기하지 않으므로 유니온일 이유가 없다

「전부 유니온이어야 한다」로 두면 그 여섯을 유니온으로 만들라고 요구하는 그물이 되는데, 그건 이 대조가 막으려는 결함과 무관합니다.

허용 목록이 없습니다

지금 22 개가 전부 짝이 있습니다. 예외 목록을 만들면 어긋난 것을 목록에 넣어 통과시키게 되고 그러면 그물이 아니라 장식이 됩니다(WebTypesMirrorContractTest 와 같은 판단).

닻을 먼저 잽니다

정규식이 깨지면 유니온이 0 건이 되고, 그러면 「짝 없는 유니온 0 건」으로 초록입니다. 그래서 ApiError.code 집합이 뽑히는지 먼저 단정합니다 — 그 한 벌은 ErrorCodeContractTest 가 이미 지키고 있어서, 여기에 숫자를 적어 두면 그 숫자가 낡습니다.

역검증

변이 결과
계약 enum 에 여섯째 값을 더한다(types.ts 그대로) 빨강#596 이 겪은 그 상황
types.ts 유니온에서 값 하나를 뺀다 빨강
정규식에서 줄 주석 건너뛰기를 뺀다 닻 테스트 빨강
openapi.yaml 만 읽는다 빨강 — risk_item 쪽 둘이 짝을 잃는다

셋째가 둘째 단정의 전제를 지킵니다. 넷째는 거짓 양성 방향이라 그 설계가 필요했다는 근거입니다.

검증

server 전체 832건 · 실패 0 · skip 0   (새 대조 2건)

build.gradle../web/src/api/types.ts../contracts 를 이미 입력으로 들고 있어 둘 중 하나만 고쳐도 이 대조가 다시 돕니다 — 새 입력 선언이 필요 없습니다.

Closes #597

WebTypesMirrorContractTest 는 필드 «이름» 만 본다. 그래서 계약 enum 에 값이 하나 늘고
types.ts 유니온이 안 따라와도 아무것도 안 울었다.

  ApiError.code   핸들러·openapi·CLAUDE.md·유니온·문면 표·명세 §9   여섯 벌
  나머지 enum      openapi · types.ts 유니온                      0 벌

#594 가 유니온을 들고 오고 #596 이 같은 enum 에 다섯째 값을 더했는데, 두 PR 이 서로를
알고 있어서 사람이 맞췄다. 다음 카드가 생기는 날에는 두 변경이 겹치지 않을 수 있다.

갈리면 화면이 값으로 분기하는 자리가 조용히 기본 갈래로 떨어진다 — 운영 콘솔이면 카드
하나가 이름 없이 그려지고, 하필 그 카드가 지금 문제인 카드일 수 있다(#316 과 같은 모양).

- 짝을 손으로 적지 않는다. 「어느 enum 이 어느 유니온과 짝인가」를 목록으로 두면 그 목록이
  새 사본이 되고 늘릴 때 같이 안 고쳐진다(#586 이 SOURCES 에서 밟은 자리). 값 집합이
  같은지로 짝을 찾으므로 계약이 값을 더하는 순간 어느 enum 과도 안 맞아 빨개진다
- contracts/ 전체를 읽는다. RiskItem 의 importance·status 는 risk_item.schema.json 에
  있고 화면이 그 둘도 유니온으로 든다 — openapi.yaml 만 보면 맞는 코드가 빨개진다
- 반대 방향은 안 본다. 계약 enum 28 개 중 유니온으로 온 것이 22 개이고 나머지(ageBand ·
  amountBand · experienceLevel 등)는 화면이 string 으로 받는다. 값으로 분기하지 않으므로
  유니온일 이유가 없고, 「전부 유니온이어야 한다」로 두면 그것을 요구하는 그물이 된다
- 허용 목록이 없다. 지금 22 개가 전부 짝이 있다
- 닻으로 ApiError.code 집합이 뽑히는지 먼저 잰다. 정규식이 깨지면 0 건이 되고 그러면
  대조가 아무것도 안 재고 통과한다. 숫자를 적어 두지 않는 이유는 그 숫자가 낡아서다

역검증:
  계약 enum 에 여섯째 값을 더한다(types.ts 그대로)   빨강  ← #596 이 겪은 그 상황
  types.ts 유니온에서 값 하나를 뺀다                 빨강
  정규식에서 줄 주석 건너뛰기를 뺀다                  닻 테스트 빨강
  openapi.yaml 만 읽는다                           빨강 (risk_item 쪽 둘이 짝을 잃는다)

server 전체 832건 · 실패 0 · skip 0

Closes #597

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hd0rable hd0rable added 계약 모듈 간 계약 — contracts/, openapi.yaml, 스키마 server Spring (:8000) labels Sep 14, 2026
@hd0rable
hd0rable requested a review from junseo2323 September 14, 2026 04:46
@github-actions github-actions Bot added 리뷰대기: 정세현 정세현 이 배정됐고 아직 아무것도 제출하지 않았다 리뷰대기: 오준서 오준서 이 배정됐고 아직 아무것도 제출하지 않았다 labels Sep 14, 2026

@junseo2323 junseo2323 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

방향은 맞고 #597 이 든 자리는 실제로 막힙니다(아래 ①). 그런데 짝을 「값 집합」으로만 짓는 탓에 types.ts 유니온 22 개 중 11 개가 이 그물에 안 걸립니다 — 계약에 같은 값집합이 두 자리 이상 있으면, 그중 하나가 값을 더해도 유니온이 나머지와 여전히 맞아서 초록입니다. 재현했습니다.

① 먼저 — 되는 것부터 확인했습니다

기준선                                        server 전체 BUILD SUCCESSFUL
변이 ⓐ OpsComponent.id 에 여섯째 값 추가         everyWebUnionMatchesAContractEnum  FAILED  ✅
변이 ⓑ GAP 정규식을 깨뜨린다(줄 주석 미처리)      theExtractorActuallyFindsUnions    FAILED  ✅

ⓑ 가 잡히는 것이 이 PR 에서 제일 좋은 부분입니다. 「0 건으로 조용히 통과」를 먼저 막고 시작한 것이 맞고, 닻으로 ApiError.code 를 쓰면서 숫자를 안 적은 것도 맞습니다.

❗② 그런데 productType 으로 같은 변이를 냈더니 초록입니다

변이 ⓒ  contracts/openapi.yaml:1148  ProductSummary.productType
        enum: [ELS, VARIABLE_INSURANCE]  →  [ELS, VARIABLE_INSURANCE, FUND]
        (web/src/api/types.ts:561 ProductSummary.productType 은 그대로 두 값)

결과    WebUnionsMirrorContractEnumsTest   tests="2"  BUILD SUCCESSFUL   ❗초록

화면이 그 필드를 유니온으로 들고 값으로 분기하는데 계약이 값을 더했고, 이 대조는 아무 말도 안 합니다. 본문·javadoc 이 "계약이 값을 하나 더하는 순간 어느 enum 과도 안 맞아서 여기가 빨개진다" 고 단정한 바로 그 갈래입니다.

이유는 짝짓기 방식입니다. 대조가 묻는 것은 «이 유니온과 같은 집합인 enum 이 계약 어딘가에 있나» 이지 «짝인 enum 이 같은 집합인가» 가 아닙니다. ELS|VARIABLE_INSURANCE 는 계약에 세 자리(openapi:44 · openapi:1148 · parsed_document.schema.json)가 있어서, 한 자리가 늘어도 나머지 둘이 옛 집합을 그대로 들고 있어 짝이 계속 잡힙니다.

③ 전수로 셌습니다 — 절반입니다

web 유니온 22 개 중 «값집합이 계약에 두 자리 이상» 인 것      11 개  ❗이 그물에 안 걸린다

types.ts:63   U1|U2|U3|U4                    계약 2자리 (openapi:1358 · judgment.schema.json)
types.ts:66   GREEN|YELLOW|RED               계약 3자리
types.ts:71   CREATED|IN_PROGRESS|…|ABORTED  계약 2자리
types.ts:367  parsed|parse_failed            계약 2자리
types.ts:561  ELS|VARIABLE_INSURANCE         계약 3자리     ← ⓒ 로 재현한 자리
types.ts:562  parsed|parse_failed            계약 2자리
types.ts:659/738/774/871  org|branch         계약 4자리
types.ts:670  seller|branch|item             계약 3자리

나머지 11 개(OpsComponent.id 처럼 값집합이 계약에서 유일한 것)는 ⓐ 대로 제대로 물립니다. 즉 지금 이 그물은 「값집합이 계약에서 유일한 유니온」에만 성립합니다. 등급·세션 상태·상품유형처럼 화면이 제일 많이 분기하는 축이 하필 안 걸리는 쪽입니다.

④ 고치는 방향 — 짝 목록을 만들자는 말이 아닙니다

#586 의 교훈(짝 목록은 새 사본이 된다)에 동의하고, 목록을 만들라는 요청이 아닙니다. 이름이 이미 있는 자리는 이름으로 짝을 지으면 목록 없이 좁혀집니다.

필드 이름이 있는 유니온    ProductSummary.productType  ↔  계약의 같은 이름 property 의 enum
                          → 집합을 비교한다. 이름 짝짓기는 WebTypesMirrorContractTest 가 이미 하는 일이다
이름 없는 인라인 유니온    OpsComponent.id 처럼        →  지금처럼 값집합으로 짝짓는다

아니면 훨씬 싸게, 지금 구멍을 문면으로 남기는 것도 받겠습니다 — javadoc 의 단정을 "값집합이 계약에서 유일한 유니온에만 성립한다" 로 고치고, 위 11 개를 알려진 사각으로 적는 것입니다. 지금 문면대로 두는 것만 피하고 싶습니다: 다음 사람이 이 그물을 믿고 productType 에 값을 더합니다. 그 상태는 그물이 없는 것보다 나쁩니다.

둘 중 어느 쪽이든 제가 다시 보고 바로 승인하겠습니다.

⑤ 나머지는 이견 없습니다

  • contracts/ 전체를 읽는 것risk_item.schema.jsonimportance·statusopenapi.yaml 에 없어서 한 파일만 보면 맞는 코드가 빨개집니다. 역검증 ⓓ 로 그걸 잡아 두신 것이 맞습니다.
  • 반대 방향을 안 보는 것 — 「전부 유니온이어야 한다」가 되면 ageBand 여섯을 유니온으로 만들라는 그물이 됩니다. 이 대조의 몫이 아닌 게 맞습니다.
  • 허용 목록을 안 만든 것 — 예외 목록이 장식이 된다는 판단에 동의합니다.
  • WebTypesMirrorContractTest 에 상호 참조를 적은 것 — 이름/값이 갈라진 이유가 두 파일에 다 있어야 한다는 것도 맞습니다.

@github-actions github-actions Bot added 리뷰중: 오준서 오준서 이 코멘트·변경요청을 냈고 아직 승인하지 않았다 and removed 리뷰대기: 오준서 오준서 이 배정됐고 아직 아무것도 제출하지 않았다 labels Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

server Spring (:8000) 계약 모듈 간 계약 — contracts/, openapi.yaml, 스키마 리뷰대기: 정세현 정세현 이 배정됐고 아직 아무것도 제출하지 않았다 리뷰중: 오준서 오준서 이 코멘트·변경요청을 냈고 아직 승인하지 않았다

Projects

None yet

Development

Successfully merging this pull request may close these issues.

계약 enum ↔ web 유니온이 ApiError.code 하나만 대조된다 — OpsComponent.id 는 0 벌이다 (#594·#596 리뷰)

2 participants