Files
llm-wiki/raw/branch-notes/feature-frontend-binary-file-io-store-contract.md

33 KiB

title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, imports, delegates, accepts_delegations, contract_packet, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label
title source_type status id kind project work_item inherits refines overrides depends_on imports delegates accepts_delegations contract_packet branch parent_branch related_projects governing_docs tags created target_merge status_label
branch / feature-frontend-binary-file-io-store-contract branch-note raw BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028 project-work-item ca-skeleton-frontend-operational-contract WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BINARY-STORE-001@1
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-002
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011
FE-GATE-027@1
FE-OC-002@1
FE-OC-013@1
FE-OC-022@1
DELEG-FE-008@1
1 feature-frontend-binary-file-io-store-contract
ca-skeleton-frontend
ca-skeleton
raw/project-notes/ca-skeleton-frontend-operational-contract.md
branch
ca-skeleton-frontend
storage
binary
file-io
2026-07-28 in-progress

branch: feature-frontend-binary-file-io-store-contract

부모 (필수)

형제 branch (같은 부모, 이번 확장에서 함께 생성):

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 2
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: picker·다운로드·object URL 해제·quota·OPFS·Cache Storage fixture가 통과하고 binary I-O report가 생성된다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1 신규 runtime capability 6종은 FE-REG-CAPABILITY flag로 default OFF이며 활성화는 owner·gate·runbook을 동반한다 CAP_FE_BINARY_IO 를 이 branch 가 소유하고 default OFF 로 유지한다 raw/project-notes/ca-skeleton-frontend-operational-contract
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BINARY-STORE-001@1 로컬 바이너리 backend는 IndexedDB를 default로 하고 OPFS는 대용량 순차 write에 opt-in, Cache Storage는 정책상 service worker 호스팅 response cache 전용으로 제한한다 BlobStorePort adapter 의 backend 선택 순서에 적용한다 raw/project-notes/ca-skeleton-frontend-operational-contract
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1 route, API operation, env, storage, error, query, telemetry, release token, capability를 9개 registry로 관리한다 FE-REG-STORAGE 신규 4행(UPLOAD_PART_STATE·TRANSFER_OBJECT_BUFFER·QUERY_CACHE_SNAPSHOT·SW_RESPONSE_CACHE)의 payloadClass·evictionOrder 를 소비한다 raw/project-notes/ca-skeleton-frontend-operational-contract

브랜치 지역 결정

Decision ID Decision Relation Supporting Claims Status
D1 object URL 의 생성과 해제는 adapters/file 이 쌍으로 소유하고 presentation 에 raw URL 문자열을 넘기지 않는다 local raw/official-docs/mdn-object-url-cache-storage.md#C1, #C2 proposed
D2 BlobStorePort 는 backend 를 호출자에게 노출하지 않고 registry 의 backend 값으로만 선택한다 refines DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BINARY-STORE-001@1 UNSUPPORTED_DECISION — 조사 후에도 근거 없음. trade-off: backend 를 노출하면 호출부가 IndexedDB/OPFS 를 직접 분기해 FE-OC-002 의 port 경계가 새므로 은닉을 택했다. 비용은 backend 별 최적화 불가 proposed
D3 FileDialogPort기준선은 <input type=file> + <a download> 이고, File System Access picker 는 feature detection 후 얹는 progressive enhancement 다 local raw/official-docs/mdn-file-system-access-opfs.md#C1, #C2, #C4 proposed
D4 picker 취소와 "user agent 가 위험하다고 판단한 파일"은 같은 AbortError 로 오므로 구분하지 않고 둘 다 FILE_PICKER_DISMISSED 로 정규화한다 local raw/official-docs/mdn-file-system-access-opfs.md#C3 proposed
D5 OPFS 는 비동기 API 를 기본으로 쓰고, 동기 access handle 이 필요한 경우에만 WorkerTaskPort 를 경유한다 refines DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BINARY-STORE-001@1 raw/official-docs/mdn-file-system-access-opfs.md#C5, #C6 proposed
D6 FE-REG-STORAGE.evictionOrder애플리케이션 주도 정리 순서이며 브라우저 eviction 에는 적용되지 않는다 local raw/official-docs/mdn-storage-quotas-eviction-persistence.md#C1, #C3 proposed
D7 correctness 값을 쓰는 capability 는 boot 시 navigator.storage.persist() 를 1회 요청하고, 미허가 상태를 실패로 취급하지 않되 재개 보장 없음을 표면화한다 local raw/official-docs/mdn-storage-quotas-eviction-persistence.md#C4, #C5, #C7 proposed

D8(IndexedDB 스키마·버전 관리와 migration 절차)은 이번 회차 자동조사 상한(6개)을 넘어 deferred 다. 다음 /branch-spec 회차 또는 수동 조사 대상이며, 그 전까지 §구현 가이드에 IndexedDB 버전 전략을 적지 않는다.

선언한 예외

해당 없음. inherited decision 과 다른 동작을 요구하지 않는다.

가져온 artifact 계약

Artifact Ref Owner Producer Schema Ref

가져온 프로젝트 계약

Ref Owner 요약 Branch 적용
FE-GATE-027@1 raw/project-notes/ca-skeleton-frontend-operational-contract picker·다운로드·quota·object URL 해제 fixture 가 실패하면 merge 를 MUST 차단 이 branch 가 owner 로서 fixture 와 report 를 산출
FE-OC-002@1 raw/branch-notes/feature-frontend-clean-architecture-layering-contract domain <- application <- presentation 의존 방향과 application-owned output port를 MUST 지킴 port 는 application 소유, adapter 가 구현
FE-OC-013@1 raw/branch-notes/feature-frontend-storage-registry-contract storage key는 namespace·version·classification을 MUST 가지며 token/secret 저장을 금지 바이너리 key 도 예외 없이 registry 경유
FE-OC-022@1 raw/branch-notes/feature-frontend-contract-registry-governance 9개 registry는 single primary owner와 compatibility impact를 MUST 기록 FE-REG-STORAGE 확장의 compatibility impact 기록

수신한 위임

Delegation Ref From Concern Status
DELEG-FE-008@1 raw/branch-notes/feature-frontend-large-object-transfer-contract fe.deleg.binary-handle-ownership accepted

가져온 흐름 단계

Stage Ref Order Owner Input Action Output

목표

FileDialogPortBlobStorePort 를 정의하고, IndexedDB·OPFS·Cache Storage adapter 와 object URL 수명 계약을 고정한다. 이 계약이 없으면 컴포넌트가 URL.createObjectURL 을 직접 부르고 revokeObjectURL 을 빠뜨려 탭 수명 동안 메모리가 증가하며, quota 초과 시 correctness 값이 조용히 memory 로 fallback 된다.

  • 이슈:
  • PR:

범위

포함 범위

  • FileDialogPort — 파일 선택(<input type=file> / File System Access) 과 저장 dialog
  • BlobStorePort — IndexedDB(default) · OPFS(opt-in) · Cache Storage(SW 전용) backend
  • object URL 생성·해제 쌍 관리와 누수 검출 fixture
  • quota 매핑(BLOB_STORE_QUOTA_EXCEEDED)과 evictionOrder 기반 제거 순서
  • FE-REG-STORAGE 신규 4행의 소비와 payloadClass·evictionOrder 강제
  • CAP_FE_BINARY_IO capability 행 소유

제외 범위

  • use case, domain model, business rule — 이 branch 는 port 와 adapter 계약까지만 정의한다. port 를 호출하는 use case 는 적용 프로젝트가 작성한다.
  • 파일 형식별 처리 — 이미지 리사이즈·비디오 트랜스코딩·문서 파싱
  • 실제 네트워크 전송 — [[raw/branch-notes/feature-frontend-large-object-transfer-contract]] 소유
  • storage physical key·namespace·classification 정의 — [[raw/branch-notes/feature-frontend-storage-registry-contract]] 소유
  • service worker 등록·수명주기 — [[raw/branch-notes/feature-frontend-background-execution-worker-contract]] 소유 (Cache Storage 는 그 위에 얹힌다)

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

Source 정당화하는 결정
raw/official-docs/mdn-file-system-access-opfs D3 picker 기준선 선택 · D4 취소 매핑 · D5 OPFS worker 제약
raw/official-docs/mdn-storage-quotas-eviction-persistence D6 evictionOrder 적용 범위 · D7 correctness 값의 persist 요청
raw/official-docs/mdn-object-url-cache-storage D1 object URL 수명 소유 · Cache Storage 실행 컨텍스트 전제
[[docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design]] §5.1·§6.2 port 12개 분해와 FE-REG-STORAGE 확장
raw/project-notes/ca-skeleton-frontend-operational-contract §4.4·§5.5·§5.11 port ownership, storage registry, capability registry

근거 등급 경계 (2026-07-28 조사 후 갱신): 2026-07-28 /branch-spec 조사로 MDN 근거 3건을 수집해 D1·D3~D7 은 official-reference 근거를 갖게 됐다. 남은 경계는 두 가지다.

  • D2 는 여전히 project-local — port 가 backend 를 노출하지 않는다는 추상화 선택은 외부 문서가 다루는 주제가 아니다.
  • FE-D027 의 backend 우선순위(IndexedDB default / OPFS opt-in)는 성능 근거가 없다mdn-file-system-access-opfs#C6 이 말하는 OPFS 의 속도 우위는 File System Access API 대비이지 IndexedDB 대비가 아니다. IndexedDB↔OPFS 비교는 자체 벤치마크가 필요하며 ## 검증해야 할 주장 에 남긴다.

ca-tmpl ground truth 는 이 branch 에 적용되지 않는다(NO_GROUND_TRUTH) — §Audit & Findings 참조.

TODO

  • FileDialogPort 인터페이스 확정 — 등급: planned
  • BlobStorePort 인터페이스와 backend 선택 규칙 확정 — 등급: planned
  • object URL 수명 계약과 누수 fixture — 등급: planned
  • quota 초과 시 evictionOrder 동작과 null 행 보호 fixture — 등급: planned
  • OPFS 순차 write fixture — 등급: planned
  • Cache Storage 버전 파티션 fixture — 등급: planned
  • FE-GATE-027 binary I-O report 산출 — 등급: planned

진행 중 메모

FE-REG-STORAGEUPLOAD_PART_STATEquotaFallback: 없음, evictionOrder: null 이다. 이 두 값은 §9.4 의 "correctness 에 영향을 주는 값은 storage fallback 을 임의 적용하지 않는다" 를 행 단위로 구현한 것이므로, adapter 가 이 행에 대해 memory fallback 을 하면 gate negative fixture 가 잡아야 한다.

결정 사항

  • 2026-07-28: object URL 생성·해제를 adapter 가 쌍으로 소유 / 이유: 해제 누락이 컴포넌트 단위로 흩어지면 검출이 불가능 / 검토한 대안: 컴포넌트 훅에서 useEffect cleanup 으로 관리 / 근거: 근거 raw 미수집, project-local 판단 (FE-Q-011)

결정-근거 매핑

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 object URL 생성·해제를 adapters/file 이 쌍으로 소유 항상. 컴포넌트가 URL 문자열을 장기 보유해야 하는 요구(장기 미리보기)가 생기면 handle 기반 대여 API 로 재검토 mdn-object-url-cache-storage.md#C1(해제는 명시 호출 필요), #C2(SW 미제공 사유가 memory leak) official-reference + project-decision(소유 주체는 MDN 이 말하지 않음) 해제 시점을 adapter 가 알 수 없는 사용 패턴. 대여 만료 타이머가 필요할 수 있음
D2 BlobStorePort 가 backend 를 노출하지 않음 항상. OPFS 전용 최적화가 use case 레벨에서 필요해지면 재검토 UNSUPPORTED_DECISION — 조사 후에도 외부 근거 없음 project-local default (라벨됨) backend 별 성능 특성이 크게 다르면 추상화가 새는 지점이 생김
D3 <input type=file> + <a download> 를 기준선, File System Access picker 를 progressive enhancement 항상. 대상 브라우저 매트릭스가 picker 전량 지원으로 확정되면(FE-Q-007) 기준선을 picker 로 올릴 수 있음 mdn-file-system-access-opfs.md#C1(not Baseline), #C2(transient activation), #C4(secure context) official-reference 두 경로의 UX 가 달라진다 — picker 는 저장 위치 선택, fallback 은 브라우저 다운로드 폴더 고정
D4 취소와 "위험 파일 거부"를 구분하지 않고 FILE_PICKER_DISMISSED 로 정규화 항상. 브라우저가 두 사유를 구분 가능한 신호로 분리하면 재검토 mdn-file-system-access-opfs.md#C3(둘 다 같은 AbortError) official-reference 거부 사유를 사용자에게 설명할 수 없다. "선택된 파일이 없습니다" 수준의 중립 문구만 가능
D5 OPFS 는 비동기 API 기본, 동기 handle 이 필요할 때만 WorkerTaskPort 경유 대용량 순차 write 로 메인 스레드 블로킹이 측정될 때만 동기 경로. 그 전에는 비동기 mdn-file-system-access-opfs.md#C5(동기 API 는 worker 전용), #C6(속도 우위의 비교 대상은 File System Access API) official-reference worker 경유는 CAP_FE_BACKGROUND_EXEC 활성을 전제한다 — 두 capability 가 얽힌다
D6 evictionOrder 는 애플리케이션 주도 정리 순서로만 유효 항상. 브라우저가 per-key eviction 힌트 API 를 제공하면 재검토 mdn-storage-quotas-eviction-persistence.md#C1(origin 전량 삭제), #C3(LRU origin 단위) official-reference 없음 — 2026-07-28 hub §5.5 필드 Rule 이 이 경계를 담도록 정정됐다(§Audit & Findings EVICTION_SCOPE_DRIFT resolved)
D7 correctness 값 사용 시 persist() 1회 요청 + 미허가를 표면화 correctness 값(UPLOAD_PART_STATE 등)을 쓰는 capability 가 활성일 때. 순수 캐시만 쓰면 요청하지 않음 mdn-storage-quotas-eviction-persistence.md#C4(persist 는 LRU 제외), #C5(허가는 브라우저 재량), #C7(Safari 7일 규칙) official-reference persist 미허가 + Safari ITP 조합이면 재개 가능 전송이 7일 만에 무효가 된다. 제품이 이를 수용 가능한지 미확인

구현 가이드

2026-07-28 /branch-spec 조사(MDN 3건)로 in-scope detail 을 채웠다. 근거가 원칙만 지지하고 detail 은 지지하지 않는 cell 은 UNSUPPORTED_IMPL_DECISION + trade-off 한 줄로 표시했다(CLAUDE.md §15.5 R2). 다른 branch 결정 영역은 남기지 않았다(R3). 구현 repository 가 아직 없으므로 아래 경로·명명은 전부 planned 다. actually-implemented 로 승격하려면 repo·commit·path 가 필요하다(hub §17.2).

1. FileDialogPort — 2경로 구조와 feature detection

Trace: D3(기준선 선택) ← mdn-file-system-access-opfs.md#C1·#C2·#C4 / D4(취소 정규화) ← 같은 문서 #C3

  • UNSUPPORTED_IMPL_DECISION: port 메서드 이름(pickFiles/saveFile)과 descriptor 필드명. MDN 은 API 표면만 말하고 우리 port 의 명명을 지지하지 않는다. trade-off: 브라우저 API 명(showOpenFilePicker)을 그대로 쓰면 fallback 경로에서 이름이 거짓이 되므로 중립 동사를 택했다.
항목 planned 명세 근거
경로 src/adapters/file/file-dialog.adapter.js — (UNSUPPORTED_IMPL_DECISION, hub §4.6 blueprint 관례를 따름)
detection typeof window.showOpenFilePicker === 'function' 그리고 window.isSecureContext 가 모두 참일 때만 picker 경로 #C1, #C4
열기 — enhanced showOpenFilePicker(...)FileSystemFileHandle[] #C1
열기 — 기준선 숨긴 <input type="file"> 을 클릭 이벤트 핸들러 안에서 트리거 → FileList #C2(제스처 필요)
저장 — enhanced showSaveFilePicker(...)FileSystemFileHandlecreateWritable() #C1
저장 — 기준선 object URL + <a download> 클릭. 덮어쓰기 불가이며 저장 위치를 사용자가 고를 수 없음을 UI 문구에서 약속하지 않음 #C1 (fallback 한계)
호출 컨텍스트 두 경로 모두 사용자 제스처 핸들러 안에서 동기적으로 호출한다. await 이후 호출하면 activation 이 소모돼 실패한다 #C2
취소 AbortErrorFILE_PICKER_DISMISSED. 사유를 구분하지 않는다 #C3, D4
제약 위반 accept/size 검사는 adapter 가 수행 → FILE_REJECTED. 파일명은 telemetry 로 보내지 않음 hub §5.8 forbiddenAttributes

2. object URL 수명 — 대여(lease) 모델

Trace: D1 ← mdn-object-url-cache-storage.md#C1(해제는 명시 호출)·#C2(SW 미제공 사유 = memory leak)

  • UNSUPPORTED_IMPL_DECISION: "대여 handle" 이라는 형태 자체. MDN 은 해제 필요성만 말하고 소유·반납 모델을 말하지 않는다. trade-off: 컴포넌트가 URL 문자열을 들고 있으면 해제 시점을 adapter 가 알 수 없어, 반납 가능한 handle 로 감쌌다.
규칙 planned 동작
발급 adapter 가 createObjectURL 호출 후 { url, release() } 형태의 대여 handle 을 반환. raw 문자열 단독 반환 금지
반납 release()revokeObjectURL 을 1회만 호출(멱등). 이중 호출은 no-op
adapter 파괴 미반납 대여를 전부 revoke 하고, 그 수를 WORKER/FILE 계열이 아닌 gate fixture 용 카운터로 노출
service worker object URL 을 만들지 않는다 — 플랫폼이 제공하지 않는다 (#C2)
누수 판정 adapter 파괴 시점의 미반납 대여 수 > 0 이면 FE-GATE-027 실패

3. BlobStorePort — backend 선택과 quota 처리

Trace: D2(backend 비노출) ← 근거 없음(project-local) / D5(OPFS 비동기 기본) ← mdn-file-system-access-opfs.md#C5·#C6 / D6(evictionOrder 범위) ← mdn-storage-quotas-eviction-persistence.md#C1·#C3 / D7(persist) ← 같은 문서 #C4·#C5·#C7

  • UNSUPPORTED_IMPL_DECISION: IndexedDB 를 default 로, OPFS 를 opt-in 으로 두는 우선순위. #C6 의 OPFS 속도 우위는 File System Access API 대비이지 IndexedDB 대비가 아니다. trade-off: IndexedDB 가 지원 범위가 넓고 구조화 값과 바이너리를 한 backend 로 다룰 수 있어 기준선으로 두었다. 벤치마크 전까지 이 순서는 측정 근거가 없다.
항목 planned 명세 근거
backend 선택 호출자는 registry backend 값만 지정. adapter 가 구현체를 고른다 D2
OPFS 접근 비동기 File System API 기본. createSyncAccessHandle() 은 worker 안에서만 가능하므로 WorkerTaskPort 경유 #C5
quota 초과 evictionOrder 오름차순으로 애플리케이션이 정리 후 1회 재시도. evictionOrder: null 행은 정리 대상에서 제외 D6
브라우저 eviction 막을 수 없다. origin 전량 삭제이므로 부분 복구 로직을 두지 않는다 #C1, #C3
persist 요청 CAP_FE_BINARY_IO 활성 boot 시 navigator.storage.persist() 1회. 결과를 capability 상태에 기록 #C4, #C5
persist 미허가 실패가 아니다. 기능은 그대로 동작하되 correctness 값 사용 화면에 "재개가 보장되지 않음" 을 표시 #C5, D7
Safari 경고 ITP 활성 + 7일 무상호작용이면 script 생성 데이터가 삭제된다. 재개 가능 전송의 상한을 이 값 이하로 잡는다 #C7

4. Cache Storage backend

Trace: mdn-object-url-cache-storage.md#C3(SW 전용 아님)·#C4(버전 캐시명)·#C5(keys()/delete())

  • UNSUPPORTED_IMPL_DECISION: 캐시명 형식 <app>-<releaseId>. MDN 예제는 `myapp-${cacheVersion}` 패턴만 보이고 우리 토큰 구성을 지지하지 않는다. trade-off: FE-REG-RELEASE.releaseId 를 재사용하면 rollback 시 파티션이 자동으로 갈라진다.
항목 planned 명세 근거
접근 Window.caches 로도 접근 가능하다 — service worker 는 기술적 필수 조건이 아니다 #C3
정책 그럼에도 이 skeleton 은 Cache Storage 를 SW 호스팅 response cache 로 한정한다. 이는 플랫폼 제약이 아니라 FE-D027 의 정책 선택이다 §Audit & Findings
파티션 캐시명에 release 토큰 포함. 활성 release 외의 캐시는 keys() 열거 후 delete() #C4, #C5
정리 시점 SW activate 단계. 이 branch 는 파티션 규칙만 소유하고 실행 시점은 feature-frontend-background-execution-worker-contract 소유 R3 경계

엣지·실패·의존

  • 실패·엣지 경로
    • 사용자가 dialog 를 닫음 → FILE_PICKER_DISMISSED, error surface 없음, telemetry event 없음
    • accept/size 제약 위반 → FILE_REJECTED, 위반 제약만 안내하고 파일명은 telemetry 에 남기지 않음
    • private mode 등으로 storage 접근 불가 → BLOB_STORE_UNAVAILABLE, registry quotaFallback 적용, 없음 행은 terminal
    • quota 초과 → BLOB_STORE_QUOTA_EXCEEDED, evictionOrder 순 제거 후 재시도. evictionOrder: null 행은 제거 대상이 아니다
    • OPFS 미지원 브라우저 → CAPABILITY_UNSUPPORTED, disabledFallback: feature-hidden
  • 다른 계약 의존 (대상 브랜치 + 그 Decision ID)
    • raw/branch-notes/feature-frontend-storage-registry-contract D1(versioned namespace)·D2(classification 필수)·D5(quotaFallback 을 registry field 로 관리)·D6(token·secret·PII 저장 거부) — 본 branch 는 FE-REG-STORAGE 신규 4행을 소비만 하고 key 형식·classification 을 정의하지 않는다. D5 가 바뀌면 본 branch 의 quota 처리(§구현 가이드 3)가 함께 바뀐다.
    • raw/branch-notes/feature-frontend-error-classification-boundary-contract D1(총함수 정규화)·D2(safe field 만 보존)·D3(FE-REG-ERROR single-owner)·D6(recovery action closed vocabulary) — 본 branch 가 만드는 4개 kind(FILE_PICKER_DISMISSED·FILE_REJECTED·BLOB_STORE_UNAVAILABLE·BLOB_STORE_QUOTA_EXCEEDED)는 D1 의 총함수에 매핑되어야 하고, D6 의 닫힌 action 어휘 밖의 action 을 만들 수 없다.
    • raw/branch-notes/feature-frontend-background-execution-worker-contract D3(worker/SW 엔트리의 상위 layer import 금지) — D5 의 OPFS 동기 경로WorkerTaskPort 를 요구하므로, worker 엔트리 규칙이 본 branch 의 OPFS 구현 형태를 제약한다. Cache Storage backend 의 SW 호스팅은 D1(자동 skipWaiting 금지)·D2(serviceWorkerVersion)와 파티션 시점을 공유한다.
    • raw/branch-notes/feature-frontend-env-runtime-config-contract D4(React mount 전 runtime config fetch·검증) — D7 의 persist() 요청 시점이 boot 순서(hub §4.5 6단계 capability 해석) 안에 있어야 한다. D4 의 mount-전 게이트가 바뀌면 persist 요청 위치도 바뀐다.
    • raw/branch-notes/feature-frontend-large-object-transfer-contract D1(별도 credential-less transport) — DELEG-FE-008@1 로 본 branch 가 File/Blob handle 과 object URL 수명을 수신했다. 그 branch 의 전송 descriptor 형태가 바뀌면 본 branch 의 대여 handle 반환 형태가 영향받는다.

검증해야 할 주장

Claim Why uncertain How to verify Status
picker 취소가 error surface 를 띄우지 않는다 취소를 실패로 처리하는 구현이 흔함 component test — dialog 취소 후 error role 요소 0개 planned
quota 초과 시 UPLOAD_PART_STATE 가 memory 로 fallback 되지 않는다 fallback 이 기본 동작으로 새기 쉬움 negative fixture — quota 초과 강제 후 해당 key 의 fallback 시도가 예외로 거부되는지 planned
object URL 이 해제된다 브라우저가 누수를 조용히 허용 unit test — 대여/반납 카운트 일치 + adapter 파괴 후 미반납 0 planned
OPFS 순차 write 가 IndexedDB 보다 대용량에서 유리하다 mdn-file-system-access-opfs#C6 의 속도 우위는 File System Access API 대비이지 IndexedDB 대비가 아니다. FE-D027 의 backend 우선순위는 이 점에서 측정 근거가 없다 벤치마크 — 동일 크기 순차 write 지연을 IndexedDB·OPFS 비동기·OPFS 동기(worker) 3경로로 비교. 결과를 FE-D027 revisit trigger 에 연결 needs-confirmation
Cache Storage 버전 파티션이 release 간 오염을 막는다 SW 수명주기와 얽혀 있음 integration test — 이전 release 파티션이 새 release 에서 조회되지 않는지 planned
navigator.storage.persist() 가 대상 브라우저에서 실제로 허가된다 #C5 가 "browser may or may not honor" 로만 말한다. 허가 조건은 브라우저별 비공개 휴리스틱 대상 브라우저 매트릭스(FE-Q-007)에서 persist() 반환값 실측 + persisted() 재확인 needs-confirmation
재개 가능 전송이 Safari ITP 7일 규칙을 견딘다 #C7 에 따르면 사용자 상호작용 없이 7일 지나면 script 생성 데이터가 삭제된다. persist 미허가 시 방어 수단이 없다 Safari + ITP 환경에서 7일 경과 시나리오 재현 또는 제품이 7일 상한을 수용하는지 결정 needs-confirmation
File System Access picker 가 대상 브라우저에서 동작한다 #C1 이 "not Baseline… does not work in some of the most widely-used browsers" 로만 말하고 구체 목록을 주지 않는다 FE-Q-007 브라우저 매트릭스 확정 후 FE-NFR-C02 크로스브라우저 fixture 에서 두 경로 모두 실행 needs-confirmation
사용자 제스처 핸들러에서 await 이후 picker 를 호출하면 실패한다 #C2 는 transient activation 요구만 말하고 소모 시점을 명시하지 않는다 fixture — await 뒤 picker 호출이 거부되는지 확인. 거부되면 adapter 의 동기 호출 규칙이 필수임이 확정됨 needs-confirmation

Audit & Findings

/branch-spec 2026-07-28 조사에서 발견한 상위 계약의 사실 오류. FE-D027FE-REG-STORAGE 는 hub 소유이므로 이 branch 는 권고만 냈고, 실제 반영은 사용자 승인 후 hub §3.3 프로토콜(둘 다 compatibility_impact: none, revision 유지)로 수행했다.

Finding ID 대상 현재 서술 조사 결과 권고 처리
EVICTION_SCOPE_DRIFT hub §5.5 FE-REG-STORAGE.evictionOrder "quota 압박 시 제거 순서(정수, 낮을수록 먼저)" — 주체가 명시되지 않아 브라우저 eviction 에도 적용되는 것처럼 읽힌다 mdn-storage-quotas-eviction-persistence#C1: "When an origin's data is evicted by the browser, all of its data, not parts of it, is deleted at the same time." #C3: LRU 는 origin 단위 필드 Rule 에 "애플리케이션 주도 정리 순서. 브라우저 eviction 은 origin 전량 삭제이므로 이 순서가 적용되지 않는다" 를 추가 resolved 2026-07-28 — hub §5.5 필드 Rule + 해설 문단 반영, §6.1 개정 기록 등재
CACHE_STORAGE_CONSTRAINT_DRIFT hub FE-D027 / DEC-…-BINARY-STORE-001@1 "Cache Storage는 service worker 호스팅 response cache 전용이다" — 기술 제약처럼 읽힌다 mdn-object-url-cache-storage#C3: "you're not limited to only using it with service workers", Window.caches 로 접근 가능 결정 자체는 유효(정책 선택). §5.5 또는 FE-D027 rationale 에 "플랫폼 제약이 아니라 release coherence 를 위한 정책 선택" 임을 명시 resolved 2026-07-28 — FE-D027 서술·rationale + DEC-…-BINARY-STORE-001 Summary·Evidence 정정, 위 상속 표 동기화
NO_GROUND_TRUTH /branch-spec §2 ca-tmpl 대조 명령은 /home/donghyeon/workspace/ca-tmpl 의 registry·코드와 대조하라고 요구 ca-tmpl 은 Gradle/Java 백엔드 전용(domain-core·adapter-web·shared-contract). package.json·vite.config·.jsx 부재. frontend 구현 repo 는 hub §0.3 대로 미식별 이 branch 의 모든 명세는 planned. actually-implemented 승격은 frontend repo 식별(FE-Q-001) 이후 openFE-Q-001 해소 전까지 유지
CAPABILITY_NAME_COLLISION ca-tmpl/docs/registries/capabilities.yaml vs hub FE-REG-CAPABILITY 두 registry 가 같은 "capability" 어휘를 쓴다 ca-tmpl 은 use case → infrastructure 접근 권한(READ_REPOSITORY 등), hub 는 브라우저 런타임 기능 flag(CAP_FE_BINARY_IO 등). 다른 개념 계약을 상호 참조하지 않는다. 혼동 방지를 위해 frontend 쪽은 CAP_FE_ prefix 를 유지 accepted — prefix 유지로 종결, 추가 조치 없음

관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)

2026-07-28 /branch-spec §8b. agent dispatch 없이 수기 판정했다(세션 제약). governing doc = raw/project-notes/ca-skeleton-frontend-operational-contract. 기준은 hub §2.2 의 10개 universal acceptance question — "하나라도 비어 있으면 branch 는 documented-only 를 넘을 수 없다".

관심사 (hub §2.2) 상태 owner 심각도 근거
1. 이 contract 가 막는 concrete failure covered-here §목표 — object URL 누수, quota 초과 시 correctness 값의 조용한 memory fallback
2. input 과 output covered-here §구현 가이드 1(선택 제약 → descriptor)·3(등록 key + 바이너리 descriptor → 저장/조회/삭제 결과)
3. project-wide default 와 limit covered-here D3(기준선 <input>), D5(비동기 OPFS 기본), D6(evictionOrder 적용 범위), D7(persist 1회)
4. 허용되는 예외와 승인 owner covered-here §선언한 예외 "해당 없음" + D3·D5 의 선택 조건(브라우저 매트릭스 확정 / 블로킹 측정 시)
5. 금지 구현 covered-here §구현 가이드 2 — raw object URL 문자열 단독 반환 금지, SW 에서 object URL 생성 금지, evictionOrder: null 행 정리 금지
6. failure 가 어떤 normalized error·UX 로 나타나는가 delegated raw/branch-notes/feature-frontend-error-classification-boundary-contract D1·D3·D6 OK 본 branch 는 4개 kind 를 생산하고 정규화 총함수·UX 어휘는 error-classification 소유
7. 어떤 telemetry 가 남고 무엇이 redacted 되는가 covered-here Should-fix §구현 가이드 1 이 "파일명은 telemetry 로 보내지 않음" 을 명시하나, FE-REG-TELEMETRY 에 이 branch 전용 event 를 등록하지 않았다 — quota/eviction 관측 event 부재
8. 어떤 test 가 위반 시 실패하는가 covered-here §검증해야 할 주장 9행 + FE-GATE-027 fixture 5종
9. 어떤 evidence artifact 가 생성되는가 covered-here hub §15.1 FE-GATE-027binary I-O report
10. release·rollback 에 미치는 영향 delegated raw/branch-notes/feature-frontend-background-execution-worker-contract D2 OK Cache Storage 파티션이 release 토큰(serviceWorkerVersion)에 묶이며, rollback 시 되돌림 판정은 release branch 소유(DELEG-FE-011@1)

판정: Covered (missing 0)🔴 missing 0건, Should-fix 1건(관심사 7 telemetry event 미등록).

마주친 문제

없음.

묶음 (이 branch에서 파생된 자료)

Sub-branches (세부 작업)

아직 없음.

오류 기록 (이 branch 작업 중 발생)

아직 없음.

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

아직 없음.

강의 (이 작업을 위해 학습한 강의)

아직 없음.

job-posting tie-ins (이 작업에서 파생된 글감)

아직 없음.

관련 일일 노트

  • 아직 없음

완료 후 정리

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