35 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
| 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 | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-frontend-error-classification-boundary-contract | branch-note | raw | BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-007 | project-work-item | ca-skeleton-frontend-operational-contract | WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-007 |
|
|
1 | feature-frontend-error-classification-boundary-contract |
|
|
|
2026-07-18 | in-progress | 24279f92059756981b403bc43da12c4b65488a08cc137f39a2277e0ae83dfdc7 |
|
branch: feature-frontend-error-classification-boundary-contract
Layer:
raw/branch-notes/— 단일 브랜치의 TODO·결정·진행 기록. 머지/종료 후 verified 결과는/ingest로wiki/projects/에 추출한다.
부모 (필수)
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: normalization matrix와 raw body·stack leakage negative test가 통과한다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-VALIDATION-001@1 |
boundary runtime validation은 Zod schema로 수행한다 | validation failure signal을 stable frontend error kind로 정규화한다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | 모든 failure를 total function으로 단일 kind에 정규화한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D2 | normalized failure는 safe field만 보존한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D3 | FE-REG-ERROR를 error UX의 single-owner registry로 사용한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D4 | project trigger-to-kind matrix를 구현 계약으로 사용한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D5 | user copy는 userMessageKey로 간접화한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D6 | recovery action을 closed vocabulary로 제한한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D7 | defaultRetryable은 분류 힌트로만 사용한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D8 | Zod validation failure를 stage별 kind로 매핑한다 | local |
raw/official-docs/zod-runtime-schema-validation-official.md#ZOD-VALID-C4, raw/official-docs/zod-runtime-schema-validation-official.md#ZOD-VALID-C5 |
proposed |
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
없음.
목표
이 브랜치는 project-wide 계약 FE-OC-008("모든 failure 는 stable frontend error kind 로 MUST 정규화하고 raw body·stack 을 UI 에 노출하면 안 됨")을 구현 착수 가능한 상세 명세로 내린다. 핵심은 두 불변식이다. (1) Total normalization — HTTP response·adapter exception·browser exception 어느 경로든 정확히 하나의 안정 error kind(hub §5.6 의 26-kind enum)로 정규화되고, 어떤 named branch 와도 일치하지 않으면 catch-all UNKNOWN_FAILURE 로 폐기되며, 정규화되지 않은 throw 가 presentation 으로 통과하는 경로는 없다(hub §8.2 total-function 문단). (2) Redaction boundary — normalized failure 는 §8.1 의 안전 필드 집합만 담고 raw body·token·authorization header·full URL/query·stack·storage value 는 절대 포함하지 않는다. 이 브랜치는 error 계약 registry FE-REG-ERROR(src/contracts/errors.js)의 single owner 이며(hub §5.1), 그 산출물을 세 계약에 기여한다 — FE-OC-011(async terminal-error state 가 registry action 을 소비), FE-OC-015(operational failure 를 normal state 로 반환해 render boundary 로 throw 하지 않는 분리 신호 제공), FE-OC-020(negative fixture 카탈로그). 모든 진술은 코드가 없으므로 planned 등급이다.
- 이슈:
- PR:
범위
포함 범위
- Total normalization function — response/adapter/browser exception → 26-kind 중 정확히 하나, 최종 catch-all
UNKNOWN_FAILURE, presentation 으로의 un-normalized throw 금지 (hub §8.2, §5.6). 등급planned.- 이 총함수가 곧 응답 처리 순서의 마지막 단계이며 그 stage 의 owner 는 본 branch 다 — hub §2.1.4 Flow Stage Registry
FLOW-FE-RESP-008@1(application model 또는 실패 신호 → 정규화된 결과 반환; 총함수이므로 미매핑 예외는UNKNOWN_FAILURE로 귀결하고 throw 를 presentation 으로 통과시키지 않는다). 이 단계의 Invariants 를 바꾸려면 본 branch 가 revision 을 올려야 한다. stage 1~7 은 남의 소유라imports로만 pin 한다.
- 이 총함수가 곧 응답 처리 순서의 마지막 단계이며 그 stage 의 owner 는 본 branch 다 — hub §2.1.4 Flow Stage Registry
FE-REG-ERRORregistry (src/contracts/errors.js) — kind/defaultRetryable/severity/userMessageKey/action/telemetryEvent/redaction 7-field row 를 26 kind 에 대해 소유 (hub §5.6, §5.1 owner map). 등급planned.- Trigger → kind 매핑 매트릭스 — hub §8.2 의 트리거(network/timeout/abort/content-type/JSON/envelope/schema/HTTP status class/chunk/boot/release/storage/render/telemetry/query-cache/unknown) → kind 총함수 매핑 구현 명세 (hub §8.2, §8.5). 등급
planned. - Normalized failure safe-shape + redaction projection — §8.1 필드 allowlist 만 통과, 나머지 drop (hub §8.1, §7.1 "raw response body 를 log 금지"). 이게 "raw body/stack 미노출" 절반. 등급
planned. actionclosed vocabulary 매핑 — 각 kind →retry/reauth/navigate/reload-once/contact-support/none중 하나 + allowed-when/MUST-NOT 제약 (hub §8.4). 등급planned.- Negative fixtures + total-normalization matrix test + raw-body/stack leakage negative test — §20 Measurable completion 의 두 산출물 (hub §8.5). 등급
planned.
제외 범위
의도적 제외. 각 항목은 소유 브랜치를 명시(§15.5 R3 OUT_OF_BRANCH_SCOPE 방지). 아래 sibling 링크는 hook quirk 회피를 위해
FE-OC-###계약 ID 로만 짝지음.
- Retry algorithm/loop(backoff·jitter·
Retry-After·cap) — raw/branch-notes/feature-api-client-response-envelope-contract 의FE-OC-009소유. 본 브랜치는 kind 별defaultRetryable분류 힌트만 선언하고 실제 재시도 루프는 실행하지 않는다. - Schema/envelope validation 실패 신호 생성(ZodError) — raw/branch-notes/feature-runtime-schema-validation-contract 의
FE-OC-007소유. 본 브랜치는 그 실패를 소비해 kind 로 매핑만 한다. - Telemetry transport/queue/redaction sink — raw/branch-notes/feature-frontend-observability-logging-trace-contract 의
FE-OC-014소유. registry 는telemetryEvent참조와 redaction 규칙만 선언한다. - Error boundary component ownership + reload-loop guard 메커니즘 — raw/branch-notes/feature-frontend-render-recovery-boundary-contract 의
FE-OC-015소유. 본 브랜치는 operational-vs-defect 분류 입력만 공급한다. - Async surface state 렌더링 — raw/branch-notes/feature-async-ui-state-contract 의
FE-OC-011소유. 본 브랜치는 kind + action 만 공급한다. - Token lifecycle / 401 recovery callback state machine — auth·api-client 소유(
FE-OC-010/FE-OC-006). 본 브랜치는 401→AUTH_REQUIRED, 403→FORBIDDEN, adapter throw→AUTH_INTEGRATION_FAILURE매핑만.
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
| raw/project-notes/ca-skeleton-frontend-operational-contract | §8 Frontend Failure Taxonomy(§8.1 shape·§8.2 matrix·§8.3 retry order·§8.4 action·§8.5 fixture) + §5.6 error registry + §5.1 FE-REG-ERROR owner map — FE-OC-008 의 project-decision SSOT. D1·D2·D3·D4·D5·D6·D7 근거. |
| raw/official-docs/zod-runtime-schema-validation-official | FE-D007(boundary runtime validation = Zod). .parse() 실패 시 granular ZodError throw(ZOD-VALID-C4)·.safeParse() discriminated union(ZOD-VALID-C5) 가 SCHEMA_MISMATCH/ENVELOPE_MISMATCH 매핑의 소비 대상 신호. D8 근거. 단 validator 소유는 sibling(FE-OC-007). |
TODO
각 항목 옆에 증거 등급 표기. 현재 frontend 코드가 없으므로 전부 planned.
FE-REG-ERRORregistrysrc/contracts/errors.js— 26-kind × 7-field row 정의 (D3/D4/D5/D6) — 등급:plannedadapters/httptotal normalization function — dispatch 순서 + catch-all + safe-shape projection (D1/D2/D4/D7/D8) — 등급:planned- Trigger → kind 매핑 매트릭스 구현 (D4) — 등급:
planned - Redaction / safe-shape projection — 필드 allowlist + drop rule (D2/D5) — 등급:
planned - Total-normalization matrix test + raw-body/stack leakage negative test + §8.5 8종 negative fixture (D1/D2/D4) — 등급:
planned
진행 중 메모
없음 — /branch-spec 자동 채움 단계. 코드 미착수.
결정 사항
아래 8개 결정은 Decision Evidence Map 의 prose mirror. 근거는 대부분 hub 의 project decision(§8/§5.6)이며, D8 만 외부 official-doc(Zod)이 병행 근거.
- 2026-07-19: 모든 failure 를 total function 으로 단일 kind 정규화 / 이유: presentation 이 raw exception·status 로 분기하면 계약이 깨지고 leakage 발생 / 검토한 대안: page 별 ad hoc try/catch(hub §5.1
FE-REG-ERROR"raw status/message 로 UI 분기" = ad hoc failure) — 배포 0회 throwaway 에서만 / 근거: hub §8.2 total-function 문단, §5.6. - 2026-07-19: normalized failure 는 §8.1 safe 필드 집합만; raw body·token·header·URL·stack·storage value drop / 이유: FE-OC-008 의 "raw body/stack 미노출" 강제 / 검토한 대안: 전체 error object 전달 후 UI 에서 마스킹 — 유출 위험으로 기각 / 근거: hub §8.1, §7.1.
- 2026-07-19:
FE-REG-ERROR를 error kind → 기본 UX 의 단일 owner registry 로 고정 / 이유: kind/action/userMessageKey/redaction 을 code 전역에서 재정의하면 single-owner 계약 위반 / 검토한 대안: 각 adapter 가 로컬 enum 소유 — governance 붕괴로 기각 / 근거: hub §5.6, §5.1. - 2026-07-19: hub §8.2 trigger→kind 매핑(31-row / 고유 kind 26종)을 구현 매트릭스로 채택 / 이유: 트리거별 정규화 결과를 명세로 고정해야 total 성 검증 가능 / 검토한 대안: 상위 status class 만 매핑하고 나머지는 generic — negative fixture 통과 불가로 기각 / 근거: hub §8.2, §8.5.
- 2026-07-19: user copy 는
userMessageKey간접화,severity(telemetry routing)와 분리, raw backend message 금지 / 이유: 다국어·문안 변경·PII 유출 방지 / 검토한 대안: backenderror.message직접 표시 — §5.6 금지 / 근거: hub §5.6. - 2026-07-19:
action은 6개 closed vocabulary 로 제한 / 이유: 무한 spinner·history loop·반복 reload 같은 UX anti-pattern 을 계약으로 차단 / 검토한 대안: 자유 문자열 action — §8.4 제약 강제 불가로 기각 / 근거: hub §8.4, §5.6. - 2026-07-19:
defaultRetryable은 분류 힌트일 뿐 재시도 결정이 아님 / 이유: 재시도 루프는 api-client 소유(method/idempotency/cap 조합), 분류는 요청을 발행하지 않음 / 검토한 대안: 분류 계층이 retryable=true 를 보고 직접 재시도 — safe/idempotency 조건 무시로 storm 위험, 기각 / 근거: hub §5.6(defaultRetryableoverride 가능), §8.3, §8.2 note. - 2026-07-19: schema/envelope invalid 는 runtime-schema-validation 의 ZodError 를 소비해
SCHEMA_MISMATCH/ENVELOPE_MISMATCH로 매핑, safe issue-path count + schema ID 만 보존 / 이유: validator 소유는 sibling, 분류는 결과 계약만 소비 / 검토한 대안: 분류 계층에서 zod schema 직접 실행 — 소유 경계 위반, 기각 / 근거: ZodZOD-VALID-C4/ZOD-VALID-C5, hub §8.2·§5.6.
결정-근거 매핑
Supporting Claims는 hook quirk 회피를 위해FE-D###를 hub 경로에만 붙인다(sibling branch 링크 근처에 두지 않는다).
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | 모든 failure(response·adapter·browser exception)를 total function 으로 정확히 하나의 26-kind 로 정규화; 불일치·mapper 실패 시 catch-all UNKNOWN_FAILURE; un-normalized throw 의 presentation 통과 금지 (FE-OC-008) |
client SPA 가 공유 backend 계약을 소비하고 배포·라우트가 존재하는 한 이 default 유지 / ad hoc page-local try/catch 는 route 1개·외부 API 0개·배포 0회 throwaway prototype 일 때만(hub §0.4 escape) | raw/project-notes/ca-skeleton-frontend-operational-contract.md §8.2 total-function 문단·§5.6 enum |
project-decision |
총함수성은 exhaustive matrix test 로만 증명 가능(§8.5) — 미구현 시 mapper 누락 경로가 leak |
| D2 | normalized failure 는 §8.1 safe 필드(kind/code/httpStatus?/retryable/operationId/attemptCount/requestId?/traceId?/userMessageKey/action/causeClass)만 담고 raw body·token·authorization header·full URL/query·stack·storage value 는 drop (FE-OC-008) |
모든 kind·모든 경로에서 불변(FE-OC-008 이 무조건 강제) / 예외 없음 — 예외 필요 시 FE-OC-008 자체 변경 절차(hub §3.3) | ...frontend-operational-contract.md §8.1 shape·§7.1 "raw response body 를 log 금지"·§8.2 telemetry 열 |
project-decision |
leakage 는 negative test(직렬화 후 금지 필드 부재 assert)로만 확인 — 이게 FE-OC-008 minimum evidence |
| D3 | FE-REG-ERROR(src/contracts/errors.js)를 error kind→기본 UX 의 single-owner registry 로 고정; kind/defaultRetryable/severity/userMessageKey/action/telemetryEvent/redaction 7-field |
8-registry governance(hub FE-D018)가 유효한 한 registry-first / code generation SSOT 채택 시 재검토 |
...frontend-operational-contract.md §5.6·§5.1(FE-REG-ERROR owner=this branch, ad hoc=raw status/message 분기); ...frontend-operational-contract.md FE-D018 |
project-decision |
registry snapshot·single-owner scan 강제는 FE-OC-022 sibling 소유 — 본 브랜치는 스키마·row 만 |
| D4 | hub §8.2 trigger→kind 매핑(31-row / 고유 kind 26종)을 구현 매트릭스로 채택; 각 트리거는 정확히 하나의 kind, §8.5 8종 negative fixture 로 검증 | backend 가 structured JSON envelope + 표준 HTTP status 를 제공하는 한 유지 / backend protocol 이 근본적으로 다르면(hub 가정 C 무효) 매트릭스 재도출 | ...frontend-operational-contract.md §8.2 matrix·§8.5 fixtures |
project-decision |
일부 row 는 sibling 이 실패 신호를 생성해야 성립(schema→FE-OC-007, status/retry→FE-OC-009) — 그 계약 shape 미확정 시 매핑 재조정 |
| D5 | user copy 는 userMessageKey 간접화, severity(telemetry routing hint)와 분리, raw backend error.message 표시 금지 |
다국어/문안 거버넌스가 존재하는 한 항상 keyed / 대안 없음 — raw message 표시는 §5.6 이 금지 | ...frontend-operational-contract.md §5.6(userMessageKey·severity rule) |
project-decision |
message key → 실제 copy 카탈로그 소유(i18n)는 본 브랜치 밖 — 미정 시 key 계약만 고정 |
| D6 | 각 kind 는 6개 closed action(retry/reauth/navigate/reload-once/contact-support/none) 중 하나로 매핑, §8.4 allowed-when/MUST-NOT 제약 준수 |
UX 계약이 유지되는 한 closed set / product 가 새 recovery 모드를 요구하면 §8.4 확장 후 registry 갱신 | ...frontend-operational-contract.md §8.4 vocabulary·§5.6 action field |
project-decision |
action 의 실제 UI 실행은 async-ui(FE-OC-011)·render-recovery(FE-OC-015) 소유 — 본 브랜치는 kind→action 계약만 |
| D7 | defaultRetryable 은 분류 힌트일 뿐 재시도 결정·루프가 아님; 분류 계층은 어떤 요청도 발행하지 않음, request context override 가능 |
재시도 정책이 api-client(FE-OC-009) 소유인 한 힌트-only / 대안(분류가 직접 재시도)은 method+idempotency+cap 조건을 통합 소유하도록 scope 병합 시에만 |
...frontend-operational-contract.md §5.6(defaultRetryable override 가능)·§8.3 retry decision order·§8.2 note("retryable=true 는 필요조건이지 충분조건 아님") |
project-decision (delegated boundary) |
힌트와 실제 정책이 어긋나면(backend retryable=true 지만 unsafe mutation) storm — 통합 테스트로 경계 검증 필요 |
| D8 | content-type/JSON/envelope/payload invalid 는 runtime-schema-validation 이 낸 ZodError 를 소비해 CONTENT_TYPE_MISMATCH/MALFORMED_JSON/ENVELOPE_MISMATCH/SCHEMA_MISMATCH 로 매핑, schema ID + safe issue-path count 만 보존 |
FE-D007(Zod boundary validation)이 유효한 한 소비-매핑 / bundle budget·generated schema pipeline 이 대체안을 요구하면 재검토(hub FE-D007 revisit) |
raw/official-docs/zod-runtime-schema-validation-official.md#ZOD-VALID-C4, #ZOD-VALID-C5; ...frontend-operational-contract.md FE-D007·§8.2 해당 row·§5.6 |
official-vendor-doc + project-decision |
ZodError → 어느 kind(envelope vs payload)인지는 sibling 이 어느 단계에서 던졌는지에 의존 — 처리 순서(§7.3 4~6단계) 계약 미확정 시 매핑 모호 |
구현 가이드
plannedblueprint. 경로는 hub §4.6 Planned directory blueprint + §5.1 owner map 에서 유도되므로 grounded 하지만 repository 생성 시 바뀔 수 있어 전체planned. sibling 링크가 필요한 detail 은 §범위 Out of scope 로 위임했고 여기 남기지 않는다(R3).
1. FE-REG-ERROR 계약 registry (src/contracts/errors.js)
Trace: D3 + D4 + D5 + D6 /
FE-OC-008·FE-REG-ERROR·hub §5.6·§8.2·§8.4. 26-kind enum(hub §5.6) 각각에 대해 7-field row.
- UNSUPPORTED_IMPL_DECISION:
code필드 포맷(§8.1 은code존재만 명시, 포맷 미규정) →<KIND>접미 없는 안정 문자열 상수 채택. trade-off: kind 와 1:1 이면 code 잉여지만, backenderror.code(§7.3)와 대응시키려면 별 축이 필요 — 초기엔 kind 파생 상수로 두고 backend code 매핑표는 추후.- UNSUPPORTED_IMPL_DECISION:
userMessageKey명명 스킴(§5.6 은 "key" 만 요구, 규칙 미규정) →error.<kind_snake>.message제안(planned). trade-off: i18n 카탈로그 소유 밖이므로 key 계약만 고정, 실제 문안은 미정.
| Field | 규칙(hub §5.6) | 이 브랜치 명세 |
|---|---|---|
kind |
frontend stable enum | §5.6 26-kind enum 그대로, rename 금지 |
defaultRetryable |
request context override 가능 | boolean 기본값; 실제 재시도는 D7 대로 미실행 |
severity |
telemetry routing hint, user copy 분리 | enum(예: low/warn/error) — telemetry 소비, D5 대로 copy 와 분리 |
userMessageKey |
raw backend message 금지 | key 상수(UNSUPPORTED_IMPL_DECISION 스킴) |
action |
6-value closed set | D6 vocabulary 중 하나 |
telemetryEvent |
registry event 매핑 | FE-REG-TELEMETRY event 참조(소유는 FE-OC-014, 여기선 참조만) |
redaction |
cause/body/header drop rule | D2 safe-shape 와 일치하는 drop rule id |
2. Total normalization 함수 (adapters/http error mapper)
Trace: D1 + D2 + D4 + D7 + D8 /
FE-OC-008·hub §8.2·§8.1·§7.3(처리 순서 4~8단계).adapters/http가 "envelope/schema/error mapping" 을 소유(hub §4.2).
- UNSUPPORTED_IMPL_DECISION: 정규화 함수 파일/심볼명(hub 는
adapters/http/폴더와src/contracts/errors.jsregistry 만 grounding, 함수명 미규정) →adapters/http/normalize-failure.js단일 export 제안. trade-off: 이름은 임의지만 "단일 진입 + adapters/http 내부" 두 제약만 지키면 계약 동등.- UNSUPPORTED_IMPL_DECISION: dispatch 메커니즘(§8.2 는 총함수·catch-all 만 요구, switch vs lookup table 미규정) → 트리거 판별 → kind lookup 순서 dispatch 제안. trade-off: lookup table 은 registry 대조가 쉽고 switch 는 분기 명시적 — 총함수성만 test 로 보장하면 무관.
- UNSUPPORTED_IMPL_DECISION:
causeClassinternal allowlist 실제 값(§8.1 "internal allowlist only" 만, 목록 미열거) → 초기 allowlist(예:network/parse/schema/auth/http-status/browser-storage/render/unknown) 제안(planned). trade-off: allowlist 밖 값은unknown으로 접어 leak 방지, 세분화는 telemetry 요구에 따라 확장.
처리 순서(§7.3 4~8단계 하류에서 호출됨, 요청 발행 없음):
input = { transportOutcome | thrownValue, requestContext }
1. aborted(navigation/user/superseded) 이면 REQUEST_ABORTED
2. network-level opaque 실패면 NETWORK_UNREACHABLE / timeout 이면 REQUEST_TIMEOUT
3. content-type/JSON/envelope/payload 실패 신호(sibling 생성)면 D8 매핑
4. HTTP status class 면 §8.2 status row 매핑(auth/authz/not-found/conflict/validation/rate/server/generic)
5. chunk/boot/release/deploy/storage/render/telemetry/query-cache 트리거면 해당 kind
6. 위 어디에도 안 맞거나 mapper 자체 throw 면 UNKNOWN_FAILURE(catch-all)
7. 매핑 결과를 §3 safe-shape 로 projection 후 반환 (raw value 폐기)
3. Trigger → kind 매핑 매트릭스
Trace: D4 + D8 / hub §8.2 (31-row / 고유 kind 26종 — row 기준으로 세면 같은 kind 로 매핑되는 status row 5개가 누락된다)·§8.5. 아래는 hub §8.2 를 이 브랜치의 in-scope(=여기서 정규화 산출) 관점으로 재기술한 것이며, "생성 소유"가 sibling 인 트리거는 소비만 표시(값 재정의 아님).
- UNSUPPORTED_IMPL_DECISION: 없음 — 모든 row 는 hub §8.2 가 trigger·kind·retry·fallback·UX·telemetry 를 직접 grounding.
| 트리거 그룹(§8.2) | 산출 kind | 생성 소유 | 본 브랜치 역할 |
|---|---|---|---|
| network opaque / total timeout / abort | NETWORK_UNREACHABLE·REQUEST_TIMEOUT·REQUEST_ABORTED |
api-client transport(FE-OC-006) |
소비→정규화 |
| content-type/JSON/envelope/payload invalid | CONTENT_TYPE_MISMATCH·MALFORMED_JSON·ENVELOPE_MISMATCH·SCHEMA_MISMATCH |
schema-validation(FE-OC-007) |
소비→정규화(D8) |
| 401/403/404/409/422/other-4xx/429/5xx | AUTH_REQUIRED·FORBIDDEN·NOT_FOUND·CONFLICT·VALIDATION_REJECTED·UNKNOWN_CLIENT_FAILURE·RATE_LIMITED·SERVER_FAILURE |
api-client status(FE-OC-006) |
소비→정규화, defaultRetryable 힌트만(D7) |
| auth attach/recovery adapter 실패 | AUTH_INTEGRATION_FAILURE |
auth/api-client(FE-OC-010) |
소비→정규화 |
| chunk/boot/release/deploy | CHUNK_LOAD_FAILURE·BOOT_CONFIG_FAILURE·RELEASE_MANIFEST_FAILURE·DEPLOY_MISMATCH |
bootstrap/release(FE-OC-015/FE-OC-016) |
소비→정규화 |
| storage unavailable/quota | STORAGE_UNAVAILABLE·STORAGE_QUOTA_EXCEEDED |
storage(FE-OC-013) |
소비→정규화 |
| render throw / telemetry fail / query-cache fail / unknown | RENDER_FAILURE·TELEMETRY_FAILURE·QUERY_CACHE_FAILURE·UNKNOWN_FAILURE |
각 owner / catch-all | 소비→정규화, 최종 catch-all 소유 |
4. Redaction & safe-shape projection
Trace: D2 + D5 / hub §8.1·§7.1·§8.2 telemetry 열. 정규화 함수 마지막 단계(§2 step 7).
- UNSUPPORTED_IMPL_DECISION: projection 구현 방식(§8.1 은 필드 집합만, allowlist-copy vs blocklist-delete 미규정) → allowlist-copy(안전 필드만 새 객체로 복사) 제안. trade-off: blocklist-delete 는 신규 raw 필드 추가 시 leak 위험 — allowlist 가 fail-closed 이므로 채택.
- 통과 허용(allowlist): §8.1 필드 집합 그대로.
- 항상 drop: raw response body, token, authorization header, full URL/query, stack, storage value(§8.1) + backend raw
error.message(D5, §5.6). - telemetry projection: §8.2 telemetry 열의 kind별 safe 항목만(예: status group·attempts·elapsed bucket·schema ID·safe issue-path count) — raw URL·body·principal·token 금지. 실제 전송은
FE-OC-014소유(여기선 payload 계약만).
5. test 카탈로그 (§20 Measurable completion)
Trace: D1 + D2 + D4 / hub §8.5·§20("total normalization matrix + raw body/stack leakage negative tests").
FE-OC-020기여.
- UNSUPPORTED_IMPL_DECISION: test 파일 경로·러너별 배치(hub §4.6 은
tests/unit|component|...폴더만) →tests/unit/error-classification/*배치 제안. trade-off: 경로 임의, "unit 레벨 + registry/mapper 대상" 계약만 유지.
| Fixture(§8.5) | 기대 정규화 결과 |
|---|---|
JSON operation + text/html response |
CONTENT_TYPE_MISMATCH |
| auth attach callback throw/reject | AUTH_INTEGRATION_FAILURE |
| bounded recovery invalid state | AUTH_INTEGRATION_FAILURE |
| release manifest network/parse/schema 실패 | RELEASE_MANIFEST_FAILURE |
| QueryCachePort adapter throw / invalid result | QUERY_CACHE_FAILURE |
unregistered 418/기타 unmapped 4xx |
UNKNOWN_CLIENT_FAILURE |
thrown non-Error / symbol / mapper exception |
UNKNOWN_FAILURE |
| 총함수 matrix test(추가) | 26-kind 전체 트리거 exhaustive → 정확히 1 kind |
| leakage negative test(추가) | 정규화 결과 직렬화 후 body/token/header/URL/stack/storage value 부재 assert |
엣지·실패·의존
- 실패·엣지 경로:
- Mapper 자체 throw → 최종 catch-all 이 raw value 폐기 후
UNKNOWN_FAILURE반환(§8.2 total-function 문단). 정규화 실패로 인한 un-normalized throw 는 계약상 존재 불가. - Unmapped 4xx(예:
418) →UNKNOWN_CLIENT_FAILURE; unmapped thrown value(non-Error/symbol) →UNKNOWN_FAILURE(§8.5). - 이미 정규화된 failure 재진입 → 재정규화는 idempotent 여야 함(같은 kind 유지) — Claims To Verify 로 승격.
- registry 미등록 kind 사용 → registry 가 closed enum 이므로 컴파일/lint 단계 차단이 이상적(강제는
FE-OC-022governance sibling). defaultRetryable=true이지만 unsafe mutation → 분류는 힌트만 노출, 재시도 미실행(D7). 실제 안전성은 api-client 가 method/idempotency/cap 으로 최종 판단.
- Mapper 자체 throw → 최종 catch-all 이 raw value 폐기 후
- 다른 계약 의존(hook quirk 회피: sibling 링크는
FE-OC-###로만 짝지음):- raw/branch-notes/feature-api-client-response-envelope-contract (
FE-OC-006/FE-OC-009) — transport outcome·HTTP status·retry 정책을 생성/소유. 그 계약(§7.3 처리 순서, §7.4 timeout/abort) 이 바뀌면 본 브랜치 트리거→kind 매핑 재조정 필요. - raw/branch-notes/feature-runtime-schema-validation-contract (
FE-OC-007) — content-type/JSON/envelope/payload 검증 실패(ZodError)를 생성. 어느 단계에서 던지는지가 envelope vs payload kind 를 결정(D8) — 계약 변경 시 매핑 영향. - raw/branch-notes/feature-frontend-observability-logging-trace-contract (
FE-OC-014) —telemetryEvent·redaction sink 를 소비. registry 의 telemetry payload 계약이 그 소유와 정합해야 함. - raw/branch-notes/feature-async-ui-state-contract (
FE-OC-011) 와 raw/branch-notes/feature-frontend-render-recovery-boundary-contract (FE-OC-015) — normalized kind + action 을 소비(terminal-error state·operational-vs-defect 분리). 본 브랜치 산출이 이들 입력. - raw/branch-notes/feature-frontend-test-taxonomy-contract (
FE-OC-020) — negative fixture 를 gate 로 소비.
- raw/branch-notes/feature-api-client-response-envelope-contract (
검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| 정규화가 진짜 total 이다 — 어떤 경로도 un-normalized 로 presentation 도달 안 함 | 코드 미존재, mapper 누락 분기 가능 | exhaustive trigger matrix test + mapper-throws fixture → UNKNOWN_FAILURE (§8.5) |
needs-confirmation |
| normalized failure 에 raw body/stack/token/header/URL/storage value 가 유출되지 않는다 | allowlist projection 미구현 | leakage negative test — 결과 직렬화 후 금지 필드 부재 assert (FE-OC-008 minimum evidence) | needs-confirmation |
| 26-kind 각각 정확히 1 registry row + closed action 1개를 갖는다 | registry 미작성 | registry snapshot test + action ∈ 6-set 검증 | needs-confirmation |
| 분류 계층은 어떤 요청도 발행하지 않는다(재시도는 api-client 소유) | 힌트/정책 경계가 코드로 미분리 | 분류 함수 단위 test 에서 fetch/network mock 호출 0회 assert | needs-confirmation |
| ZodError → envelope vs payload kind 매핑이 처리 순서와 정합 | sibling 처리 단계 계약 미확정 | schema-invalid fixture(envelope-level, payload-level 각각) → ENVELOPE_MISMATCH/SCHEMA_MISMATCH |
needs-confirmation |
| 재정규화가 idempotent 하다(이미 정규화된 failure 재진입 시 동일 kind) | 재진입 경로 미설계 | 정규화 결과를 재입력 → 동일 kind assert | planned |
관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
/coverage가 채우는 생성물이며 손으로 유지하지 않는다.
| 관심사 | 상태 | owner | 심각도 | 근거 |
|---|---|---|---|---|
TODO — /coverage 실행 전 |
missing | (없음) | 미평가 | TODO |
마주친 문제
없음 — scaffolding 단계
묶음 (이 branch에서 파생된 자료)
가져온 흐름 단계
| Stage Ref | Order | Owner | Input | Action | Output |
|---|---|---|---|---|---|
FLOW-FE-RESP-001@1 |
1 | raw/branch-notes/feature-api-client-response-envelope-contract | HTTP 요청 | transport 완료 대기 | raw Response |
FLOW-FE-RESP-002@1 |
2 | raw/branch-notes/feature-api-client-response-envelope-contract | raw Response | content-type 기대값 검사 | 본문 판독 가능 Response |
FLOW-FE-RESP-003@1 |
3 | raw/branch-notes/feature-api-client-response-envelope-contract | 본문 판독 가능 Response | JSON parse | unvalidated JSON |
FLOW-FE-RESP-004@1 |
4 | raw/branch-notes/feature-runtime-schema-validation-contract | unvalidated JSON | envelope 공유 스키마 검증 | discriminated envelope |
FLOW-FE-RESP-005@1 |
5 | raw/branch-notes/feature-runtime-schema-validation-contract | discriminated envelope | success/failure 분기 검증 | 분기 확정 envelope |
FLOW-FE-RESP-006@1 |
6 | raw/branch-notes/feature-runtime-schema-validation-contract | 분기 확정 envelope | payload per-operation 스키마 검증 | 검증된 payload(deep clone) |
FLOW-FE-RESP-007@1 |
7 | raw/branch-notes/feature-boundary-mapper-viewmodel-contract | 검증된 payload | DTO → application model 매핑 | application model |
가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
FE-OC-006@1 |
raw/branch-notes/feature-api-client-response-envelope-contract | 모든 HTTP는 shared client를 MUST 통과하고 timeout·abort·response parsing을 page에서 구현하면 안 됨 | import 참조로 적용 |
FE-OC-007@1 |
raw/branch-notes/feature-runtime-schema-validation-contract | JSON envelope와 payload는 boundary에서 runtime schema를 MUST 통과 | import 참조로 적용 |
FE-OC-009@1 |
raw/branch-notes/feature-api-client-response-envelope-contract | retry는 safe/idempotent request에 한정하고 cap·jitter·Retry-After를 MUST 적용 |
import 참조로 적용 |
FE-OC-010@1 |
raw/branch-notes/feature-frontend-auth-session-integration-contract | skeleton은 session state를 소비하되 token lifecycle을 MUST 소유하지 않음 | 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-013@1 |
raw/branch-notes/feature-frontend-storage-registry-contract | storage key는 namespace·version·classification을 MUST 가지며 token/secret 저장을 금지 | import 참조로 적용 |
FE-OC-014@1 |
raw/branch-notes/feature-frontend-observability-logging-trace-contract | telemetry는 best-effort이며 render·API success를 차단하면 안 되고 PII·token을 전송하면 안 됨 | import 참조로 적용 |
FE-OC-015@1 |
raw/branch-notes/feature-frontend-render-recovery-boundary-contract | expected operational error와 render defect를 MUST 분리하고 reload loop를 금지 | import 참조로 적용 |
FE-OC-016@1 |
raw/branch-notes/feature-frontend-release-cache-rollback-contract | HTML, asset, runtime config, release manifest cache policy를 MUST 구분 | import 참조로 적용 |
FE-OC-022@1 |
raw/branch-notes/feature-frontend-contract-registry-governance | 8개 registry는 single primary owner와 compatibility impact를 MUST 기록 | 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):