Files
clean-architecture-frontend…/docs/reviews/adapters
DongHyeonkaandClaude Opus 5 f4bfdf0365 fix: close the live V3 authority findings from the adapter re-review
LIVE-01. A credential collaborator that returns UNAVAILABLE, throws, rejects
or answers off-contract is an outage of the auth integration, not evidence
about the user's session. Each of those now closes as AUTH_INTEGRATION_FAILURE
with zero fetches, so the composition root's logout path stays reserved for a
genuinely absent session. The synchronous and asynchronous failure sites share
one classifier.

LIVE-02 / LIVE-03. Object.freeze(new Map(...)) freezes the wrapper, not the
backing store, so an exported registry could still be cleared or replaced after
composition. Both the installed REST auth profile registry and the composed
HTTP/event lookups are now read facades over private stores, and every composed
row is an exact own-data snapshot that rejects accessors, inherited and
symbol-keyed fields.

LIVE-04. The total deadline now bounds the physical waits rather than being
checked between them: dispatch and response admission race the attempt signal,
the bounded reader takes that signal, and an abandoned operation is still
observed once so a late native rejection cannot surface unhandled. A body that
completes after the deadline or the caller owns the execution is no longer
admitted; a stale generation keeps its more specific SCOPE_FENCED verdict.

LIVE-05. DEADLINE is no longer treated as a caller-owned cancellation, so a
timeout reaches api.request.failed exactly once while caller, route, scope and
shutdown aborts stay excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 13:43:59 +09:00
..

Adapter 전수 리뷰 — 통합 인덱스와 확정 결정

검토 기준: develop / 4dc033cf33a5b6173bbf960d5eb464a406dc4c92 (2026-08-13)

검토 범위: src/adapters/**의 117개 TypeScript 파일과 1개 README, 총 53,475 TypeScript LOC. 직접 연결된 contracts, application ports, bootstrap composition, feature gateway, unit/integration test, ADR와 운영 문서를 함께 대조했다.

결론

adapter 계층의 큰 방향은 유지할 가치가 있다. native 객체와 raw provider material을 application 경계 밖에 두고, strict decoder·immutable capability·generation fence·bounded queue·typed failure를 사용하며, 선택되지 않은 capability를 조용히 fallback하지 않는 구조는 일관적이다. 정적 architecture gate도 현재 계층 위반을 찾지 않았다.

반면 lifecycle과 effect certainty에는 반복되는 공백이 있다. 가장 높은 위험은 OPFS 보상 정리의 journal 순서이며, 현재 조립 경로에서는 V3 HTTP 관찰 전체 유실, auth profile 미강제, retry 중 command effect 하향, telemetry의 dispose 이후 동작이 우선 수정 대상이다. 선택되지 않은 realtime, Browser RPC, Web Push, image/transfer capability의 결함은 현재 production incident로 과장하지 않되, 해당 capability를 조립하기 전 필수 promotion gate로 둔다.

이 문서와 하위 리뷰는 구현자가 추가 제품 결정을 요청하지 않도록 다음을 고정한다.

  • 현재 코드로 재현되는 결함, contract gap, 구조 리팩터링, 문서화된 미구현을 분리한다.
  • 각 finding마다 적용 패턴, 수정할 파일/API, 테스트 이름과 기대 결과, migration·deployment·rollback을 지정한다.
  • 기존 public facade와 persisted/wire V1 호환을 언제 유지하고 언제 version-up할지 명시한다.
  • default bootstrap에 optional capability를 새로 조립하지 않는다. 구현과 browser/provider evidence가 준비된 뒤 별도 product selection으로 승격한다.

보고서 구성과 범위

문서 구현 범위 파일 수 핵심 주제
01 — Network and state http, auth, query-cache, cross-context-invalidation, platform, diagnostics, telemetry 24 HTTP authority/effect, diagnostics·telemetry, ETag key, cancellation
02 — Realtime and Browser RPC realtime, browser-rpc 21 stream lease, DRAINING, handoff writer, immutable binding, backpressure
03 — Storage and browser files storage, browser-files, browser-file-storage, cache-storage 32 OPFS saga, IndexedDB maintenance, file URL, public cache, quota/migration
04 — Browser transfer browser-transfer 24 presigned capability, resumable upload, image CDN
05 — Service Worker and Web Push service-worker, web-push 17 cache ownership, activation/removal, worker protocol, push authority

합계는 118/118 파일이다. 전수 inventory가 full path와 상세 리뷰를 일대일로 연결하고, 각 하위 문서의 파일 표가 책임, 직접 dependency/downstream, 판정을 기록한다.

최우선 finding

순서 ID 상태/심각도 확정 영향 구현 결정
1 STO-01 확정 / Critical OPFS pre-commit cleanup 실패·취소 뒤 journal을 지워 복구 근거를 잃고, 늦은 generation-only cleanup이 후속 write를 삭제할 수 있다. cleanup 확인 전 journal/budget rollback 금지, compensation signal 분리, transaction-unique physical generation token, cleanup 종료까지 mutation lease 유지
2 N-01 확정 / High / 현재 V3 HTTP V3 observation의 미허용 context key 때문에 모든 request diagnostic이 drop되고 terminal failure telemetry도 없다. typed observation을 closed diagnostic/telemetry bucket으로 투영하고 route ID를 executor context에 보존
3 N-02 확정 / High / 현재 V3 authProfileId가 조립·강제되지 않아 bearer 필수 header와 transport-owned credentials/header invariant를 증명하지 못한다. immutable auth Profile/Strategy registry, credential owner는 허용된 proof header만 제공, missing/extra는 fetch 전 fail-close
4 N-03 확정 / High 이미 dispatch된 command가 retry-time scope fence에서 MAYBE_APPLIED에서 NOT_STARTED로 하향될 수 있다. logical execution 전체에 monotonic effect-certainty join 적용
5 N-04 확정 / High telemetry가 dispose 뒤 scheduled/new/in-flight delivery를 계속하고 composition teardown이 dispose를 호출하지 않는다. ACTIVE/DISPOSED, joined flush, in-flight abort, infrastructure teardown 연결
6 STO-02 확정 / High download URL은 baseOrigin으로 검증하지만 원문 상대 URL은 document.baseURI로 실행된다. parse-once canonical absolute URL만 handoff
7 SW-URL-01, SW-01~SW-05 확정/gap / P1 generated URL 분류 불일치, stale static response 선택, 과도한 prefix delete, 거짓 unregister/removal success, manifest 검증 부재 canonical absolute runtime URL set, current-cache-only lookup, exact ownership parser, truthful cleanup result, shared strict manifest codec
8 WP-01~WP-03 확정/gap / P1 / 미조립 fence revision·mutation effect·backend authority receipt가 충분히 묶이지 않는다. exact next revision, unknown effect recovery, V2 full authority/request binding receipt
9 R-01~R-04 확정 / High / 미조립 non-cooperative stream/effect가 무한 대기하거나 active writer가 유실되고 Browser RPC binding이 TOCTOU다. explicit stream lease, retained DRAINING registry, retired writer set, immutable parse/validate/install
10 BT-PRE-01, BT-PRE-02, BT-UP-03 확정/gap / P1 / 미조립 eager download 자원 누수, wire envelope version 부재, late IndexedDB delete effect 오보고 lazy closeable lease, protocol literal, PENDING/effect UNKNOWN outcome

하위 문서의 나머지 Medium/P2/P3 항목도 생략 대상이 아니다. 위 표는 release·promotion을 막는 순서만 압축한 것이다.

공통 설계 결정

D-01 — effect certainty는 단조 증가한다

한 번 native/network mutation을 dispatch한 뒤에는 새 retry가 아직 시작되지 않았다는 이유로 전체 logical operation을 NOT_STARTED로 되돌리지 않는다. 결과는 NOT_STARTED → NOT_APPLIED/MAYBE_APPLIED → APPLIED_CONFIRMED의 보수적 lattice로 join한다. IndexedDB/OPFS/Web Push처럼 deadline 뒤 native commit 가능성을 취소할 수 없는 API는 UNKNOWN을 명시하고 bounded read-back/reconcile만 허용한다.

D-02 — commit fence와 resource settlement를 분리한다

abort/deadline 시 late commit capability는 즉시 폐기하지만, non-cooperative Promise·stream·writer reference는 실제 settlement까지 버리지 않는다. public wait은 bounded하게 끝내되 내부 lifecycle은 DRAINING으로 남고 같은 physical owner의 신규 admission을 막는다. close()가 성공했다면 tracked task가 실제로 quiescent여야 한다.

D-03 — 외부/조립 입력은 parse → validate → install한다

TypeScript Readonly나 한 번의 boolean validator를 runtime immutability로 취급하지 않는다. registry, contract binding, provider response는 exact own-data descriptor와 closed key set을 검사한 immutable snapshot으로 설치하고 이후 원본을 다시 읽지 않는다. getter, extra/symbol key, revoked proxy는 composition/decoder 경계에서 fail-close한다.

D-04 — 검증한 값을 그대로 실행한다

URL·path·header·manifest는 parse-once canonical form을 반환하고 network/navigation/cache operation은 그 canonical 값을 사용한다. boolean 검증 후 원문을 다른 base/decoder로 다시 해석하지 않는다. provider별 double-decode 가능성이 있는 encoded separator는 계약 fixture로 닫는다.

D-05 — marker와 hint는 권위가 아니다

cache release marker는 “작성 완료 주장”일 뿐 모든 entry의 존재·digest 증거가 아니다. BroadcastChannel/storage event와 realtime cancellation은 hint이며 server/CAS/generation authority를 대신하지 않는다. 재사용·activation·복구 경로는 exact identity와 content를 다시 검증한다.

D-06 — operation별 최소 dependency만 요구한다

stage에는 fetch가 필요하지만 local activate/cleanup에는 필요하지 않다. capability availability를 편의상 하나의 공통 guard로 묶지 않고 operation별로 분리한다. offline rollback/cleanup을 네트워크 부재 때문에 차단하지 않는다.

D-07 — state machine과 Saga 경계로만 큰 runtime을 나눈다

파일 길이만으로 분해하지 않는다. 먼저 facade의 success/failure/cancel/call-order characterization을 고정한 뒤 순수 transition, retry policy, bounded scheduler, persistence reconciler, compensation saga를 추출한다. public capability identity, failure taxonomy, persisted schema, wire semantics는 별도 versioned migration 없이는 바꾸지 않는다.

D-08 — abort/deadline mechanics만 공유한다

listener/timer 정리, first-terminal-owner, late rejection 관찰, late native handle compensation은 platform utility로 통합할 수 있다. HTTP, browser data, Web Push, realtime의 result taxonomy와 recovery vocabulary는 각 adapter에 남긴다. 범용 middleware/interceptor나 하나의 generic repository로 합치지 않는다.

D-09 — optional capability의 미조립 상태를 유지한다

AVAILABLE_NOT_COMPOSED, DESIGNED_NOT_IMPLEMENTED, NOT_SELECTED는 defect status가 아니다. realtime, Browser RPC, Web Push, resumable upload, image provider, storage coordinator를 이번 remediation만으로 default bootstrap에 설치하지 않는다. 관련 P1/P2 closure, actual browser/provider/load evidence, product-owned policy·consent·registry가 모두 준비되어야 별도 selection change를 연다.

구현 순서

서로 다른 subsystem을 한 PR에 섞지 않는다. 각 항목은 failing characterization → 최소 수정 → focused green → type/architecture/lint → commit 순서다.

  1. Containment: product-specific composition에서 OPFS v1 writer 사용 여부를 확인하고, 사용 중이면 신규 write admission을 read-only/export-required로 닫는다. template 기본 bootstrap은 OPFS를 조립하지 않는다.
  2. 현재 실행 경로: STO-01, N-01~N-04, STO-02를 독립 PR로 수정한다.
  3. 기존 rollback/sidecar: N-05~N-11과 legacy HTTP V2 hardening을 처리한다. V2를 지우는 일은 zero-caller와 rollback-window 종료 뒤 별도 PR이다.
  4. 선택 capability correctness: SW-URL-01, SW-01SW-09, WP-01WP-07, R-01~R-06, browser-transfer P1/P2를 subsystem별 PR로 닫는다.
  5. 기존 version/migration 계획: Service Worker V2(SW-10), OPFS physical/protocol V2, presigned/Web Push receipt V2를 expand → dual-read/emit → old-writer drain → contract 순서로 배포한다.
  6. 구조 리팩터링: behavior가 모두 green인 상태에서 resumable upload, image CDN, OPFS worker, public cache, download strategy를 characterization-preserving extraction으로 나눈다.
  7. Promotion gaps: preview decode, bounded origin/cache maintenance, Browser RPC concrete transport, image descriptor provider 등 명시된 gap을 실제 browser/provider conformance와 함께 구현한다. 완료 전 availability state를 올리지 않는다.

질문 없는 세부 실행 절차는 Adapter Remediation Implementation Plan에 있으며, finding별 exact API·test·migration은 각 하위 리뷰가 source of truth다.

기존 계획과의 우선권

기존 계획 유지할 내용 이번 리뷰가 추가하는 선행 조건
2026-08-01 HTTP/worker remediation Tasks 13 installed HTTP contract 단일 권위, provider-neutral outcome, bound-only query API N-01~N-03 auth/observation/effect 결함을 같은 V3 migration에 먼저 포함
같은 계획 Task 4 bounded Service Worker marker reader 그대로 유지; SW-01~SW-09의 cache/lifecycle truth를 함께 닫은 뒤 V2로 이동
같은 계획 Task 5 full identity Service Worker protocol V2 SW-10으로 승계. 새 protocol을 두 번 설계하지 않는다.
같은 계획 Task 6 shared IndexedDB persisted-row schema 그대로 유지하되 STO-06 deadline/drain lease test를 extraction 전 추가
같은 계획 Task 7 OPFS/cache/download cohesive decomposition STO-01~STO-05 correctness fix와 characterization이 먼저다.
2026-08-01 runtime correctness Tasks 15 query key/invalidation, application mutation intent, keyed command preflight, effect-aware settlement 새 plan이 대체하지 않는다. N-03, N-05, N-06을 동일 certainty/key authority에 병합한다.

충돌 시 우선순위는 현재 재현 결함의 fail-close 수정 → 기존 plan의 계약 통합 → 구조 추출 → optional capability 조립이다. 두 기존 plan을 완료로 표시하거나 삭제하지 않는다.

검증 기준선

  • corepack pnpm check:types: 통과.
  • corepack pnpm lint: 통과.
  • corepack pnpm check:architecture: sandbox child-process 제약에서는 실패했으나 동일 명령을 허용된 실행 환경에서 다시 수행해 286 modules / 854 dependencies, 12 fixture, TS-only/allowed/forbidden gate가 모두 통과했다.
  • 영역별 focused baseline:
    • network/state: 21 files / 144 tests 통과, check:diagnostics 통과.
    • realtime/Browser RPC: 16 files / 185 tests 통과, source boundary gate 통과.
    • storage/files/cache: 7 files / 105 tests 통과.
    • browser transfer: 6 files / 93 tests 통과; Service Worker/Web Push: 8 files / 52 tests 통과(독립 재감사 실행).
  • 전체 test:unit은 이 sandbox에서 child spawnSync ... EPERM이 발생한 세 CI/evidence test file 때문에 108 files 통과, 3 files 실패(1465 tests 통과, 50 실패)였다. adapter focused suite의 실패가 아니며 전체 green으로 주장하지 않는다.

최종 산출물 검증은 118/118 inventory 포함, placeholder/깨진 local path 검사, Markdown diff 검사, focused adapter tests, type/architecture/lint를 다시 실행한다.

명시적으로 하지 않는 변경

  • 이 리뷰에서는 production source를 수정하거나 optional adapter를 bootstrap에 조립하지 않는다.
  • private/range cache, persistent browser handles, resumable range download, arbitrary Web Push copy/URL 같은 별도 미선택 capability를 기존 adapter에 섞지 않는다.
  • timeout을 이유로 irreversible native mutation이 적용되지 않았다고 추정하지 않는다.
  • cleanup 실패를 observation만 남기고 success로 바꾸지 않는다.
  • schema/database version을 downgrade하거나 broad prefix/root/database 전체 삭제를 rollback으로 사용하지 않는다.
  • SSE↔WebSocket, Connect↔gRPC-Web↔REST를 장애 중 자동 전환하지 않는다.