Files
llm-wiki/raw/branch-notes/feature-frontend-release-cache-rollback-contract.md
DongHyeonka d6dfda64ab docs(branch): 기존 7개 노트를 개정 결정·신규 위임에 정합
- REGISTRY-001 Summary 문자열 4곳 (additive, revision 은 1 유지).
  registry-governance 는 본문 서술 12곳의 '8개'도 함께 9개로 갱신
- OFFLINE-CACHE-001 pin @1->@2 와 Summary·적용점 (behavior-change)
- DELEG-FE-007~011 delegate 5곳 접수 완료 — 미접수 위임 0건
- runtime-schema-validation 이 FLOW-FE-EVENT-003/004 소유를 명시
- env-runtime-config 가 FE-REG-CAPABILITY registry 와 FE-GATE-033 gate
  owner 를 취득하고 claim 2건 추가
- 신규 6개 노트의 delegation pin 을 기존 @1 형식으로 정규화
2026-07-28 14:40:38 +09:00

295 lines
32 KiB
Markdown

---
title: branch / feature-frontend-release-cache-rollback-contract
source_type: branch-note
status: raw
id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-024
kind: project-work-item
project: ca-skeleton-frontend-operational-contract
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-024
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-DEPLOYMENT-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CACHE-POLICY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001@2]
refines: []
overrides: []
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-020, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-004, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-023]
contract_packet: 1
branch: feature-frontend-release-cache-rollback-contract
parent_branch:
related_projects: [ca-skeleton-frontend, ca-skeleton]
governing_docs: [raw/project-notes/ca-skeleton-frontend-operational-contract]
tags: [branch, ca-skeleton, frontend, ci-cd, build-tooling, externalized-config]
created: 2026-07-18
target_merge:
status_label: in-progress
contract_packet_sha256: 63a7ea47dea99d7a8dfe7275a2636dd5f529c280884fe593d2f083dfb15ed1fc
imports: [ART-FE-001@1, FE-OC-019@1]
accepts_delegations: [DELEG-FE-011@1]
---
# branch: feature-frontend-release-cache-rollback-contract
> 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`
- **완료 조건**: release tuple·cache header·mixed fixture failure·rollback drill이 검증된다
<!-- section-id: inherited-project-decisions -->
### 상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-DEPLOYMENT-001@1` | static release는 immutable release directory와 atomic active pointer로 배포한다 | immutable release layout·atomic switch·rollback에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CACHE-POLICY-001@1` | hashed asset은 immutable, HTML·runtime config·release manifest는 revalidate/no-store로 분리한다 | surface별 cache header와 coherence gate에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001@2` | service worker의 release asset precaching은 default off이고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용한다 | release asset precaching 은 off 로 유지하고, capability opt-in 된 service worker 의 버전(`serviceWorkerVersion`)을 release·rollback coherence 판정에 연결한다 (`DELEG-FE-011`) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
<!-- section-id: branch-local-decisions -->
### 브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | surface별 cache policy를 분리한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D2 | immutable release directory와 atomic active pointer를 사용한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D3 | service worker와 offline asset cache를 기본 off로 둔다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D4 | rollback은 coherent prior-release set을 복원한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D5 | FE-REG-RELEASE와 typed compatibility comparison을 사용한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D6 | `FE-GATE-019@2`의 security-header 축 검증 메커니즘을 소유하고 정책 내용은 browser-security가 공급한다 | `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-016`(HTML/asset/runtime-config/release-manifest cache policy를 MUST 구분)과 `FE-OC-017`(rollback은 immutable prior release로 수행하고 build/config/API compatibility를 MUST 검증)을 *구현 착수 가능한 명세*로 내린다. hub의 결정 `FE-D019`(service worker/offline cache default off), `FE-D020`(hashed asset immutable + HTML/config/manifest revalidate·no-store 분리), `FE-D023`(immutable release directory + atomic active pointer)와 registry `FE-REG-RELEASE`(release token registry, §5.9)를 owner로서 상세화하고, 여기에 §12.3 compatibility tuple / §12.4 atomic deploy expectation / §12.5 rollback invariant를 착수 수준으로 고정한다. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D019 · FE-D020 · FE-D023 · §12. 아직 frontend repository·hosting provider가 없으므로 본 노트의 모든 구현 항목 등급은 `planned`이며, 코드/헤더/드릴 evidence가 생기기 전에는 `actually-implemented`로 승급하지 않는다.
- 이슈: 없음 (스캐폴딩 단계)
- PR: 없음
<!-- section-id: branch-scope -->
## 범위
### 포함 범위
- **Cache policy 소유** (`FE-OC-016`): hashed JS/CSS/font/image, `index.html`, `/config.json`(runtime config), `release-manifest.json`, source map, service worker 6개 surface의 default cache policy 명세 (§12.2). 실제 `Cache-Control` header syntax는 policy로만 소유하고 provider 확정 후 adapter runbook에 기록.
- **Immutable release + atomic pointer** (`FE-D023`, §12.4): immutable release directory layout + atomic active-pointer deploy order.
- **Rollback contract** (`FE-OC-017`, §12.5): coherent prior-release set 정의 + rollback invariant + FE-RB-005 drill evidence 요건(`FE-GATE-016`).
- **Release token registry** (`FE-REG-RELEASE`, §5.9): release/compatibility tuple 토큰 + typed(비-lexical) compatibility comparison.
- **Release coherence gate + mixed-version negative fixture** (`FE-GATE-015@1`): HTML/asset/config mismatch 탐지 fixture.
- **Hosting header gate** (`FE-GATE-019@2`, 2026-07-21 에 security 축 편입): 응답 header 의 declared-vs-actual 대조를 **cache 축과 security 축 둘 다** 담당한다. 본 branch 는 gate owner 로서 **검증 메커니즘**(응답 probe · 대조 · `hosting-headers.json` artifact)을 소유하고, 검증 대상 **security header 정책의 내용**은 [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`) 가 공급한다. directive 값 자체는 여전히 hosting/backend header owner 소유다(D6).
### 제외 범위
> 의도적으로 제외한 것. 면접 등에서 "이건 범위에 없었습니다"라고 답할 근거.
- **Hosting/CDN provider의 실제 콘솔 command와 deploy execution** — provider 확정 후 adapter/runbook에서 채움.
- **Runtime config 자체의 3-way 분리·boot 검증 로직** (`FE-OC-004`) — owner는 [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] (`FE-OC-004`). 본 브랜치는 그 config의 *cache/coherence*만 소유.
- **Build output의 asset hashing·build manifest·dependency inventory 생성** (`FE-OC-018`) — owner는 [[raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract]] (`FE-OC-018`). 본 브랜치는 그 산출물을 *release coherence 입력*으로 consume만.
- **Version tuple compatibility 규칙(additive/breaking/migration)** (`FE-OC-023`) — owner는 [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] (`FE-OC-023`). 본 브랜치는 그 규칙을 rollback 판정에 *적용*만.
- **Runbook 서술 문서(FE-RB-002/FE-RB-005 narrative) 유지와 5개 drill orchestration** (`FE-OC-025`) — owner는 [[raw/branch-notes/feature-frontend-operational-runbook-contract]] (`FE-OC-025`). 본 브랜치는 rollback *기술 escalation 대상*이자 drill evidence 요건 제공자.
- **DEPLOY_MISMATCH 사용자 recovery UI·reload-loop 방지** (`FE-OC-015`) — owner는 [[raw/branch-notes/feature-frontend-render-recovery-boundary-contract]] (`FE-OC-015`).
- **8-registry single-owner governance orchestration** (`FE-OC-022`) — owner는 [[raw/branch-notes/feature-frontend-contract-registry-governance]] (`FE-OC-022`). 본 브랜치는 `FE-REG-RELEASE` 한 registry의 *content owner*.
## 근거 (필수, 최소 1개+)
> 이 branch의 구현·설계 결정의 **근거가 되는 외부 자료**.
| Source | 정당화하는 결정 |
|---|---|
| [[raw/official-docs/vite-build-tool-official]] `VITE-C2` | production build가 content-hash 붙은 optimized static asset을 산출한다는 공식 근거 — D1(hashed asset = long-lived immutable) cache 분리와 D2(static-hosting immutable release directory) 전제의 build-tool 근거. cache header 자체는 hosting provider 확정 후 보강. |
| [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §15.1 `FE-GATE-019@2` · §2.1.1(revision 2, Owner = 본 branch) · §14.3(`pnpm verify:hosting-headers`) | D6 — 이 gate 가 cache header 뿐 아니라 **security header 집합**의 declared-vs-actual 대조까지 담당한다는 근거. 정책 내용 공급자는 [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`). |
| [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D019 · FE-D020 · FE-D023 (§12 Release/Cache/Version/Rollback, §5.9 FE-REG-RELEASE) | 본 브랜치 owner 결정 3건 + release token registry + compatibility tuple/atomic deploy/rollback invariant의 project decision SSOT. release coherence·rollback invariant는 외부 vendor 표준이 아니라 project inference이므로 hub row를 근거로 인용. |
## TODO
각 항목 옆에 증거 등급 표기.
- [ ] `FE-REG-RELEASE` release token registry(`src/contracts/release-tokens.js`) + typed compatibility comparator 명세 — 등급: `planned`
- [ ] surface별 cache policy 표 + `pnpm verify:hosting-headers`(`FE-GATE-019@2`) assertion 명세 — 등급: `planned`
- [ ] `FE-GATE-019@2` security-header 축: browser-security 가 공급한 정책 집합(CSP/HSTS/frame/referrer)의 declared-vs-actual 대조를 같은 probe·artifact 로 편입 — 등급: `planned`
- [ ] immutable release directory layout + atomic active-pointer deploy order(§12.4) 명세 — 등급: `planned`
- [ ] rollback coherent-set invariant + FE-RB-005 drill evidence(`FE-GATE-016`) 요건 명세 — 등급: `planned`
- [ ] mixed-version negative fixture + release coherence gate(`FE-GATE-015`) 명세 — 등급: `planned`
## 진행 중 메모
- hosting/CDN provider 미확정 → cache header 문자열·atomic switch primitive·purge semantics는 provider 확정 시 adapter runbook에서 확정. 현재는 policy와 invariant만 소유한다.
- 모든 항목 `planned` — frontend repository가 없어 코드/헤더/드릴 evidence 부재.
## 결정 사항
> 각 결정의 근거는 hub decision register(§3.2)와 §12/§5.9.
- 2026-07-18: **surface별 cache policy 분리 채택** / 이유: hashed asset은 content-hash로 identity가 고정돼 immutable 가능하지만 HTML/runtime-config/release-manifest는 release마다 교체·mismatch 탐지가 필요 / 검토한 대안: 전 surface 단일 cache 규칙(운영 단순) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D020 · §12.2.
- 2026-07-18: **immutable release directory + atomic active pointer 채택** / 이유: rollback 가능한 artifact와 partial-deploy 없는 전환을 위해 / 검토한 대안: in-place overwrite deploy(rollback 불가·mixed window 발생) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D023 · §12.4.
- 2026-07-18: **service worker/offline asset cache default off** / 이유: stale asset·config mismatch surface 축소 / 검토한 대안: SW precache(오프라인 UX 확보하나 stale 복잡도 증가) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D019.
- 2026-07-18: **rollback = coherent prior-release set + compatibility 검증** / 이유: HTML만 되돌리고 runtime config를 최신에 남기면 mismatch로 boot/route 실패 / 검토한 대안: HTML pointer만 교체하는 fast rollback(§12.5가 금지) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-OC-017 · §12.5 · §16.5.
- 2026-07-21: **`FE-GATE-019` 에 security-header 축 편입(D6)** / 이유: hub §15.1 이 이 gate 의 Covered FE-OC 에 `FE-OC-019` 를 추가해 pass condition 이 security header 까지 넓어졌다. 응답 header 의 declared-vs-actual 대조라는 메커니즘이 cache header 와 동일하므로 같은 probe·같은 artifact 를 쓴다 / 검토한 대안: `FE-GATE-013`(security) 에 두기 — 그쪽은 artifact 를 스캔하는 gate 라 실행 시점·증거 형식이 달라 기각 / 근거: hub §15.1 `FE-GATE-019@2` · §2.1.1 revision 2. 검증 대상 정책 집합은 [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] 가 공급.
- 2026-07-18: **release token registry + typed(비-lexical) compatibility comparison** / 이유: `releaseId`/schema/API version을 string lexical로 비교하면 오판정(§12.3 금지) / 검토한 대안: page 안에서 직접 version string 비교(§5.1 ad hoc failure) / 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.9 · §12.3.
## 결정-근거 매핑
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | `FE-OC-016` surface별 cache policy 분리: hashed asset = long-lived immutable, `index.html` = no-cache/revalidate, `/config.json` = no-store(또는 URL explicit version), `release-manifest.json` = no-store/immediate revalidate, source map = public off, service worker = off | 기본값으로 이 분리를 적용. hosting cache primitive가 surface별 `Cache-Control`을 표현하지 못하면(단일 global 규칙만 제공) provider-specific 등가 정책을 adapter runbook + decision row에 기록해 대체 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D020, FE-OC-016 · §12.2 · §6.1(runtime public=no-store); [[raw/official-docs/vite-build-tool-official]] `VITE-C2`(content-hash static asset) | `project-decision + official-doc` | 실제 hosting header가 선언 policy와 일치하는지 미검증(`FE-GATE-019@2` 필요); 정확한 `max-age`/`immutable` directive 문자열 미확정 |
| D2 | `FE-D023` immutable release directory + atomic active pointer 배포. deploy order: immutable asset → release manifest → runtime config → asset reachability smoke → active HTML pointer switch → post-switch smoke (§12.4) | provider가 atomic pointer switch를 지원하면 이 primitive 사용. provider가 *다른* atomic primitive만 제공하면 그 등가 primitive + rollback semantics를 decision row에 기록(§12.4 fallback) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D023, FE-OC-016, FE-OC-017 · §12.4 · §12.1(artifact set) | `conditional-default` | provider primitive 미확정 — atomic switch·purge semantics는 hosting owner 확정 전 `TBD`; partial-deploy window 무발생 검증 필요 |
| D3 | `FE-D019` service worker·offline asset cache default off | stale asset/config mismatch surface 축소를 위해 기본 off. offline product requirement + update UX가 *설계된 뒤에만* SW precache 재검토(FE-D019 revisit trigger) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D019, FE-OC-016 · §12.2(service worker=default off row) | `conditional-default` | SW가 실제로 등록되지 않는지 build/e2e로 미검증; offline 요구가 생기면 update UX 설계 없이는 재도입 금지 |
| D4 | `FE-OC-017` rollback = coherent prior-release set 복구 + build/config/API compatibility 검증. 금지: rebuild-as-rollback, HTML-only 교체, compatibility 미확인 pointer 변경, smoke 없는 close (§16.5) | release-blocking defect가 확인되고 forward fix가 incident window 안에서 안전하다고 증명되지 않을 때 rollback(§16.5 activation). prior immutable release·config·API compatibility가 알려져 있어야 실행 가능(preconditions) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-OC-017, FE-D023 · §12.5(rollback invariant) · §16.5(FE-RB-005 procedure invariant) | `project-decision` | recovery를 cache purge 완료가 아니라 old/new reachability probe로 판정해야 함(§12.5) — provider probe 미구현; rollback drill(`FE-GATE-016`) evidence 부재 |
| D5 | `FE-REG-RELEASE` release token registry(토큰 목록은 hub §5.9 소유 — 8-token tuple) + typed compatibility comparison — string lexical version 비교 금지(§12.3) | tuple 토큰과 comparator를 registry factory로 소유. page/component가 raw string version을 비교하거나 cache key를 직접 작성하면 ad hoc use failure(§5.1) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.9(release token schema) · §12.3(compatibility tuple + no-lexical-compare rule) · §5.1(FE-REG-RELEASE owner) | `project-decision` | comparator API 모양·semver 파싱 규칙 미확정(UNSUPPORTED_IMPL_DECISION); `builtAt`이 cache identity로 오용되지 않는지 검증 필요 |
| D6 | `FE-GATE-019@2`**security-header 축**: 본 branch 는 gate owner 로서 declared-vs-actual **검증 메커니즘**(응답 probe · 대조 · `hosting-headers.json` artifact)을 소유하고, 검증 대상 security header **정책의 내용**은 [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`) 가 공급한다 | hub §15.1 이 이 gate 의 Covered FE-OC 에 `FE-OC-019` 를 포함하는 한 유지. cache header 와 같은 probe·같은 artifact 를 쓰므로 별도 command 를 만들지 않는다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §15.1(`FE-GATE-019@2` — pass condition 에 security-header 포함) · §2.1.1(revision 2, Owner = 본 branch) · §14.3(`pnpm verify:hosting-headers` 행) | `project-decision` | directive 값은 hosting/backend header owner 소유라 실제 응답 대조는 provider 확정 후에만 가능; 정책 공급자(browser-security)의 정책 집합이 바뀌면 본 gate fixture 재도출 필요 |
## 구현 가이드
> 모든 경로는 `planned` — frontend repository 미생성. 경로는 hub §4.6 Planned directory blueprint + §5.1 registry owner map에서 도출(grounded)하되 코드가 없으므로 전체 `planned`.
### 1. Release token registry + typed compatibility comparator
> **Trace**: D5 — [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.9(FE-REG-RELEASE schema) · §12.3(compatibility tuple, no-lexical-compare) · §5.1(owner map: `src/contracts/release-tokens.js`). Registry content owner = 본 브랜치.
>
> - **UNSUPPORTED_IMPL_DECISION**: comparator 함수 이름/시그니처와 version 파싱 규칙(semver vs 명시적 정수 필드)은 hub가 원칙(“lexical 금지”)만 주고 detail은 미권고 → 임의 선택. trade-off: 명시적 정수 필드 비교는 구현이 단순하나 organization version 규약이 semver를 강제하면 재작성 필요.
- **Planned path**: `src/contracts/release-tokens.js` (§5.1).
- **Tokens**: 8-token release tuple 의 **정의(토큰명 · Source · Compatibility role)는 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.9 소유**이며 여기에 옮겨 적지 않는다. 본 § 이 쓰는 불변식만: `builtAt` 은 진단용이고 **cache identity 가 아니다**.
- **Comparison contract (§12.3)**: `config schema major incompatible → boot fail`; `API contract incompatible → route mount fail 또는 supported compatibility adapter`; `asset manifest mismatch → controlled reload once`; `releaseId mismatch but all versions compatible → warning telemetry 후 continue`. 판정은 구조적 비교로만 — **string lexical compare 금지**.
### 2. Per-surface hosting header contract (cache + security)
> **Trace**: D1 — [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D020 · §12.2(cache policy 표) · §6.1(runtime public=no-store). 정책만 소유, header 문자열은 provider adapter로 위임.
>
> - **UNSUPPORTED_IMPL_DECISION**: 정확한 `Cache-Control` directive 문자열(예: `max-age` 초, `immutable`, `no-store`)과 hosting 설정 문법은 미권고 → provider 확정 후 확정. trade-off: 지금 숫자를 고정하면 provider 제약과 충돌 위험.
| Surface | Default cache policy | Reason (§12.2) |
|---|---|---|
| hashed JS/CSS/font/image | long-lived immutable | content hash identity |
| `index.html` | `no-cache` / revalidate | active entry point 교체 |
| `/config.json` (runtime config) | `no-store` 또는 URL explicit version | deploy-specific public config |
| `release-manifest.json` | `no-store` 또는 immediate revalidate | mismatch detection |
| source map | public hosting off; secured artifact store | stack/source exposure boundary |
| service worker | off (D3/FE-D019) | stale release 복잡도 |
- **Verification (§14.3)**: `pnpm verify:hosting-headers``artifacts/release/hosting-headers.json`; assertion = HTML/config/manifest/hashed-asset 응답의 header 가 선언 policy 와 일치(`FE-GATE-019@2`). **cache header 뿐 아니라 security header(CSP/HSTS/frame/referrer)도 같은 probe 로 대조**한다 — 정책 내용은 [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] 가 공급.
### 3. Immutable release directory + atomic active-pointer deploy
> **Trace**: D2 — [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-D023 · §12.1(artifact set) · §12.4(atomic deploy order).
>
> - **UNSUPPORTED_IMPL_DECISION**: release directory naming 규약(예: `releases/<releaseId>/`)은 hub가 명시하지 않음 → 임의. trade-off: `releaseId` 기반 디렉토리는 rollback target 매핑이 단순하나 provider 경로 제약과 충돌 가능. provider-specific atomic switch/purge command는 **OUT_OF_BRANCH_SCOPE** → §범위 참조([[raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract]] `FE-OC-018` build output, hosting owner).
- **Artifact set (§12.1)**: `dist/index.html`, `dist/assets/<content-hash>.*`, `dist/config.json`, `dist/release-manifest.json`, `dist/config/runtime-config.schema.json`, `artifacts/release/build-manifest.json`, `artifacts/release/dependency-inventory.*`, `artifacts/release/checksums.txt`.
- **Atomic deploy order (§12.4)**: (1) immutable asset upload → (2) release manifest upload → (3) runtime config upload → (4) asset reachability smoke → (5) active HTML pointer switch → (6) post-switch boot/e2e smoke. provider가 이 순서를 지원하지 않으면 등가 atomic primitive + rollback semantics를 decision row에 기록.
### 4. Rollback coherent-set invariant + drill evidence
> **Trace**: D4 — [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-OC-017 · §12.5(rollback invariant) · §16.5(FE-RB-005 procedure invariant). Runbook *서술 문서*와 drill orchestration은 [[raw/branch-notes/feature-frontend-operational-runbook-contract]] `FE-OC-025` 소유 — 본 브랜치는 invariant + evidence 요건 제공 + 기술 escalation 대상(§16.5).
>
> - **UNSUPPORTED_IMPL_DECISION**: reachability probe의 구체 구현(요청 방식·판정 임계)은 provider 미확정으로 임의 → trade-off: probe를 origin에만 하면 edge 불일치를 놓칠 수 있어 old/new 양쪽 URL 실측 필요.
- **Coherent rollback set (§12.5)**: prior HTML + prior asset manifest·assets + compatible runtime config + compatible API contract(또는 backend compatibility window) + release manifest를 **함께** 되돌린다. HTML만 과거로, runtime config는 최신 유지하는 rollback은 **금지**.
- **Procedure invariant (§16.5)**: target release tuple 선택 → prior assets reachability 확인 → prior runtime config compatibility 확인 → active pointer atomic switch → provider cache action → boot+route+API critical smoke → telemetry/reload-loop 확인 → rollback record 저장.
- **Recovery 판정**: cache purge *완료*가 아니라 old/new reachability probe 결과로 판정(§12.5).
- **Evidence**: `artifacts/runbooks/FE-RB-005/<release-id>/record.json`; drill = `pnpm drill:runbook -- FE-RB-005`(`FE-GATE-016` rollback drill / `FE-GATE-025` FE-RB-005 drill).
### 5. Release coherence gate + mixed-version negative fixture
> **Trace**: D1·D4 — [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-OC-016 · FE-OC-017 · §8.2(DEPLOY_MISMATCH / RELEASE_MANIFEST_FAILURE) · §15.2(negative fixture “HTML build A + asset manifest B”). config-schema *검증 로직*은 [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] `FE-OC-004`(boot sequence §6.3) 소유 — 본 브랜치는 release/asset coherence 판정만.
>
> - **UNSUPPORTED_IMPL_DECISION**: fixture를 구성하는 구체 mock 파일 세트·verify 스크립트 내부 알고리즘은 repository 확정 전 미권고 → 임의. trade-off: 최소 fixture(HTML A + manifest B)만으로 시작하면 config mismatch 조합은 별도 fixture 필요.
| Fixture | 기대 정규화 결과 (§8.2) |
|---|---|
| HTML(build A) + asset manifest(build B) | `DEPLOY_MISMATCH` — request retry 없이 controlled reload once 또는 rollback |
| release manifest fetch/parse/schema 실패 | `RELEASE_MANIFEST_FAILURE` — boot 시 bounded refetch 1회, update/support shell |
| chunk fetch 실패(release check 후) | `CHUNK_LOAD_FAILURE` — release check 후 controlled reload 1회만 |
- **Verification (§14.3)**: `pnpm verify:release``artifacts/release/verification.json`(compatibility tuple coherent); `FE-GATE-015` release coherence = mixed set은 mismatch detected, coherent set은 pass.
- **schema = `ART-FE-003@1`** (hub §2.1.3 · `harness/source/artifact-schemas/ca-skeleton-frontend/release-verification.schema.json`). 위 `verification.json` 의 **Schema Owner 는 본 branch 단독**이며, 필드 추가·rename 은 스키마 파일을 고쳐 revision 을 올리는 것으로 한다. 소비 branch([[raw/branch-notes/feature-frontend-contract-compatibility-governance]])는 본문에 스키마를 옮겨 적지 않고 `imports``ART-FE-003@1` 로 pin 하므로, revision 이 오르면 낡은 pin 이 자동으로 잡힌다. 필드 명명은 hub §2.1.3 의 camelCase 규약을 따른다.
## 엣지·실패·의존
- **실패·엣지 경로** (§8.2 / §16.2):
- `DEPLOY_MISMATCH` (HTML/asset/config release mismatch): request retry 금지, controlled reload once 또는 rollback, telemetry = mismatch kind + IDs(raw 금지).
- `RELEASE_MANIFEST_FAILURE` (manifest fetch/parse/schema 실패): boot 시 bounded refetch 1회만; 실패 시 reload하지 말고 update/support shell로 격리(§16.2 immediate containment 3).
- `CHUNK_LOAD_FAILURE`: release manifest를 `no-store`로 1회 조회해 active release mismatch가 *확인된 경우에만* reload guard 기록 후 1회 reload; asset set incomplete면 prior coherent release로 rollback(§16.2 mitigation).
- CDN propagation 불일치(origin 정상, edge stale): active switch를 되돌리고 reachability probe 재실행 후 hosting/CDN owner로 escalation(§16.2).
- **다른 계약 의존**:
- [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] `FE-OC-004` — runtime config publish + boot config validation(§6.3/§6.4)을 consume. config schema 계약이 바뀌면 compatibility tuple 판정과 coherent-set 정의에 영향.
- [[raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract]] `FE-OC-018` — asset content-hash·`build-manifest.json`·`assetManifestHash`를 생성; 이것이 release coherence 입력. hashing 규칙이 바뀌면 asset immutability·mismatch 탐지 영향.
- [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] `FE-OC-023` — additive/breaking/migration 규칙을 정의; rollback의 “compatible config/API” 판정이 이 규칙에 의존.
- [[raw/branch-notes/feature-frontend-operational-runbook-contract]] `FE-OC-025` — FE-RB-002/FE-RB-005 runbook 서술과 drill orchestration 소유; 본 브랜치는 기술 escalation 대상 + drill evidence 요건 제공(`FE-GATE-016`/`FE-GATE-022`/`FE-GATE-025`).
- [[raw/branch-notes/feature-frontend-render-recovery-boundary-contract]] `FE-OC-015``DEPLOY_MISMATCH` 사용자 recovery UI와 reload-loop 방지 소유; 본 브랜치는 normalized kind와 “reload once” 계약만 제공.
- [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] `FE-OC-019``FE-GATE-019@2` 의 security-header 축에서 **검증 대상 정책 집합(CSP/HSTS/frame/referrer)을 공급**(D6). 그 정책이 바뀌면 본 gate 의 fixture·probe 기대값 재도출.
- [[raw/branch-notes/feature-frontend-contract-registry-governance]] `FE-OC-022` — 8-registry single-owner/snapshot governance; `FE-REG-RELEASE`는 그 governance 하에 관리되는 registry.
## 검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| rollback이 coherent prior release(HTML+assets+config+API+manifest)를 복구한다 | deploy artifact·drill evidence 없음 | mixed-version fixture + `pnpm drill:runbook -- FE-RB-005`(`FE-GATE-016`), recovery = old/new reachability probe pass | `needs-confirmation` |
| 실제 hosting header가 선언 cache policy와 일치한다 | header 문자열·provider 미확정 | `pnpm verify:hosting-headers`(`FE-GATE-019@2`) → `hosting-headers.json` 대조 | `needs-confirmation` |
| 실제 hosting 응답의 security header(CSP/HSTS/frame/referrer)가 선언 정책과 일치한다 | 정책 내용은 browser-security 공급분이고 provider 미확정 | 같은 `pnpm verify:hosting-headers` probe 에 security header 축 편입(`FE-GATE-019@2`) | `needs-confirmation` |
| mixed HTML/asset/config가 `DEPLOY_MISMATCH`로 탐지되고 coherent set은 pass한다 | verify 스크립트·fixture 미구현 | `pnpm verify:release`(`FE-GATE-015`) mixed vs coherent fixture | `needs-confirmation` |
| compatibility comparison이 string lexical compare를 쓰지 않는다 | comparator 미구현 | comparator unit test에 lexical-trap fixture(예: `"10"` vs `"9"`) 투입 → 정확 판정 확인 | `planned` |
| atomic active-pointer 전환 중 HTML과 asset이 서로 다른 release인 window가 없다 | atomic primitive 미확정 | 배포 시뮬레이션 중 boot e2e + reachability probe | `needs-confirmation` |
| service worker가 실제로 등록되지 않는다(D3) | 코드 없음 | production build 산출물 scan + e2e에서 SW registration 부재 확인 | `planned` |
## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
- 스캐폴딩 단계: `/coverage` 실행 전 수동 행을 만들지 않는다.
## 마주친 문제
- 없음 — 스캐폴딩 단계.
## 묶음 (이 branch에서 파생된 자료)
<!-- GENERATED: received-delegations:start -->
### 수신한 위임
| Delegation Ref | From | Concern | Status |
|---|---|---|---|
| `DELEG-FE-011@1` | [[raw/branch-notes/feature-frontend-background-execution-worker-contract]] | `fe.deleg.sw-release-coherence` | accepted |
<!-- GENERATED: received-delegations:end -->
<!-- GENERATED: project-contract-imports:start -->
## 가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
| `FE-OC-019@1` | [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] | browser bundle에 secret을 넣지 않고 untrusted HTML injection을 기본 금지 | import 참조로 적용 |
<!-- GENERATED: project-contract-imports:end -->
<!-- GENERATED: artifact-imports:start -->
### 가져온 artifact 계약
| Artifact Ref | Owner | Producer | Schema Ref |
|---|---|---|---|
| `ART-FE-001@1` | [[raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract]] | [[raw/branch-notes/feature-frontend-project-bootstrap-toolchain-contract]] | `harness/source/artifact-schemas/ca-skeleton-frontend/build-manifest.schema.json` |
<!-- GENERATED: artifact-imports:end -->
- 없음 — 자식 자료는 생성 후 controller가 parent Cluster와 함께 등록한다.
## 관련 일일 노트
- 없음 — daily note는 이 작업에서 수정하지 않는다.
## 완료 후 정리
- PR 링크: 없음
- 리뷰 메모: 없음
- 머지 결과 / 배포 환경: `planned`
- **wiki 추출 대상** (verified만): 없음
- **추출하지 않을 항목** (planned / documented-only / abandoned): 현재 전체