43 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-observability-logging-trace-contract | branch-note | raw | BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-012 | project-work-item | ca-skeleton-frontend-operational-contract | WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-012 |
|
|
1 | feature-frontend-observability-logging-trace-contract |
|
|
|
2026-07-18 | in-progress | e79f4a8ea9b3ea9f54126cdb47a1228194322b9fa883ca499d546f9ffa607e63 |
|
branch: feature-frontend-observability-logging-trace-contract
Layer:
raw/branch-notes/— 단일 브랜치의 TODO·결정·진행 기록./branch-spec로 hub 계약을 구현-준비 spec 으로 내렸다. 프론트엔드 코드가 아직 없으므로 모든 구현 주장은planned이며 코드 evidence 는 repository 생성 후 채운다.
부모 (필수)
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: telemetry registry·redaction·bounded queue·sink failure test가 통과한다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1 |
telemetry는 best-effort queue와 redaction을 사용하며 sink failure가 UI를 실패시키지 않는다 | TelemetryPort·queue·redaction·degradation 계약에 적용한다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1 |
route, API operation, env, storage, error, query, telemetry, release token을 8개 registry로 관리한다 | hub §5.8이 정의한 FE-REG-TELEMETRY 스키마·초기 event를 코드 registry로 구현한다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | telemetry를 best-effort non-blocking 경로로 격리한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D2 | low-cardinality allowlist와 forbidden attribute redaction을 강제한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D3 | bounded queue와 비재귀 drop reporting을 사용한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D4 | FE-REG-TELEMETRY를 event schema의 single SSOT로 사용한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D5 | backend 지원 여부에 따라 trace correlation을 전파하거나 local ID로 강등한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D6 | delivery transport를 adapter-owned degradation 경로로 둔다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D7 | terminal failure telemetry를 bounded safe event로 제한한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
| D8 | TELEMETRY_ENABLED를 composition-root kill-switch로 소비한다 | local |
raw/project-notes/ca-skeleton-frontend-operational-contract | proposed |
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
없음.
목표
이 브랜치는 project-wide contract FE-OC-014 (telemetry 는 best-effort 이며 render·API success 를 차단하면 안 되고 PII·token 을 전송하면 안 됨) 와 그 owner decision raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 (telemetry = best-effort queue + redaction, sink failure 는 UI 를 실패시키지 않음) 를 구현자가 되묻지 않아도 코드를 쓸 수 있는 수준의 spec 으로 내린다. 핵심 불변식은 운영 격리 (operational isolation) — telemetry 실패가 사용자 경험(render/API critical path)과 완전히 분리된다는 것이다. 동시에 이 브랜치는 FE-REG-TELEMETRY registry (§5.8 event/attribute/redaction) 의 single owner 로서 hub §5.8 이 정의한 최소 스키마와 초기 event 집합을 코드 registry 로 구현하고 emit 지점을 확정하며, FE-OC-008 (실패→telemetry rule), FE-OC-021 (low-cardinality 성능 attribute), FE-OC-025 (FE-RB-004 telemetry sink failure runbook) 에 telemetry 기여 edge 를 제공한다. 등급: 전 항목 planned (repository 부재).
- 이슈: 없음 (repository 미생성)
- PR: 없음
범위
포함 범위
- Best-effort 전달 불변식 — telemetry send 가 render·API critical path 를 절대 block 하지 않음, sink/queue/adapter-init 실패가 UI 를 실패시키지 않음 (
FE-OC-014, raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.2). FE-REG-TELEMETRYregistry 파일 소유 — registry 스키마와 초기 5 event 의 정의 는 hub §5.8 소유이고, 본 브랜치는 그 registry 를 코드로 구현하고 emit 지점을 확정한다(§5.8, §5.1). 자유 문자열 event 금지.- Redaction — low-cardinality allowlist context 만 전송, forbidden attribute(token·email·raw URL/query/body·storage value·stack) 전송 금지 (§11.1, §5.8).
- Bounded queue + overflow 정책 + 비재귀 — bounded queue, overflow drop 정책 registry 명시, telemetry 실패를 동일 sink 로 재귀 보고하지 않음 (§11.2, §16.4).
- Delivery degradation — local/dev console-safe sink, prod endpoint 부재/invalid 시 telemetry 만 degrade 하고 app 계속 실행 (§11.2, §16.4).
TELEMETRY_ENABLEDkill-switch 소비 — runtime flag(defaultfalse)가 off 일 때 telemetry 전체를 무력화하는 소비 측 의미와 그 단일 적용 지점 확정,FE-RB-004mitigation "telemetry runtime flag disable" 의 실행 가능성 보장 (§5.4, §16.4). key 선언·schema 검증 자체는FE-OC-004소유.- Trace correlation (telemetry 관점) — W3C
traceparent가 backend contract 상 허용될 때만 전파, 미지원 시 local operation ID 로 degrade, retry 는 같은 logical operation correlation 유지하되 attempt 구분 (§11.3, §8.1). - 기여 edge —
FE-OC-008실패→telemetry rule column,FE-OC-021duration/attempt bucket 제공,FE-OC-025FE-RB-004recovery assertion.
제외 범위
의도적으로 제외 — 다른 owner 브랜치/외부 계약이 소유. 본 브랜치는 telemetry 관점의 consume/기여만 한다.
- Error kind 정규화 taxonomy 자체 —
FE-OC-008owner (frontend-error-classification-boundary branch). 본 브랜치는error_kind를 소비만 하고 정의하지 않음. - Render error boundary 소유·복구 —
FE-OC-015owner (frontend-render-recovery-boundary branch). 본 브랜치는 boundary-catch 신호를 consume 해ui.render.failed를 emit 만 함. - Web Vitals 측정·NFR 리포트 —
FE-OC-021owner (raw/branch-notes/feature-web-vitals-performance-budget-contract). 본 브랜치는 low-cardinality attribute bucket 만 공급. FE-RB-004runbook 1차 소유 —FE-OC-025owner (frontend-operational-runbook branch). 본 브랜치는 technical escalation 이며 diagnosis evidence field 만 공급.- Telemetry endpoint 의 CSP
connect-src·bundle 내 secret 금지 강제 —FE-OC-019owner (frontend-browser-security-boundary branch). - Runtime config 로딩·검증 —
FE-OC-004owner (frontend-env-runtime-config branch). 본 브랜치는 endpoint 값을 consume 만 함(의존, §엣지·실패·의존). - Token lifecycle — 외부 Keycloak / raw/branch-notes/feature-frontend-auth-session-integration-contract (
FE-OC-010). telemetry 는 token 을 절대 전송하지 않음.
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
| raw/project-notes/ca-skeleton-frontend-operational-contract | 본 브랜치의 거의 모든 결정의 SSOT — FE-D021(§3.2), FE-OC-014(§2.1), telemetry 계약(§11), FE-REG-TELEMETRY(§5.8/§5.1), 실패 matrix telemetry column(§8.2), FE-RB-004(§16.4), TELEMETRY_ENABLED runtime key(§5.4) + boot sequence(§6.3)/config validation(§6.4)/composition root(§4.5). D1~D8 전부 이 hub 의 project decision 을 인용한다. |
| raw/official-docs/react-ui-library-official | REACT-UI-C1 — presentation 이 React component 로 구성됨(버튼~페이지). ui.render.failed event 의 emit point 가 React component boundary catch 라는 D4 event catalog 항목을 간접 뒷받침. boundary 자체의 소유는 render-recovery branch(FE-OC-015)에 위임. |
참고: §11.3 trace correlation 이 언급하는 W3C
traceparent(Trace Context) 는 실제 표준이나raw/official-docs/에 아직 아카이브되지 않았다. 따라서 사실로 인용하지 않고 hub §11.3 의 project decision(허용될 때만 전파)만 근거로 쓴다. 표준 자체를 근거로 삼아야 할 결정이 생기면wiki-source-summarizer로 먼저 아카이브한다.
TODO
각 항목 옆 증거 등급. repository 부재 → 전부 planned / needs-confirmation.
FE-REG-TELEMETRYregistry (src/contracts/telemetry.js): hub §5.8 의 7-field 스키마와 초기 5 event 를 코드로 구현 + emit 지점 배선 — 등급:planned- Redaction 강제 (allowlist projection) + forbidden-attribute scan test — 등급:
planned - Bounded queue + overflow drop 정책 + queue drain/memory test — 등급:
planned - Sink failure / degradation test (endpoint invalid → telemetry 만 degrade, app 계속) — 등급:
planned - Trace correlation 전파 + retry attempt 구분 test — 등급:
planned TelemetryPort(application) + telemetry adapter + composition-root wiring — 등급:plannedTELEMETRY_ENABLED=false→ no-op port 주입 + zero-network/zero-queue 회귀 test (FE-RB-004mitigation 재현) — 등급:planned- 구현 repository 및 검증 evidence 식별 — 등급:
needs-confirmation
진행 중 메모
/branch-spec로 hub §2/§3/§5/§8/§11/§16 을 내려 D1~D7 을 확정. 모든 grounding 은 hub project decision(FE-D021 중심) — 외부 official-doc 은 react-ui(간접)만 관여. web research 0건(hub 가 충분).- 2026-07-20 loop-back fill: coverage 감사에서
TELEMETRY_ENABLEDkill-switch 소비 측 메커니즘이 미결정(MISSING_CONCERN)으로 드러나 D8 + 구현 가이드 7 을 추가했다. hub §5.4 는 key 를 선언하고 §16.4 는 그 disable 을 mitigation lever 로 요구 하지만 소비 형태는 미명시 — 사용자 소유 브랜치가 없어 본 브랜치가 소비 owner 다(FE-OC-004는 key 선언·schema 검증만 소유). 같은 pass 에서telemetry.delivery.dropped의 전달 채널(비재귀 구체화)과route_id/operation_idproducer 의존을 명시했다. - 운영 격리(operational isolation)가 이 브랜치의 축: telemetry 는 관찰 목적이며 절대 UX 를 볼모로 잡지 않는다. 그래서 delivery guarantee 를 주장하지 않고 best-effort 로 못 박는다.
결정 사항
아래 Decision Evidence Map 의 prose mirror. 각 결정의 근거는 hub project decision.
- 2026-07-18: Telemetry = best-effort, non-blocking — render/API critical path 를 차단하지 않고 sink failure 가 UI 를 실패시키지 않는다. 대안(delivery-guaranteed audit channel)은 regulated audit event 가 필요할 때만 별도 계약으로 분리. 근거: raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.2.
- 2026-07-18: Redaction 우선 — low-cardinality allowlist context 만 전송, token/PII/raw payload 는 forbidden. 근거: hub §11.1, §5.8.
- 2026-07-18: Bounded queue + 비재귀 — overflow drop 정책을 registry 에 명시, telemetry 실패를 동일 sink 로 재귀 전송하지 않음. 근거: hub §11.2, §16.4.
- 2026-07-18:
FE-REG-TELEMETRYsingle SSOT — 자유 문자열 event 금지, 초기 5 event 고정. 근거: hub §5.8, §5.1, FE-D018. - 2026-07-18: Trace correlation 은 조건부 전파 — backend contract 가 허용할 때만 traceparent 전파, 아니면 local operation ID 로 degrade. 근거: hub §11.3, §8.1.
- 2026-07-18: Delivery transport 는 adapter-owned·degradable — dev console sink, prod endpoint invalid 시 telemetry 만 degrade. 근거: hub §11.2, §4.2, §16.4.
- 2026-07-18: 실패→telemetry 매핑은 bounded·safe (
FE-OC-008기여) — terminal 실패당 safe field 만으로 최대 1 event, abort 는 error event 미발생,TELEMETRY_FAILURE재귀 금지. 근거: hub §8.2, §8.1. - 2026-07-20:
TELEMETRY_ENABLED는 composition-root 단일 지점의 kill-switch — flag 가false(hub 기본값)면 real adapter 를 아예 구성하지 않고 no-opTelemetryPort를 주입한다. queue·redaction·sink·counter 가 전혀 생성되지 않으므로 disable 은 "전송 억제"가 아니라 "경로 부재"다. flag 는 boot-time runtime config 이므로 in-session flip 은 없고, 다음 boot 에 반영된다. 근거: hub §5.4(TELEMETRY_ENABLEDruntime·required·defaultfalse), §16.4 Mitigation("telemetry runtime flag disable"), §6.3 boot sequence, §4.5 composition root.
결정-근거 매핑
모든 Supporting Claim 은 hub project decision.
[[...operational-contract]](project link) 옆의FE-D###·§n은 consistency hook 상 project 링크로 안전하게 검증된다.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | Telemetry 는 best-effort — render·API critical path 를 block 하지 않고 sink failure 가 UI 를 실패시키지 않는다 (FE-OC-014) |
product telemetry 는 best-effort default 유지. regulated audit event 처럼 delivery guarantee 가 필요하면 best-effort 와 분리된 별도 audit channel 계약 신설 (FE-D021 revisit trigger) | raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.2 | project-decision |
repository 부재 — telemetry throw 가 render/API success 를 깨지 않음을 증명하는 non-blocking test 필요 |
| D2 | Redaction — low-cardinality allowlist context 만 전송, forbidden attribute(token·email·raw URL/query/body·storage value·stack) 전송 금지 | allowlist 가 invariant(accepted-documented-only). 신규 attribute 는 registry 추가 전 low-cardinality + non-PII 검토 통과 시에만 허용; 실패하면 forbidden 분류 | raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.1 §5.8 | project-decision |
redaction 은 caller 가 아니라 transport boundary(adapter)에서 강제해야 함 — forbidden-attribute scan test 로 leakage 0 증명 필요 |
| D3 | Bounded queue + overflow drop 정책 registry 명시 + telemetry 실패 비재귀 보고 | queue 는 항상 bounded. drop 방향(oldest vs newest)은 event class 별 registry 선언값 — 미선언 시 기본 oldest-drop (§구현 가이드 4 의 UNSUPPORTED_IMPL_DECISION) |
raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.2 §16.4 | project-decision |
queue 상한 크기 미확정 — memory/queue drain test 로 bound 내 drain 증명 필요 |
| D4 | FE-REG-TELEMETRY 가 event/attribute/redaction 의 single SSOT; 자유 문자열 event 금지; 초기 5 event(app.boot.failed·api.request.failed·ui.render.failed·release.mismatch.detected·telemetry.delivery.dropped) 고정 |
registry-owned 유지. code generation SSOT 채택이 FE-D018 revisit trigger. ui.render.failed trigger 는 React boundary catch (REACT-UI-C1 이 presentation=React 구성을 뒷받침) |
raw/project-notes/ca-skeleton-frontend-operational-contract FE-D018 §5.8 §5.1; raw/official-docs/react-ui-library-official REACT-UI-C1 | project-decision |
registry schema validation test(자유 문자열 event reject) 필요; event 별 required attribute 가 실제 발생 지점에서 수집 가능한지 미검증 |
| D5 | Trace correlation — W3C traceparent 는 backend contract 허용 시에만 전파, requestId/traceId 는 safe internal reference 로 보관, raw trace header user 미노출, 미지원 backend 는 local operation ID 로 degrade, retry 는 같은 logical operation correlation 유지하되 attempt 구분 |
backend contract 가 traceparent 지원 → 전파; 미지원 → local operation ID 로 degrade | raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.3 §8.1 | conditional-default |
전파는 backend contract 의존(외부); W3C Trace Context 표준 미아카이브 → 표준 세부는 사실 인용 불가; retry 간 correlation(같은 op, distinct attempt) test 필요 |
| D6 | Delivery transport 는 adapter-owned·degradable — local/dev console-safe sink, prod endpoint 부재/invalid 면 telemetry 만 degrade 하고 app 계속, page-hide sendBeacon 은 adapter decision 이며 delivery guarantee 아님 |
local/dev → console sink; prod → endpoint sink; page-hide sendBeacon 은 optional(no guarantee) |
raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.2 §4.2 §16.4 | project-decision |
endpoint invalid boot path 가 telemetry 만 degrade(app 계속)함을 증명하는 sink-failure test 필요 |
| D7 | 실패→telemetry 매핑은 bounded·safe (FE-OC-008 기여) — §8.2 각 terminal normalized failure 는 safe field(status group·attempt bucket·route ID)만으로 최대 1 event, abort 는 error event 미발생, TELEMETRY_FAILURE 는 재귀 금지 |
normalized error taxonomy 는 error-classification branch(FE-OC-008) 소유 — 본 브랜치는 그 kind 를 consume 해 telemetry rule column 만 구현. taxonomy 가 바뀌면 매핑 갱신 |
raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §8.2 §8.1 | project-decision |
error_kind registry 소유는 error-classification boundary branch(FE-OC-008) — 그 registry 미확정 시 매핑 draft 상태 |
| D8 | TELEMETRY_ENABLED kill-switch 는 composition root 단일 지점에서 소비 — false(hub default)면 real adapter 미구성 + no-op TelemetryPort 주입(queue·redaction·sink·counter 모두 미생성), true 면 D6 delivery ladder 진입. flag 는 boot-time 값이므로 in-session flip 없음(다음 boot 반영), 따라서 flip 시 stranded queue 문제가 정의상 발생하지 않음. FE-RB-004 mitigation "telemetry runtime flag disable" 은 이 경로로 실행된다 |
flag false → no-op(관측 0, 부작용 0); true → 정상 경로. call-site 조건 분기(if (telemetry))나 port null 주입은 채택하지 않음 — hub §4.2 상 presentation/use-case 는 TelemetryPort 만 참조하므로 disable 이 call site 로 새면 안 됨 |
raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §5.4 §16.4 §6.3 §4.5 §11.2 | project-decision |
no-op vs 미구성의 구현 형태 는 hub 미명시(구현 가이드 7 의 UNSUPPORTED_IMPL_DECISION); flag off 상태에서도 product e2e 가 동일해야 함을 증명하는 both-state test 필요 |
구현 가이드
plannedblueprint (프론트엔드 코드 부재). 경로는 hub §4.6 Planned directory blueprint + §5.1 registry owner map 에서 도출된plannedanchor 이며 repository 생성 시 변경될 수 있다. 3-rule (R1 Trace 필수 / R2 UNSUPPORTED_IMPL_DECISION / R3 no OUT_OF_BRANCH_SCOPE) 준수.
1. TelemetryPort + adapter + composition-root wiring
Trace: D1 + D6 ·
FE-OC-014· raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §4.2 §4.6
- UNSUPPORTED_IMPL_DECISION: port method 표면(
record(event)단일 vsrecord+flush+shutdown) 과 파일명은 hub 미명시 → 최소 표면(recordonly)을 초기 default 로 제안. trade-off: 최소 표면은 오용 여지가 적으나 page-hide flush 를 adapter 내부로 숨겨야 함.
| 요소 | Planned 경로 | 책임 | MUST NOT |
|---|---|---|---|
TelemetryPort (application-owned interface) |
src/application/ports/ |
use-case/presentation 이 부르는 telemetry 계약 정의 | 구현·browser transport·UX 결정 |
| telemetry adapter | src/adapters/telemetry/ |
queue·redaction·sink 구현, port 구현 | navigation/UX 결정 (hub §4.2) |
| composition root | src/bootstrap/composition-root.js |
runtime config(TELEMETRY_ENABLED + endpoint)로 real adapter 또는 no-op port 를 생성·주입 (kill-switch 단일 지점 — 7 참조) |
business rule, call-site 조건 분기 |
- presentation/use-case 는
TelemetryPort만 참조하고 transport 를 직접 부르지 않는다 (hub §4.2 presentation MUST NOT own telemetry transport). - adapter 는 endpoint 값을 runtime config 에서 주입받는다 (config 로딩은 env-runtime-config branch 소유 — §엣지·실패·의존).
2. FE-REG-TELEMETRY registry
Trace: D4 ·
FE-REG-TELEMETRY· raw/project-notes/ca-skeleton-frontend-operational-contract FE-D018 §5.8 §5.1
- UNSUPPORTED_IMPL_DECISION: 없음 — 스키마 필드와 초기 event 집합은 hub §5.8 을 그대로 채택(신규 제안 아님).
Planned 경로: src/contracts/telemetry.js (single owner: 본 브랜치, hub §5.1).
registry 최소 스키마(7-field)의 owner 는 raw/project-notes/ca-skeleton-frontend-operational-contract §5.8 이다 — "§5.8 그대로" 라고 스스로 밝혔듯 복제였으므로 걷어낸다. 요약 한 줄: event 는 eventName·trigger·requiredAttributes·optionalAttributes·forbiddenAttributes·sampling·delivery 를 모두 갖고, required attribute 는 low-cardinality 만 허용한다.
초기 5 event 의 정의(trigger + required attributes)는 raw/project-notes/ca-skeleton-frontend-operational-contract §5.8 소유다. 본 절은 그 event 를 어디서 emit 하는가 만 정한다 — 정의를 옮겨 적으면 hub 가 attribute 를 바꿀 때 이 표가 조용히 낡는다(실제로 attempt_count → attempt_count_bucket rename 을 놓쳤었다).
| Event | 본 브랜치의 emit 지점 |
|---|---|
app.boot.failed |
boot config/release validation 실패 경로 |
api.request.failed |
API client 의 terminal normalized failure 반환 직전 |
ui.render.failed |
render recovery boundary 의 catch 핸들러 |
release.mismatch.detected |
release check 가 mismatch 를 확정한 지점 |
telemetry.delivery.dropped |
본 브랜치 sink adapter 의 queue drop 경로 |
- 자유 문자열 event 전송 금지 (hub §5.1 ad hoc use failure). registry 미등록 event 는 build/test 에서 reject.
3. Redaction 강제
Trace: D2 ·
FE-OC-014· raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.1 §5.8
- 해소됨(2026-07-21) — 근거 있는 결정: redaction 메커니즘은 hub 가 정한다. raw/project-notes/ca-skeleton-frontend-operational-contract §11.1 이 "이 목록은 exhaustive default-deny allowlist다 … 목록 밖 attribute 는 transport boundary 에서 제거된다" 로 메커니즘(default-deny allowlist projection)과 강제 지점(transport boundary)을 모두 명시했다. 본 브랜치가 고른 trade-off 가 아니므로
UNSUPPORTED_IMPL_DECISION라벨을 뗀다.
- 허용/금지 attribute 어휘의 owner 는 raw/project-notes/ca-skeleton-frontend-operational-contract §11.1 이며 exhaustive default-deny allowlist 다. 목록을 여기에 옮겨 적지 않는다 — 옮겨 적은 사본이 hub 보다 짧으면 본 절 §2 가 선언한 event(
release.mismatch.detected의active_release_id·mismatch_kind,telemetry.delivery.dropped의reason·queue_size_bucket)가 transport boundary 에서 전부 제거되어 계약이 자기모순에 빠진다. - 본 브랜치가 소유하는 것은 강제 방법 이다: redaction 은 adapter 의 transport boundary 에서 수행하고 caller 를 신뢰하지 않는다. forbidden-attribute scan test 가 emit payload 를 검사해 위반 시 실패(§검증).
4. Bounded queue + overflow + degradation ladder + 비재귀
Trace: D3 + D6 · raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.2 §16.4
- UNSUPPORTED_IMPL_DECISION: (a) queue 상한 크기, (b) 기본 drop 방향(oldest vs newest), (c) page-hide
sendBeacon사용 여부는 hub 미명시 → 초기 default 로 oldest-drop + 유한 상한(초기 제안값, memory test 로 확정) 제안,sendBeacon은 adapter 내부 optional. trade-off: oldest-drop 은 최신 event 를 보존하나 boot 초기 event 를 잃을 수 있음.
| 단계 | 동작 | 근거 |
|---|---|---|
| 정상 | bounded queue 적재 → sink flush | §11.2 |
| overflow | drop 정책(registry 선언; 기본 oldest-drop) 적용 + telemetry.delivery.dropped self-metric 1건 |
§11.2, §5.8 |
| sink non-2xx/network 실패 | product flow 계속, console-safe fallback(safe field 한정), 동일 sink 재귀 보고 금지 | §16.4 Containment |
| adapter init 실패 | telemetry 만 degrade, app 계속 | §11.2 |
| prod endpoint 부재/invalid | telemetry 만 degrade, app 계속 | §11.2 |
- telemetry failure 를 telemetry 로 재귀 전송하지 않는다 (hub §11.2).
telemetry.delivery.dropped는 self-metric 이며 sink 실패의 원인 event 를 다시 sink 로 보내지 않는다.
telemetry.delivery.dropped 자체의 전달 채널 (비재귀 불변식의 구체화):
UNSUPPORTED_IMPL_DECISION: hub §5.8 은
telemetry.delivery.dropped의 event shape 만 정의하고 그 event 자신이 어느 채널로 나가는지는 명시하지 않는다. hub §16.4 Diagnosis evidence 가 요구하는 산출물이 event stream 이 아니라 "dropped event count"·"queue size bucket" 이라는 점에 근거해, 아래 counter-우선 채널을 초기 default 로 제안한다. trade-off: counter 는 drop 폭주 시에도 자기 증폭이 없고 §16.4 evidence 형태와 1:1 이지만, 개별 drop 의 시점 분포(timeline)를 잃는다.
- self-metric 은 동일 bounded queue 에 재적재(re-enqueue)하지 않는다 — full/dead queue 로 되돌리는 것은 정의상 순환이며 overflow 를 가속한다.
- 대신 adapter 내부의 in-process 단조 counter(key =
reason×queue_size_bucket, hub §5.8 required attribute 와 동형)로 집계하고, hub §16.4 Containment 의 console-safe fallback(safe field 한정)으로 즉시 관측 가능하게 한다. - 이 counter 는
FE-RB-004diagnosis evidence 의dropped event count로 그대로 공급된다(§6 기여 edge). - sink 가 회복되어 정상 flush 가 성공한 이후에 한해, 누적 counter 를 aggregated event 1건으로 승격 전송하는 것은 adapter 의 optional 결정이다 — 실패 중인 sink 로는 시도하지 않으며 delivery guarantee 로 표현하지 않는다 (hub §11.2).
- counter 자체는 sink 실패로 소실되지 않아야 하므로 queue 와 독립된 lifetime 을 가진다(document lifetime 한정, 영속화 없음 — 영속화는 storage registry owner 영역).
5. Trace correlation
Trace: D5 · raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §11.3 §8.1
- UNSUPPORTED_IMPL_DECISION: local operation ID 포맷(예:
operationId#attempt)은 hub 미명시 → 사용자 선택. trade-off: 짧은 포맷은 로그 가독성↑ 이나 충돌 회피를 위해 request-scoped uniqueness 보장 로직 필요.
- W3C
traceparent는 외부 auth/backend contract 가 허용할 때만 전파 (hub §11.3). - backend 응답의
requestId/traceId(envelopemeta, §7.3)는 safe support reference 로 내부 state 보관 가능, user 에 raw 노출 금지. - normalized failure shape(§8.1)의
requestId/traceId는 optional — 존재 시 telemetry attribute 로 승격하지 않고 내부 correlation 에만 사용. - retry(new request)는 같은 logical operation correlation 유지하되
attempt로 구분 (hub §11.3, §7.2attempt). - trace propagation 미지원 backend 는 local operation ID 로 degrade.
6. 기여 edge (contribution, ownership 은 위임)
Trace: D7 ·
FE-OC-008/FE-OC-021/FE-OC-025기여 · raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §8.2 §16.4
- UNSUPPORTED_IMPL_DECISION: 없음 — 아래는 hub 계약 인용이며 각 owner 브랜치에 위임(R3). 본 절은 telemetry 기여 edge 만 명세.
| 기여 대상 | 본 브랜치가 제공하는 telemetry edge | Owner (위임) |
|---|---|---|
FE-OC-008 실패 taxonomy |
§8.2 Telemetry rule column 구현 — terminal 실패당 safe field 만으로 최대 1 event, abort 는 error event 미발생, raw URL/body 금지 | error-classification boundary branch |
FE-OC-021 NFR |
duration_bucket·attempt_count_bucket 등 low-cardinality attribute 공급(측정·리포트는 미소유) |
web-vitals-performance-budget branch |
FE-OC-025 runbook |
FE-RB-004 diagnosis evidence field(endpoint classification·queue size bucket·dropped count·build/release ID·redaction test result) + recovery assertion 공급, 및 Mitigation "telemetry runtime flag disable" 의 실행 경로(D8, 구현 가이드 7) 보장 |
frontend-operational-runbook branch |
7. TELEMETRY_ENABLED kill-switch 소비
Trace: D8 (+ D1 non-blocking / D6 degradation ladder) ·
FE-OC-014· raw/project-notes/ca-skeleton-frontend-operational-contract FE-D021 §5.4 §16.4 §6.3 §4.5 §11.2
- UNSUPPORTED_IMPL_DECISION: hub §5.4 는
TELEMETRY_ENABLED를 required runtime key(defaultfalse)로 선언하고 §16.4 는 그 disable 을 mitigation lever 로 요구하지만, 소비 형태(real adapter 미구성 + no-op port 주입 vs port 자체를 optional/null 로 두고 call site 에서 분기)는 명시하지 않는다 → no-op port 주입 을 초기 default 로 제안. trade-off: no-op 은 disable 경로를 composition root 한 곳에 가두고 call site 를 flag-무지 상태로 유지하나(hub §4.2 의 "presentation 은TelemetryPort만 참조" 와 정합), no-op 객체가 항상 존재하므로 "telemetry 가 꺼져 있다"는 사실이 호출자에게 보이지 않는다(관측은 boot-time config snapshot 으로만 확인 가능).
flag 상태별 구성 (composition root 분기 지점 1곳)
TELEMETRY_ENABLED |
composition root 동작 | 생성되는 것 | 생성되지 않는 것 | 근거 |
|---|---|---|---|---|
false (hub default, §5.4) |
no-op TelemetryPort 주입 |
port 표면(record)만 |
queue · redaction projection · sink/transport · dropped counter · TELEMETRY_ENDPOINT 해석 |
§5.4, §16.4 Mitigation |
true |
real telemetry adapter 구성 후 주입 | 구현 가이드 2~5 전체 경로 | — | §11.2, §4.5 |
- no-op 의 계약:
record(event)는 인자를 읽지 않고 즉시 반환하며 throw 하지 않는다(D1 non-blocking 불변식을 flag 양쪽 상태에서 동일하게 유지). 어떤 event 도 buffer 하지 않으므로 나중에 flag 가 켜져도 소급 전송되는 event 는 없다. - disable 은 "전송 억제"가 아니라 "경로 부재": queue 도 counter 도 생성되지 않으므로 §11.1 redaction 위반 표면과 §11.2 overflow 표면이 동시에 0 이 된다.
TELEMETRY_ENDPOINT는 hub §5.4 상Required: conditional— 그 조건이 곧TELEMETRY_ENABLED=true라는 것이 본 브랜치의 소비 측 해석이며, schema 상 conditional 강제는FE-OC-004소유(§엣지·실패·의존). - runtime flip 가능성: runtime config 는 hub §6.3 boot sequence 에서
GET /config.json(no-store) 로 boot 시 1회 로드된 뒤 §4.5 composition root 가 의존성을 구성한다. hub 에 config hot-reload 계약이 없으므로 in-session flip 은 존재하지 않는다 — flag 변경은 provider 측에서 반영한 뒤 다음 document load(boot) 부터 적용된다. - flip 시 이미 queue 에 쌓인 event: 위 결과로 정의상 문제가 발생하지 않는다.
true→false는 이전 session 의 queue 를 flush 하지 않고 document 와 함께 폐기하며(§11.2 best-effort — delivery guarantee 없음이므로 손실이 계약 위반이 아님),false→true는 시작 시점부터의 event 만 다룬다(no-op 이 아무것도 보관하지 않았으므로 backfill 대상 없음). FE-RB-004mitigation 충족 경로: §16.4 Mitigation 의 "telemetry runtime flag disable" 은 ① provider 의 runtime config 에서TELEMETRY_ENABLED=false설정 → ② 이후 boot 부터 no-op 주입 → ③ sink 호출·queue 적재·drop counter 증가가 발생 원천에서 중단 → ④ §16.4 Containment("product flow 계속")와 Recovery assertion("product e2e unaffected")이 flag 양쪽 상태에서 동일하게 성립, 의 순서로 실행된다. 이 lever 는 sink restore 없이도 즉시 사용 가능한 격리 수단이다.- invalid value: hub §5.4 failure column 은
TELEMETRY_ENABLEDinvalid 를 boot fail 로 규정하고 §6.4 는 "boolean parsing without truthy string ambiguity" 를 요구한다. 따라서 composition root 는 검증된 boolean 만 받으며"false"같은 문자열을 스스로 해석하지 않는다(파싱·거부는FE-OC-004). endpoint 부재/invalid 의 telemetry degrade(§5.4)와 달리 flag invalid 는 degrade 가 아니라 boot fail 이라는 비대칭에 유의.
엣지·실패·의존
R4 캡처. sibling 브랜치 링크는 소유 계약
FE-OC-###로만 참조(consistency hook 안전).
- 실패·엣지 경로:
- sink non-2xx/network 실패 →
TELEMETRY_FAILURE(hub §8.2), product error 없음, console-safe/drop, 재귀 금지. - queue overflow → 정책(기본 oldest-drop) 적용 +
telemetry.delivery.droppedself-metric, unbounded 적재 금지 (§16.4). - telemetry adapter init 실패 / prod endpoint 부재·invalid → telemetry 만 degrade, app 계속 (§11.2).
- redaction miss(forbidden attribute 유출) → forbidden-attribute scan test 가 build 를 실패시켜야 함 (§검증).
- page hide →
sendBeaconbest-effort, delivery guarantee 로 표현 금지 (§11.2). - backend 가
traceparent미지원 → local operation ID 로 degrade (§11.3). TELEMETRY_ENABLED=false(hub §5.4 기본값) → real adapter 미구성, no-op port 주입, network·queue·counter 전부 부재. app 은 정상 동작하며FE-RB-004mitigation lever 로 사용 (구현 가이드 7).TELEMETRY_ENABLEDinvalid → boot fail (§5.4, degrade 아님). 파싱·거부는FE-OC-004소유이며 telemetry adapter 는 검증된 boolean 만 수신.- flag
true→false전환 → 이전 session queue 는 flush 되지 않고 폐기 (§11.2 best-effort, delivery guarantee 없음). in-session flip 은 §6.3 boot-time config 로딩상 존재하지 않으며 다음 boot 부터 반영. - navigation/user abort(
REQUEST_ABORTED, §8.2) → error telemetry event 미발생(interaction-only).
- sink non-2xx/network 실패 →
- 다른 계약 의존:
- raw/branch-notes/feature-frontend-env-runtime-config-contract (
FE-OC-004) —TELEMETRY_ENABLED(boolean, required, defaultfalse) 와TELEMETRY_ENDPOINT(conditional) 를 runtime config 로 consume. 그 registry 는 key 선언·분류·schema 검증만 소유하고 전송·redaction·kill-switch 소비 메커니즘은 본 브랜치 소유(D8, 구현 가이드 7). config 계약이 바뀌면 flag 해석·endpoint 해석·boot degrade 경로 영향. (hub §20 Dependency 가 본 브랜치의 유일 명시 dependency 로 이 브랜치를 지목.) - raw/branch-notes/feature-routing-navigation-guard-contract (
FE-OC-005) —route_id의 producer.FE-REG-ROUTE가 low-cardinality route ID 를 발급하며, telemetry 는ui.render.failed·api.request.failed의 required attribute 로 그 값을 그대로 소비한다(직접 생성·정규화 금지). route ID 어휘가 바뀌면 event attribute cardinality 가 영향받음. - raw/branch-notes/feature-api-client-response-envelope-contract (
FE-OC-006) —operation_id(+route_id·attempt)의 producer. hub §7.2 request context 가 logical request 마다operationId/routeId/attempt를 보유하므로, telemetry emit point 는 이 request context 에서 값을 읽고attempt→attempt_count_bucket만 파생한다. request context 필드가 바뀌면 emit point 수집 경로 영향. - raw/branch-notes/feature-frontend-error-classification-boundary-contract (
FE-OC-008) —error_kind를 consume 해api.request.failed등 event 의 required attribute 채움. taxonomy 변경 시 매핑 갱신. - raw/branch-notes/feature-frontend-render-recovery-boundary-contract (
FE-OC-015) — React boundary-catch 신호를 consume 해ui.render.failedemit. boundary 소유 계약 변경 시 emit point 영향. - raw/branch-notes/feature-frontend-release-cache-rollback-contract (
FE-OC-016) —build_id·active_release_id·release token 을 consume 해app.boot.failed·release.mismatch.detectedattribute 채움. - raw/branch-notes/feature-frontend-browser-security-boundary-contract (
FE-OC-019) — telemetry endpoint 의 CSPconnect-src·bundle 내 secret 금지를 강제(그 브랜치가 본 브랜치를 contributor 로 지목). - raw/branch-notes/feature-frontend-operational-runbook-contract (
FE-OC-025) —FE-RB-004recovery assertion(product e2e unaffected·delivery self-check·queue drains·forbidden-attribute scan pass) 소비. - raw/branch-notes/feature-frontend-contract-registry-governance (
FE-OC-022) —FE-REG-TELEMETRY를 8-registry governance 의 single-owner/compatibility check 로 감사.
- raw/branch-notes/feature-frontend-env-runtime-config-contract (
검증해야 할 주장
hub 계약은 근거지만 내 프로젝트 코드의 동작을 자동 보장하지 않는다. repository 생성 후 검증. 모두
needs-confirmation.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| telemetry throw/sink 실패가 render·API critical path 를 깨지 않는다 (D1) | 코드 부재; non-blocking 은 wiring 방식에 의존 | throwing sink 주입 후 render + API success 유지 assert 하는 sink failure test (§20 Measurable completion) | needs-confirmation |
| forbidden attribute 가 client 를 절대 떠나지 않는다 (D2) | redaction 이 transport boundary 에서 강제되는지 코드로 확인 필요 | emit payload 를 검사하는 forbidden-attribute scan / redaction test; 위반 시 build 실패 | needs-confirmation |
| bounded queue 가 planned bound 내 drain 하고 정책대로 drop 한다 (D3) | queue 상한·drop 방향이 UNSUPPORTED_IMPL_DECISION | memory/queue drain test (FE-RB-004 recovery assertion) |
needs-confirmation |
| 자유 문자열/미등록 event 가 reject 된다 (D4) | registry enforcement 미구현 | FE-REG-TELEMETRY schema validation test |
needs-confirmation |
| retry 간 같은 logical operation correlation 유지 + attempt 구분 (D5) | traceparent 전파는 backend contract 의존 | local operation ID + attempt 구분 correlation test (MSW 로 backend 유/무 traceparent 시나리오) | needs-confirmation |
| prod endpoint 부재/invalid 시 telemetry 만 degrade 하고 app 계속 (D6) | boot 경로에서 degrade 격리 미검증 | invalid endpoint boot/sink-failure matrix test | needs-confirmation |
TELEMETRY_ENABLED=false 에서 network 요청·queue·counter 가 전혀 생성되지 않고 product e2e 가 flag true 와 동일하다 (D8) |
no-op 주입이 composition root 한 곳에만 있는지, call site 로 새지 않는지 코드로 확인 필요 | flag off/on both-state test — off 상태에서 telemetry 관련 network 호출 0건 assert + FE-RB-004 recovery assertion("product e2e unaffected") 양쪽 상태 재실행 |
needs-confirmation |
telemetry.delivery.dropped self-metric 이 실패한 queue/sink 로 재진입하지 않는다 (D3 + 구현 가이드 4) |
counter 채널이 queue 와 독립 lifetime 인지 미검증 | overflow 유발 후 비재귀 test — queue 재적재 0건 assert + dropped counter 가 FE-RB-004 diagnosis evidence 로 노출되는지 확인 |
needs-confirmation |
관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
| 관심사 | 상태 | owner | 심각도 | 근거 |
|---|
마주친 문제
- 없음 — scaffolding/spec 단계 (구현 전).
묶음 (이 branch에서 파생된 자료)
가져온 프로젝트 계약
| 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-015@1 |
raw/branch-notes/feature-frontend-render-recovery-boundary-contract | expected operational error와 render defect를 MUST 분리하고 reload loop를 금지 | import 참조로 적용 |
FE-OC-021@1 |
raw/branch-notes/feature-web-vitals-performance-budget-contract | NFR은 device/network/cache/build context와 함께 MUST 측정 | import 참조로 적용 |
FE-OC-025@1 |
raw/branch-notes/feature-frontend-operational-runbook-contract | boot, chunk mismatch, API degradation, telemetry failure, rollback runbook을 MUST 유지 | import 참조로 적용 |
Sub-branches (세부 작업)
- 없음 — scaffolding 단계
오류 기록 (이 branch 작업 중 발생)
- 없음 — scaffolding 단계
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- 없음 — scaffolding 단계
강의 (이 작업을 위해 학습한 강의)
- 없음 — scaffolding 단계
job-posting tie-ins (이 작업에서 파생된 글감)
- 없음 — scaffolding 단계
���련 일일 노트
- 없음 — scaffolding 단계
완료 후 정리
- PR 링크: TODO
- 리뷰 메모: TODO
- 머지 결과 / 배포 환경: TODO
- wiki 추출 대상: 없음 — 전 항목
planned(repository 부재, 추출 조건 미충족) - 추출하지 않을 항목: D1~D8 전부 —
planned등급이므로 verified 승급 및 wiki/projects 추출 전까지 제외