293 lines
30 KiB
Markdown
293 lines
30 KiB
Markdown
---
|
|
title: branch / feature-frontend-contract-compatibility-governance
|
|
source_type: branch-note
|
|
status: raw
|
|
id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-023
|
|
kind: project-work-item
|
|
project: ca-skeleton-frontend-operational-contract
|
|
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-023
|
|
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CONFIG-FALLBACK-001@1]
|
|
refines: []
|
|
overrides: []
|
|
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-022, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-006, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011]
|
|
contract_packet: 1
|
|
branch: feature-frontend-contract-compatibility-governance
|
|
parent_branch:
|
|
related_projects: [ca-skeleton-frontend, ca-skeleton]
|
|
governing_docs: [raw/project-notes/ca-skeleton-frontend-operational-contract]
|
|
tags: [branch, ca-skeleton, frontend, api-design, semver, api-contract]
|
|
created: 2026-07-18
|
|
target_merge:
|
|
status_label: in-progress
|
|
contract_packet_sha256: eb4a422e6da50f16e5b6d59964943ebca79d655fc09066815953aa3ba22e4311
|
|
imports: [ART-FE-003@1, FE-GATE-004@1, FE-GATE-015@1, FE-GATE-016@1, FE-OC-004@1, FE-OC-007@1, FE-OC-012@1, FE-OC-013@1, FE-OC-016@1, FE-OC-017@1]
|
|
---
|
|
|
|
# branch: feature-frontend-contract-compatibility-governance
|
|
|
|
> Layer: `raw/branch-notes/` — TODO·결정·진행 기록. 구현 결과는 검증 뒤 `/ingest`로만 추출한다.
|
|
|
|
<!-- section-id: branch-parent -->
|
|
## 부모 (필수)
|
|
|
|
[[raw/project-notes/ca-skeleton-frontend-operational-contract]]
|
|
|
|
<!-- GENERATED: branch-contract:start -->
|
|
<!-- section-id: branch-contract-packet -->
|
|
## 브랜치 계약 패킷
|
|
|
|
- **생성 시 프로젝트 개정**: `1`
|
|
- **패킷 스키마**: `contract_packet: 1`
|
|
- **완료 조건**: version tuple·additive/breaking fixture·migration/rollback rule가 검증된다
|
|
|
|
<!-- section-id: inherited-project-decisions -->
|
|
### 상속한 프로젝트 결정
|
|
|
|
| Decision Ref | Project Summary | Branch Application | Source |
|
|
|---|---|---|---|
|
|
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1` | route, API operation, env, storage, error, query, telemetry, release token을 8개 registry로 관리한다 | registry 변경의 compatibility impact와 version tuple 입력을 집행한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
|
|
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CONFIG-FALLBACK-001@1` | runtime config fallback 시 environment별 rebuild는 허용하되 artifact의 multi-environment 재사용은 금지한다 | config 변경의 migration·fallback·rollback 호환성 규칙에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
|
|
|
|
<!-- section-id: branch-local-decisions -->
|
|
### 브랜치 지역 결정
|
|
|
|
| Decision ID | Decision | Relation | Supporting Claims | Status |
|
|
|---|---|---|---|---|
|
|
| D1 | compatibility impact 공통 어휘를 고정한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
|
|
| D2 | boot compatibility를 version tuple로 판정한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
|
|
| D3 | schema 계열별 독립 version field를 사용한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
|
|
| D4 | breaking 변경은 migration·version bump·discard·fallback과 test evidence를 요구한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
|
|
| D5 | rollback은 coherent tuple 집합을 복원한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
|
|
| D6 | 호환 불가 cache data는 기본 discard한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
|
|
|
|
<!-- section-id: declared-overrides -->
|
|
### 선언한 예외
|
|
|
|
| Override ID | Overrides | Reason | Approval | Status |
|
|
|---|---|---|---|---|
|
|
|
|
없음.
|
|
<!-- GENERATED: branch-contract:end -->
|
|
|
|
<!-- section-id: branch-goal -->
|
|
## 목표
|
|
|
|
이 브랜치는 프로젝트 계약 `FE-OC-023`("API/config/storage/release schema의 breaking change는 migration 또는 version bump 없이 배포하면 안 됨", minimum evidence = compatibility report)을 **구현 착수 가능한 명세**로 낮춘다. hub는 호환성 규칙을 여러 곳에 흩어 정의해 두었다 — 분류 어휘([[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3), registry 변경 프로토콜(§5.10), boot compatibility tuple(§12.3), rollback invariant(§12.5). 본 브랜치는 이들을 **하나의 governance 계약**(버전 tuple 행렬 + additive/breaking 분류 fixture + migration/rollback 규칙)으로 통합해 owner로서 mechanism과 test를 제공한다. 결정 자체(`FE-D012/013/016/019`)는 다른 owner 브랜치가 소유하고, 본 브랜치는 그 결정들이 공유하는 `FE-OC-023` 계약의 **집행 규칙**만 소유한다.
|
|
|
|
- 이슈: 없음 (스캐폴딩 단계)
|
|
- PR: 없음
|
|
|
|
산출물 등급: 프론트엔드 코드가 없으므로 이 브랜치의 모든 구현 주장은 `planned`이다.
|
|
|
|
<!-- section-id: branch-scope -->
|
|
## 범위
|
|
|
|
### 포함 범위
|
|
|
|
- **버전 tuple 행렬**: `(buildId, configSchemaVersion, apiContractVersion, assetManifestHash, releaseId)` + storage schemaVersion + query namespace version 을 필드별 source·compatibility 역할·mismatch 결과로 정리한 표(hub §12.3 / §5.9 통합).
|
|
- **additive vs breaking 분류 fixture**: `compatibility_impact ∈ {none, additive, behavior-change, breaking}` 어휘(hub §3.3)를 API/config/storage/release 4개 schema 계열에 적용하는 synthetic fixture 집합과 각 등급의 required action.
|
|
- **migration/rollback 규칙**: breaking 변경이 version bump·migration·discard·fallback 없이 merge/배포되지 않게 하는 규칙 + rollback이 coherent tuple 집합을 복원하도록 하는 규칙(hub §5.10 / §9.2 / §12.5).
|
|
- **compatibility gate 소유**: `FE-GATE-014@1`(config compatibility) 의 fixture·report artifact 정의. `FE-GATE-015`(release coherence) 는 **소유가 아니라 소비/기여** 다 — Owner 는 hub §2.1.1 이 [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 로 확정했고, 본 branch 는 그 gate 가 쓰는 version tuple 호환 판정을 공급한다.
|
|
|
|
### 제외 범위
|
|
|
|
> 의도적으로 제외. 인접 계약은 각 owner 브랜치가 소유하며 본 브랜치는 그 계약을 *소비*하고 호환성 영향만 집행한다.
|
|
|
|
- runtime config schema 정의·boot 검증 mechanism → [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] (owns `FE-OC-004`).
|
|
- boundary runtime(Zod) schema 검증 → [[raw/branch-notes/feature-runtime-schema-validation-contract]] (owns `FE-OC-007`).
|
|
- storage key namespace·schemaVersion·migration mechanism → [[raw/branch-notes/feature-frontend-storage-registry-contract]] (owns `FE-OC-013`).
|
|
- 8개 registry single-owner·diff-check tooling → [[raw/branch-notes/feature-frontend-contract-registry-governance]] (owns `FE-OC-022`).
|
|
- release directory·atomic pointer·실제 rollback drill 실행 → [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] (owns `FE-OC-016`, `FE-OC-017`).
|
|
- API client retry/idempotency 동작 → [[raw/branch-notes/feature-api-client-response-envelope-contract]] (owns `FE-OC-006`, `FE-OC-009`).
|
|
- CI gate blocking 분리 wiring → [[raw/branch-notes/feature-frontend-ci-quality-gates-contract]].
|
|
- backend API versioning 정책과 실제 migration 실행 → backend / 외부 owner (frontend 계약 밖).
|
|
|
|
## 근거 (필수, 최소 1개+)
|
|
|
|
| Source | 정당화하는 결정 |
|
|
|---|---|
|
|
| [[raw/official-docs/semver-2-0-0-spec-semver-official]] | D1 분류 어휘의 공식 근거(`SEMVER-C1`: MAJOR=incompatible / MINOR=backward-compatible additive / PATCH=backward-compatible fix). 단 SEMVER-C1은 "무엇이 breaking인지" 자동 분류는 증명하지 않으므로 경계 정의는 project decision(D1). |
|
|
| [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.3 compatibility_impact 어휘·§5.10 registry change protocol·§12.3 compatibility tuple·§12.5 rollback invariant·§9.2 cache discard·§6.4 config 검증·§15 `FE-GATE-014/015` — D1~D6 전부의 project-decision 근거. |
|
|
|
|
> 공식 표준(semver)이 *어휘*를 주고, hub가 *프로젝트 적용 규칙과 tuple 필드*를 준다. 두 계층이 함께 D1~D6을 닫는다.
|
|
|
|
## TODO
|
|
|
|
각 항목 등급: `planned`(코드 없음).
|
|
|
|
- [ ] 버전 tuple 행렬을 §구현 가이드 1에 확정 — 필드·source·compatibility 역할·mismatch 결과 — 등급: `planned`
|
|
- [ ] additive/breaking 분류 fixture 표를 §구현 가이드 2에 확정(4개 schema 계열 × 각 등급 예시) — 등급: `planned`
|
|
- [ ] migration/rollback 규칙 R1~R5를 §구현 가이드 3에 확정 — 등급: `planned`
|
|
- [ ] `FE-GATE-014` config compatibility fixture(old/new config) + report artifact 스펙 — 등급: `planned`
|
|
- [ ] `FE-GATE-015` release coherence fixture(mixed HTML/asset/config) + verification artifact 스펙 — 등급: `planned`
|
|
- [ ] cache 호환성 default(discard) vs migration 선택 규칙 명세(§9.2 소유 조건) — 등급: `planned`
|
|
|
|
## 진행 중 메모
|
|
|
|
- hub는 `FE-OC-023`의 owner를 이 브랜치로 지정하지만 `FE-D*` 결정 표에는 이 브랜치를 owner로 둔 행이 없다. 즉 이 브랜치는 *결정*이 아니라 *집행 규칙(governance)*을 소유한다 — 다른 브랜치의 `FE-D012/013/016/019`가 만든 schema 변경을 `FE-OC-023` 규칙으로 검사한다.
|
|
- 미해결 위험(seed에서 승계): additive 변경이 cache+config+release **조합**에서 breaking이 될 수 있다(§구현 가이드 3의 Open Risk / R4에서 추적).
|
|
- 버전 encoding(정수 MAJOR vs semver 문자열)은 hub가 "major incompatibility"만 말하고 literal 표기는 정하지 않았다 → §구현 가이드에서 `UNSUPPORTED_IMPL_DECISION`으로 표시.
|
|
|
|
## 결정 사항
|
|
|
|
> 아래는 Decision Evidence Map의 prose 요약. 근거는 Sources 및 hub 섹션 참조.
|
|
|
|
- 2026-07-18: **D1** compatibility_impact 분류 어휘를 `{none, additive, behavior-change, breaking}` 단일 enum으로 채택하고 API/config/storage/release 4개 schema 계열 모두에 적용 / 이유: hub §3.3이 이 4값을 이미 정의; semver `SEMVER-C1`이 breaking/additive/fix 의미론을 공식 뒷받침 / 대안: 계열별 별도 어휘 / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3 + `raw/official-docs/semver-2-0-0-spec-semver-official.md#SEMVER-C1`.
|
|
- 2026-07-18: **D2** boot 호환성 identity를 `(buildId, configSchemaVersion, apiContractVersion, assetManifestHash, releaseId)` tuple로 판정하고 string lexical compare를 금지 / 이유: hub §12.3이 tuple과 비교 규칙을 명시 / 대안: 단일 monolithic release 버전 문자열 비교 / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §12.3 + §5.9.
|
|
- 2026-07-18: **D3** 각 schema 계열은 독립 버전 필드를 가지며 breaking = MAJOR 상향(config/API), storage는 `schemaVersion` increment, query는 namespace version bump / 이유: hub §5.4/§5.5/§5.7이 필드를 정의; semver `SEMVER-C1` MAJOR 의미론 / 대안: 전 계약 공통 단일 버전 / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.4 §5.5 §5.7.
|
|
- 2026-07-18: **D4** breaking/behavior-change 변경은 migration·version bump·discard·fallback 중 하나 + test evidence 없이 merge 금지 / 이유: hub §3.3(4)·§5.10(4) 규칙 / 대안: 없음(invariant) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3 §5.10.
|
|
- 2026-07-18: **D5** rollback은 coherent tuple 집합(HTML+asset manifest+assets+compatible config+compatible API+release manifest)을 복원하고 HTML-only rollback을 금지 / 이유: hub §12.5 rollback invariant / 대안: 없음(invariant) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §12.5.
|
|
- 2026-07-18: **D6** 호환 불가 cache data는 default로 discard(재사용 금지)하며 migration을 선택할 때만 본 브랜치가 fixture·rollback을 소유 / 이유: hub §9.2 / 대안: 항상 migration / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9.2.
|
|
|
|
## 결정-근거 매핑
|
|
|
|
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|
|
|---|---|---|---|---|---|
|
|
| D1 | compatibility_impact 어휘 = `{none, additive, behavior-change, breaking}` 단일 enum, 4개 schema 계열 공통 (`FE-OC-023`) | 4개 계열이 하나의 governance register를 공유하는 한 유지; 어떤 계열이 5번째 impact class가 필요하면 계열별 어휘로 분기 | `raw/official-docs/semver-2-0-0-spec-semver-official.md#SEMVER-C1`; [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3 | `official-standard`(어휘) + `project-decision`(경계) | semver는 "무엇이 breaking인지"를 자동 분류하지 않음(`SEMVER-C1` does-not-prove) — 경계 정의가 사람 판단에 남음 |
|
|
| D2 | boot 호환성 identity = 5-field tuple `(buildId, configSchemaVersion, apiContractVersion, assetManifestHash, releaseId)`, lexical compare 금지 (`FE-OC-023`, `FE-OC-016`) | static SPA release 인 동안 유지; SSR/edge 도입 시 별도 project fork(§6.2) 또는 tuple 차원 추가 시 재검토 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §12.3, §5.9 | `project-decision` | tuple 필드 중 하나라도 source가 비어 있으면(예: provider가 releaseId 미노출) 판정 불가 → §9 검증 대상 |
|
|
| D3 | 계열별 독립 버전 필드; breaking→config/API MAJOR 상향, storage `schemaVersion` increment, query namespace version bump (`FE-OC-004`, `FE-OC-007`, `FE-OC-012`, `FE-OC-013`) | 외부 codegen SSOT가 없는 동안 유지; code generation SSOT 채택 시 버전 표기를 codegen 산출로 이관(hub `FE-D018` revisit trigger와 정렬) | `raw/official-docs/semver-2-0-0-spec-semver-official.md#SEMVER-C1`; [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.4, §5.5, §5.7 | `official-standard` + `project-decision` | literal encoding(정수 MAJOR vs semver 문자열) 미확정 → §구현 가이드 `UNSUPPORTED_IMPL_DECISION` |
|
|
| D4 | breaking/behavior-change는 migration·version bump·discard·fallback 중 하나 + test evidence 없이 merge 금지 (`FE-OC-023`) | invariant — 항상 성립. 단 "additive"로 분류된 변경은 이 게이트를 우회하므로 분류 정확성이 전제 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3, §5.10 | `project-decision`(invariant) | 오분류(breaking을 additive로) 시 게이트가 조용히 통과 → D1 분류 fixture로 방어 |
|
|
| D5 | rollback은 coherent tuple 집합 복원, HTML-only rollback 금지 (`FE-OC-017`, `FE-OC-023`) | invariant — 항상 성립. 실제 drill 실행·pointer switch mechanism은 release-cache-rollback owner에 위임 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §12.5 | `project-decision`(invariant) | provider가 atomic pointer/cache purge를 지원하지 않으면 coherence 보장 불가 → reachability probe 필요(§12.5) |
|
|
| D6 | 호환 불가 cache data는 default discard; migration 선택 시에만 본 브랜치가 fixture·rollback 소유 (`FE-OC-012`, `FE-OC-013`) | offline/persistence 요구가 없어 data 손실이 허용되는 동안 discard 유지; offline 요구가 생기면 migration으로 전환(hub `FE-D019` service worker off 조건과 연동) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9.2 | `project-decision` + `conditional-default` | discard가 UX상 허용되는지 미검증(현재 persistence default off이라 위험 낮음) |
|
|
|
|
## 구현 가이드
|
|
|
|
> `planned` blueprint. 프론트엔드 코드가 없으므로 경로는 hub §4.6 Planned directory blueprint / §5 registry owner map에서 인용한 *예정 경로*이다. 실제 path는 repository 생성 후 확정한다.
|
|
|
|
### 1. 버전 tuple 행렬 (Version tuple matrix)
|
|
|
|
> **Trace**: D2 (5-field boot tuple) + D3 (계열별 버전 필드). 근거 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §12.3 (tuple + 비교 규칙), §5.9 (release token registry), §5.4 (`CONFIG_SCHEMA_VERSION`/`API_CONTRACT_VERSION`).
|
|
>
|
|
> - **UNSUPPORTED_IMPL_DECISION**: literal 버전 encoding(정수 MAJOR `"3"` vs semver 문자열 `"3.1.0"`). hub는 "major incompatibility"만 말하고 표기를 정하지 않음. trade-off: 정수 MAJOR는 boot 호환 판정이 가장 단순하나 additive/minor 가시성을 잃음 → **boot 판정용 정수 MAJOR + 진단용 optional MINOR** 병기를 제안(planned).
|
|
> - **UNSUPPORTED_IMPL_DECISION**: 필드 저장 위치 파일명(예: `src/contracts/compatibility-tuple.js`). hub §4.6은 `src/bootstrap/`, `src/contracts/` 계층만 주고 파일명은 미지정. trade-off: contract 계층에 두어 boot·application 양쪽이 참조 가능하게 함.
|
|
|
|
| 버전 필드 | Source (§5 registry) | Compatibility 역할 | Mismatch 시 동작 (§12.3) | 정규화 error kind (§5.6) |
|
|
|---|---|---|---|---|
|
|
| `buildId` | CI build (`VITE_BUILD_ID`, §5.4) | asset/HTML coherence | assetManifestHash와 함께 coherence 판정 | `DEPLOY_MISMATCH` |
|
|
| `configSchemaVersion` | runtime config schema (`CONFIG_SCHEMA_VERSION`, §5.4/§5.9) | boot compatibility | major incompatible → boot fail, product route 미mount | `BOOT_CONFIG_FAILURE` |
|
|
| `apiContractVersion` | frontend/backend agreement (`API_CONTRACT_VERSION`, §5.4/§5.9) | schema compatibility | incompatible → route mount fail 또는 explicitly supported compatibility adapter | `DEPLOY_MISMATCH` |
|
|
| `assetManifestHash` | build output (§5.9) | chunk integrity/mismatch | mismatch → controlled reload **once**(§10.2 guard) | `CHUNK_LOAD_FAILURE` |
|
|
| `releaseId` | deploy system (§5.9) | rollback target | 나머지 버전 호환 시 mismatch → warning telemetry 후 continue 가능 | (telemetry only) |
|
|
| storage `schemaVersion` | storage registry physicalKey `v<schema>` (§5.5) | 영속 data 호환 | previous version 읽으면 migration 또는 discard | `STORAGE_*` / discard |
|
|
| query namespace version | query key registry (§5.7) | cache identity partition | API/schema breaking → namespace version bump; 호환 불가 cache → discard(D6) | `QUERY_CACHE_FAILURE` |
|
|
|
|
핵심 규칙(§12.3 그대로): **string lexical compare로 버전 호환을 판정하지 않는다.** 각 필드는 선언된 버전 값으로만 비교한다.
|
|
|
|
### 2. Additive vs breaking 분류 fixture
|
|
|
|
> **Trace**: D1 (분류 어휘) + D4 (분류→required action). 근거 `raw/official-docs/semver-2-0-0-spec-semver-official.md#SEMVER-C1`, [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3, §6.4 (unknown key policy), §5.5, §5.7.
|
|
>
|
|
> - **UNSUPPORTED_IMPL_DECISION**: 분류를 사람이 PR checklist로 판정할지 diff 도구로 자동화할지. hub §3.3은 *수동 프로토콜*만 정의. trade-off: 초기엔 수동 checklist + fixture로 회귀 방지, 자동 diff 도구는 registry-governance 브랜치 tooling으로 위임(planned).
|
|
> - **UNSUPPORTED_IMPL_DECISION**: fixture 디렉터리·파일명(예: `test/compatibility/fixtures/*.json`). hub는 fixture *존재*(§15 "old/new config versions", "mixed HTML/assets/config")만 요구, 경로 미지정. trade-off: gate별 하위 폴더로 분리해 `FE-GATE-014`/`015`가 독립 소비.
|
|
|
|
| 변경 예시 | compatibility_impact | 근거 규칙 | Required action |
|
|
|---|---|---|---|
|
|
| config에 optional key 추가(schema passthrough/default 존재) | `additive` | §6.4 unknown key: additive keys allowed only if schema explicitly passthroughs | 버전 bump optional, migration 불필요 |
|
|
| config에 required key 추가 / 기존 key 의미 변경 | `breaking` | §5.4 `CONFIG_SCHEMA_VERSION` compatibility fail | configSchemaVersion MAJOR 상향 + migration/fallback + `FE-GATE-014` fixture |
|
|
| API 응답에 optional field 추가(schema가 unknown 안전 처리) | `additive` | §6.4 default strict; passthrough 시 additive | none/additive, apiContractVersion 유지 |
|
|
| API 응답 field 제거·rename(mapper가 소비) | `breaking` | §5.7 "API/schema breaking change" | apiContractVersion 상향 + compatibility adapter 또는 coordinated release |
|
|
| storage 값 shape 변경 | `breaking` | §5.5 "incompatible change 시 increment", migration/discard | storage `schemaVersion` increment + migration 또는 discard(D6) |
|
|
| release asset set 변경(chunk hash 변경) | 호환상 `none` | §12.3 assetManifestHash coherence | atomic deploy 순서(§12.4), coherence는 `FE-GATE-015`가 검증 |
|
|
| error kind enum 제거 | `breaking`(behavior-change) | §5.6 stable enum | consumer migration + version note, D4 게이트 |
|
|
|
|
분류 경계의 근거 한계: `SEMVER-C1`은 MAJOR=incompatible / MINOR=additive / PATCH=fix *의미론*을 주지만 "내부 구현 변경이 API에 미치는 영향을 자동 분류하지 않는다"(does-not-prove). 따라서 위 표의 각 행 경계는 **project decision(D1)**이며 fixture로 회귀 고정한다.
|
|
|
|
### 3. rollback 규칙
|
|
|
|
> **Trace**: D4 (merge 게이트) + D5 (rollback coherence) + D6 (cache discard). 근거 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §3.3, §5.10, §9.2, §12.5.
|
|
>
|
|
> - **UNSUPPORTED_IMPL_DECISION**: migration 함수 배치·명명(예: storage per-version migrator API 모양). hub §5.5는 "migration 또는 discard" 원칙만, mechanism 미지정. trade-off: storage adapter 소유이므로 storage-registry 브랜치와 공동 정의 — 본 브랜치는 *규칙*만, migrator *구현*은 위임(R3).
|
|
|
|
- **R1 (no silent breaking)**: `compatibility_impact ∈ {behavior-change, breaking}` 인 변경은 migration OR version bump + test evidence 없이 merge 금지(§3.3.4). additive/none은 게이트 우회 가능하나 §2 분류 fixture로 오분류 방어.
|
|
- **R2 (breaking → 처리 택1)**: registry/storage/cache breaking은 version bump와 함께 **migration · discard · fallback** 중 하나를 명시(§5.10.4, §9.2). "택1"을 비우면 orphan token scan(§5.10.8)과 D4 게이트가 fail.
|
|
- **R3 (rollback coherence)**: rollback target은 prior HTML + prior asset manifest·assets + compatible runtime config + compatible API contract(또는 backend compatibility window) + release manifest 의 **coherent set**을 복원한다(§12.5). HTML만 과거로 되돌리고 config를 최신에 남기는 rollback 금지.
|
|
- **R4 (조합 breaking 방어)**: 개별 additive라도 cache+config+release **조합**에서 incompatible하면 D6에 따라 cache discard로 강등한다(§9.2). 이 조합 판정은 §1 tuple 행렬 전체를 함께 평가한다. — *잔여 위험: 조합 폭발을 전수 fixture로 덮지 못할 수 있음(§9 검증 대상).*
|
|
- **R5 (비교 방식)**: 모든 버전 비교는 선언 필드 기준(§12.3), lexical string compare 금지.
|
|
|
|
gate 소유 매핑:
|
|
|
|
| Gate | 이 브랜치 산출물 |
|
|
|---|---|
|
|
| `FE-GATE-014@1` config compatibility (Owner = 본 branch) | old/new config version fixture 제공 |
|
|
| `FE-GATE-015@1` release coherence (Owner = release-cache) | version tuple 호환 판정 공급 |
|
|
| `FE-GATE-004@1` runtime schema (Owner = runtime-schema-validation) | config invalid matrix 에 compatibility 필드 기여 |
|
|
|
|
각 gate 의 blocking scope·pass condition·evidence artifact 는 hub §15.1 소유이며 여기에 옮겨 적지 않는다.
|
|
|
|
> **UNSUPPORTED_IMPL_DECISION**: artifact 파일 경로(예: `artifacts/release/compatibility-report.json`). hub §15는 artifact *이름*("compatibility report"/"release verification")만 주고 경로 미지정. trade-off: §14.3 `pnpm verify:release`(`artifacts/release/verification.json`) 관례를 따라 `artifacts/release/` 하위로 통일(planned).
|
|
|
|
## 엣지·실패·의존
|
|
|
|
- **실패·엣지 경로**:
|
|
- config schema major incompatible → `BOOT_CONFIG_FAILURE`, product route 미mount, boot error shell만 렌더(§6.3).
|
|
- API contract incompatible → route mount fail 또는 supported compatibility adapter, `DEPLOY_MISMATCH`(§12.3).
|
|
- asset manifest mismatch → controlled reload **once**; 같은 release pair 두 번째 실패 시 auto reload 중단·rollback/support surface(§10.2 `CHUNK_RELOAD_GUARD`).
|
|
- releaseId만 mismatch·나머지 호환 → warning telemetry(`release.mismatch.detected`) 후 continue(§12.3).
|
|
- 호환 불가 cache → discard, 재사용 금지(§9.2, D6).
|
|
- partial rollout / cached config / mixed release: tuple 조합이 incompatible일 수 있음 → R4로 강등, 잔여는 `needs-confirmation`.
|
|
- **다른 계약 의존** (§20 Dependency + §4.3 matrix; 각 sibling은 FE-OC 계약으로만 참조 — 로컬 D 번호 미확인):
|
|
- [[raw/branch-notes/feature-frontend-contract-registry-governance]] 의 `FE-OC-022` — 8개 registry가 single owner·compatibility impact를 기록해야 본 브랜치 분류가 대상 필드를 가짐. 그 계약이 바뀌면 §1 tuple 행렬 필드 source가 흔들린다.
|
|
- [[raw/branch-notes/feature-runtime-schema-validation-contract]] 의 `FE-OC-007` — boundary schema 검증이 additive/breaking을 실제로 감지(unknown key strict/passthrough)한다. §2 분류의 런타임 근거.
|
|
- [[raw/branch-notes/feature-frontend-storage-registry-contract]] 의 `FE-OC-013` — storage `schemaVersion`·migration/discard mechanism 소유. 본 브랜치의 cache-discard 결정과 §3 R2가 이 계약 위에서 동작.
|
|
- [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] 의 `FE-OC-004` — `CONFIG_SCHEMA_VERSION` 을 runtime config로 공급(그 브랜치 결정 근거는 hub [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D012, FE-D013).
|
|
- [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 의 `FE-OC-016`, `FE-OC-017` — 실제 rollback drill·release tuple 산출. 본 브랜치 rollback-coherence 규칙의 집행 주체(그 브랜치 근거는 hub [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D019~FE-D023).
|
|
|
|
## 검증해야 할 주장
|
|
|
|
| Claim | Why uncertain | How to verify | Status |
|
|
|---|---|---|---|
|
|
| breaking change가 migration/version bump 없이 배포되지 않는다 | CI·release flow 없음, 코드 없음 | additive/breaking synthetic fixture(§2) → `FE-GATE-014` config compatibility test(old/new config: supported pass / incompatible boot fail) | `needs-confirmation` |
|
|
| release coherence가 mixed HTML/asset/config를 탐지한다 | 실제 release verification 미실행 | `FE-GATE-015` mixed fixture → mismatch detected / coherent set passes → release verification artifact | `needs-confirmation` |
|
|
| 버전 비교가 lexical string compare에 의존하지 않는다 | 구현 없음 | tuple 비교 함수 unit test에 `"9" vs "10"` 류 lexical trap fixture 포함 | `planned` |
|
|
| 호환 불가 cache data가 discard되고 재사용되지 않는다 | query cache 구현 없음 | query namespace version bump 시 stale cache discard integration test(§9.2) | `planned` |
|
|
| rollback이 coherent tuple 집합을 복원한다(HTML-only rollback 차단) | 실제 rollback drill 없음 | `FE-GATE-016` rollback drill: HTML-only rollback fixture가 fail, coherent tuple rollback이 pass(§12.5) | `needs-confirmation` |
|
|
| additive 변경이 cache+config+release 조합에서 breaking이 되지 않는다(또는 R4로 강등된다) | 조합 폭발, 전수 fixture 어려움 | 대표 조합 fixture matrix로 R4 강등 경로 검증; 미커버 조합은 명시적 잔여 위험 기록 | `needs-confirmation` |
|
|
|
|
## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
|
|
|
|
- 스캐폴딩 단계: `/coverage` 실행 전 수동 행을 만들지 않는다.
|
|
|
|
## 마주친 문제
|
|
|
|
- 없음 — 스캐폴딩 단계.
|
|
|
|
## 묶음 (이 branch에서 파생된 자료)
|
|
|
|
<!-- GENERATED: artifact-imports:start -->
|
|
### 가져온 artifact 계약
|
|
|
|
| Artifact Ref | Owner | Producer | Schema Ref |
|
|
|---|---|---|---|
|
|
| `ART-FE-003@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | `harness/source/artifact-schemas/ca-skeleton-frontend/release-verification.schema.json` |
|
|
<!-- GENERATED: artifact-imports:end -->
|
|
|
|
<!-- GENERATED: project-contract-imports:start -->
|
|
## 가져온 프로젝트 계약
|
|
|
|
| Ref | Owner | 요약 | Branch 적용 |
|
|
|---|---|---|---|
|
|
| `FE-GATE-004@1` | [[raw/branch-notes/feature-runtime-schema-validation-contract]] | invalid fixture 가 예상 kind 로 거부되지 않으면 merge 를 MUST 차단 | import 참조로 적용 |
|
|
| `FE-GATE-015@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | 혼재된 release 조합이 감지되지 않으면 release 를 MUST 차단 | import 참조로 적용 |
|
|
| `FE-GATE-016@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | rollback 과 smoke 증거가 없으면 production promotion 을 MUST 차단 | import 참조로 적용 |
|
|
| `FE-OC-004@1` | [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] | build-time, runtime-public, secret config를 MUST 분리하고 boot 전에 runtime config를 검증 | import 참조로 적용 |
|
|
| `FE-OC-007@1` | [[raw/branch-notes/feature-runtime-schema-validation-contract]] | JSON envelope와 payload는 boundary에서 runtime schema를 MUST 통과 | import 참조로 적용 |
|
|
| `FE-OC-012@1` | [[raw/branch-notes/feature-server-state-caching-contract]] | query key와 invalidation은 registry factory만 MUST 사용 | import 참조로 적용 |
|
|
| `FE-OC-013@1` | [[raw/branch-notes/feature-frontend-storage-registry-contract]] | storage key는 namespace·version·classification을 MUST 가지며 token/secret 저장을 금지 | import 참조로 적용 |
|
|
| `FE-OC-016@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | HTML, asset, runtime config, release manifest cache policy를 MUST 구분 | import 참조로 적용 |
|
|
| `FE-OC-017@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | rollback은 immutable prior release로 수행하고 build/config/API compatibility를 MUST 검증 | import 참조로 적용 |
|
|
<!-- GENERATED: project-contract-imports:end -->
|
|
|
|
- 없음 — 자식 자료는 생성 후 controller가 parent Cluster와 함께 등록한다.
|
|
|
|
## 관련 일일 노트
|
|
|
|
- 없음 — daily note는 이 작업에서 수정하지 않는다.
|
|
|
|
## 완료 후 정리
|
|
|
|
- PR 링크: 없음
|
|
- 리뷰 메모: 없음
|
|
- 머지 결과 / 배포 환경: `planned`
|
|
- **wiki 추출 대상** (verified만): 없음
|
|
- **추출하지 않을 항목** (planned / documented-only / abandoned): 현재 전체
|