Files
clean-architecture-frontend…/docs/operations/browser-file-storage-recovery.md
T

515 lines
27 KiB
Markdown

# Browser file and storage recovery runbook
이 runbook은 VD-11 capability를 실제 프로젝트에서 선택한 뒤 사용하는
production 운영 template이다. 현재 skeleton에는 native reference runtime이
`AVAILABLE_NOT_COMPOSED`로 존재하지만 제품 dataset과 bootstrap에는 연결되지
않았으므로 이 문서 자체가 현재 서비스 incident procedure를 활성화하지 않는다.
설치 branch는 owner, dashboard, alert threshold, kill-switch key,
backend/storage 연락처와 evidence 위치를 채워야 한다.
VD-15가 설계한 origin-wide pressure/GC coordinator, OPFS/Cache forward
migration, OPFS real readiness preflight, bounded Cache cleanup과 preview decode
probe는 현재 `DESIGNED_NOT_IMPLEMENTED`다. 아래 절차에서 이 기능을 전제로 한
자동 조치는 해당 runtime이 구현·조합된 제품에서만 실행한다. 현재 reference
primitive를 coordinator 완료 증거로 사용하지 않는다.
## 1. 공통 원칙
incident 중에도 다음 작업은 금지한다.
- 자동 또는 일괄 `deleteDatabase()`
- origin의 모든 `caches.keys()` 삭제
- user-authored/unsynced IndexedDB 또는 OPFS data 자동 purge
- schema version downgrade
- 무한 reload/update loop
- filename, path, record/object key, URL/query, digest, body를 incident log에 복사
- fake/unavailable adapter로 바꾸고 정상 복구로 선언
공통 안전한 degrade 순서는 다음과 같다.
```text
선택 capability의 신규 write/activation 중지
-> 진행 중 operation 정리
-> read-only
-> online-only/network-only
-> authoritative server re-read
```
read-only나 online-only가 사용자 작성 내용을 잃게 한다면 먼저 export/sync
경로를 제공하고 UI에 명시적으로 알린다.
## 2. 최초 10분
1. 영향 release, browser family/version, capability와 최초 발생 시각을 확인한다.
2. user dismissal과 실제 failure를 분리한다.
3. safe metric의 `failure_kind`, `phase`, `strategy`, `backend`, `size_bucket`,
`release_id`만으로 범위를 좁힌다.
4. integrity mismatch, authorization/cache classification breach, committed
user-data corruption이면 신규 write/cache activation을 즉시 중지한다.
5. kill switch를 가장 좁은 범위로 적용한다.
6. current와 N-1 release의 schema/cache compatibility를 확인한다.
7. 복구 전후 diagnostic count와 browser smoke evidence를 저장한다.
심각도 시작점:
| 상황 | 시작 심각도 |
| --- | --- |
| authorization 우회, private/auth response cache, content integrity mismatch | P1 |
| committed user-authored data unreadable/corrupt, widespread migration failure | P1 |
| upload/download 실패 급증, IndexedDB blocked 증가, OPFS reconstructable loss | P2 |
| enhanced picker만 실패하고 baseline 정상 | P3 |
실제 조직 severity policy가 있으면 그 정책이 우선한다.
## 3. File/picker/download와 별도 upload example
### 신호
- `PERMISSION_DENIED`, `NOT_READABLE`, `INTEGRITY_FAILED`
- closed byte stream이 failure chunk 뒤 추가 byte를 내보내거나 raw exception을 throw
- browser handoff는 정상인데 confirmed save가 감소
- large download에서 memory/stall failure
- 별도 backend upload를 설치한 feature만 session expiry/conflict,
quarantined/available 전환 정체
### 확인 순서
1. 사용자가 실제 취소한 flow가 error로 집계되지 않았는지 확인한다.
2. user activation 전에 비동기 작업이 추가됐는지 확인한다.
3. native input fallback이 Chromium/Firefox/WebKit에서 동작하는지 확인한다.
4. count, per-file, total bytes, MIME/extension/signature policy version을 확인한다.
raw policy가 port caller에서 들어오지 않고 composition registry의 정확한
`FilePolicyReference` identity로 resolve되는지, verification receipt가 같은
profile/file snapshot에 binding됐는지 확인한다. 같은
`policyKey`/`intention`을 가진 새 객체는 거절되어야 한다.
5. File/OPFS/Cache/download byte source가 chunk마다 closed Result를 반환하고 첫
failure에서 consumer와 producer 모두 종료되는지 확인한다.
6. download `Content-Type`, `Content-Disposition`, CORS exposed header와
short-lived capability expiry를 확인한다. browser-managed resolver receipt가
caller의 branded receipt와 정확히 같고 resource ID, media type, safe
extension, server max, optional digest와 expiry를 synchronous하게 정확히
binding하는지 확인한다.
현재 save path는 whole-object foreground streaming이며 Range resume가 아니다.
partial destination에 append하지 않고, Range를 선택한 제품은 VD-14와
browser-transfer runbook의 별도 절차를 따른다.
7. whole-buffer API 또는 object URL lease 누수가 배포됐는지 확인한다.
8. image preview를 설치했다면 object URL 발급 전에 header dimensions, pixel,
decoded-byte와 animation/static-only 제한을 검사하는 VD-15 probe가 실제
조합됐는지 확인한다. 현재 byte/signature 검사만으로 decode safety를
주장하지 않는다.
9. upload를 별도 설치했다면 backend 401/403/409/413/415/422/429/5xx,
CORS/preflight, session TTL/clock skew, part checksum, idempotency, orphan
cleanup과 quarantine queue를 그 feature runbook에서 확인한다.
### 안전한 조치
- enhanced open/save picker off → native input/direct authorized download
- active-content preview off
- preview pixel/decode/frame probe가 없거나 실패하면 object URL preview off
- client-generated large download off → server-side artifact generation
- broken stream adapter off → bounded fallback 또는 operation 중지; raw exception을
성공/EOF로 변환하지 않음
- upload를 별도 설치했다면 multipart concurrency/part size 하향,
resumable off → approved hard cap의 simple upload, 문제 MIME 임시 차단
- expired upload session은 authorization 후 새 session; 기존 session을
재활성화하지 않음
성공 판정:
- user cancellation 제외 file/download start 대비 success rate 회복
- integrity/authorization mismatch 0
- 세 browser baseline smoke 통과
- object URL/file ref cleanup count 0 leak
- preview를 설치한 경우 malformed/oversize/animated image가 object URL 발급
전에 거절되고 native decode resource 0 leak
- upload를 별도 설치했다면 orphan session/quarantine backlog SLO와 session
cleanup 0 leak
## 4. IndexedDB upgrade blocked/versionchange
### 신호
- `BLOCKED`, `UPGRADE_BLOCKED` 또는 blocked duration bucket 증가
- `versionchange` 뒤 connection이 남음
- repeated reload/update loop
- open/maintenance의 `POLICY_REJECTED`: immutable dataset binding missing/mismatch
### 확인 순서
1. target schema와 current/future schema, release ID를 확인한다.
2. registry-issued `authorityToken`, `namespaceToken`, `partitionToken`이 같은
dataset의 승인된 값인지 확인한다. readable namespace/account/business ID를
token이나 physical DB name에 넣지 않는다.
3. physical DB name이 세 opaque token에서만 파생됐는지, caller
`databaseNameAssertion`이 exact match인지 확인한다.
4. governance store의 immutable scope + full `BrowserStoragePolicy` binding을
versionchange, post-open, maintenance 모두에서 확인한다. raw token이나 binding
내용을 incident log에 복사하지 않는다.
5. old tab, worker 또는 test/debug context가 connection을 닫지 않는지 확인한다.
6. 모든 connection에 `versionchange`/forced-close handler가 설치됐는지 확인한다.
7. BroadcastChannel prepare hint는 참고만 하고 실제 open/connection registry를
확인한다.
8. N-1 bundle이 future schema를 read-only/online-only로 처리하는지 확인한다.
### 안전한 조치
- 신규 offline write와 background migration 중지
- 사용자에게 다른 tab close와 명시적 retry UI 제공
- current connection을 draining 후 close
- upgrade release rollout 중지 또는 compatible N-1 online-only로 rollback
- binding mismatch를 caller DB 이름 변경, policy 덮어쓰기 또는 DB 전체 삭제로
우회하지 않고 registry/composition 오류를 forward fix
remote tab 강제 종료, database 삭제, 무한 reload는 금지한다.
성공 판정:
- connection registry와 blocked request 0
- fresh tab과 two-tab versionchange/blocked smoke 통과
- future schema에서 N-1이 destructive write 없이 기동
- open과 maintenance에서 동일 scope/policy binding 검증 통과
## 5. IndexedDB migration/corruption
### 신호
- `MIGRATION_FAILED`, unknown codec, schema postcondition failure
- `CORRUPT_DATA`, `NOT_READABLE`, forced close
- transaction request success 후 commit failure
- `LIMIT_EXCEEDED`: dataset logical byte/receipt budget 초과
- lifecycle batch가 proof 없이 실행되거나 TTL/UNTIL_SYNCED record가 잘못 노출·삭제
- migration/lifecycle batch가 500 rows 또는 30,000ms를 넘거나 checkpoint 없이 중단
### 확인 순서
1. DDL schema version과 record codec version을 구분한다.
2. migration ID, last safe keyset checkpoint, revision fence,
`budgetExhausted`, processed/remaining bucket과 old-writer drain proof를
확인한다.
3. caller budget과 구현 absolute budget(500 rows/30,000ms), async operation 사이
deadline check를 확인한다.
4. codec `measureStoredBytes`, retention sidecar `measuredBytes`,
`dataset-budget.usedBytes/receiptCount`가 CAS/remove/lifecycle/migration
transaction과 함께 갱신됐는지 확인한다. 이 값은 native physical size가 아니다.
5. actual `StoredRecord``key/codecVersion/revision/payload`만 포함하고
`writtenAtEpochMs`, synchronization, `measuredBytes`, `eligibleAtEpochMs`
`retentionStore` sidecar에 분리돼 있는지 확인한다.
6. receipt retention이 31일 이하인지, configured `maxIdempotencyReceipts`
1,000,000 이하인지, prune/purge가 receipt count를 같은 transaction에서
감소시켰는지 확인한다.
7. TTL record가 sweep 전 read에서 `EXPIRED_RESOURCE`, query에서 skip되는지,
`UNTIL_SYNCED``CONFIRMED`만 eligible한지 확인한다.
8. lifecycle action마다 composition의
`authorizeLifecycle(action, scope, frozen policy)`가 호출됐고 opaque proof가
검증 후 비영속·비관측 상태로 폐기됐는지 확인한다.
9. historical schema fixture에서 같은 migration을 재현한다.
10. reconstructable, synced copy, unsynced/user-authored 분류를 확인한다.
11. partial batch가 row/sidecar/budget/checkpoint와 원자적으로 rollback됐는지
확인한다.
12. full partition purge가 record/retention/idempotency와 등록된 모든
`lifecycleMetadataStores`를 bounded transaction으로 정리하고 immutable
governance binding은 유지하는지 확인한다.
13. raw record, opaque scope/proof를 ticket/log에 복사하지 않고 승인된 local
recovery tooling만
사용한다.
### 안전한 조치
- migration 중지, repository read-only/online-only
- reconstructable만 purge/re-fetch
- synced copy는 revision 확인 후 rehydrate
- unsynced/user-authored는 quarantine marker + export/sync/recovery
- adapter bounded reopen 최대 한 번
- schema/codec compatible fix를 새 forward migration으로 배포
- migration은 old-writer drain authority를 복구한 뒤 더 작은 bounded batch로
checkpoint부터 resume
- lifecycle authority가 불명확하면 deletion을 재시도하지 않고 read-only;
proof를 운영자가 수동 생성·재사용하지 않음
database 전체 삭제는 data owner가 export/recovery와 영향 scope를 승인한 별도
action이다.
성공 판정:
- historical fixture의 fresh, interrupted, resume, replay가 모두 통과
- corrupted user-authored row 자동 삭제 0
- migration canary failure 0
- N-1 rollback/read-only smoke 통과
- dataset budget/sidecar/receipt count 재검증과 bounded lifecycle fixture 통과
## 6. Origin quota, persistence denial, storage eviction
### 신호
- usage ratio pressure bucket 증가
- `QUOTA_EXCEEDED`, `STORAGE_EVICTED`
- startup sentinel과 logical manifest 불일치
- persistence request denied
### 확인 순서
1. `estimate()`가 rough origin total임을 전제로 IndexedDB/OPFS/Cache 공동 증가를
확인한다.
2. exact free space를 계산하거나 예약했다고 가정하지 않는다.
3. expired/reconstructable, synced copy, user-authored 사용량 bucket을 분리한다.
4. IndexedDB의 exact logical dataset budget과 origin-wide `estimate()`
구분한다. 전자는 codec measurement + conservative reservation이고 native
physical usage/free space가 아니다.
5. private mode, WebView, browser storage policy와 user clear 여부를 확인한다.
6. persistence denial을 capability failure가 아닌 best-effort outcome으로 처리했는지
확인한다.
### 안전한 조치
현재 공통 coordinator가 없으면 다음 순서를 자동 실행하거나 “exact one retry”를
보장한다고 기록하지 않는다. 제품 owner가 store별 primitive와 retention policy를
확인해 수동/feature-local로 안전하게 수행하거나 write를 read-only/online-only로
닫는다. VD-15 coordinator가 조합된 경우에만 동일 mutation owner 안에서 다음을
bounded orchestration으로 실행한다.
1. 신규 speculative/reconstructable write admission 중지
2. incomplete candidate와 stale staging 제거
3. expired reconstructable record/object 제거
4. grace가 지난 unreferenced immutable chunk 제거
5. inactive public cache release 제거
6. authoritative revision/sync receipt가 확인된 synced copy compact
7. unsynced/user-authored sync/export UI
8. 필요하면 offline read-only/online-only
각 GC invocation은 기본 100 items/5초, 구현 절대 상한 500 items/30초와 opaque
cursor를 지킨다. failed write의 자동 retry는 다음 조건이 모두 맞을 때만 정확히
한 번 허용한다.
- 첫 write가 실제 quota failure로 원자적 rollback됨
- 같은 idempotency key, revision fence와 payload digest
- 외부 side effect/cross-store publish가 commit되지 않음
- bounded GC가 실제 candidate를 제거했거나 pressure가 내려감
- 현재 revision/generation 재확인과 새 admission token 발급
두 번째 failure나 effect certainty가 unknown이면 retry하지 않는다.
`persist()`를 boot나 반복 loop에서 요청하지 않는다. 사용자가 durable offline
기능을 선택하고 unsynced data 보호 이유를 이해하는 동작에서만 요청한다.
성공 판정:
- coordinator를 설치한 경우 pressure가 hysteresis lower bound 아래
- partial logical/physical marker mismatch는 rehydrate 또는 explicit
read-only/export-required로 닫힘
- 모든 local marker가 소실된 경우 backend opaque installation epoch로
authorization 후 구분하거나 `storage-reset-possible` ambiguity UX를 표시함;
이를 “첫 설치로 판별 완료”라고 기록하지 않음
- user-authored 자동 purge 0
- storage clear 뒤 reconstructable rehydrate/explicit degraded UI 통과
## 7. OPFS partial write/corruption/worker crash
현재 capability/property probe와 native conformance test는 존재하지만 composition
readiness에서 worker/lock/journal/small write-read-delete-cleanup을 한 번에
검증하는 real preflight는 아직 없다. preflight success를 운영 전제에 넣으려면
VD-15 목표 runtime을 먼저 구현한다.
### 신호
- journal이 `PREPARING`/`FILES_READY`에 오래 머묾
- committed logical row와 physical manifest/file 불일치
- digest/length mismatch
- worker crash, handle lock timeout, `NoModificationAllowedError`
- sensitive policy maintenance의 `POLICY_REJECTED`, proof replay/expiry 또는
authority provider/consumer unavailable
### 확인 순서
1. mutation Web Lock owner와 timeout을 확인한다.
2. worker protocol/version과 모든 sync handle의 `finally close`를 확인한다.
3. journal operation phase별 count와 age bucket을 확인한다.
4. VD-15 forward migrator를 설치하지 않은 현재 v1 reference runtime에서는
physical layout이
`/ca-frontend-opfs-v1/authorities/<authorityToken>/<namespaceToken>/<partitionToken>/`
아래의 `objects`, `chunks/sha256`, `staging`인지 확인한다. readable namespace,
filename, account ID가 path segment이면 신규 write를 중지한다. migrator를
설치한 조합에는 이 v1 path를 authoritative target 조건으로 적용하지 않는다.
5. journal의 physical scope binding과 logical namespace binding이 둘 다 존재하고,
같은 scope/policy fingerprint를 가리키는지 확인한다. 한쪽만 없거나 mismatch면
자동 재생성하지 않는다.
6. runtime/byte-store composition의 frozen scope와 policy namespace가 일치하는지
확인한다.
7. `LOGOUT`, `UNTIL_SYNCED`, `ACCOUNT_DELETION` maintenance에는 composition의
`requestMaintenanceAuthority` provider와 `consumeMaintenanceAuthority`
consumer가 둘 다 주입됐는지 확인한다. application request에는 proof 필드가
없어야 한다.
8. provider가 exact reason/frozen scope/frozen policy에 묶인 새 proof와 최대
5분 expiry를 발급하고, consumer가 같은 binding을 원자적으로 검증·consume해
replay를 거절하는지 확인한다. proof/token/raw scope는 log에 복사하지 않는다.
9. physical path/ID/digest를 log에 복사하지 않고 reconciliation tool이
manifest schema와 digest를 검증하게 한다.
10. logical row가 commit authority인지 확인한다.
11. VD-15 forward migrator를 설치했다면 source/target physical layout와 journal
version, migration checkpoint, copy-on-write generation, publish authority,
rollback window와 N-1 reader 결과를 확인한다.
### recovery
- `PREPARING`: partial staging 검증 후 idempotent resume 또는 purge
- `FILES_READY`: expected generation/digest 일치 시 logical commit, 아니면
quarantine
- `COMMITTED` + file missing/corrupt: reconstructable만 server rehydrate;
user-created private는 read-only/export/recovery
- stale staging/orphan chunk는 grace period와 bounded mark/sweep 후 제거
- lock/worker 문제면 OPFS write off → approved capped fallback 또는 online-only
- scope binding mismatch면 affected scope를 read-only로 격리하고 registry/
composition을 forward fix; 다른 token path로 bytes를 이동하거나 추측 복구 금지
- sensitive maintenance authority provider/consumer가 없거나 replay/expiry
검증이 실패하면 삭제를 재시도하지 않고 read-only로 전환한다. 운영자가 proof를
직접 생성·주입·재사용하지 않는다.
- forward migration 중단이면 target generation을 publish하지 않고 bounded
checkpoint에서 resume한다. publish 뒤에는 source generation을 rollback
window까지 보존하고, N-1이 target을 이해하지 못하면 read-only/online-only로
닫는다. source/target을 in-place 혼합하거나 layout version을 내리지 않는다.
committed object를 sync handle로 in-place repair하지 않는다. 새 generation에
정상 object를 만들고 generation CAS로 logical pointer를 전환한다.
성공 판정:
- unresolved old journal 0
- committed read integrity failure 0
- worker/handle registry 0 leak
- 각 journal phase fault injection과 concurrent put/delete/GC 통과
- sensitive maintenance의 fresh proof consume 성공, replay/expired/mismatched
proof와 provider/consumer 누락은 모두 deletion 전 fail-closed
## 8. Cache Storage/Service Worker stale or poisoned release
public static Cache release runtime은 존재하지만 cursor/count/deadline이 있는
bounded inspect/cleanup과 Service Worker waiting/client-drain controller는 아직
없다. Service Worker는 제품이 PWA/offline fetch를 별도로 선택한 경우에만 아래
worker 절차를 적용한다.
### 신호
- incomplete candidate activation
- integrity/type/size mismatch
- auth/private/no-store/opaque policy rejection
- Service Worker를 별도 선택한 조합의 stale worker/update/reload loop
- active asset miss 또는 offline boot failure
### 확인 순서
1. hosting/CDN cache와 browser Cache Storage를 별개로 확인한다.
2. active/candidate/previous release ID와 manifest digest를 확인한다.
3. candidate 모든 entry의 status, `expectedContentType`, size, integrity 검증
marker를 확인한다. canonical manifest digest가 정규화된 Content-Type까지
binding하는지 확인한다.
4. 실제 response의 정규화된 `Content-Type`과 manifest
`expectedContentType`이 정확히 일치하는지 확인한다. body digest가 맞아도 type
mismatch candidate는 폐기한다.
5. config/release manifest/auth/API가 network-only인지 확인한다.
6. query/Vary exact match와 `ignoreSearch/ignoreVary` 미사용을 확인한다.
7. Service Worker를 별도 선택했다면 old controlled clients와 current
waiting/active worker 상태를 확인한다.
8. Service Worker를 별도 선택했다면 unregister만 하고 owned cache cleanup을
빠뜨리지 않았는지 확인한다.
9. cleanup caller가 cache name, release registry ID 또는 retain list를 제출할 수
없고 보존 집합이 verified active pointer와 composition retention에서만
계산되는지 확인한다.
10. active pointer/release marker control JSON이 정확히 2 MiB(2,097,152 bytes)
cap의 stream reader와 strict UTF-8/runtime schema를 통과하며 oversized body를
초과 지점에서 cancel하는지 확인한다.
### 안전한 조치
static Cache-only 조합:
- 신규 candidate activation/cache write 중지
- verified current 또는 previous release로 explicit rollback
- incomplete candidate와 runtime-public cache부터 owned-prefix cleanup
- 현재 cleanup/inspect가 cache 개수에 대해 unbounded임을 고려해 incident
invocation을 추가 budget으로 반복 실행하지 않는다. VD-15 bounded cursor
runtime 구현 전에는 큰 namespace를 자동 sweep하지 않는다.
Service Worker를 별도 선택한 조합에서만 추가:
- fetch interception을 network-only kill switch로 전환
- new worker activation 중지
- 필요하면 unregister + 다음 navigation cleanup migration
- old controlled client가 drain되기 전 해당 release cleanup 금지
hosting/CDN purge는 두 branch와 분리된 provider 절차로 실행한다.
auth/private response가 cache에 실제 저장됐을 가능성이 있으면 P1로 승격하고
owned affected namespace를 정확히 식별해 제거한다. origin의 unrelated cache는
삭제하지 않는다.
성공 판정:
- static Cache-only 조합은 verified active/previous release와 candidate cleanup이
일관되고 network-only fallback smoke를 통과
- Service Worker를 별도 선택한 조합만 clean/old controlled client가 같은
verified release로 수렴하고 online/offline/update/rollback smoke를 통과
- auth/private cache entry 0
- update/reload loop 0
- config/release manifest network-only header contract 통과
## 9. Drill evidence
실제 capability를 project catalog의 `INSTALLED`로 바꾸기 전에 최소 다음 drill을
실행하고 release-specific evidence를 저장한다. 이 legacy selection label은
primary status `COMPOSED`와 별도
`TrafficAdmission/RuntimeHealth/PromotionEvidence` 축이 준비된 제품 상태를
뜻하며 새로운 primary status literal이 아니다. 각 축의 literal과
contract/provider/browser/operations component gate에서 `PromotionEvidence`
계산하는 규칙은 completion ledger를 그대로 따른다.
| drill | 필수 증적 |
| --- | --- |
| 별도 upload workflow를 설치한 경우 session abort/expiry/checksum | orphan cleanup, quarantine state, retry/idempotency |
| large save abort/integrity | partial commit 0, memory high-water |
| IndexedDB two-tab upgrade blocked | close/retry UX, connection leak 0 |
| IndexedDB governance/lifecycle | opaque scope binding, logical budget/TTL, proof discard, receipt cap |
| interrupted historical migration | old-writer drain proof, 500 rows/30s budget, checkpoint resume, atomicity, N-1 fallback |
| quota/persistence denied/storage clear | reconstructable GC, user data 보존, degraded UI |
| VD-15 coordinator를 설치한 경우 pressure/one-retry | hysteresis, bounded cursor/deadline, store priority와 retry 최대 1회 |
| OPFS journal phase crash/scope mismatch/maintenance authority | bidirectional binding, actual opaque layout, invisible partial object, reconcile summary, integrity, provider/consumer one-time proof |
| OPFS preflight/migration을 설치한 경우 | worker/lock/journal/small operation cleanup, interrupted copy-on-write와 N-1 fallback |
| cache candidate poison/update rollback | expectedContentType binding, active release 불변, previous rollback, caller retain 부재, 2 MiB control cap, auth rejection |
| bounded Cache/SW lifecycle을 설치한 경우 | cursor/count/deadline, waiting activation, controlled-client drain과 network-only rollback |
| preview probe를 설치한 경우 | pixel/decoded-byte/static-only rejection, timeout와 decode resource cleanup |
evidence에는 raw 사용자 data를 포함하지 않는다. 허용 metadata는 release/build,
browser engine/version, fixture ID, fault phase, bounded counts/buckets와 PASS/FAIL
결과뿐이다.
promotion 직전에는 다음 repository evidence도 함께 보존한다.
- `test:browser-capabilities`가 만든 JUnit에서 Chromium, Firefox, WebKit이 동일
14개 testcase set(File 2, IndexedDB 4, OPFS/Cache/StorageManager 각 1,
cross-context invalidation 2, presigned streaming download/multipart
upload/Image CDN 각 1)을 실제 실행해 총 42개이며 failure/error/skipped가 모두
0이어야 한다.
`verify:browser-capability-evidence`가 engine 집합과 testcase 동일성을
기계적으로 검증한다. 현재 artifact는 Chromium/Firefox 14개씩 총 28개가
통과했지만 WebKit 실행에 필요한 native libraries(예:
`libbacktrace.so.0`, `libevent-2.1.so.7`, `libjxl.so.0.8`,
`libavif.so.16`과 WPE 계열)가 이 host에 없으므로 아직 promotion 가능 상태가
아니다.
- `artifacts/quality/vite-module-inventory.json`에서 optional runtime source root가
production chunk에 없음을 `check:optional-recipes`로 검증한다.
- `check:browser-file-storage-boundaries`로 native API 경계 위반을 막고,
`test:browser-file-storage-removal`로 runtime과 전용 gate를 제거한 격리 copy가
base typecheck/lint/architecture/test/build/catalog/CI contract를 통과함을
검증한다.
- catalog의 `referenceRuntime.status``AVAILABLE_NOT_COMPOSED`,
`productionComposition``false`로 유지한다. dataset owner가 모든 policy와
evidence를 승인하고 실제 composition을 추가하기 전에는 `INSTALLED`
해석하지 않는다.
## 10. 관련 문서
- [Browser data capability completion ledger](../architecture/browser-data-capability-completion-ledger.md)
- [Browser file and origin-storage platform](../architecture/browser-file-and-origin-storage.md)
- [VD-11 Browser file and origin-storage 경계](../architecture/decisions/VD-11-browser-file-and-origin-storage.md)
- [VD-15 Origin storage lifecycle and migration](../architecture/decisions/VD-15-origin-storage-lifecycle-and-migration.md)
- [VD-14 Resumable download와 background download](../architecture/decisions/VD-14-resumable-download-and-background-transfer.md)
- [Browser transfer recovery](./browser-transfer-recovery.md)