Files
llm-wiki/raw/branch-notes/feature-frontend-storage-registry-contract.md
T

296 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: branch / feature-frontend-storage-registry-contract
source_type: branch-note
status: raw
id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011
kind: project-work-item
project: ca-skeleton-frontend-operational-contract
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1]
refines: []
overrides: []
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-002]
contract_packet: 1
branch: feature-frontend-storage-registry-contract
parent_branch:
related_projects: [ca-skeleton-frontend, ca-skeleton]
governing_docs: [raw/project-notes/ca-skeleton-frontend-operational-contract.md]
tags: [branch, ca-skeleton, frontend, persistence, security, javascript]
created: 2026-07-18
target_merge:
status_label: in-progress
contract_packet_sha256: aa55f276dab66670f66f2424f059e394925f5f1c84ec23381fe506064f4823a1
imports: [FE-GATE-005@1, FE-OC-002@1, FE-OC-010@1, FE-OC-019@1, FE-OC-023@1]
---
# branch: feature-frontend-storage-registry-contract
> Layer: `raw/branch-notes/` — 단일 브랜치의 TODO·결정·진행 기록. 현재는 `/branch-spec` 로 채운 `planned` 명세 단계다 (frontend repository 미생성).
<!-- 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`
- **완료 조건**: namespace·version·classification·quota fallback test가 통과한다
<!-- 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로 관리한다 | FE-REG-STORAGE namespace·version·classification schema에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] |
<!-- section-id: branch-local-decisions -->
### 브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | storage key를 FE-REG-STORAGE와 versioned namespace로 관리한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D2 | storage item classification을 필수로 둔다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D3 | schemaVersion mismatch를 migration 또는 discard로 처리한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D4 | application-owned StoragePort와 storage adapter를 사용한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D5 | quotaFallback을 registry field로 관리한다 | `local` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | `proposed` |
| D6 | token·secret·PII·raw payload 저장을 거부한다 | `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-013` (browser storage key 는 namespace·version·classification 을 MUST 보유하고 token/secret 저장을 금지) 를, 다음 구현자가 되묻지 않고 `src/contracts/storage-keys.js``adapters/storage` 를 작성할 수 있는 implementation-ready 명세로 내린다. `FE-REG-STORAGE` 는 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-D018` 이 규정한 8개 registry 중 하나이며 본 브랜치가 single owner 다. 최소 스키마는 §5.5, 런타임 동작은 §9.4, 브라우저 보안 불변식(번들·storage = 공개물, secret 저장 금지)은 §13.2, quota/unavailable 실패 정규화는 §8.2 에 근거한다. 아직 frontend repository 가 없으므로 본 브랜치의 모든 항목은 `planned` 등급이다.
- 이슈: TODO (아직 없음)
- PR: TODO (아직 없음)
<!-- section-id: branch-scope -->
## 범위
### 포함 범위
- `FE-REG-STORAGE` registry 스키마 정의 및 single-owner 소유 (§5.5): `logicalName` / `physicalKey` (`<app>:<scope>:v<schema>:<name>`) / `backend` / `classification` / `schemaVersion` / `ttl` / `migration` / `quotaFallback` 필드 계약.
- 구조화된 physical key 규약(namespace + schema version 내장) + raw literal key 금지 강제.
- classification 3분류(`public-preference` / `opaque-cache` / `sensitive-forbidden`) + sensitive 저장 금지 불변식.
- `schemaVersion` + previous-version migration-or-discard 규약.
- 단일 application 소유 `StoragePort` + `adapters/storage` 어댑터 boundary, try/catch 로 unavailable / security / quota 구분.
- quota fallback 정책(`memory` / `no-persist` / `feature-disable`) + correctness-critical 값의 fallback 금지.
- storage 관련 negative fixture: token key 등록 시도 실패(§15.2), quota-exceeded → memory fallback, 미등록 raw key 사용 금지.
### 제외 범위
> 의도적으로 제외 — 다른 owner 브랜치가 소유. CLAUDE.md §15.5 R3(OUT_OF_BRANCH_SCOPE) 준수.
- Token / refresh token / auth session material 의 lifecycle·저장 위치 — 외부 auth owner + [[raw/branch-notes/feature-frontend-auth-session-integration-contract]] (`FE-OC-010`) 소유. 본 registry 는 이를 `sensitive-forbidden` 으로 *거부* 만 한다.
- CSP / header / secret-scan 등 브라우저 보안 경계 전반 — [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`) 소유. 본 브랜치는 storage 관련 fixture 만 기여.
- Query cache 의 in-memory 정책·persistence 활성화 — [[raw/branch-notes/feature-server-state-caching-contract]] (`FE-OC-012`) 소유. 본 registry 는 opt-in persistence 가 요구하는 storage key 계약만 제공.
- 8-registry governance 전반의 single-owner / compatibility 추적 메커니즘 — [[raw/branch-notes/feature-frontend-contract-registry-governance]] (`FE-OC-022`) 소유. 본 브랜치는 storage registry 스냅샷 1개를 기여.
- storage schema 의 breaking-change migration / version-bump 판정 규약 — [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] (`FE-OC-023`) 소유. 본 브랜치는 `schemaVersion` 필드와 discard 기본값만 정의.
- `STORAGE_UNAVAILABLE` / `STORAGE_QUOTA_EXCEEDED` error kind enum 정의 — [[raw/branch-notes/feature-frontend-error-classification-boundary-contract]] (`FE-OC-008`) 소유. 본 브랜치는 adapter 실패 → 해당 kind 매핑만.
## 근거 (필수, 최소 1개+)
> 본 브랜치는 project-decision-heavy — 외부 storage best-practice 인용 없이 hub 계약(SSOT)에 근거한다. 아카이브된 6개 frontend official-doc(vite/react-ui/tailwind/tanstack-query/zod/react-router) 중 browser storage 를 다루는 것은 없음(확인 완료).
| Source | 정당화하는 결정 |
|---|---|
| [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | 본 브랜치 SSOT. `FE-OC-013` + `FE-D018` + §5.5 / §9.4 / §13.2 / §8.2 / §5.1 이 D1D6 전부의 근거 (project decision). |
| [[raw/official-docs/react-ui-library-official]] | 시드된 일반 frontend UI-composition source (hub §21.3, `FE-D004` React 선택 근거 `REACT-UI-C1`). **storage 전용 결정을 직접 정당화하지 않음** — 본 브랜치 grounding 은 위 hub 계약이다. |
## TODO
각 항목 옆 증거 등급 표기. frontend repository 미생성이므로 전부 `planned` / `needs-confirmation`.
- [ ] `src/contracts/storage-keys.js``FE-REG-STORAGE` 스키마 + 초기 행(COLOR_SCHEME / CHUNK_RELOAD_GUARD / QUERY_PERSISTENCE / AUTH_TOKEN) 정의 — 등급: `planned`
- [ ] physical key 빌더 `<app>:<scope>:v<schema>:<name>` + raw literal 금지 lint/test — 등급: `planned`
- [ ] classification enforcement + `sensitive-forbidden` 등록 거부 negative fixture(token key 등록 시도) — 등급: `planned`
- [ ] `schemaVersion` + migration-or-discard 경로 및 previous-version fixture — 등급: `planned`
- [ ] `StoragePort` + `adapters/storage` try/catch 어댑터, unavailable / security / quota 분기 매핑 — 등급: `planned`
- [ ] quota fallback 정책 test(`memory` / `no-persist` / `feature-disable`) + correctness-critical no-fallback assertion — 등급: `planned`
- [ ] 구현 repository·검증 evidence 식별 — 등급: `needs-confirmation`
## 진행 중 메모
- `/branch-spec` fill 완료 (2026-07-19). 모든 근거는 hub 계약(FE-OC-013 / FE-D018 / §5.5 / §9.4 / §13.2 / §8.2). 외부 storage best-practice 인용 없음 — project-decision 중심 브랜치.
## 결정 사항
> Decision Evidence Map 의 prose mirror. 각 근거는 hub 계약을 가리킨다(외부 source 없음).
- **D1**: 모든 storage 항목은 `FE-REG-STORAGE` registry 에만 등록하고 physical key 는 `<app>:<scope>:v<schema>:<name>` 구조를 MUST 가진다(raw `localStorage` literal 금지). 검토한 대안: code-generation SSOT 로 key 생성. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §5.5 · §5.1.
- **D2**: 각 항목은 classification(`public-preference` / `opaque-cache` / `sensitive-forbidden`)을 MUST 명시하며 분류 불명 항목은 등록 거부한다. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §5.5.
- **D3**: 각 항목은 `schemaVersion` 을 MUST 가지며 incompatible change 시 증가, previous version 을 읽으면 migration 또는 discard(기본 discard). 검토한 대안: 무버전 + 항상 discard. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.5 · §9.2.
- **D4**: 모든 Web Storage 접근은 application 소유 `StoragePort` + `adapters/storage` 어댑터를 통해서만 하고 try/catch 로 unavailable / security / quota 를 구분한다. 검토한 대안: 컴포넌트 직접 `localStorage` 접근. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9.4 · §4.4 · `FE-D010`(port ownership).
- **D5**: `quotaFallback` 은 필수 필드(`memory` / `no-persist` / `feature-disable`)이며 quota 초과 시 허용된 cache 를 registry 명시 순서로 evict 후 memory fallback, 단 correctness-critical(mutation / idempotency record) 값은 fallback 금지·terminal 처리한다. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.5 · §9.4 · §8.2.
- **D6**: token / secret / PII / raw API response / error body 는 default registry 에 등록 불가(`sensitive-forbidden`)이며 브라우저 번들·storage 를 공개물로 간주한다. 근거: [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §9.4 · §13.2. 공동 집행: [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`); token lifecycle 은 [[raw/branch-notes/feature-frontend-auth-session-integration-contract]] (`FE-OC-010`) 외부 소유.
## 결정-근거 매핑
> `선택 조건` = hub 결정이 `accepted-documented-only`(`FE-D018`) 이므로 대부분 불변식을 고정. 분기 있는 것만 대안 조건 명시. Supporting Claims 는 hub 계약을 가리킨다(project-decision-heavy 브랜치 — 외부 doc 없음).
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | storage 항목은 `FE-REG-STORAGE` 에만 등록, physical key `<app>:<scope>:v<schema>:<name>` 구조 필수, raw literal 금지 (`FE-OC-013`) | skeleton storage 는 항상 registry 경유; 대안(code-generation SSOT 로 key 생성)은 `FE-D018` revisit trigger(code generation SSOT 채택) 발생 시에만 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §5.5 · §5.1 | `project-decision` | `<app>` literal 값과 `<scope>` 분류 체계(feature별 vs flat) 미확정 — 구현 시 결정 |
| D2 | 각 항목 classification 3분류 MUST 명시; 분류 불명 → 등록 거부 | 모든 항목 분류 강제(안전 기본); 분기 없음 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §5.5 | `project-decision` | `opaque-cache` vs `public-preference` 경계 판정 기준 문서화 필요 |
| D3 | `schemaVersion` 필수 + incompatible 시 증가, previous version 은 migration 또는 discard | 기본 discard; migration 선택 시 fixture·rollback 은 compatibility-governance(`FE-OC-023`)로 위임 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.5 · §9.2 | `project-decision` | migration 필요 항목 발생 시 `FE-OC-023` 과 계약 조율 필요 |
| D4 | 단일 application 소유 `StoragePort` + `adapters/storage` try/catch, unavailable / security / quota 분기 구분 | Clean Arch layering(`FE-OC-002`) 하에 port-owned 항상; 직접 `localStorage` 접근 금지 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9.4 · §4.4 · `FE-D010` | `project-decision` | private-mode / 정책 차단의 SecurityError 세부 분기 미검증 |
| D5 | `quotaFallback` 필수(`memory` / `no-persist` / `feature-disable`); quota 초과 시 evict→memory, correctness-critical 값 fallback 금지 | preference write 실패 → memory fallback 무중단; mutation / idempotency 등 correctness-critical → fallback 없이 terminal | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.5 · §9.4 · §8.2 | `project-decision` | eviction 순서(어떤 cache 먼저)의 registry 표기 형식 미정 |
| D6 | token / secret / PII / raw response / error body = `sensitive-forbidden`, default registry 등록 불가, storage = 공개물 | skeleton default 는 항상 금지; auth owner 가 storage 사용 필요 시 별도 threat model + owner evidence(§6.1) — 본 브랜치 범위 밖 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §9.4 · §13.2 · §5.4 | `project-decision` | 공동 집행 경계(browser-security `FE-OC-019` / auth `FE-OC-010`) fixture 중복·누락 조율 |
## 구현 가이드
> `planned` blueprint — frontend repository 미생성. 경로는 hub §4.6 Planned directory blueprint + §5.1 registry owner map 에서 도출(grounded)되나, 코드는 아직 없으므로 전체가 `planned`. CLAUDE.md §15.5 R1(Trace)·R2(UNSUPPORTED_IMPL_DECISION)·R3(OUT_OF_BRANCH_SCOPE) 준수.
### 1. `FE-REG-STORAGE` registry schema (`src/contracts/storage-keys.js`)
> **Trace**: D1, D2, D3, D5 → [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · `FE-D018` · §5.5 · §5.1.
>
> - **UNSUPPORTED_IMPL_DECISION**:
> - physical key 의 `<app>` literal 값(예: `ca`)과 `<scope>` 분류 체계(feature-prefix vs flat namespace) — §5.5 는 *형식*만 규정하고 구체 값을 권고하지 않음. trade-off: 짧은 prefix = 충돌 위험, 긴 prefix = key 길이 증가.
> - registry 를 JS object literal vs factory 함수로 표현 — hub 미권고. trade-off: object = 단순, factory = 등록 시 검증 강제 용이.
> - `schemaVersion` 표기(정수 vs semver) — §5.5 는 increment 만 규정. trade-off: 정수 = 단순 비교, semver = additive/breaking 구분.
**필드 계약(8-field 스키마)과 초기 4행의 owner 는 [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.5 다** — 이전 판은 두 표를 1:1 로 옮겨 적고 있었고("전부 §5.5 grounded" · "§5.5 planned rows 그대로" 라고 스스로 밝힌 그대로), 그러면 §5.5 가 필드를 추가할 때 이 사본이 조용히 낡는다. 요약 한 줄: storage key 는 `logicalName`·`physicalKey`·`backend`·`classification`·`schemaVersion`·`ttl`·`migration`·`quotaFallback` 8필드를 가지고, 초기 행은 색상 테마·chunk reload guard·query persistence(비활성)·auth token(금지) 4개다.
본 브랜치가 소유하는 것은 그 위의 **강제 방법**이다 — 아래 enforcement point, key-name deny 패턴, quota fallback 사다리.
### 2. `StoragePort` boundary + adapter failure mapping (`application/ports` + `adapters/storage`)
> **Trace**: D4, D5 → [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §9.4 · §4.4 · §8.2 · `FE-D010`.
>
> - **UNSUPPORTED_IMPL_DECISION**:
> - `StoragePort` method 시그니처(예: `get(logicalName)` / `set(logicalName, value)` / `remove(logicalName)`)의 정확한 이름·인자 — §9.4 는 boundary 원칙만 규정. trade-off: 좁은 API = 안전, 넓은 API = 유연.
> - **OUT_OF_BRANCH_SCOPE**: `STORAGE_UNAVAILABLE` / `STORAGE_QUOTA_EXCEEDED` **kind enum 정의**는 [[raw/branch-notes/feature-frontend-error-classification-boundary-contract]] (`FE-OC-008`) 소유(§5.6). 본 § 는 adapter 실패 → 해당 kind *매핑*만 명세한다.
어댑터 실패 매핑 (§8.2 · §9.4 grounded):
| adapter 조건 | normalized kind | fallback |
|---|---|---|
| Storage API 부재 / `SecurityError`(private mode·정책 차단) | `STORAGE_UNAVAILABLE` | memory-only (§8.2) |
| `setItem` quota 초과 | `STORAGE_QUOTA_EXCEEDED` | 허용 cache evict → memory-only (§8.2) |
### 3. Classification enforcement + `sensitive-forbidden` invariant
> **Trace**: D2, D6 → [[raw/project-notes/ca-skeleton-frontend-operational-contract]] `FE-OC-013` · §5.5 · §9.4 · §13.2 · §15.2 · §6.1.
>
> - **UNSUPPORTED_IMPL_DECISION**:
> - 거부 강제 지점(build-time lint vs runtime registry assert vs 둘 다) — hub 미권고. trade-off: lint = 조기 차단, runtime = 동적 등록도 방어.
> - 금지 key 이름 패턴(정규식/glob) 구체 — §6.1 은 이름 목록(`SECRET`/`PASSWORD`/`PRIVATE_KEY`/`TOKEN`)만 제시. trade-off: 넓은 패턴 = 오탐, 좁은 패턴 = 누락.
> - **OUT_OF_BRANCH_SCOPE**: CSP / secret-scan / `dangerouslySetInnerHTML` 등 브라우저 보안 경계 전반은 [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`) 소유(§13.2). 본 § 는 storage 등록 거부만.
강제 규약:
- `classification: sensitive-forbidden` 항목은 등록 자체를 거부(§5.5 · §9.4).
- key 이름에 `SECRET` / `PASSWORD` / `PRIVATE_KEY` / `TOKEN` 포함 시 거부(§6.1 정책을 storage 에 적용).
- negative fixture: `token key registration attempt` → 반드시 실패(§15.2).
### 4. Quota fallback + correctness-critical policy
> **Trace**: D5 → [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §5.5 · §9.4 · §8.2.
>
> - **UNSUPPORTED_IMPL_DECISION**:
> - eviction 순서 표기 형식(registry 필드 vs 별도 목록)과 `feature-disable` 시 UX notice 형식 — §5.5·§9.4 는 "허용 순서를 registry 에 기록"만 요구, 형식 미권고. trade-off.
값 등급별 fallback (§9.4 · §5.5 · §8.2 grounded):
| value class | quota / unavailable 시 동작 |
|---|---|
| `public-preference` (예: `COLOR_SCHEME`) | memory fallback, silent — product flow 중단 없음 |
| `opaque-cache` (예: `CHUNK_RELOAD_GUARD`) | 허용 cache evict 후 memory; guard 손실 허용 |
| correctness-critical (mutation / idempotency record) | fallback 없음 → terminal; 임의 storage fallback 금지 |
## 엣지·실패·의존
- **실패·엣지 경로**:
- Storage API 부재 / `SecurityError`(private mode·정책 차단) → `STORAGE_UNAVAILABLE`, memory-only, 대개 silent (§8.2).
- `setItem` quota 초과 → `STORAGE_QUOTA_EXCEEDED`, 허용 cache evict 후 memory, feature 영향 시 non-blocking notice (§8.2).
- previous `schemaVersion` 데이터 read → migration 또는 discard; discard 시 기본값 재생성 (D3 · §9.2).
- `sensitive-forbidden` 값 등록 시도 → 등록 거부(negative fixture, §15.2).
- correctness-critical 값의 storage 실패 → fallback 금지, terminal 처리 (D5 · §9.4).
- **다른 계약 의존**:
- [[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]] (`FE-OC-002`) — `StoragePort` 를 application 이 소유하고 adapter 가 구현하는 layering·port 규약에 의존(§20 Dependency). 이 계약이 바뀌면 port 위치·주입 방식 영향.
- [[raw/branch-notes/feature-frontend-error-classification-boundary-contract]] (`FE-OC-008`) — `STORAGE_UNAVAILABLE` / `STORAGE_QUOTA_EXCEEDED` kind 정의를 consume; 본 브랜치는 매핑만.
- [[raw/branch-notes/feature-frontend-contract-registry-governance]] (`FE-OC-022`) — 8-registry single-owner·compatibility governance 에 storage snapshot 기여.
- [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] (`FE-OC-023`) — schema breaking-change migration·version-bump 판정 위임.
- [[raw/branch-notes/feature-sample-feature-slice-contract-fixture]] (`FE-OC-024`) — sample slice 가 storage key 계약을 fixture 로 사용.
- [[raw/branch-notes/feature-frontend-auth-session-integration-contract]] (`FE-OC-010`) — token lifecycle 외부 소유; 본 registry 는 token 저장 거부만.
- [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] (`FE-OC-019`) — secret·storage 브라우저 경계 fixture 공동.
## 검증해야 할 주장
> hub 계약은 근거지만 내 프로젝트에서의 동작을 자동 보장하지 않는다. frontend repository 미생성이므로 전부 `needs-confirmation`. 검증 아티팩트는 §20 Measurable completion(namespace/version/classification/quota fallback tests) + §15.2 negative fixture 에서 도출.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| physical key 규약이 실제 코드에서 raw literal 사용을 0건으로 만든다 | repo·lint 규칙 미구현 | namespace/registry lint + "raw localStorage key literal" negative fixture (§5.1·§15.2) | `needs-confirmation` |
| token key 등록 시도가 반드시 실패한다 | 강제 지점(build vs runtime) 미구현 | "token key registration attempt" negative fixture (§15.2) | `needs-confirmation` |
| `schemaVersion` mismatch 시 migration-or-discard 가 결정적으로 동작 | migration 경로 미작성 | previous-version fixture + discard/default 재생성 test | `needs-confirmation` |
| quota 초과 시 preference = memory fallback, correctness-critical = no fallback | 브라우저 quota 동작 환경차 | quota fallback 결정적 test(mock quota) + correctness-critical no-fallback assertion | `needs-confirmation` |
| classification 3분류가 모든 항목에 강제된다 | registry validation 미구현 | 미분류 항목 등록 거부 unit test (FE-GATE-005 registries) | `needs-confirmation` |
## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
| 관심사 | 상태 | owner | 심각도 | 근거 |
|---|---|---|---|---|
## 마주친 문제
- 없음 — `/branch-spec` fill 단계 (구현 전).
## 묶음 (이 branch에서 파생된 자료)
<!-- GENERATED: project-contract-imports:start -->
## 가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
| `FE-GATE-005@1` | [[raw/branch-notes/feature-frontend-test-taxonomy-contract]] | unit 레벨이 실패하면 merge 를 MUST 차단하고 warning 으로 낮추면 안 됨 | import 참조로 적용 |
| `FE-OC-002@1` | [[raw/branch-notes/feature-frontend-clean-architecture-layering-contract]] | `domain <- application <- presentation` 의존 방향과 application-owned output port를 MUST 지킴 | import 참조로 적용 |
| `FE-OC-010@1` | [[raw/branch-notes/feature-frontend-auth-session-integration-contract]] | skeleton은 session state를 소비하되 token lifecycle을 MUST 소유하지 않음 | import 참조로 적용 |
| `FE-OC-019@1` | [[raw/branch-notes/feature-frontend-browser-security-boundary-contract]] | browser bundle에 secret을 넣지 않고 untrusted HTML injection을 기본 금지 | import 참조로 적용 |
| `FE-OC-023@1` | [[raw/branch-notes/feature-frontend-contract-compatibility-governance]] | API/config/storage/release schema의 breaking change는 migration 또는 version bump 없이 배포하면 안 됨 | import 참조로 적용 |
<!-- GENERATED: project-contract-imports:end -->
### Sub-branches (세부 작업)
- 없음 — scaffolding 단계
### 오류 기록 (이 branch 작업 중 발생)
- 없음 — scaffolding 단계
### 면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- 없음 — scaffolding 단계
### 강의 (이 작업을 위해 학습한 강의)
- 없음 — scaffolding 단계
### job-posting tie-ins (이 작업에서 파생된 글감)
- 없음 — scaffolding 단계
## 관련 일일 노트
- 없음 — scaffolding 단계
## 완료 후 정리
- PR 링크: TODO
- 리뷰 메모: TODO
- 머지 결과 / 배포 환경: TODO
- **wiki 추출 대상**: 없음 — 전부 `planned` (frontend repository 미생성)
- **추출하지 않을 항목**: D1–D6 전체 — 구현·검증 evidence 확보 전까지 추출 금지