Files
llm-wiki/raw/branch-notes/feature-frontend-operational-runbook-contract.md
T

269 lines
28 KiB
Markdown

---
title: branch / feature-frontend-operational-runbook-contract
source_type: branch-note
status: raw
id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-026
kind: project-work-item
project: ca-skeleton-frontend-operational-contract
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-026
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-DEPLOYMENT-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1]
refines: []
overrides: []
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-024, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-005, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-012, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-004]
contract_packet: 1
branch: feature-frontend-operational-runbook-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, runtime, observability, externalized-config]
created: 2026-07-18
target_merge:
status_label: in-progress
contract_packet_sha256: f1bc0e83f35bfe8d37d36486dffefddcbdd308cb9b5820c5945b54a3ba163e8e
imports: [FE-GATE-014@1, FE-GATE-015@1, FE-OC-001@1, FE-OC-004@1, FE-OC-006@1, FE-OC-009@1, FE-OC-014@1, FE-OC-016@1, FE-OC-017@1, FE-OC-023@1, FE-OC-026@1]
---
# branch: feature-frontend-operational-runbook-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`
- **완료 조건**: 5개 drill의 trigger·window·escalation·evidence assertion이 검증된다
<!-- 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로 배포한다 | release mismatch와 rollback runbook의 trigger·recovery assertion에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1` | telemetry는 best-effort queue와 redaction을 사용하며 sink failure가 UI를 실패시키지 않는다 | telemetry sink failure runbook의 containment와 evidence에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
<!-- section-id: branch-local-decisions -->
### 브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | 다섯 operational runbook을 4-assertion 계약으로 관리한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D2 | window와 rate를 planned conditional-default로 라벨한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D3 | deterministic drill과 record evidence로 runbook을 검증한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D4 | escalation을 technical owner에서 platform·approver로 이어지는 고정 chain으로 둔다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D5 | recovery는 action 수행이 아니라 assertion evidence로 판정한다 | `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 -->
## 목표
이 브랜치는 project-wide 계약 `FE-OC-025`("boot, chunk mismatch, API degradation, telemetry failure, rollback runbook을 MUST 유지, evidence = drill records")를 *구현 착수 가능한 runbook 계약*으로 내린다. hub [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §16이 정의한 다섯 runbook(`FE-RB-001`~`FE-RB-005`)을 각각 **trigger 집합 / immediate containment + window / escalation chain / recovery-evidence assertion**의 4-계약으로 고정하고, 이를 `FE-GATE-021`~`FE-GATE-025`(production-promotion drill gate)로 매핑한다. 동시에 boot config(`FE-OC-004`), API degradation(`FE-OC-006`), telemetry sink(`FE-OC-014`), release cache/rollback(`FE-OC-016`·`FE-OC-017`)의 acceptance drill을 *기여*한다. 이 브랜치는 runbook 계약과 drill 증거 스키마만 소유하며, 각 runbook이 소비하는 하부 메커니즘(config load, retry, telemetry queue, release pointer)은 owner 브랜치에 위임한다. 원천 상태가 전부 `planned`(코드 없음, hub §16이 유일 SSOT)이므로 모든 항목 등급은 `planned`.
- 이슈: 없음 (스캐폴딩 단계)
- PR: 없음
<!-- section-id: branch-scope -->
## 범위
### 포함 범위
- `FE-OC-025` 소유 항목: 다섯 runbook 계약(`FE-RB-001` boot config / `FE-RB-002` chunk·release-manifest·deploy mismatch / `FE-RB-003` backend API degradation / `FE-RB-004` telemetry sink failure / `FE-RB-005` release rollback)의 trigger·containment+window·escalation·recovery-evidence assertion 고정.
- drill harness 계약(`pnpm drill:runbook -- FE-RB-00X``artifacts/runbooks/FE-RB-00X/<release-id>/record.json`)과 `FE-GATE-021`~`FE-GATE-025` 매핑 + 각 drill의 negative fixture 요구.
- window/rate 값을 `planned conditional-default`(measured SLO 아님)로 라벨하고 재검토 트리거를 명세.
- escalation 2-hop chain(technical owner 브랜치 → platform/approver)의 routing 계약.
### 제외 범위
> 의도적으로 제외. 다른 owner 브랜치 소유이거나 hosting 확정 이후 항목.
- boot config load + runtime config schema/validation 메커니즘 → [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] 소유 (`FE-OC-004`).
- retry/timeout/idempotency·degradation triage 메커니즘 → [[raw/branch-notes/feature-api-client-response-envelope-contract]] 소유 (`FE-OC-006` · `FE-OC-009`).
- telemetry queue/redaction/sink adapter 메커니즘 → [[raw/branch-notes/feature-frontend-observability-logging-trace-contract]] 소유 (`FE-OC-014`).
- release tuple/cache header/atomic pointer/rollback 메커니즘 → [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 소유 (`FE-OC-016` · `FE-OC-017`).
- drill gate를 CI 파이프라인 blocking stage로 wiring → [[raw/branch-notes/feature-frontend-ci-quality-gates-contract]] 소유 (orchestration 담당이며 `FE-OC-*` owner 는 아니다).
- provider-specific console command과 실제 incident response 수행 → hosting 확정(`FE-Q-003`) 이후 release 브랜치가 채움.
## 근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
| [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | primary SSOT. §16 다섯 runbook 정의, §14.3 drill 명령/artifact, §15 gate matrix(`FE-GATE-021`~`025`)+negative fixture, §12.5 rollback invariant, §8.2 failure taxonomy — D1~D5 전부의 project-decision 근거. |
| [[raw/official-docs/vite-build-tool-official]] | `VITE-C2`(production build가 content-hash 정적 자산을 산출) — chunk/deploy mismatch(`FE-RB-002`)가 *실재 operational failure class*라는 근거(D1). |
| [[raw/official-docs/prometheus-alertmanager-silences]] | operational recovery를 "action 수행"이 아니라 시간제한 window + suppression/evidence 규율로 판정하는 cross-domain 공식 precedent — drill window + recovery-evidence 계약(D3)의 참고 근거. frontend 계약 값 자체는 아님. |
## TODO
- [ ] 다섯 runbook의 4-assertion 계약(trigger / containment+window / escalation / recovery-evidence)을 표로 고정 — 등급: `planned`
- [ ] drill harness 계약(`pnpm drill:runbook -- FE-RB-00X``record.json`) + record 스키마 초안 정의 — 등급: `planned`
- [ ] `FE-GATE-021`~`FE-GATE-025` 매핑 + 각 runbook의 negative fixture(고의 실패 drill) 정의 — 등급: `planned`
- [ ] window/rate 값 `planned conditional-default` 라벨 + 재검토 트리거(첫 drill + baseline) 명세 — 등급: `planned`
- [ ] escalation 2-hop chain을 owner 브랜치 위임 링크로 고정 — 등급: `planned`
## 진행 중 메모
- Ground truth: frontend 코드/repo 없음. 다섯 runbook의 trigger·window·assertion은 전부 hub §16의 `planned conditional-default`이며 measured SLO가 아니다. 이 브랜치는 hub §16을 재진술이 아니라 *drill-backed 계약 + gate 매핑*으로 내린다.
- window 값(5분 triage, rolling 5분 rate window, 10/15분 등)은 첫 drill 결과 + hosting/backend baseline이 생길 때까지 owner가 유지·변경. 외부 답변에서 이 값을 달성 SLO처럼 말하면 §22 answer-boundary 위반.
## 결정 사항
> 각 결정의 근거는 Sources 또는 hub §-ref. 대안과 함께 기록.
- 2026-07-19: hub §16이 정의한 다섯 runbook을 `FE-OC-025` 소유 집합으로 채택하고 각각 4-assertion(trigger/containment+window/escalation/recovery-evidence)으로 고정 / 이유: `FE-OC-025`의 minimum evidence가 drill records이므로 runbook을 검증 가능한 계약으로 내려야 함 / 검토한 대안: HTTP status별 개별 runbook 세분화 / 근거: hub §16 · §8.2 · `VITE-C2`.
- 2026-07-19: 모든 window/rate 값을 `planned conditional-default`(measured SLO 아님)로 라벨 / 이유: implementation/telemetry evidence 없음(hub §16 서두 명시) / 검토한 대안: 초기 값을 target SLO로 선언 / 근거: hub §16 서두 · `FE-OC-001`·`FE-OC-026`.
- 2026-07-19: runbook 검증은 결정론적 drill harness(`pnpm drill:runbook`) + evidence record + `FE-GATE-021`~`025` + runbook별 negative fixture로 수행 / 이유: rule 존재만으론 `locally-verified` 부족(§15.2) / 검토한 대안: 수동 체크리스트 review / 근거: hub §14.3 · §15.
- 2026-07-19: escalation은 runbook별 고정 2-hop chain이며, 하부 메커니즘은 owner 브랜치에 위임(R3) / 이유: runbook 브랜치는 routing+evidence 계약만 소유 / 검토한 대안: 메커니즘까지 runbook에 재명세 / 근거: hub §16 escalation rows · §20 dependency · §4.3.
- 2026-07-19: recovery는 assertion evidence(reachability probe/e2e/self-check)로만 판정하며 "mitigation action 수행"으로 판정하지 않음 / 이유: cache purge 완료≠recovery(hub §12.5) / 검토한 대안: provider action 완료를 recovery로 간주 / 근거: hub §12.5 · §16 recovery assertions.
## 결정-근거 매핑
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | 다섯 runbook(`FE-RB-001`~`005`)을 `FE-OC-025` 소유 집합으로 채택, 각각 trigger/containment+window/escalation/recovery-evidence 4-assertion으로 고정 | §8.2 failure taxonomy의 *operational(비-request) failure class*가 이 다섯에 매핑되는 한 이 집합 유지 / §8.2에 어느 runbook에도 안 담기는 owner-blocking operational class가 새로 생기면 runbook 추가·분할. HTTP status별 개별 runbook은 만들지 않음(request-level은 §8.2 failure matrix가 처리) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-OC-025 · FE-D019 · FE-D020 · FE-D023 · §16 · §8; [[raw/official-docs/vite-build-tool-official]] VITE-C2 | `project-decision` + `official-doc` (VITE-C2) | §8.2에 다섯이 못 덮는 operational class가 나타날 수 있음 — 집합 완전성은 현재 taxonomy 기준으로만 주장됨 |
| D2 | 모든 window/rate 값을 `planned conditional-default`로 라벨(measured SLO 아님), 첫 drill 결과 + hosting/backend baseline 전까지 유지 | baseline·첫 drill 이전엔 documented window(default) 유지 / (a) 해당 runbook 첫 drill의 timing evidence 와 (b) hosting/backend baseline SLO 가 둘 다 생기면 owner가 measured target으로 교체. 그 전까지 이 값을 달성 SLO로 인용하면 answer-boundary 위반 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §16(서두: window=planned conditional default, measured SLO 아님) · FE-OC-001 · FE-OC-026 | `conditional-default` | window가 첫 drill에서 달성 불가로 판명될 수 있고, downstream 문서가 이를 SLO로 오인 인용할 위험 |
| D3 | 검증은 결정론적 drill harness(`pnpm drill:runbook -- FE-RB-00X`) + `record.json` evidence + `FE-GATE-021`~`025` + runbook별 negative fixture | drill record + negative fixture(깨진 경로에서 실제 실패 증명)가 둘 다 있을 때만 runbook을 operational로 주장 / repo/harness 없으면 runbook은 `documented-only`(drill=`PLANNED_NOT_EXECUTED`, §14.3) | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §14 · §15(FE-GATE-021~025 · negative fixture) · FE-OC-025; [[raw/official-docs/prometheus-alertmanager-silences]] (recovery-evidence 규율 precedent) | `project-decision` + `official-doc` precedent | `record.json` 필드 스키마를 hub가 정의하지 않음(§구현 가이드 2의 UNSUPPORTED_IMPL_DECISION) |
| D4 | escalation은 runbook별 고정 2-hop chain(technical owner 브랜치 → platform/approver), 하부 메커니즘은 owner 브랜치 위임(R3) | 이 브랜치는 escalation routing + evidence assertion만 명세 / 메커니즘 detail(retry cap·config schema·cache header·atomic pointer)은 owner 브랜치 FE-OC 계약으로 위임하고 여기서 재명세 금지. 기존 owner 브랜치가 제공 못하는 escalation hop이 필요할 때만 재검토 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §16(escalation rows) · §20(dependency) · §4 · FE-OC-025 | `project-decision` | rollback 결정 주체(config owner↔release owner) hand-off가 모호하면 runbook이 단절될 수 있음(FE-RISK-002) — §16이 hand-off를 고정하나 drill 전까지 미검증 |
| D5 | recovery는 assertion evidence(clean boot·asset 2xx·reachability probe·critical e2e·telemetry self-check·forbidden-attribute scan)로만 판정, "action 수행"으로 판정 금지; provider console command은 hosting 확정까지 유보 | 항상 evidence 기반 / cache purge 필요한 provider는 purge 완료가 아니라 실제 old/new reachability probe 결과로 recovery 판정(§12.5). provider console command은 hosting 확정(FE-Q-003) 후 release 브랜치가 채움 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §12 · §16(recovery assertions · "provider console command 발명 안 함") · FE-OC-017 | `project-decision` | `FE-RB-005`의 provider-dependent recovery target은 hosting 확정 전 `TBD`(FE-Q-003) |
## 구현 가이드
> `planned` blueprint. 코드 없음 — 경로/명령은 hub §14.3 blueprint(`pnpm drill:runbook`, `artifacts/runbooks/...`)에서 유래하므로 근거가 있으나 전체 섹션은 `planned`.
### 1. 다섯 runbook의 4-assertion 계약
> **Trace**: D1 · D2 · D5 · [[raw/project-notes/ca-skeleton-frontend-operational-contract]] FE-OC-025 · §16 · §8
>
> - **UNSUPPORTED_IMPL_DECISION**: 없음. 아래 trigger·window·assertion·escalation 값은 전부 hub §16에서 그대로 내려받았고, 임의 발명 값이 없다. window는 §16이 명시한 `planned conditional-default`이므로 measured SLO로 표기하지 않는다(D2).
| Runbook | Trigger(정규화 kind) | Immediate containment + window(planned-default) | Escalation 1-hop | Recovery-evidence assertion | Drill gate |
|---|---|---|---|---|---|
| `FE-RB-001` boot config | `BOOT_CONFIG_FAILURE`(config non-2xx/parse/schema, refetch 1회도 실패) | product route mount 중단 + safe support shell, auto refetch ≤1회; owner triage 목표 5분 | env-config owner → release owner | clean session boot 성공 · product root mount · config validation artifact pass · 반복 boot error telemetry 없음 | `FE-GATE-021` |
| `FE-RB-002` chunk/manifest/deploy mismatch | `CHUNK_LOAD_FAILURE` · `RELEASE_MANIFEST_FAILURE` · `DEPLOY_MISMATCH`(asset 404/integrity, manifest active≠loaded) | dirty-state 경고 후 manifest `no-store` 1회 조회; mismatch면 reload guard 기록 후 reload 1회만; release owner triage 5분 | release-cache owner → hosting/CDN owner | entry+lazy asset 2xx · manifest fetch·parse·schema+tuple coherence pass · 2차 auto reload 없음 · release coherence gate pass · route e2e pass | `FE-GATE-022` |
| `FE-RB-003` API degradation | terminal network/timeout/5xx rate > threshold(rolling 5분) 또는 `SCHEMA_MISMATCH` 1건 | retry cap runtime 확대 금지 · safe cache는 stale-degraded 제공 · mutation은 idempotency 없이 retry 금지 · schema mismatch는 retry 금지; 최초 분류 10분 | api-client owner → backend operation owner → release compatibility owner | terminal failure rate가 baseline window로 복귀 · retry amplification 없음 · critical read/write e2e pass · schema fixtures pass | `FE-GATE-023` |
| `FE-RB-004` telemetry sink | `TELEMETRY_FAILURE`(sink non-2xx/network, queue overflow, adapter init 실패) | product flow 유지 · bounded queue 초과 적재 금지 · 동일 sink 재귀 보고 금지 · console fallback은 safe field 한정; platform triage 15분 | observability owner → telemetry platform owner | product e2e 영향 없음 · delivery self-check 성공 · queue가 planned bound 내 drain · forbidden-attribute scan pass | `FE-GATE-024` |
| `FE-RB-005` release rollback | release-blocking boot/chunk/render/API/security defect이고 forward fix가 incident window 내 안전 미증명 | prior immutable release로 target tuple 선택 → asset·config·API compat 확인 → active pointer atomic switch → smoke; provider recovery target은 hosting 전 `TBD` | release-cache owner → release approver/hosting owner | `FE-GATE-014`·`FE-GATE-015` pass · critical e2e pass · 반복 `DEPLOY_MISMATCH` 없음 · incident timeline에 release ID 기록 | `FE-GATE-025` |
### 2. Drill harness + evidence record
> **Trace**: D3 · [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §14 · §15 · FE-OC-025
>
> - **UNSUPPORTED_IMPL_DECISION**: `record.json` 필드 스키마 — hub §14.3은 artifact *경로*(`artifacts/runbooks/FE-RB-00X/<release-id>/record.json`)만 고정하고 JSON 필드는 정의하지 않음. 아래 필드 집합은 이 브랜치의 임의 제안(trade-off: assertion 결과를 기계 판정 가능하게 최소 필드만 고정 — 확장은 owner drill 구현 시). 실제 필드명은 harness 구현 시 확정.
- 명령: `pnpm drill:runbook -- FE-RB-00X` (hub §14.3, 상태 `PLANNED_NOT_EXECUTED`).
- 산출물: `artifacts/runbooks/FE-RB-00X/<release-id>/record.json` (hub §14.3).
- 제안 record 필드(planned, UNSUPPORTED_IMPL): `runbookId`, `releaseId`, `drillTimestamp`, `triggerInjected`(주입한 정규화 kind), `containmentAsserted`(bool), `escalationPathAsserted`(2-hop 도달 여부), `recoveryAssertions`(assertion→pass/fail 목록), `negativeFixtureFailedAsExpected`(bool), `windowObservedBucket`(planned-default 비교용 bucket, SLO 아님).
- Negative fixture(runbook별 고의 실패 drill, §15.2 규율):
| Runbook | Negative fixture(반드시 실패해야 함) | 근거 |
|---|---|---|
| `FE-RB-001` | 유효 config인데 boot을 mount 실패로 처리 → recovery assertion이 fail 나야 정상 | §15.2 runtime schema/reload 계열 |
| `FE-RB-002` | 동일 release pair에서 2차 chunk 실패 → reload guard가 반복 reload를 막아야(§15.2 reload guard) | §15.2 reload guard |
| `FE-RB-003` | idempotency key 없는 POST가 503 수신 → 자동 retry 하면 fail | §15.2 retry |
| `FE-RB-004` | telemetry event에 raw URL/query 포함 → forbidden-attribute scan이 fail 나야 | §15.2 telemetry |
| `FE-RB-005` | HTML build A + asset manifest B(mixed) → release coherence가 mismatch 검출해야 | §15.2 release |
### 3. Escalation & delegation map (R3 경계)
> **Trace**: D4 · [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §16 · §20 · §4
>
> - **UNSUPPORTED_IMPL_DECISION**: 없음. 각 hop의 owner 브랜치와 계약 ID는 hub §16 escalation row + §20 dependency에서 그대로 내려받음. 하부 메커니즘은 아래 owner 브랜치로 위임하며 여기서 재명세하지 않음.
| Runbook | Technical owner (mechanism 위임) | Platform / approver hop |
|---|---|---|
| `FE-RB-001` | [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] (`FE-OC-004`) | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] (`FE-OC-016` · `FE-OC-017`) |
| `FE-RB-002` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] (`FE-OC-016` · `FE-OC-017`) | hosting/CDN owner (외부, hosting 확정 후) |
| `FE-RB-003` | [[raw/branch-notes/feature-api-client-response-envelope-contract]] (`FE-OC-006` · `FE-OC-009`) | backend operation owner → release compatibility (외부/`FE-OC-023`) |
| `FE-RB-004` | [[raw/branch-notes/feature-frontend-observability-logging-trace-contract]] (`FE-OC-014`) | telemetry platform owner (외부) |
| `FE-RB-005` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] (`FE-OC-016` · `FE-OC-017`) | release approver / hosting owner (외부) |
### 4. Window/rate governance
> **Trace**: D2 · [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §16 · FE-OC-001 · FE-OC-026
>
> - **UNSUPPORTED_IMPL_DECISION**: 없음. window 값은 §16이 명시한 conditional-default를 그대로 인용. 새 값을 발명하지 않음.
- 라벨 규칙: 모든 window/rate(`FE-RB-001` 5분, `FE-RB-002` 5분, `FE-RB-003` rolling 5분 rate + 10분 분류, `FE-RB-004` 15분, `FE-RB-005` provider-dependent `TBD`)는 `planned conditional-default`로만 표기.
- 재검토 트리거: 해당 runbook 첫 drill의 `windowObservedBucket` + hosting/backend baseline SLO 존재 → owner가 measured target으로 승격.
- 금지: 이 값을 measured SLO/달성 지표로 외부 답변에 사용(§22 answer boundary). 위반 시 `/lint` answer-boundary 검사 대상.
## 엣지·실패·의존
- **실패·엣지 경로** (runbook 계약 자체의 meta-failure):
- drill이 negative fixture 없이 "pass" → 거짓 보증. 기대 동작: 각 gate는 고의 실패 drill을 포함해야 통과 인정(§15.2).
- window 값을 measured SLO로 외부 인용 → answer-boundary 위반. 기대 동작: `planned conditional-default` 라벨 강제(D2).
- recovery를 "action 수행"(purge 발행/pointer switch)으로 판정 → 거짓 recovery. 기대 동작: reachability probe/e2e evidence로만 판정(§12.5, D5).
- rollback 결정 hand-off 모호(config owner ↔ release owner) → runbook 단절(FE-RISK-002). 기대 동작: config owner가 원인 분류 실패 시 release owner에게 rollback 결정 이관(§16.1).
- `FE-RB-004` drill 중 telemetry 실패를 동일 sink로 재귀 보고 → amplification. 기대 동작: 재귀 금지 + console-safe fallback(§11.2).
- `FE-RB-002` reload가 user input 손실(FE-RISK-009). 기대 동작: dirty-state guard + one-reload cap.
- **다른 계약 의존** (owner 브랜치 위임, `FE-OC` 계약 consume):
- [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] (`FE-OC-016` · `FE-OC-017`) — release tuple/cache header/atomic pointer/rollback; `FE-RB-002`·`FE-RB-005`가 consume. 이 계약 변경 시 chunk/rollback runbook assertion 재검토.
- [[raw/branch-notes/feature-api-client-response-envelope-contract]] (`FE-OC-006` · `FE-OC-009`) — degradation triage/retry cap; `FE-RB-003`이 consume.
- [[raw/branch-notes/feature-frontend-observability-logging-trace-contract]] (`FE-OC-014`) — telemetry queue/redaction/sink; `FE-RB-004`가 consume.
- [[raw/branch-notes/feature-frontend-env-runtime-config-contract]] (`FE-OC-004`) — boot config validation; `FE-RB-001`이 consume.
- [[raw/branch-notes/feature-frontend-ci-quality-gates-contract]] — `FE-GATE-021`~`025`를 파이프라인 blocking stage로 wiring; 이 브랜치의 drill 계약에 의존. (`FE-OC-020` owner 는 [[raw/branch-notes/feature-frontend-test-taxonomy-contract]] 이고 ci-quality-gates 는 `FE-OC-*` owner 가 아니다.)
## 검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| 다섯 runbook 각각이 trigger→containment→escalation→recovery를 drill evidence로 닫는다 | repo/harness 없음 | `pnpm drill:runbook -- FE-RB-00X``record.json` 생성 + `FE-GATE-021`~`025` pass(negative fixture 동반) | `needs-confirmation` |
| window/rate default가 달성 가능하고 SLO 아님으로 정직히 라벨된다 | baseline/첫 drill 없음 | 첫 drill `windowObservedBucket` vs hosting/backend baseline 비교 + answer-boundary scan | `needs-confirmation` |
| recovery가 action이 아니라 evidence로 판정된다 | 설계 assertion | drill이 reachability/e2e/self-check를 assert하고 "action 발행"을 assert하지 않음 확인 | `planned` |
| escalation hand-off(config→release rollback 결정)가 단절되지 않는다 | hand-off 미검증 | `FE-RB-001``FE-RB-005` chained drill이 hand-off 경로를 exercise | `needs-confirmation` |
| chunk-mismatch runbook이 reload 시 user input을 잃지 않는다 | reload semantics | `FE-RB-002` e2e에 dirty-state + one-reload guard fixture | `needs-confirmation` |
## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
- 스캐폴딩 단계: `/coverage` 실행 전 수동 행을 만들지 않는다.
## 마주친 문제
- 없음 — 스캐폴딩 단계.
## 묶음 (이 branch에서 파생된 자료)
<!-- GENERATED: project-contract-imports:start -->
## 가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
| `FE-GATE-014@1` | [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] | 지원 대상 config 버전이 boot 에 실패하면 release 를 MUST 차단 | import 참조로 적용 |
| `FE-GATE-015@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | 혼재된 release 조합이 감지되지 않으면 release 를 MUST 차단 | import 참조로 적용 |
| `FE-OC-001@1` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | 모든 구현 주장은 evidence grade를 MUST 표시하고 repo evidence가 없는 상태에서 구현 완료를 MUST NOT 주장 | 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-006@1` | [[raw/branch-notes/feature-api-client-response-envelope-contract]] | 모든 HTTP는 shared client를 MUST 통과하고 timeout·abort·response parsing을 page에서 구현하면 안 됨 | import 참조로 적용 |
| `FE-OC-009@1` | [[raw/branch-notes/feature-api-client-response-envelope-contract]] | retry는 safe/idempotent request에 한정하고 cap·jitter·`Retry-After`를 MUST 적용 | import 참조로 적용 |
| `FE-OC-014@1` | [[raw/branch-notes/feature-frontend-observability-logging-trace-contract]] | telemetry는 best-effort이며 render·API success를 차단하면 안 되고 PII·token을 전송하면 안 됨 | 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 참조로 적용 |
| `FE-OC-023@1` | [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] | API/config/storage/release schema의 breaking change는 migration 또는 version bump 없이 배포하면 안 됨 | import 참조로 적용 |
| `FE-OC-026@1` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | 외부 답변은 evidence grade를 MUST 보존하고 목표 수치를 측정 결과처럼 말하면 안 됨 | import 참조로 적용 |
<!-- GENERATED: project-contract-imports:end -->
- 없음 — 자식 자료는 생성 후 controller가 parent Cluster와 함께 등록한다.
## 관련 일일 노트
- 없음 — daily note는 이 작업에서 수정하지 않는다.
## 완료 후 정리
- PR 링크: 없음
- 리뷰 메모: 없음
- 머지 결과 / 배포 환경: `planned`
- **wiki 추출 대상** (verified만): 없음
- **추출하지 않을 항목** (planned / documented-only / abandoned): 현재 전체