Files
llm-wiki/raw/branch-notes/feature-api-compatibility-deprecation-contract.md
T

20 KiB

title, source_type, status, branch, related_projects, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, parent_branch, contract_packet_sha256
title source_type status branch related_projects tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet parent_branch contract_packet_sha256
branch / feature-api-compatibility-deprecation-contract branch-note raw feature-api-compatibility-deprecation-contract
ca-skeleton
branch
ca-skeleton
api-compatibility
deprecation
2026-05-22 in-progress BR-CA-SKELETON-OPERATIONAL-CONTRACT-026 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-026
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-API-VERSIONING-001@1
1 b0999dd64e9b6815a5e42c1c75e34bdccd2eb746e6572aedb12a4ac6b1d21fd8

branch: feature-api-compatibility-deprecation-contract

Layer: raw/branch-notes/ — API compatibility와 deprecation 기준을 정의합니다.

부모 (필수)

ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§<관련 섹션>) 의 결정/근거/금지 사항을 정제한다.

묶음

본 feature branch 는 leaf — 자식 자료 없음. Phase C2 실 코드 작성 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.

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

  • (없음 — 현재 documented-only 단계)

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

  • (없음 — Phase C2 실 구현 단계에 누적)

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: /v1 compatibility·deprecation contract test가 통과한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-API-VERSIONING-001@1 URI prefix /v1이 default이며 X-Api-Version은 compatibility 실험용 보조 header다 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

목표

API versioning만으로는 장기 유지보수가 부족합니다. breaking change, response field removal, deprecated field, migration window 기준을 skeleton에 포함해야 합니다.

  • 이슈:
  • PR:

범위

포함 범위

  • breaking change 정의.
  • response field removal 금지 기준.
  • deprecated field 정책.
  • migration window 기준.
  • backward compatibility test 기준.
  • OpenAPI diff 기준.

제외 범위

  • public API product lifecycle.
  • external developer portal.
  • multi-version runtime router 구현.

TODO

TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / "Breaking Change Catalog" / "Decisionized Work Items" 참조. breaking change 정의/response field removal/deprecation marker/migration window/backward compat/OpenAPI diff 모두 catalog 또는 표 row로 반영됨. 잔존 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 승급 위치

진행 중 메모

  • 이 branch는 API contract baseline과 schema serialization contract를 보완합니다.

결정 사항 (decisions)

  • 2026-05-22: compatibility/deprecation은 API versioning과 별도 기준으로 관리.
  • 2026-05-22: breaking change catalog는 이 branch가 소유하고 OpenAPI diff 집행은 feature-contract-verification-test-suite가 수행.
  • 2026-05-22: migration window 기본값은 90일. internal-only API는 30일로 줄일 수 있으나 branch note에 근거와 소비자 목록이 필요.
  • 2026-05-22: published response field removal은 deprecated marker + migration window + compatibility fixture 없이는 금지.
  • 2026-05-22: API deprecation 응답은 Sunset: <date> + Deprecation: <date> 헤더 함께 전송. 단독 Sunset 금지. 추가로 Link: <url>; rel="sunset" 권장.

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

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

Source 정당화하는 결정
raw/official-docs/compat-rfc-8594-sunset-header IETF RFC 8594 Sunset header 표준 (ca-tmpl 채택 근거
raw/company-tech-blogs/api-versioning-stripe-date-based account pin + freeze; 외부 컨슈머 규모 큰 경우 우위
raw/company-tech-blogs/api-versioning-github-rest-date-header long EOL window + explicit 410 응답
raw/official-docs/api-versioning-google-aip-180 enum value 제거도 금지; ca-tmpl narrow enum = breaking 결정과 부분 정합
raw/official-docs/sunset-deprecation-headers-paired-usage 참조
raw/official-docs/openapi-spec-3-1-0 OpenAPI Specification v3.1 (JSON Schema 2020-12 alignment) — OAS 의 normative scope/structure 근거. ⚠️ Operation Object 의 deprecated: boolean 필드 자체는 OPENAPI31-C1~C7 발췌에 포함되지 않음 (raw 자체 Usage Boundary 명시) — D8 deprecation marker 의 OpenAPI spec normative 인용은 별도 raw 발췌 필요

외부 근거 / 대안 조사 (2026-05-22 — Group G-F: API Compatibility / Deprecation)

본 branch의 90d public + 30d internal migration window + breaking change catalog 7행 + Sunset header + OpenAPI deprecated:true 결정에 대한 외부 source.

  • 채택 결정 (window + Sunset header + OpenAPI deprecation):
  • 검토한 대안:
  • 비교 핵심: Stripe(freeze forever) vs ca-tmpl(90d/30d window) vs GitHub(24mo EOL + 410): 외부 컨슈머 규모와 운영 비용 trade-off. ca-tmpl internal-first면 90d 합리. 보강 후보 2가지: (a) EOL 응답 코드(410 Gone)가 ca-tmpl catalog에 누락 — GitHub 사례 차용 검토, (b) Sunset(RFC 8594) + Deprecation 헤더는 함께 보내야 정합 — ca-tmpl 결정은 marker만 명시.

후속 보강 (2026-05-22): Sunset 헤더는 Deprecation 헤더와 paired로 보내야 함. raw/official-docs/sunset-deprecation-headers-paired-usage 참조.

Breaking Change Catalog

change classification default action
remove response field breaking deprecate first, remove after migration window
rename response field breaking add new field, keep old deprecated field through window
change field type/format breaking new version or additive field
narrow enum values breaking new version
add required request field breaking new version or default server-side
add optional response field additive allowed with schema update
change error code/category breaking for clients foundation registry change + migration note

Decisionized Work Items

item Decision Allowed Forbidden Required test Failure condition
migration window 90 days public/default, 30 days internal-only shorter only with owner approval immediate field removal compatibility fixture deprecated field removed early
deprecation marker OpenAPI deprecated: true + branch note response header optional undocumented deprecation OpenAPI diff deprecated field lacks marker
breaking diff verification suite release-blocking warning-only only for additive diff breaking diff warning-only openapi-diff gate breaking diff passes CI

테스트 계약

  • published response field가 사전 deprecation 없이 제거되면 실패.
  • OpenAPI diff에서 breaking change가 감지되면 실패.
  • deprecated field가 migration window 없이 제거되면 실패.
  • backward compatibility fixture가 깨지면 실패.

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. company-tech-blog 출처는 company-case-study 로 라벨링하며 공식 best practice 로 격상하지 않는다.

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 compatibility / deprecation 은 API versioning 과 별도 기준으로 관리 (2026-05-22) UNSUPPORTED_DECISION (project-internal scoping decision; 외부 표준이 두 영역의 분리를 normative 로 강제하지 않음) N/A scoping 결정의 정합성은 sibling branch (feature-api-contract-baseline) 와 cross-review 필요
D2 breaking change catalog 7행 분류 — remove response field, rename, change type/format, narrow enum values, add required request field, add optional response field, change error code raw/official-docs/api-versioning-google-aip-180.md#AIP180-C1 (component 제거 금지), #AIP180-C2 (rename = remove+add), #AIP180-C3 (default behavior preservation 으로 additive 분류), #AIP180-C4 (required field 추가 금지), #AIP180-C5 (minor/patch client breaking 금지), raw/company-tech-blogs/api-versioning-github-rest-date-header.md#GH-APIV-C4 (GitHub 의 동일 7행 breaking 분류 사례) official-vendor-doc + company-case-study AIP-180 은 Google internal API design guideline — IETF/W3C 표준 아님 (외부 인용 시 "Google AIP" 명시 필수). GitHub 사례는 company-case-study — 7행 분류가 모든 API 의 표준이라는 일반화 금지
D3 OpenAPI diff release-blocking 집행은 feature-contract-verification-test-suite 가 수행 (이 branch 는 catalog 소유, 집행 위임) UNSUPPORTED_DECISION (project-internal SSOT 분할 결정; 외부 표준 근거 없음) N/A catalog owner 와 enforcement owner 분리 시 drift 위험 — verification suite 의 입력 catalog 정합성 추적 필요
D4 migration window 기본값 90일 (public) / 30일 (internal-only) UNSUPPORTED_DECISION (cited AIP180-C1 은 same major version 안에서 "must not be removed" — ca-tmpl 의 window 후 제거 정책과 다름. cited GH-APIV-C7 의 24개월 EOL 도 90/30일과 직접 일치하지 않음. cited STRIPE-APIV-C4 는 "as long as possible" 철학으로 window 자체를 권고하지 않음) N/A window 길이의 정당성은 internal-first skeleton 의 운영 부담 trade-off — 외부 표준 인용 불가. canonical 승급 시 design rationale 별도 문서화 필요
D5 published response field removal 은 deprecated marker + migration window + compatibility fixture 없이 금지 raw/official-docs/api-versioning-google-aip-180.md#AIP180-C1 (component 제거 금지), #AIP180-C2 (rename = remove+add), #AIP180-C5 (minor/patch client breaking 금지), raw/company-tech-blogs/api-versioning-github-rest-date-header.md#GH-APIV-C4 (response field 제거가 breaking) official-vendor-doc + company-case-study AIP-180 은 same major version 안에서 사실상 영구 금지 — ca-tmpl 의 "migration window 후 제거 허용" 정책은 AIP 보다 약함 (외부 인용 시 정합성 caveat 필요)
D6 API deprecation 응답은 Sunset: <date> + Deprecation: <date> 헤더 함께 전송; 단독 Sunset 금지; 추가로 Link: <url>; rel="sunset" 권장 raw/official-docs/sunset-deprecation-headers-paired-usage.md#SD-PAIR-C1 (Sunset = decommissioning 시점), #SD-PAIR-C3 (Deprecation = 상태 신호), #SD-PAIR-C5 (Sunset MUST NOT be earlier than Deprecation), #SD-PAIR-C6 (sunset / deprecation link relation 용도), raw/official-docs/compat-rfc-8594-sunset-header.md#RFC8594-C1 (Sunset 정의), #RFC8594-C4 (sunset link relation IANA 등록) official-standard IETF httpapi WG 의 권고 — client tooling 의 실제 paired 감지 여부는 vendor 별 (예: Spring HATEOAS, Apigee). 단독 송신을 안 하면 client 가 deprecation 감지 못 한다는 절대 사실은 spec 에 없음 (해석)
D7 breaking diff CI gate 가 release-blocking; additive diff 만 warning-only 허용 raw/official-docs/api-versioning-google-aip-180.md#AIP180-C3 (additive 의 default behavior 보존 시 호환), #AIP180-C5 (minor/patch breaking 금지), raw/company-tech-blogs/api-versioning-github-rest-date-header.md#GH-APIV-C5 (breaking 은 새 버전 release + 사전 공지) official-vendor-doc + company-case-study "release-blocking" 자동 enforcement 메커니즘 자체는 AIP-180 / GitHub 모두 정책만 명시 — CI gate 강제는 ca-tmpl 의 운영적 보강
D8 deprecation marker 는 OpenAPI deprecated: true + branch note; response header optional raw/official-docs/sunset-deprecation-headers-paired-usage.md#SD-PAIR-C3 (Deprecation 헤더 정의), #SD-PAIR-C6 (link relation), raw/official-docs/compat-rfc-8594-sunset-header.md#RFC8594-C1 (Sunset 정의), raw/official-docs/openapi-spec-3-1-0.md#OPENAPI31-C1 (OAS normative keyword 해석 BCP 14), #OPENAPI31-C2 (OAS = HTTP API contract scope), #OPENAPI31-C7 (Schema Object = JSON Schema 2020-12 superset — deprecated 가 OAS-specific extension 으로 언급되나 본 raw 발췌에 직접 인용 없음) — marker (OpenAPI) 와 응답 헤더의 paired 송신은 D6 에서 강제 official-standard + official-vendor-doc (partial — OpenAPI scope/normative-keyword 까지만) ⚠️ OpenAPI Operation Object 의 deprecated: boolean 필드 자체의 normative 정의는 openapi-spec-3-1-0 raw 의 OPENAPI31-C1~C7 발췌에 포함되지 않음 (raw 자체 §"Usage Boundaries 이 자료가 증명하지 않는 것" 명시: "deprecated: true 의 정확한 의미론 — 본 발췌에 직접 인용 없음"). §4.8.10 Operation Object 의 deprecated 필드 별도 발췌 또는 §4.8.24 Schema Object 의 deprecated keyword 별도 발췌가 필요한 follow-up. 현재 OPENAPI31-* 는 OAS 의 scope/normative-keyword/JSON-Schema-alignment 만 corroborate — deprecation marker 의미론은 여전히 직접 표준 인용 부재

검증해야 할 주장

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

Claim Why uncertain How to verify Status
Sunset + Deprecation 헤더가 paired 로 송신되며 Sunset >= Deprecation invariant 가 강제되는지 (SD-PAIR-C5 준수) header middleware 구현 위치 (Spring filter / interceptor / @ControllerAdvice) 에 따라 invariant 누락 가능 header invariant CI gate 추가 + integration test (deprecated endpoint 응답에 두 헤더 존재 + Sunset >= Deprecation 검증) planned
OpenAPI deprecated: true 마커와 응답 헤더의 동기화가 보장되는지 marker 추가만 하고 헤더 누락 또는 그 반대 가능성 OpenAPI snapshot grep + 실제 응답 contract test cross-check planned
90d (public) / 30d (internal) migration window 가 release process 에 실제로 강제되는지 window 정책이 process 문서에만 있고 CI / release gate 에 강제 메커니즘 없을 위험 release calendar / CI gate 가 deprecation marker 추가 시각 + sunset date 차이를 검증하는지 dry-run needs-confirmation
breaking diff CI gate 가 release-blocking 으로 실제 동작하는지 (AIP180-C5 invariant 강제) gate 가 warning-only 로 misconfigured 가능 breaking diff 의도적 도입 후 CI build fail 검증 planned
7행 catalog 의 모든 row 가 OpenAPI diff tool 의 분류와 1:1 mapping 되는지 tool (openapi-diff / oasdiff) 의 자체 분류와 catalog 의 분류가 다를 위험 tool dry-run 결과 + catalog mapping 표 작성 planned
EOL 응답 코드 (410 Gone, GH-APIV-C6) 가 ca-tmpl catalog 에 누락된 점 — sunset 이후 응답 정책 결정 필요 GitHub 사례 차용 검토 필요 항목으로 본문 명시 — 결정 미정 catalog 보강 결정 + sunset 시점 이후 응답 contract test 작성 needs-confirmation
OpenAPI deprecated: true (Operation Object / Schema Object) 의 normative 정의를 표준 인용으로 확보 openapi-spec-3-1-0 raw 의 OPENAPI31-C1~C7 발췌에 deprecated boolean 필드 인용 누락 — D8 의 marker 정책이 외부 표준 직접 인용 없이 운영. raw 자체 Usage Boundary 가 "본 발췌에 직접 인용 없음" 명시 OpenAPI 3.1 §4.8.10 Operation Object + §4.8.24 Schema Object 의 deprecated 필드 발췌를 별도 raw 또는 기존 raw 보강으로 확보 → DEM D8 의 Evidence Strength 를 partial → official-standard 로 승급 needs-confirmation

마주친 문제

  • 아직 없음.

구현 가이드

  • version·deprecation·sunset 값은 API registry가 소유하고 controller는 registry를 참조한다.
  • additive fixture와 breaking fixture를 분리하며, 제거는 deprecation window와 소비자 확인 뒤에만 허용한다.
  • OpenAPI diff가 breaking change를 검출하면 CI가 실패하고 승인 기록 없이는 우회하지 않는다.

엣지·실패·의존

  • 필드 삭제·타입 변경·enum 축소는 기존 소비자를 깨뜨리므로 명시적 migration 경로가 필요하다.
  • 본 계약은 API versioning·OpenAPI registry·contract verification Work Item에 의존한다.

관련 일일 노트

  • 별도 일일 노트 없음.

완료 후 정리

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