32 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-multi-protocol-api-transport-contract | branch-note | raw | BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-031 | project-work-item | ca-skeleton-frontend-operational-contract | WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-031 |
|
|
|
|
1 | feature-frontend-multi-protocol-api-transport-contract |
|
|
|
2026-07-28 | in-progress |
branch: feature-frontend-multi-protocol-api-transport-contract
부모 (필수)
형제 branch (같은 부모, 이번 확장에서 함께 생성):
- raw/branch-notes/feature-frontend-binary-file-io-store-contract
- raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract
- raw/branch-notes/feature-frontend-large-object-transfer-contract
- raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract
- raw/branch-notes/feature-frontend-background-execution-worker-contract
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
2 - 패킷 스키마:
contract_packet: 1 - 완료 조건: protocol별 성공/실패 정규화와 gateway fallback fixture가 통과한다
상속한 프로젝트 결정
| 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_ALT_PROTOCOL 을 이 branch 가 소유하고 default OFF 로 유지한다 |
raw/project-notes/ca-skeleton-frontend-operational-contract |
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-PROTOCOL-001@1 |
transport default는 REST이고 GraphQL·gRPC-Web·Connect-Web은 FE-REG-API의 protocol 필드로 opt-in하며 미지원 환경은 REST gateway로 fallback한다 | FE-REG-API.protocol 값에 따른 adapter 선택 규칙에 적용한다 |
raw/project-notes/ca-skeleton-frontend-operational-contract |
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-VALIDATION-001@1 |
boundary runtime validation은 Zod schema로 수행한다 | codec 디코드 결과도 예외 없이 스키마 검증을 거친다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | 이 branch 는 신규 port 를 정의하지 않는다. GraphQL·gRPC-Web·Connect-Web adapter 는 기존 ResourceQueryPort/ResourceCommandPort 를 구현한다 |
refines DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-PROTOCOL-001@1 |
UNSUPPORTED_DECISION — 조사 후에도 외부 근거 없음. trade-off: 프로토콜별 port 를 만들면 use case 가 프로토콜을 알게 되어, backend 가 REST 에서 gRPC 로 옮길 때 use case 를 다시 써야 한다. 비용은 프로토콜 고유 기능(양방향 스트림 등)이 필요해질 때 port 를 새로 뚫어야 하는 것 |
proposed |
| D2 | transport status 만으로 성공을 판정하지 않는다. protocol 별 성공 판정 함수가 별도로 존재한다 | local |
raw/official-docs/graphql-over-http-draft-status-errors.md#C3 (상태 코드와 무관하게 본문 처리), raw/official-docs/grpc-connect-status-codes-error-model.md#C3 (status 는 transport 와 별도), #C5 (Connect 는 non-200) |
proposed |
| D3 | GraphQL 응답에 errors 가 있으면 PARTIAL_RESULT_FAILURE 로 정규화한다. 규격은 이를 "successful execution" 이라 부르므로 이 결정은 의도적 이탈이다 |
local |
raw/official-docs/graphql-over-http-draft-status-errors.md#C4 (규격의 명명), #C6 (data: null 이면 errors 가 반드시 있음) |
proposed |
| D4 | GraphQL 성공 판정은 상태 코드가 아니라 본문의 data·errors 구조로 한다. 200 만 검사하지 않는다 |
local |
raw/official-docs/graphql-over-http-draft-status-errors.md#C1 (data+errors 는 294 권고), #C2 (data 있으면 2xx), #C3 (상태 코드 무관 처리) |
proposed |
| D6 | grpc-status → 재시도 가능 여부 매핑은 우리 프로젝트 결정으로 등록하고 그 근거를 남긴다. 규격 인용으로 대신하지 않는다 |
local |
raw/official-docs/grpc-connect-status-codes-error-model.md#C1 (코드 목록은 확정), #C2 (재시도 판정은 애플리케이션 몫이라고 규격이 명시) |
proposed |
| D7 | gRPC-Web adapter 와 Connect adapter 를 분리한다. 성공 판정 코드를 공유하지 않는다 | local |
raw/official-docs/grpc-connect-status-codes-error-model.md#C5 (Connect 오류는 non-200), #C6 (Connect 는 trailer 미사용), #C7 (gRPC-Web 은 다른 프로토콜) |
proposed |
deferred (이번 회차 조사 범위 밖): D8 — persisted-document ID 기반 GraphQL 요청의 전송 방식(GET vs POST, 캐시 가능성, media type 협상). GraphQL over HTTP draft §5·§6.2 를 따로 읽어야 하며, 이번 조사는 §6.4 상태 코드·오류 처리에 한정했다.
선언한 예외
해당 없음.
가져온 artifact 계약
| Artifact Ref | Owner | Producer | Schema Ref |
|---|
가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
FE-GATE-030@1 |
raw/project-notes/ca-skeleton-frontend-operational-contract | protocol 별 성공/실패 정규화 fixture 가 실패하면 merge 를 MUST 차단 | 이 branch 가 owner 로서 fixture 와 report 를 산출 |
FE-OC-006@1 |
raw/branch-notes/feature-api-client-response-envelope-contract | 모든 HTTP는 shared client를 MUST 통과하고 timeout·abort·response parsing을 page에서 구현하면 안 됨 | protocol adapter 도 shared client 위에 얹힌다 |
FE-OC-007@1 |
raw/branch-notes/feature-runtime-schema-validation-contract | JSON envelope와 payload는 boundary에서 runtime schema를 MUST 통과 | 디코드 후 검증을 DELEG-FE-010 으로 위임 |
FE-OC-008@1 |
raw/branch-notes/feature-frontend-error-classification-boundary-contract | 모든 failure는 stable frontend error kind로 MUST 정규화하고 raw body·stack을 UI에 노출하면 안 됨 | protocol 실패 3종의 정규화 대상 |
수신한 위임
없음. 이 branch 는 DELEG-FE-010 의 delegator 다.
가져온 흐름 단계
| Stage Ref | Order | Owner | Input | Action | Output |
|---|---|---|---|---|---|
FLOW-FE-RESP-004@1 |
4 | feature-runtime-schema-validation-contract |
unvalidated JSON | envelope 공유 스키마 검증 | discriminated envelope |
FLOW-FE-RESP-005@1 |
5 | feature-runtime-schema-validation-contract |
discriminated envelope | success/failure 분기 검증 | 분기 확정 envelope |
FLOW-FE-RESP-006@1 |
6 | feature-runtime-schema-validation-contract |
분기 확정 envelope | payload per-operation 스키마 검증 | 검증된 payload(deep clone) |
목표
GraphQL·gRPC-Web·Connect-Web adapter 가 기존 ResourceQueryPort/ResourceCommandPort 를 구현하도록 고정하고, protocol 별 성공/실패 판정을 정규화된 failure 로 매핑한다. 이 계약이 없으면 200 OK + errors[] 응답이 success 로 반환되어 빈 화면이 정상처럼 보이고, HTTP 200 + grpc-status: 13 이 성공으로 처리된다.
- 이슈:
- PR:
범위
포함 범위
FE-REG-API의protocol·operationRef·transferMode소비와 adapter 선택- GraphQL codec — persisted-document ID 기반 요청,
errors[]처리 - gRPC-Web·Connect-Web codec — protobuf 인코딩/디코딩,
grpc-status↔ 정규화 kind 매핑 - REST gateway fallback (
disabledFallback: degraded-alternative) - 신규 실패 3종 정규화:
PROTOCOL_STATUS_MISMATCH·CODEC_DECODE_FAILURE·PARTIAL_RESULT_FAILURE CAP_FE_ALT_PROTOCOLcapability 행 소유
제외 범위
- use case, domain model, business rule — adapter 계약까지만 정의한다
- 신규 port 정의 — 0개가 이 branch 의 설계 결론이다. 프로토콜이 application 에 새 인터페이스로 새면
FE-D010dependency inversion 이 무너진다 - GraphQL 스키마 설계, protobuf 서비스·메시지 정의
- 스키마 생성 파이프라인의 SSOT —
FE-Q-013 - 디코드 이후 payload 의 runtime schema 검증 —
DELEG-FE-010로 raw/branch-notes/feature-runtime-schema-validation-contract 에 위임 - 스트림 protocol(
sse·websocket·poll) — raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract 소유
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
[[docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design]] §5.2·§6.2 |
신규 port 0개 결론과 FE-REG-API 확장 |
| raw/official-docs/zod-runtime-schema-validation-official | 디코드 후 검증의 상위 근거 |
| raw/official-docs/graphql-over-http-draft-status-errors | D3 errors 응답 정규화가 규격 이탈임을 밝히는 근거 · D4 상태 코드가 아니라 본문으로 성공 판정 |
| raw/official-docs/grpc-connect-status-codes-error-model | D2 protocol 별 성공 판정 분리 · D6 재시도 판정이 우리 결정인 근거 · D7 gRPC-Web 과 Connect 를 분리하는 근거 |
| raw/project-notes/ca-skeleton-frontend-operational-contract §2.1.4·§7.3·§8.2 | 응답 흐름 8단계와 실패 정규화 |
근거 등급 경계: 2026-07-28 /branch-spec 조사로 세 프로토콜의 오류 표현 방식은 규격 근거를 확보했다. 다만 두 가지를 구분해야 한다. (1) gRPC 코드 목록(0~16)은 규격이 확정해 주지만, 어떤 코드가 재시도 가능한지는 규격이 명시적으로 애플리케이션에 위임한다 — grpc-connect-status-codes-error-model#C2. 즉 매핑표는 "규격 확인 후 채운다" 가 아니라 "우리가 정하고 근거를 남긴다" 다. (2) GraphQL over HTTP 는 draft 이며, 그 규격은 field error 상황을 오히려 "successful execution" 이라 부른다(graphql-over-http-draft-status-errors#C4). 우리 PARTIAL_RESULT_FAILURE 결정은 규격 준수가 아니라 의도적 이탈이다. 신규 port 0개(D1)는 여전히 외부 근거가 없다.
TODO
FE-REG-API.protocol별 adapter 선택 규칙 확정 — 등급:planned- protocol 별 성공 판정 함수 분리 — 등급:
planned - GraphQL 본문
errors→PARTIAL_RESULT_FAILURE매핑 (상태 코드 무관,294포함) — 등급:planned grpc-status→ 정규화 kind 매핑표를 우리 결정으로 작성 후 backend 소유자와 대조 — 등급:planned- gRPC-Web adapter 와 Connect adapter 분리 유지 fixture — 등급:
planned - codec decode 실패 →
CODEC_DECODE_FAILURE— 등급:planned - REST gateway fallback 경로 — 등급:
planned - protocol 차원과 gateway fallback 발생률 telemetry 등록 (관심사 7 should-fix) — 등급:
planned FE-GATE-030protocol mapping report 산출 — 등급:planned
진행 중 메모
이 branch 의 가치는 "무엇을 추가했는가" 보다 "무엇을 추가하지 않았는가" 에 있다. 신규 port 0개라는 결론이 유지되어야 backend 가 REST 에서 gRPC 로 옮겨갈 때 use case 를 다시 쓰지 않는다. 리뷰 시 port 가 늘어나 있으면 그 자체가 회귀 신호다.
결정 사항
- 2026-07-28: 신규 port 0개 / 이유: 프로토콜은 registry 데이터이지 타입이 아니며, port 로 새면 dependency inversion 이 무너짐 / 검토한 대안:
GraphQLPort·GrpcWebPort분리 / 근거: 설계문서 §5.2 - 2026-07-28:
errors있는 응답을 실패로 정규화 / 이유: 부분 데이터를 성공으로 취급하면 빈 화면이 정상처럼 보임 / 검토한 대안: 부분 성공 상태 신설 / 근거: 규격 이탈을 자각한 project decision. GraphQL over HTTP draft 는 이를 "successful execution" 이라 부른다(graphql-over-http-draft-status-errors#C4) - 2026-07-28: 성공 판정에서 상태 코드를 빼고 본문 구조만 봄 / 이유: 규격이 data+errors 에
294를 권고하고 클라이언트에게 상태 코드와 무관한 처리를 요구함 / 검토한 대안:200·294를 모두 허용 목록에 넣기 / 근거:graphql-over-http-draft-status-errors#C1·#C3. 허용 목록 방식은 draft 가 코드를 바꾸면 다시 깨진다 - 2026-07-28: gRPC-Web 과 Connect adapter 분리 / 이유: Connect 는 오류를 non-200 으로 보내고 trailer 를 쓰지 않아 판정 규칙이 정반대 / 검토한 대안: 공통 gRPC 계열 adapter / 근거:
grpc-connect-status-codes-error-model#C5·#C6·#C7
결정-근거 매핑
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | 신규 port 0개 | 항상. 프로토콜 고유 기능(gRPC 양방향 스트림 등)이 use case 레벨에 필요해지면 재검토 | 없음 — 조사 후에도 외부 근거 없음 | UNSUPPORTED_DECISION |
추상화가 새는 프로토콜 기능이 있을 수 있음 |
| D2 | protocol 별 성공 판정 함수 분리 | 항상. 세 프로토콜의 성공 신호 위치가 서로 달라 예외가 없다 | graphql-over-http-draft-status-errors.md#C3, grpc-connect-status-codes-error-model.md#C3·#C5 |
official-reference |
판정 로직이 프로토콜마다 흩어져 중복될 수 있음 |
| D3 | errors 있으면 PARTIAL_RESULT_FAILURE |
항상. 제품이 부분 데이터를 의미 있게 쓸 수 있으면 재검토 | graphql-over-http-draft-status-errors.md#C4(규격은 성공이라 부름), #C6 |
project decision — 규격 이탈을 자각한 선택 |
일부 필드만 실패한 응답을 통째로 버린다. 규격을 따르는 다른 클라이언트와 동작이 달라진다 |
| D4 | 상태 코드가 아니라 본문으로 성공 판정 | 항상 | graphql-over-http-draft-status-errors.md#C1·#C2·#C3 |
official-reference (draft) |
draft 라 294 권고가 바뀔 수 있다. 다만 "본문으로 판정" 은 코드가 바뀌어도 유효 |
| D6 | 재시도 매핑을 우리 결정으로 등록 | 항상. 규격이 판단을 위임했으므로 위임을 받은 쪽이 근거를 남겨야 한다 | grpc-connect-status-codes-error-model.md#C1, #C2 |
official-reference(위임 사실) + project decision(매핑 내용) |
매핑이 backend 의 코드 사용 관습과 어긋나면 재시도가 과하거나 부족해진다 |
| D7 | gRPC-Web 과 Connect adapter 분리 | 항상. 두 프로토콜의 오류 위치가 정반대다 | grpc-connect-status-codes-error-model.md#C5, #C6, #C7 |
official-reference |
유사한 코드가 두 벌 생긴다. 공유하려는 리팩터가 나중에 회귀를 만든다 |
구현 가이드
2026-07-28
/branch-spec조사(GraphQL over HTTP draft + gRPC status codes + Connect protocol)로 채웠다. 규격이 확정해 주는 것과 우리가 정해야 하는 것을 절마다 구분했다. 후자는UNSUPPORTED_IMPL_DECISION+ trade-off 로 표시했다(CLAUDE.md §15.5 R2).
1. 성공 판정 — 프로토콜마다 신호가 다른 곳에 있다
Trace: D2(판정 함수 분리) ←
graphql-over-http-draft-status-errors.md#C3,grpc-connect-status-codes-error-model.md#C3·#C5/ D4(본문 판정) ←#C1·#C2·#C3/ D7(adapter 분리) ←#C5·#C6·#C7
성공을 판정하는 위치가 세 프로토콜에서 전부 다르다. 이것이 판정 함수를 공유할 수 없는 이유다.
| protocol | 성공 신호 위치 | 틀리기 쉬운 구현 |
|---|---|---|
| REST | HTTP 상태 코드 | — (기준선) |
| GraphQL | 본문의 data·errors 구조. 상태 코드는 200 일 수도 294 일 수도 있다 |
200 만 검사 → 294 응답을 실패로 오분류. 2xx 만 검사 → errors 를 놓침 |
| gRPC-Web | trailer 의 grpc-status. HTTP 는 200 이어도 실패일 수 있다 |
HTTP 상태만 검사 → 실패를 성공으로 처리 |
| Connect | HTTP 상태 코드(오류는 non-200) + 본문 JSON 의 code |
gRPC-Web 과 같은 코드로 처리 → 정반대 규칙이라 반드시 틀림 |
GraphQL 행이 특히 함정이다. 규격은 data 와 errors 가 함께 있으면 294 를 권고하고(#C1), 클라이언트는 상태 코드와 무관하게 본문을 처리하라고 명시한다(#C3). 그래서 판정은 상태 코드를 보지 않고 data 와 errors 의 존재로 한다.
gRPC-Web 과 Connect 를 한 adapter 로 묶지 않는다. Connect 는 trailer 를 아예 쓰지 않고(#C6) 오류를 non-200 으로 보내며(#C5), 규격 자신이 gRPC-Web 과 다른 프로토콜이라고 밝힌다(#C7). 이름이 비슷하다는 이유로 공유하면 한쪽이 반드시 틀린다.
UNSUPPORTED_IMPL_DECISION — 판정 함수를 protocol 값으로 조회하는 registry 형태로 두는 것. 규격은 판정 규칙만 정하고 우리 코드 구조를 정하지 않는다. trade-off: 조건 분기 대신 조회 표를 쓰면 새 프로토콜을 추가할 때 등록 누락이 boot 시점에 드러난다. 비용은 간접 참조가 한 겹 늘어나는 것.
2. GraphQL errors 처리 — 규격과 다르게 간다
Trace: D3 ←
graphql-over-http-draft-status-errors.md#C4·#C6
규격은 field error 가 있는 부분 응답을 "successful execution" 이라고 부른다(#C4). 우리는 이를 PARTIAL_RESULT_FAILURE 로 정규화한다. 규격 준수가 아니라 의도적 이탈이며, 이 문장이 노트에 남아야 다음 사람이 근거를 오해하지 않는다.
이탈하는 이유는 부분 데이터가 화면에서 정상처럼 보이기 때문이다. 목록의 절반이 비어 온 응답을 성공으로 넘기면 사용자는 "데이터가 없다" 고 읽고, 우리는 오류를 관측하지 못한다.
telemetry 에는 error 개수와 path 개수만 남기고 error message 본문은 남기지 않는다. #C6 대로 data: null 이면 errors 가 반드시 있으므로, data 유무만으로 request error 와 field error 를 가를 수 있다.
UNSUPPORTED_IMPL_DECISION — 부분 데이터를 버리는 것(수신은 하되 use case 에 넘기지 않음). 규격도 우리 근거도 "버려라" 라고 말하지 않는다. trade-off: 살려서 넘기면 use case 마다 "이 데이터가 완전한가" 를 판단해야 하고 그 판단이 빠지는 순간 조용한 오류가 된다. 비용은 일부 필드만 실패한 응답에서 쓸 수 있는 데이터까지 잃는 것.
3. gRPC 코드 매핑 — 규격이 우리에게 넘긴 결정
Trace: D6 ←
grpc-connect-status-codes-error-model.md#C1·#C2
코드 목록은 규격이 준다 — 0(OK)부터 16(UNAUTHENTICATED)까지 17개(#C1). 그러나 재시도 가능 여부는 규격이 정하지 않는다. 원문이 명시적이다: "individual applications must make their own determination as to which status codes should cause an RPC to be retried"(#C2).
따라서 매핑표는 FE-REG-ERROR 에 우리 결정으로 등록하고, 각 행에 왜 그렇게 정했는지를 남긴다. "규격이 그렇다" 는 근거로 쓸 수 없다. 매핑이 backend 의 코드 사용 관습과 어긋나면 재시도가 과하거나 부족해지므로, 표를 만든 뒤 backend 소유자와 대조하는 것이 FE-GATE-030 이전 단계로 필요하다.
UNSUPPORTED_IMPL_DECISION — 17개 코드를 어떤 kind 로 접을지, 그중 무엇을 retryable 로 둘지. 규격이 판단을 위임했으므로 이 표 전체가 우리 trade-off 다. 지금 값을 적지 않는 이유는 backend 대조 없이 정하면 두 번 정하게 되기 때문이다.
4. 이 branch 가 남기지 않는 것 (R3)
- 디코드 이후 payload 의 스키마 검증 →
DELEG-FE-010로 raw/branch-notes/feature-runtime-schema-validation-contract 에 위임(FLOW-FE-RESP-004~006) - error kind 의 등록과 총함수 정규화 → raw/branch-notes/feature-frontend-error-classification-boundary-contract 소유(
FE-OC-008). 이 branch 는 신규 3종의 진입 조건만 정한다 - timeout·retry·idempotency 기본값 → raw/branch-notes/feature-api-client-response-envelope-contract 소유(
FE-OC-006) - 스키마·코드 생성 파이프라인 SSOT →
FE-Q-013 - 스트림 protocol(
sse·websocket·poll) → raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract 소유
엣지·실패·의존
- 실패·엣지 경로
- HTTP 200 +
grpc-status비0 →PROTOCOL_STATUS_MISMATCH. status 는 transport 와 별도로 전달되므로(grpc-connect-status-codes-error-model#C3) HTTP 상태만 보는 구현은 실패를 성공으로 처리한다 (D2) - protobuf/GraphQL 디코드 실패 →
CODEC_DECODE_FAILURE, 본문을 telemetry 에 남기지 않음 - GraphQL 응답에
errors존재 →PARTIAL_RESULT_FAILURE, error 개수와 path 개수만 telemetry. 규격은 이를 "successful execution" 이라 부르므로 의도적 이탈이다(graphql-over-http-draft-status-errors#C4) (D3) - GraphQL 상태 코드가
294→ 실패가 아니다. data 와 errors 가 함께 있다는 규격 권고 신호이므로(#C1) 본문 구조로 판정한다.200만 성공으로 보는 구현은 이 응답을 잘못 분류한다 (D4) - Connect 오류를 HTTP 200 으로 기대 → Connect 는 오류를 non-200 으로 보낸다(
#C5). gRPC-Web 판정 코드를 그대로 쓰면 여기서 어긋난다 (D7) - capability OFF 또는 브라우저 미지원 → REST gateway 로 fallback (
degraded-alternative) - gateway 도 없으면
CAPABILITY_UNSUPPORTED
- HTTP 200 +
- 다른 계약 의존
- raw/branch-notes/feature-api-client-response-envelope-contract — timeout·retry·idempotency 기본값(
FE-OC-006). D6 의 재시도 매핑이 이 기본값 위에 얹히므로, 상위 retry 상한과 protocol status 기반 재시도가 곱해지지 않아야 한다 - raw/branch-notes/feature-runtime-schema-validation-contract —
FLOW-FE-RESP-004~006(DELEG-FE-010). 디코드 산출물이 이 단계로 넘어가며, 디코드가 타입을 보장한다고 건너뛰면 안 된다 - raw/branch-notes/feature-frontend-error-classification-boundary-contract — 신규 3종 kind(
PROTOCOL_STATUS_MISMATCH·CODEC_DECODE_FAILURE·PARTIAL_RESULT_FAILURE)의 등록과defaultRetryable. D6 의 매핑표가 이 registry 에 들어간다 - raw/branch-notes/feature-boundary-mapper-viewmodel-contract — DTO→model 매핑. 디코드 산출물이 mapper 입력이며, 프로토콜별로 산출물 모양이 달라지면 mapper 가 프로토콜을 알게 되어 D1 이 무너진다
- raw/branch-notes/feature-frontend-env-runtime-config-contract
D4—CAP_FE_ALT_PROTOCOL해석 시점. flag OFF 면 protocol adapter 가 번들에 없어야 한다(FE-GATE-033)
- raw/branch-notes/feature-api-client-response-envelope-contract — timeout·retry·idempotency 기본값(
검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
200 OK + errors[] 가 success 로 반환되지 않는다 |
GraphQL 클라이언트 기본 동작이 부분 성공 | negative fixture — 해당 응답 주입 후 PARTIAL_RESULT_FAILURE 확인 |
planned |
HTTP 200 + grpc-status: 13 이 실패로 정규화된다 |
transport status 만 보는 구현이 흔함 | negative fixture — trailer 주입 후 kind 확인 | planned |
| protocol adapter 가 신규 port 를 만들지 않았다 | 구현 중 편의로 port 가 늘어나기 쉬움 | architecture fixture — application/ports/ 파일 수가 늘지 않았는지 |
planned |
| REST gateway fallback 이 실제로 도달한다 | capability OFF 경로가 테스트에서 빠지기 쉬움 | integration test — flag OFF 로 같은 operation 호출 | planned |
| codec 산출물이 반드시 스키마 검증을 거친다 | 디코드가 이미 타입을 보장한다고 착각하기 쉬움 | negative fixture — 스키마 위반 디코드 결과 주입 후 SCHEMA_MISMATCH |
planned |
grpc-status 매핑표가 backend 의 코드 사용과 일치한다 |
규격은 재시도 판정을 애플리케이션에 위임했으므로(grpc-connect-status-codes-error-model#C2) 대조 상대가 명세가 아니라 backend 소유자다 |
매핑표 초안 작성 후 backend 소유자와 코드별 의미 대조 | needs-confirmation |
GraphQL 상태 코드 294 응답이 올바르게 처리된다 |
200 만 검사하는 구현이 흔하고, draft 권고라 실제로 오는지도 미확인 |
negative fixture — 294 + data + errors 응답 주입 후 PARTIAL_RESULT_FAILURE 확인. 별도로 backend 가 294 를 보내는지 실측 |
needs-confirmation |
| Connect adapter 가 gRPC-Web 판정 코드를 공유하지 않는다 | 이름이 비슷해 리팩터로 합쳐지기 쉬움 | architecture fixture — 두 adapter 가 같은 성공 판정 함수를 참조하지 않는지 | planned |
| GraphQL 성공 판정이 상태 코드에 의존하지 않는다 | 상태 코드 검사가 습관적으로 들어감 | fixture — 같은 본문을 200·294 두 상태로 주입했을 때 판정 결과가 같은지 |
planned |
| 부분 데이터를 버리는 정책이 제품에서 수용 가능하다 | 규격은 이를 성공이라 부르므로 이탈 비용을 제품이 감당해야 함 | 제품 소유자 확인 — 목록 절반이 실패한 응답을 통째로 버려도 되는지 | needs-confirmation |
Audit & Findings
/branch-spec2026-07-28 조사에서 규격 원문과 대조해 발견한 것. hub 소유 항목은 정합 권고만 남긴다(hub §3.3).
| Finding ID | 대상 | 현재 서술 | 조사 결과 | 권고 | 처리 |
|---|---|---|---|---|---|
GRAPHQL_STATUS_ASSUMPTION |
hub §8.2 실패 매트릭스 및 이 노트의 D3 초안 |
"GraphQL 200 OK + errors[]" — 상태 코드를 200 으로 특정한다 |
graphql-over-http-draft-status-errors#C1: data 와 errors 가 함께 있으면 규격은 294 를 권고한다. #C3: 클라이언트는 상태 코드와 무관하게 본문을 처리해야 한다 |
진입 조건을 "200 OK + errors[]" 가 아니라 "응답 본문에 errors 존재" 로 바꿀 것. 상태 코드를 조건에 넣으면 294 를 놓친다 |
open — hub §8.2 정정 후보 (compatibility_impact: none, 진입 조건의 정확화) |
SPEC_DEVIATION_UNDECLARED |
이 노트의 D3 초안 |
"부분 성공이 아니라 PARTIAL_RESULT_FAILURE 로 정규화한다" — 규격을 따르는 것처럼 읽힌다 |
graphql-over-http-draft-status-errors#C4: 규격은 field error 상황을 "partial response" 이자 "successful execution" 이라고 부른다 |
이탈임을 명시할 것. 이탈 자체는 유효하나 근거를 규격으로 오인하면 안 된다 | resolved 2026-07-28 — D3 서술과 §구현 가이드 2 에 명시 |
RETRY_MAPPING_MISATTRIBUTED |
이 노트의 TODO "grpc-status → 정규화 kind 매핑표 (명세 확인 후)" |
명세를 읽으면 매핑이 나온다고 전제한다 | grpc-connect-status-codes-error-model#C2: "individual applications must make their own determination as to which status codes should cause an RPC to be retried" — 규격이 판단을 명시적으로 위임한다 |
"명세 확인 후" 를 "우리가 정하고 backend 와 대조" 로 바꿀 것 | resolved 2026-07-28 — D6 신설, TODO 문구 교체 |
NO_GROUND_TRUTH |
/branch-spec §2 ca-tmpl 대조 |
명령은 ca-tmpl registry·코드와 대조하라고 요구 | ca-tmpl 은 Gradle/Java 백엔드 전용. frontend 구현 repo 미식별 |
전 항목 planned 유지 |
open — FE-Q-001 선행 |
관심사 커버리지 (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.
| # | 관심사 | 판정 | 근거 |
|---|---|---|---|
| 1 | 문제와 실패 모드가 구체적인가 | covered-here | §목표 — 빈 화면이 정상처럼 보이는 경로. §엣지 7개 |
| 2 | 상속한 결정을 실제로 적용했는가 | covered-here | PROTOCOL-001 → D1·D7, VALIDATION-001 → DELEG-FE-010, CAPABILITY-001 → CAP_FE_ALT_PROTOCOL 소유 |
| 3 | project-wide default 와 limit | covered-here | D2(판정 분리), D4(본문 판정), D6(매핑은 우리 결정), D7(adapter 분리) |
| 4 | 대안을 검토했는가 | covered-here | §결정 사항 — 프로토콜별 port / 부분 성공 상태 신설. D1 은 trade-off 명시 |
| 5 | 금지 구현 | covered-here | §구현 가이드 1 — 판정 함수 공유 금지, 상태 코드만 검사 금지. §구현 가이드 3 — 규격 인용으로 재시도 근거 대체 금지 |
| 6 | 실패 경로가 error kind 로 매핑되는가 | covered-here | 신규 3종 + CAPABILITY_UNSUPPORTED. 등록은 error-classification branch 소유 |
| 7 | 관측 가능한가 | should-fix | PARTIAL_RESULT_FAILURE 의 error·path 개수는 정했으나, 어느 protocol 로 처리됐는지를 구분하는 차원이 FE-REG-TELEMETRY 에 없다. gateway fallback 발생률도 미등록 |
| 8 | 위임 경계가 명확한가 | covered-here | DELEG-FE-010, §구현 가이드 4 의 R3 목록 |
| 9 | 검증 수단이 있는가 | covered-here | §검증해야 할 주장 11행, FE-GATE-030 fixture + protocol mapping report |
| 10 | 말할 수 있는 범위 | covered-here | 전 항목 planned — NO_GROUND_TRUTH |
판정: Covered (missing 0) · Should-fix 1건(관심사 7). Blocking 아님.
마주친 문제
없음.
묶음 (이 branch에서 파생된 자료)
Sub-branches (세부 작업)
아직 없음.
오류 기록 (이 branch 작업 중 발생)
아직 없음.
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
아직 없음.
강의 (이 작업을 위해 학습한 강의)
아직 없음.
job-posting tie-ins (이 작업에서 파생된 글감)
아직 없음.
관련 일일 노트
- 아직 없음
완료 후 정리
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경:
- wiki 추출 대상 (verified만,
wiki/projects/로만 추출):actually-implemented항목: 없음locally-verified항목: 없음prod-verified항목: 없음
- 추출하지 않을 항목: 현재 전 항목
planned