Files
llm-wiki/raw/branch-notes/feature-frontend-render-recovery-boundary-contract.md
T

38 KiB

title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label, contract_packet_sha256, imports, accepts_delegations
title source_type status id kind project work_item inherits refines overrides depends_on contract_packet branch parent_branch related_projects governing_docs tags created target_merge status_label contract_packet_sha256 imports accepts_delegations
branch / feature-frontend-render-recovery-boundary-contract branch-note raw BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-015 project-work-item ca-skeleton-frontend-operational-contract WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-015
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-UI-001@1
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-ARCHITECTURE-001@1
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-007
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-013
1 feature-frontend-render-recovery-boundary-contract
ca-skeleton-frontend
ca-skeleton
raw/project-notes/ca-skeleton-frontend-operational-contract.md
branch
ca-skeleton
frontend
error-handling
react
2026-07-18 in-progress 2c336d6be17e196dcbbbf75409f97f8ff916672d7b634db5e6cf3e568000b57b
FE-OC-008@1
FE-OC-011@1
FE-OC-014@1
DELEG-FE-006@1

branch: feature-frontend-render-recovery-boundary-contract

Layer: raw/branch-notes/ — 단일 브랜치의 TODO·결정·진행 기록. 머지/종료 후 verified 결과는 /ingestwiki/projects/에 추출한다. 현재는 /branch-spec 자동 채움 단계이며 frontend 코드가 없으므로 모든 진술은 planned다.

부모 (필수)

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: boot·route·feature·async boundary ownership과 recovery fixture가 검증된다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-UI-001@1 UI composition은 React를 사용한다 React render boundary와 recovery surface에 적용한다 raw/project-notes/ca-skeleton-frontend-operational-contract
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-ARCHITECTURE-001@1 domain, application, presentation, adapters, bootstrap 책임을 분리한다 boot·route·feature·async boundary ownership과 adapter seam에 적용한다 raw/project-notes/ca-skeleton-frontend-operational-contract

브랜치 지역 결정

Decision ID Decision Relation Supporting Claims Status
D1 operational failure와 render defect를 분리한다 local raw/project-notes/ca-skeleton-frontend-operational-contract proposed
D2 boot·route·feature·async boundary ownership을 고정한다 local raw/project-notes/ca-skeleton-frontend-operational-contract proposed
D3 route별 error surface owner를 하나로 제한한다 local raw/project-notes/ca-skeleton-frontend-operational-contract proposed
D4 release pair별 controlled reload를 한 번으로 제한한다 local raw/project-notes/ca-skeleton-frontend-operational-contract proposed
D5 boot validation failure 시 product route 대신 boot shell을 렌더한다 local raw/project-notes/ca-skeleton-frontend-operational-contract proposed
D6 render failure telemetry를 best-effort로 emit한다 local raw/project-notes/ca-skeleton-frontend-operational-contract proposed

선언한 예외

Override ID Overrides Reason Approval Status

없음.

목표

이 브랜치는 project-wide 계약 FE-OC-015("expected operational error 와 render defect 를 MUST 분리하고 reload loop 를 금지")를 구현 착수 가능한 상세 명세로 내린다. 핵심은 두 불변식이다. (1) 분리(separation) — 정규화된 운영 실패(error-classification 이 낸 26-kind operational error)는 컴포넌트의 정상 state 로 반환되며 render error boundary 로 throw 하지 않는다. render boundary 가 잡는 것은 programmer defect 또는 invariant breach(렌더 도중 던져진 예외)뿐이다(raw/project-notes/ca-skeleton-frontend-operational-contract §10.1 마지막 문단, §8.2 RENDER_FAILURE 행). (2) reload loop 금지 — chunk/deploy mismatch 복구용 자동 reload 는 §10.2 의 5개 controlled 조건과 CHUNK_RELOAD_GUARD 를 만족할 때 정확히 한 번만 허용되고, 같은 release pair 에서 두 번째 실패가 나면 auto reload 를 멈추고 rollback/support surface 로 넘어간다. 이 브랜치는 boot/route/feature/async 4계층 error boundary 의 ownership(무엇을 잡고·무엇을 안 잡고·어떻게 복구하는가)을 §10.1 매트릭스로 고정하고, 그 산출물을 세 계약에 기여한다 — FE-OC-005(route-level error/loading surface owner 와의 이중 소유 금지), FE-OC-011(async surface 의 terminal-error state 를 boundary 가 아닌 정상 state 로 소비), FE-OC-025(boot·chunk mismatch runbook 이 호출할 boundary/reload 메커니즘 제공). UI 기술은 React(FE-D004), 라우팅은 React Router Declarative Mode(FE-D008)를 전제한다.

  • 이슈:
  • PR:

범위

포함 범위

  • operational-error vs render-defect 분리 계약 — 정규화된 운영 실패는 정상 state 로 반환, render boundary 는 defect/invariant breach 만 catch (hub §10.1·§8.2). 등급 planned.
  • 4계층 error boundary ownership 매트릭스 — boot shell / route boundary / feature boundary / async boundary 각각의 catches / does-not-catch / recovery 명세 (hub §10.1). 등급 planned.
  • controlled reload + CHUNK_RELOAD_GUARD state machine — §10.2 의 5개 조건, release pair 당 1회, 2번째 실패 시 rollback/support (hub §10.2·§5.5·§8.4 reload-once). 등급 planned.
  • boot error shell — §4.5 boot order 2~4단계 실패 시 product route 미마운트, boot error shell 만 렌더 (hub §4.5·§8.2 BOOT_CONFIG_FAILURE). 등급 planned.
  • render-failure telemetry hookui.render.failed(route_id·build_id·component_boundary) best-effort emit, sink 실패가 복구를 막지 않음 (hub §5.8·§10.1). 등급 planned.
  • recovery fixtures / boundary 테스트 — §20 Measurable completion("boot/route/feature/async boundary ownership + recovery fixtures") + §8.5 관련 negative fixture. 등급 planned.

제외 범위

의도적 제외. 각 항목은 소유 브랜치를 명시(CLAUDE.md §15.5 R3 OUT_OF_BRANCH_SCOPE 방지). 아래 sibling 링크는 hook quirk 회피를 위해 FE-OC-### 계약 ID 로만 짝지음(§4b).

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

Source 정당화하는 결정
raw/project-notes/ca-skeleton-frontend-operational-contract §10.1 error boundary ownership 매트릭스·§10.2 reload loop prevention·§8.2 RENDER_FAILURE/operational-vs-defect note·§4.5 boot order·§5.5 CHUNK_RELOAD_GUARD·§5.8 ui.render.failed·§8.4 reload-once·§9.3 route error owner 중복 금지 — FE-OC-015 의 project-decision SSOT. D1·D2·D3·D4·D5·D6 근거.
raw/official-docs/react-ui-library-official FE-D004(UI composition = React). error boundary claim 은 이 자료에 없음REACT-UI-C1 은 "React 는 컴포넌트로 구성된다"만 증명하므로 render boundary 기술 전제(React 사용)만 근거하고, boundary API 는 아래 web-research 로 보강. D2·D5 부분 근거.
raw/official-docs/react-router-official FE-D008(routing = React Router Declarative Mode). REACT-ROUTER-C1/C4 가 client-side route 선언을 근거. route error element API 는 이 발췌 범위 밖(archived doc 이 명시) → route boundary 의 정확한 error element 형태는 UNSUPPORTED_IMPL_DECISION. D3 부분 근거.
react.dev 웹 조사(2026-07-19, react.dev/reference/react/Component) — 미아카이브 React error boundary 메커니즘: static getDerivedStateFromError(+옵션 componentDidCatch)를 가진 컴포넌트가 자식이 렌더 중 던진 에러를 잡되 event handler·async 코드·boundary 자신이 던진 에러는 잡지 않는다. 이 사실이 "operational 실패는 boundary 로 throw 하지 않는다"(D1)를 강화. 후속: raw/official-docs 로 정식 아카이브 필요(Claims To Verify).

TODO

각 항목 옆에 증거 등급 표기. 현재 frontend 코드가 없으므로 전부 planned.

  • 4계층 boundary 컴포넌트 배치(src/presentation/boundaries/* + boot shell) — boot/route/feature/async catches·does-not-catch·recovery 구현 (D1/D2/D5) — 등급: planned
  • operational-vs-defect seam — 정규화된 kind 를 정상 state 로, defect 만 boundary 로 라우팅하는 경계 wiring (D1) — 등급: planned
  • CHUNK_RELOAD_GUARD controlled reload state machine — 5조건 순서 + release pair 2회차 중단 (D4) — 등급: planned
  • boot error shell — composition root 가 §4.5 2~4단계 실패 시 product route 미마운트 (D5) — 등급: planned
  • ui.render.failed best-effort telemetry hook — boundary catch 시 emit, 재귀·차단 없음 (D6) — 등급: planned
  • recovery fixtures — reload-loop deterministic test + operational-vs-defect fixture + boot invalid-config → boot shell (D1~D5) — 등급: planned

진행 중 메모

없음 — /branch-spec 자동 채움 단계. 코드 미착수. React error boundary 는 class-component 전용 API(getDerivedStateFromError)라는 점을 web 조사로 확인했고, 정식 아카이브는 후속 dispatch 로 남긴다.

결정 사항

아래 6개 결정은 Decision Evidence Map 의 prose mirror. 근거는 대부분 hub 의 project decision(§10·§8·§4.5·§5)이며, D2/D3 는 외부 자료(React·React Router·react.dev web) 가 기술 전제로 병행 근거.

  • 2026-07-19: operational error 와 render defect 를 분리 — 정규화된 운영 실패는 정상 state 로 반환, render boundary 는 defect/invariant breach 만 catch / 이유: 운영 실패를 boundary 로 throw 하면 async·event-handler 경로에서 애초에 안 잡히고(React error boundary 는 그 경로를 catch 하지 않음) 정상 복구 UX(재시도·stale)를 blank crash 로 격하 / 검토한 대안: 모든 실패를 throw 해 단일 boundary 로 처리 — React 가 event/async 를 안 잡으므로 불완전, hub §10.1 default 위반으로 기각 / 근거: hub §10.1·§8.2, react.dev error boundary 조사.
  • 2026-07-19: boot / route / feature / async 4계층 boundary ownership 을 §10.1 매트릭스로 고정 / 이유: 계층마다 catch 대상·복구가 달라(config vs lazy chunk vs subtree defect vs 정규화 state) 단일 boundary 는 복구 granularity 를 잃음 / 검토한 대안: 전역 단일 boundary — route 1개·lazy chunk 0·외부 API 0 throwaway(hub §0.4)에서만 / 근거: hub §10.1·§4.5·§9.3.
  • 2026-07-19: route error surface 의 이중 소유 금지 — route element 와 React error boundary 중 route 당 정확히 하나가 owner / 이유: 둘 다 소유하면 같은 render 실패를 두 번 처리하거나 복구가 충돌 / 검토한 대안: 둘 다 두고 우선순위 규칙 — 복잡·모호로 기각 / 근거: hub §9.3 의 비중복 owner 원칙(이 결정의 실제 grounding), React Router REACT-ROUTER-C1/C4(Declarative Mode 의 client-side route 선언). 전제의 한계 명시: Declarative Mode 가 route 레벨 error API 자체(존재 여부·형태)를 제공하는지는 아카이브된 발췌 범위 밖이므로 미확정이다 — 즉 이 결정이 강제하는 것은 "route element 계층에 error API 가 있으면 boundary 와 이중 소유하지 말 것"이라는 비중복 규칙이지, 그 API 의 존재를 주장하는 것이 아니다. 정식 아카이브는 source 후속(Claims To Verify 마지막 행).
  • 2026-07-19: controlled reload 는 CHUNK_RELOAD_GUARD 로 release pair 당 1회, 2회차 실패 시 중단 / 이유: ChunkLoadError/deploy mismatch 를 무한 reload 로 대응하면 boot loop / 검토한 대안: guard 없는 즉시 reload — §8.4 가 금지(reload-once MUST NOT: session guard 없이 반복 reload) / 근거: hub §10.2 5조건·§5.5·§8.4·§8.2.
  • 2026-07-19: boot config/release 검증 실패 시 product route 미마운트, boot error shell 만 렌더 / 이유: 잘못된 config 로 앱을 띄우면 endpoint mismatch·secret 노출·부분 렌더 위험 / 검토한 대안: 실패해도 기본값으로 진행 — §4.5 가 2~4단계 실패를 hard stop 으로 규정, 기각 / 근거: hub §4.5·§8.2 BOOT_CONFIG_FAILURE.
  • 2026-07-19: render-failure telemetry(ui.render.failed)는 best-effort, sink 실패가 복구·재렌더를 막지 않음 / 이유: 관측이 복구를 blocking 하면 안 됨(operational isolation) / 검토한 대안: 전송 보장 채널 — audit 채널은 별도 owner(FE-OC-014), 기각 / 근거: hub §5.8·§10.1, FE-D021.

결정-근거 매핑

Supporting Claims 는 hook quirk 회피를 위해 hub 는 plain-text 경로(...frontend-operational-contract.md §X)로, official-doc claim 은 plain-text raw/official-docs/<slug>.md#<CLAIM> 로, FE-D### 는 hub 경로에만 붙여 sibling branch 링크 근처에 두지 않는다(§4b).

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 operational error(정규화된 26-kind 운영 실패)는 정상 컴포넌트 state 로 반환하고 render error boundary 로 throw 하지 않음; boundary 는 programmer defect / invariant breach(렌더 중 throw)만 catch (FE-OC-015) error-classification 이 실패를 총함수로 정규화하는 한(hub FE-OC-008) 이 default 유지 / "throw 후 boundary 처리" 대안은 정규화 계층이 없을 때만인데 hub 가 그것을 강제하므로 분기 없음(불변식) ...frontend-operational-contract.md §10.1 마지막 문단·§8.2 RENDER_FAILURE 행 및 total-function 문단; raw/official-docs/react-ui-library-official.md#REACT-UI-C1(React 사용); react.dev Component(error boundary 는 event handler·async·boundary 자체 throw 를 catch 안 함 → operational 을 throw 로 흘리면 애초에 미포착) project-decision + official-vendor-doc(web, 미아카이브) 총함수적 분리는 fixture 로만 증명 — operational 실패가 실수로 throw 되거나 boundary 가 실제 defect 를 operational 로 오분류하면 crash/은닉. exhaustive boundary fixture 필요
D2 boot shell / route boundary / feature boundary / async boundary 4계층 ownership 을 §10.1 매트릭스(각 계층의 catches·does-not-catch·recovery)로 고정 client SPA + lazy route chunk + async 데이터(React·React Router·TanStack Query) 구성인 한 4계층 default / 전역 단일 boundary 는 route 1개·lazy chunk 0·외부 API 0 throwaway prototype(hub §0.4 escape)에서만 ...frontend-operational-contract.md §10.1 boundary 매트릭스·§4.5 boot order(2~4단계 실패→boot error shell)·§9.3 route 동작; raw/official-docs/react-ui-library-official.md#REACT-UI-C1 project-decision async boundary 는 실제로 "throw 를 잡는 boundary"가 아니라 정규화 state 소비 surface(§10.1 행) — FE-OC-011 과의 소유 seam 이 모호하면 이중 처리. seam 명세 필요
D3 route 당 error surface 는 React Router route element 와 React error boundary 중 정확히 하나가 owner; 이중 소유 금지 (규칙의 grounding 은 hub §9.3 비중복 owner 원칙이며, Declarative Mode 의 route-error API 존재 자체를 주장하지 않음) Declarative Mode(FE-D008) 의 route element 계층이 error surface 를 소유할 수 있는 한 route 별 owner 를 하나 지정 / 그 계층에 error API 가 없으면 owner 는 전부 React error boundary 로 고정(규칙 자체는 유지, 위반 여지 소멸) / Data/Framework Mode 로 전환되면(그 mode 의 errorElement/loader 계약) 재도출 ...frontend-operational-contract.md §9.3("route error element 와 React error boundary 의 owner 를 중복하지 않는다"); raw/official-docs/react-router-official.md#REACT-ROUTER-C1, #REACT-ROUTER-C4; ...frontend-operational-contract.md FE-D008 project-decision + conditional-default(React Router) archived router doc 은 error element API 를 다루지 않음 → 정확한 error element 형태는 UNSUPPORTED_IMPL_DECISION; owner 선정 규칙이 route 별로 일관되지 않으면 §9.3 위반
D4 chunk/deploy mismatch 복구 자동 reload 는 §10.2 5조건(kind∈{CHUNK_LOAD_FAILURE,DEPLOY_MISMATCH}·release manifest fetch 성공·active release≠current build·CHUNK_RELOAD_GUARD unset·guard 선기록 후 reload)을 모두 만족할 때 release pair 당 1회; 같은 pair 2회차 실패 시 auto reload 중단→rollback/support mismatch 가 감지되고 manifest 가 더 새로운 release 를 확인할 때만 reload / manifest fetch 실패·같은 pair 이미 guard·storage 불가면 no auto reload(update/support surface) ...frontend-operational-contract.md §10.2 5조건·§5.5 CHUNK_RELOAD_GUARD(sessionStorage / session / no second auto reload)·§8.4 reload-once(MUST NOT: session guard 없이 반복 reload)·§8.2 CHUNK_LOAD_FAILURE/DEPLOY_MISMATCH project-decision guard 가 sessionStorage → StoragePort unavailable(private mode)·cross-tab 시 guard 미지속 가능 → fail-safe 로 no-auto-reload 강등 필요. deterministic reload test 로 2회차 중단 증명
D5 boot config/release 검증(§4.5 2~4단계) 실패 시 product route 를 mount 하지 않고 boot error shell 만 렌더; telemetry adapter 생성 실패(7단계)는 console-safe fallback 으로 계속 boot order 2~4단계(runtime config fetch·schema·compatibility·release manifest) 실패 → boot error shell / telemetry 등 비필수 adapter 실패 → 계속 진행 ...frontend-operational-contract.md §4.5 boot order + 실패 규칙·§8.2 BOOT_CONFIG_FAILURE/RELEASE_MANIFEST_FAILURE project-decision boot shell 자체가 실패한 config 에 의존하면 안 됨(zero-config 로 렌더 가능해야) — 미검증 시 boot shell 이 같은 실패로 재크래시. boot invalid-config fixture 필요
D6 render-failure telemetry(ui.render.failed: route_id·build_id·component_boundary)는 best-effort emit, sink/queue 실패가 복구·재렌더를 막지 않음 telemetry 가 best-effort isolation(FE-D021)인 한 항상 non-blocking / 전송 보장이 필요한 audit event 는 별도 owner(FE-OC-014) 채널이므로 본 결정 밖 ...frontend-operational-contract.md §5.8 ui.render.failed event·§10.1 feature boundary recovery; ...frontend-operational-contract.md FE-D021 project-decision (transport delegated to FE-OC-014) boundary 의 componentDidCatch 안 telemetry 호출이 throw 하면 boundary 자신이 throw(react.dev: boundary 자체 throw 는 미포착) → 상위 boundary 로 전파. emit 은 try/catch 로 감싸야 함

구현 가이드

planned blueprint. 경로는 hub §4.6 Planned directory blueprint(src/presentation/boundaries/, src/bootstrap/) + §5 registry 에서 유도되므로 grounded 하지만 repository 생성 시 바뀔 수 있어 전체 planned. sibling 소유 detail 은 §범위 Out of scope 로 위임하고 여기 남기지 않는다(R3).

1. 4계층 error boundary 배치 (src/presentation/boundaries/ + boot shell)

Trace: D1 + D2 + D5 / FE-OC-015·hub §10.1 매트릭스·§4.5. React error boundary 는 static getDerivedStateFromError(+옵션 componentDidCatch)를 가진 컴포넌트가 자식의 렌더 중 throw 를 catch(react.dev 조사).

  • UNSUPPORTED_IMPL_DECISION: boundary 구현 방식(hand-rolled class vs react-error-boundary 라이브러리) — hub·archived doc 미규정. hand-rolled class 컴포넌트(외부 의존 0) 제안. trade-off: 라이브러리는 reset/fallback API 가 편하지만 supply-chain(FE-OC-018) 표면 추가; class 는 boilerplate 지만 의존 0.
  • UNSUPPORTED_IMPL_DECISION: boundary 컴포넌트·파일명(hub 는 presentation/boundaries/ 폴더만 grounding) — RouteErrorBoundary.jsx/FeatureErrorBoundary.jsx/BootErrorShell.jsx 제안. trade-off: 이름 임의, "presentation/boundaries 내부 + 계층당 1 컴포넌트" 제약만 유지하면 계약 동등.
계층 catches (hub §10.1) does NOT catch recovery planned 배치
boot shell config/release/bootstrap 실패 product route error config refetch·support·rollback signal src/bootstrap/ composition root (D5)
route boundary route 의 lazy chunk / render 실패 expected API result(정규화 state) route retry 또는 controlled reload(D4) presentation/boundaries/ route 래핑
feature boundary 컴포넌트 subtree render defect 정규화된 operational failure component reset presentation/boundaries/ subtree 래핑
async boundary 정규화된 query/mutation state throw 된 render defect registry action FE-OC-011 async surface 와 공유 seam(D2)

2. operational-vs-defect seam (정규화 kind 라우팅)

Trace: D1 / FE-OC-015·hub §10.1·§8.2. error-classification(FE-OC-008)이 낸 정규화 kind 를 소비만 하며 정규화 자체는 하지 않는다(R3 위임).

  • UNSUPPORTED_IMPL_DECISION: 없음 — 분기 원칙은 hub §10.1(operational→정상 state, defect→boundary)이 직접 grounding. 실제 kind→state/action 매핑 값은 FE-OC-008/FE-OC-011 소유.
정규화된 failure(kind, action) 수신  → async/feature 계층의 정상 state 로 렌더 (terminal-error/stale-degraded 등, action 은 FE-OC-011 소유)
렌더 중 throw(non-normalized) 발생   → 가장 가까운 feature/route boundary 가 catch → RENDER_FAILURE recovery
boundary 가 catch 한 값이 정규화 실패로 판명 → 재-throw 금지, RENDER_FAILURE 로 처리(operational 은닉 방지는 fixture 로 검증)

3. controlled reload + CHUNK_RELOAD_GUARD state machine

Trace: D4 / FE-OC-015·hub §10.2·§5.5·§8.4. guard 저장은 StoragePort 경유(FE-OC-013 소유 registry 의 CHUNK_RELOAD_GUARD row 를 소비).

  • UNSUPPORTED_IMPL_DECISION: reload 결정 로직 위치(boundary 내부 vs release adapter) — hub 미규정. release adapter(ReleaseInfoPort 구현, §4.4)가 mismatch 판정, boundary 는 그 결과로 reload/rollback surface 분기 제안. trade-off: adapter 집중이 test 용이하나 boundary→adapter 호출 경계 추가.
  • UNSUPPORTED_IMPL_DECISION: guard 값 shape(§5.5 는 "session / no second auto reload"만) — <activeReleaseId>:<currentBuildId> pair 키 + boolean 제안. trade-off: pair 키여야 "같은 pair 2회차"를 판별; 단일 flag 면 서로 다른 release 간 오차단.
  • UNSUPPORTED_IMPL_DECISION: dirty-state 선경고 훅의 호출 위치 — raw/project-notes/ca-skeleton-frontend-operational-contract §10.2 의 5조건은 warn-first 를 포함하지 않고, §16.2 immediate containment 1단계가 "current user input 이 있으면 destructive reload 전에 경고"를 별도로 규정한다(두 절의 결합 지점은 hub 미규정). 조건 4 통과 후·조건 5(guard 기록 → reload) 직전 호출 제안. trade-off: 이 위치면 경고가 실제 reload 직전 1회만 뜨고 사용자가 취소해도 guard 미기록이라 이후 재시도가 가능하다; 앞으로 당기면(조건 1 직후) mismatch 도 아닌 경우까지 경고해 소음이 된다.
1. failure kind ∈ {CHUNK_LOAD_FAILURE, DEPLOY_MISMATCH} ?           아니면 → reload 안 함
2. release manifest fetch 성공 ?                                      실패 → no reload, update/support(RELEASE_MANIFEST_FAILURE 는 FE-OC-016 소유)
3. active release ≠ current build ?                                   같으면 → no reload(mismatch 아님)
4. CHUNK_RELOAD_GUARD[pair] unset ?                                   set 이면 → auto reload 중단, rollback/support surface
4b. dirty-state 선경고 훅(runbook 소유) 호출 → 사용자가 취소하면 reload 안 함(guard 미기록)
5. guard[pair] 기록 후 → 1회 reload

각주 — dirty-state seam 교차 참조: 위 4b 는 본 브랜치가 새로 만드는 정책이 아니라 이미 존재하는 두 계약을 명시적으로 잇는 자리다. raw/project-notes/ca-skeleton-frontend-operational-contract §19 의 FE-RISK-009("chunk auto reload 가 user input 손실", mitigation = dirty-state guard + one reload cap)는 두 짝으로만 닫힌다 — one reload cap 은 본 절의 guard 가 제공하고, dirty-state guard(warn-first) 는 §16.2 immediate containment 1단계가 규정한다.

그 warn-first step 과 위 risk row 의 owner 는 raw/branch-notes/feature-frontend-operational-runbook-contract (FE-OC-025) 이다. 본 브랜치는 훅을 호출만 하며 "무엇이 dirty 인가"의 판정 기준·경고 문안·취소 UX 는 그 소유다(R3 위임). 이 seam 을 적지 않으면 본 절의 자동 reload 가 runbook 의 warn-first 가정을 조용히 우회하고, 두 문서가 암묵적으로만 일관된 상태로 남는다.

4. boot error shell

Trace: D5 / FE-OC-015·hub §4.5·§8.2. composition root(src/bootstrap/composition-root.js, §4.5)가 boot order 를 소유.

  • UNSUPPORTED_IMPL_DECISION: boot shell 컴포넌트명·위치(hub 는 bootstrap/ 만) — src/bootstrap/BootErrorShell.jsx + composition-root 가 2~4단계 실패 시 이것만 mount 제안. trade-off: 이름 임의; "zero runtime config 로 렌더 가능 + product route 미마운트" 제약만 유지.
  • boot order §4.5 의 2단계(runtime config fetch)~4단계(release manifest 정합) 실패 → BOOT_CONFIG_FAILURE/RELEASE_MANIFEST_FAILURE → boot error shell 만 렌더(product route 미마운트).
  • 7단계(telemetry adapter) 생성 실패 → console-safe fallback, boot 계속(§4.5).
  • boot shell 은 실패한 config 에 의존 불가 — build-time 상수(§6.1 build-time public)만 참조.

5. render-failure telemetry hook

Trace: D6 / FE-OC-015·hub §5.8·§10.1. transport/redaction sink 는 FE-OC-014 소유(R3) — 본 절은 emit 시점·payload 계약만.

  • UNSUPPORTED_IMPL_DECISION: 없음(payload 는 §5.8 이 required attribute 를 grounding). emit 실패 격리 방식만: componentDidCatch 내 emit 을 try/catch 로 감싸 재귀·전파 차단 제안(react.dev: boundary 자체 throw 는 상위로 전파).
  • componentDidCatch(또는 등가 hook)에서 ui.render.failed{route_id, build_id, component_boundary} best-effort emit.
  • emit 은 try/catch — 실패해도 fallback UI 렌더·recovery 를 막지 않음(§10.1·§5.8).

6. boundary 테스트 (§20 Measurable completion)

Trace: D1 + D2 + D3 + D4 + D5 / hub §20("boot/route/feature/async boundary ownership + recovery fixtures")·§8.5·§10.2.

  • UNSUPPORTED_IMPL_DECISION: test 파일 경로·러너 배치(hub §4.6 은 tests/component|integration 폴더만) — tests/component/boundaries/* + tests/integration/reload-guard/* 제안. trade-off: 경로 임의, "component 레벨 boundary + integration 레벨 reload state machine" 계약만 유지.
Fixture 기대 결과
async operation 실패(정규화 kind) boundary 미발동, async surface 의 terminal-error/stale state 로 렌더(operational 은 정상 state)
컴포넌트 render 중 throw 가장 가까운 feature/route boundary 가 catch → RENDER_FAILURE recovery
boundary 자체 throw 상위 boundary/boot shell 로 전파(react.dev), 무한 루프 없음
CHUNK_LOAD_FAILURE 1회차 + manifest 새 release guard 기록 후 1회 reload
같은 release pair 2회차 실패 auto reload 중단 → rollback/support surface(§10.2)
StoragePort unavailable guard 미지속 → fail-safe no-auto-reload
boot invalid runtime config product route 미마운트, boot error shell 렌더(D5)

엣지·실패·의존

  • 실패·엣지 경로:
    • boundary 자체가 render 중 throw → React error boundary 는 자신이 던진 에러를 catch 하지 않음(react.dev) → 상위 boundary 또는 boot shell 이 처리. 최상위(boot shell)까지 throw 되면 최소 static crash surface.
    • event handler / async(setTimeout 등)에서 발생한 에러 → React error boundary 미포착(react.dev) → 반드시 error-classification 이 정규화한 operational failure 로 다뤄 정상 state 로 표현(D1). boundary 에 의존하면 blank crash.
    • StoragePort unavailable/quota(private mode 등) → CHUNK_RELOAD_GUARD 미지속 → fail-safe 로 auto reload 강등(no reload, update/support). guard 부재를 "unset"으로 오해해 무한 reload 하면 안 됨.
    • release manifest fetch 실패 → controlled reload 2단계 불충족 → no reload; RELEASE_MANIFEST_FAILURE 자체 생성은 FE-OC-016 소유.
    • route element 와 boundary 이중 소유 → 같은 실패 두 번 처리/복구 충돌 → route 당 owner 1개(D3)로 정적 방지.
  • 다른 계약 의존(hook quirk 회피: sibling 링크는 FE-OC-### 로만 짝지음):
    • raw/branch-notes/feature-frontend-error-classification-boundary-contract (FE-OC-008) — 정규화된 kind + action생성. 그 계약(어떤 exception→어떤 kind, operational vs RENDER_FAILURE 구분)이 바뀌면 본 브랜치 seam(D1) 재조정. 해당 sibling 은 error boundary·reload-guard 소유를 이미 본 브랜치로 위임함.
    • raw/branch-notes/feature-async-ui-state-contract (FE-OC-011) — async surface state(initial-loading/success/empty/terminal-error) 렌더를 소유. 본 브랜치는 "operational 은 boundary 아닌 정상 state" seam(D2)만; state 문안·스켈레톤은 그 소유.
    • raw/branch-notes/feature-routing-navigation-guard-contract (FE-OC-005) — route registry(errorSurface/chunkId)를 소유. route boundary 가 그 owner 필드를 채우되 스키마는 그 소유(D3).
    • raw/branch-notes/feature-frontend-release-cache-rollback-contract (FE-OC-016) — release manifest·DEPLOY_MISMATCH 신호·rollback 실행을 생성/소유. 본 브랜치는 소비해 reload/rollback 분기(D4).
    • raw/branch-notes/feature-frontend-storage-registry-contract (FE-OC-013) — CHUNK_RELOAD_GUARD storage row 를 소유. 본 브랜치는 guard 의미만(D4).
    • raw/branch-notes/feature-frontend-env-runtime-config-contract (FE-OC-004) — build/runtime/secret 분리와 boot 전 runtime config 검증을 소유하며, 그 검증 실패가 본 브랜치 boot error shell 을 발동시키는 BOOT_CONFIG_FAILURE 신호를 생성 한다(D5). hub §20 이 그 브랜치의 measurable completion 을 "build/runtime/secret registry + boot invalid matrix" 로 규정하므로 어떤 config 가 invalid 인가의 판정은 그쪽 소유이고, 본 브랜치는 그 신호를 소비해 "product route 미마운트 + shell 렌더" 분기만 한다. invalid matrix 의 kind 매핑(§8.2 행)이 바뀌면 D5·구현 가이드 §4 재조정.
    • raw/branch-notes/feature-frontend-clean-architecture-layering-contract (FE-OC-002) — boot error shell 을 호스팅하는 composition root(bootstrap 단일 root)를 소유 한다(hub §4.2 bootstrap 행: config load·adapter construction·DI·React mount). 본 브랜치는 그 host 를 소비하는 쪽이며, root 가 adapter 를 주입하는 wiring 컨벤션(주입 순서·DI 형태·단일 root 불변식)은 그쪽 소유다(R3 위임). 본 브랜치가 명세하는 것은 hub §4.5 boot order 2~4단계 실패 시의 분기 규칙(shell 만 mount)뿐이다(D5).
    • raw/branch-notes/feature-frontend-operational-runbook-contract (FE-OC-025) — boot·chunk mismatch runbook 을 소유. 본 브랜치가 제공하는 boundary/reload 를 소비. 역방향으로, runbook 이 소유한 destructive-reload 선경고 step 을 본 브랜치 reload state machine 이 호출한다(구현 가이드 §3 각주).
    • raw/branch-notes/feature-frontend-observability-logging-trace-contract (FE-OC-014) — telemetry transport/sink 를 소유. 본 브랜치는 ui.render.failed payload 계약만(D6).

검증해야 할 주장

Claim Why uncertain How to verify Status
reload loop 가 실제로 차단된다 — 같은 release pair 2회차 실패 시 auto reload 안 함 state machine·guard 미구현 deterministic reload-guard test — 1회차 reload 기록 후 2회차 → reload 미호출 assert(§10.2) needs-confirmation
operational 실패가 render boundary 에 절대 도달하지 않고, defect 만 도달한다 seam 미구현, 오분류 가능 fixture: async operational 실패 → terminal-error state(boundary 미발동) / 렌더 throw → boundary catch → RENDER_FAILURE needs-confirmation
boot error shell 이 실패한 runtime config 에 의존하지 않고 렌더된다 boot shell 미작성 boot invalid-config matrix → product route 미마운트 + shell 렌더, shell 이 runtime config 미참조 assert needs-confirmation
boundary 의 componentDidCatch telemetry emit 이 재귀·전파를 일으키지 않는다 emit try/catch 미구현 telemetry sink throw mock → boundary 가 재-throw 안 하고 fallback 렌더 assert needs-confirmation
StoragePort unavailable 시 guard 가 fail-safe(no-auto-reload)로 강등된다 fallback 경로 미설계 storage unavailable mock → reload 미호출 + update/support surface assert needs-confirmation
React error boundary 가 event-handler·async·자체 throw 를 catch 하지 않는다는 전제 react.dev web 조사만, vault 미아카이브 react.dev/reference/react/Componentwiki-source-summarizerraw/official-docs/ 정식 아카이브(verbatim quote + self-grep) 후 D1 근거 승격 planned
route 당 error surface owner 가 정확히 하나다(이중 소유 없음) route element API 미확정(archived doc 미포함) route element vs boundary owner 지정 규칙 test + React Router error element 공식 문서 보강 planned

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

/coverage 가 채우는 생성물이며 손으로 유지하지 않는다.

관심사 상태 owner 심각도 근거
TODO — /coverage 실행 전 missing (없음) 미평가 TODO

마주친 문제

없음 — scaffolding 단계

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

수신한 위임

Delegation Ref From Concern Status
DELEG-FE-006@1 raw/branch-notes/feature-async-ui-state-contract fe.deleg.reload-once-action accepted

가져온 프로젝트 계약

Ref Owner 요약 Branch 적용
FE-OC-008@1 raw/branch-notes/feature-frontend-error-classification-boundary-contract 모든 failure는 stable frontend error kind로 MUST 정규화하고 raw body·stack을 UI에 노출하면 안 됨 import 참조로 적용
FE-OC-011@1 raw/branch-notes/feature-async-ui-state-contract async surface는 initial-loading, success, empty, terminal-error를 MUST 표현 import 참조로 적용
FE-OC-014@1 raw/branch-notes/feature-frontend-observability-logging-trace-contract telemetry는 best-effort이며 render·API success를 차단하면 안 되고 PII·token을 전송하면 안 됨 import 참조로 적용

Sub-branches (세부 작업)

없음 — scaffolding 단계

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

없음 — scaffolding 단계

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

없음 — scaffolding 단계

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

없음 — scaffolding 단계

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

없음 — scaffolding 단계

관련 일일 노트

없음 — scaffolding 단계

완료 후 정리

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