Files
llm-wiki/docs/superpowers/plans/2026-07-28-ca-skeleton-frontend-runtime-adapter-features.md
T
DongHyeonkaandClaude Opus 5 8c94190c32 docs: 런타임 adapter feature 확장 구현 계획 12개 Task
설계 스펙의 41개 편집 항목 + 신규 파일 6개 + 기존 파일 7개를
Task 12개로 분해. 코드가 아니라 계약 문서 편집이므로 TDD 순환을
"체크 명령 실패 확인 -> 편집 -> 통과 확인 -> 커밋" 으로 대체했다.

하네스가 삭제돼 결정론 검사기가 없으므로 각 Task 가 자체 grep
검증을 들고 다니고, Task 12 가 참조 무결성·개수 정합·위임 왕복
대조·wikilink 유효성을 총점검한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 14:07:22 +09:00

81 KiB
Raw Blame History

CA Skeleton Frontend 런타임 adapter feature 확장 — 구현 계획

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: raw/project-notes/ca-skeleton-frontend-operational-contract.md 에 6개 능력 도메인(파일 I-O·캐시 계층·대용량 전송·멀티프로토콜·실시간·백그라운드 실행)을 port·adapter·registry·gate 계층까지 계약으로 심고, 대응 branch-note 6개를 만들고, 파급되는 기존 branch-note 7개를 정합시킨다.

Architecture: 이 작업은 코드가 아니라 계약 문서 편집이다. 산출물은 FE-OC-027032, FE-GATE-027033, FE-D026036, DEC-… 11건, DELEG-FE-007011, FLOW-FE-EVENT-001005, FE-NFR-016020, FE-RB-006~007, FE-REG-CAPABILITY 이며 전부 hub 한 파일 안에 산다. 검증은 테스트 러너가 아니라 결정론적 grep 명령이다 — 각 Task 는 "체크 명령을 먼저 돌려 실패를 확인 → 편집 → 같은 명령으로 통과를 확인 → 커밋" 순환을 따른다.

Tech Stack: Markdown, YAML frontmatter, Obsidian wikilink, grep/grep -E/grep -F. 빌드·테스트 러너 없음.

Global Constraints

  • SSOT 는 설계문서다. 모든 표 내용·문자열·수치는 docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design.md(이하 spec)에서 가져온다. 계획서가 spec 과 어긋나면 spec 이 이긴다.
  • 작업 브랜치: docs/ca-skeleton-frontend-runtime-adapter-features (이미 생성됨, spec 커밋 4533122 위에서 이어간다).
  • 편집 대상 hub: raw/project-notes/ca-skeleton-frontend-operational-contract.md (현재 2420행).
  • FE-OC-*·FE-D*·FE-GATE-*·DEC-* ID 는 rename 금지. 의미가 바뀌면 기존 ID 를 superseded 로 남기고 새 ID 를 추가한다 (hub §2.1).
  • §6.1 Summary 셀과 branch-note 상속 표는 문자열이 정확히 일치해야 한다. 조사 앞 공백 없음 — …release token을 8개 registry로 관리한다 형태. 공백 하나가 불일치다.
  • 증거 등급: 신규 행의 Status/Current 는 전부 planned 또는 FAIL_UNVERIFIED. actually-implemented·locally-verified·prod-verified 를 쓰면 안 된다 (hub §0.2).
  • 근거 표기: 신규 결정의 Evidence / rationale 열에는 project-local default, 외부 source claim 아님 을 명시한다. 없는 출처를 지어내지 않는다.
  • out of scope 를 문서에 못박는다: 6개 도메인의 use case·domain model·business rule 은 계약하지 않는다.
  • 하네스 부재: .claude/commands/·.claude/hooks/·harness/ 가 삭제돼 /branch·/lint·/sync 와 결정론 검사기가 없다. branch-note 는 templates/branch-note-template.md 로 직접 만들고, 정합은 이 계획의 grep 명령으로 확인한다.
  • ART-FE-* 행을 추가하지 않는다. 신규 gate report 는 전부 단일 branch 소유이므로 §2.1.3 등록 대상이 아니며, 끊긴 harness/source/** 경로를 늘리지 않는다.
  • 커밋 메시지 규약: docs: <내용> + 본문. 각 Task 끝에서 커밋한다.

작업 전 필독: spec 전문(886행). 각 Task 는 spec 의 특정 절을 그대로 옮기는 일이며, 절 번호를 Task 마다 명시한다.


File Structure

파일 상태 책임
raw/project-notes/ca-skeleton-frontend-operational-contract.md 수정 41개 절. 계약·결정·port·registry·gate·NFR·runbook 의 project-wide SSOT
raw/branch-notes/feature-frontend-binary-file-io-store-contract.md 신규 FE-OC-027 owner
raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract.md 신규 FE-OC-028 owner
raw/branch-notes/feature-frontend-large-object-transfer-contract.md 신규 FE-OC-029 owner
raw/branch-notes/feature-frontend-multi-protocol-api-transport-contract.md 신규 FE-OC-030 owner
raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract.md 신규 FE-OC-031 owner
raw/branch-notes/feature-frontend-background-execution-worker-contract.md 신규 FE-OC-032 owner
raw/branch-notes/feature-frontend-release-cache-rollback-contract.md 수정 OFFLINE-CACHE-001 pin @1@2 + 위임 접수
raw/branch-notes/feature-frontend-storage-registry-contract.md 수정 REGISTRY-001 문자열 + 위임 접수
raw/branch-notes/feature-frontend-observability-logging-trace-contract.md 수정 REGISTRY-001 문자열
raw/branch-notes/feature-frontend-contract-registry-governance.md 수정 REGISTRY-001 문자열
raw/branch-notes/feature-frontend-contract-compatibility-governance.md 수정 REGISTRY-001 문자열
raw/branch-notes/feature-runtime-schema-validation-contract.md 수정 위임 접수
raw/branch-notes/feature-frontend-env-runtime-config-contract.md 수정 FE-REG-CAPABILITY·FE-GATE-033 owner 취득

hub 를 쪼개지 않는 이유: 27개 기존 branch-note 와 4개 rules 문서가 §N.M 절 번호로 이 파일을 참조한다. 분할하면 그 참조가 전부 깨진다. 절 추가는 뒤에 붙이는 방식(§5.11, §9.5~§9.7)으로만 하고 기존 번호를 밀지 않는다.


공통 검증 명령

각 Task 에서 반복 사용한다. 모두 repo 루트에서 실행.

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
BN=raw/branch-notes

ID 정의 개수 세기 (표 행은 | \ID`` 로 시작):

grep -cE '^\| `FE-OC-(027|028|029|030|031|032)`' "$HUB"

참조 무결성 (hub §24.2 의 drift check 를 그대로 사용):

CONTRACT_STABLE_ID_RE='FE-D[0-9]{3}|FE-(SC|OC|NFR|GATE|RB|EV|RDY|RISK|Q)-[0-9]{3}|FE-NFR-C[0-9]{2}|FE-REG-[A-Z]+(-[A-Z]+)*'
comm -23 \
  <(grep -oE "$CONTRACT_STABLE_ID_RE" "$HUB" | sort -u) \
  <(grep -nE '^\| `FE-|^### 16\.[0-9]+ `FE-RB-' "$HUB" | grep -oE "$CONTRACT_STABLE_ID_RE" | sort -u)

출력이 비어야 한다 — "참조되지만 정의되지 않은 ID" 가 없다는 뜻이다.


Task 1: hub 계약·게이트 인덱스 (§2.1, §2.1.1)

Files:

  • Modify: raw/project-notes/ca-skeleton-frontend-operational-contract.md — §2.1 표 (현재 185210행), §2.1.1 표 (현재 225276행)

Interfaces:

  • Produces: FE-OC-027·FE-OC-028·FE-OC-029·FE-OC-030·FE-OC-031·FE-OC-032 계약 ID, FE-GATE-027~FE-GATE-033 gate ID. 이후 모든 Task 가 이 ID 를 참조한다.

  • Consumes: 없음 (첫 Task)

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE '^\| `FE-OC-(027|028|029|030|031|032)`' "$HUB"
grep -cE '^\| `FE-GATE-(027|028|029|030|031|032|033)`' "$HUB"

Expected: 두 명령 모두 0 출력, exit code 1.

  • Step 2: §2.1 Stable Contract Index 에 6행 추가

| \FE-OC-026` | project hub (this file) | …행 **바로 다음 줄**에 spec §4.2 의 표 6행을 그대로 붙인다. 열 순서는Contract ID | Single owner | Normative summary | Minimum evidence | Status이고Status는 전부 ``planned` `` 다.

  • Step 3: 같은 표에서 기존 2행의 summary 갱신

FE-OC-022 행: 8개 registry는 single primary owner와 compatibility impact를 MUST 기록9개 registry는 single primary owner와 compatibility impact를 MUST 기록

FE-OC-025 행: boot, chunk mismatch, API degradation, telemetry failure, rollback runbook을 MUST 유지boot, chunk mismatch, API degradation, telemetry failure, rollback, realtime 연결, background 실행 runbook을 MUST 유지

  • Step 4: §2.1.1 Contract Registry (typed) 에 계약 6행 추가

| \FE-OC-026` | `fe.answer-boundary` | …행 **바로 다음 줄**(=FE-GATE-001행 앞)에 spec §4.3 의 표 6행을 붙인다. 열 순서는Contract ID | Concern Key | Revision | Type | Owner | Trigger | Required Effect | Enforcement | Status, Revision1, Typeoperational-contract, Statusactive`.

같은 표의 FE-OC-022·FE-OC-025Required Effect 셀도 Step 3 과 동일하게 갱신한다 — 이 표와 §2.1 은 같은 문장을 두 곳에 두므로 한쪽만 고치면 문서가 자기모순이 된다.

  • Step 5: §2.1.1 표 끝에 gate 7행 추가

| \FE-GATE-026` | `fe.gate.lab-performance` | …행 **다음**에 spec §8.2 의 표 7행을 붙인다.Typegate, Revision1, Statusactive`.

  • Step 6: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "FE-OC 신규(기대 12): $(grep -cE '^\| `FE-OC-(027|028|029|030|031|032)`' "$HUB")"
echo "FE-GATE 신규(기대 7): $(grep -cE '^\| `FE-GATE-(027|028|029|030|031|032|033)`' "$HUB")"
echo "8개 registry 잔존(기대 0): $(grep -c '8개 registry는 single primary owner' "$HUB")"
echo "runbook 5종 문구 잔존(기대 0): $(grep -c 'telemetry failure, rollback runbook을 MUST 유지' "$HUB")"

Expected: 12, 7, 0, 0. (FE-OC-027~032 는 §2.1 과 §2.1.1 양쪽에 1행씩이므로 12 다. gate 는 이 시점에 §2.1.1 에만 있으므로 7 이다.)

  • Step 7: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): FE-OC-027~032 계약과 FE-GATE-027~033 gate 인덱스 추가

6개 능력 도메인 계약을 §2.1 과 §2.1.1 양쪽에 등록하고,
registry 개수(8→9)와 runbook 종수(5→7) 변경을 FE-OC-022·FE-OC-025
summary 에 반영."

Task 2: hub 결정 레지스트리 (§3.2, §6.1)

Files:

  • Modify: hub §3.2 Decision rows (현재 364390행), §6.1 안정 결정 레지스트리 (현재 408–439행)

Interfaces:

  • Consumes: Task 1 의 FE-OC-027~032 (신규 결정의 Affected FE-OC 열이 참조)
  • Produces: FE-D026~FE-D036, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-{CAPABILITY,BINARY-STORE,CROSS-TAB,TRANSFER-CREDENTIAL,RESUMABLE-TRANSFER,PROTOCOL,REALTIME-TRANSPORT,REALTIME-LIFECYCLE,SERVICE-WORKER-ROLE,BACKGROUND-SYNC,WORKER-TASK}-001. Task 9·10·11 이 이 문자열을 그대로 pin·복사한다.

이 Task 가 가장 위험하다. §6.1 Summary 문자열은 branch-note 7개가 글자 단위로 복사하므로 오타 하나가 문서 간 모순이 된다.

  • Step 1: 체크 명령을 돌려 아직 없음을 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE '^\| `FE-D0(2[6-9]|3[0-6])`' "$HUB"
grep -c 'DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001' "$HUB"

Expected: 두 명령 모두 0.

  • Step 2: §3.2 에 FE-D026~FE-D036 11행 추가

| \FE-D025` | sample slice는 …행 다음에 spec §7.1 의 표 11행을 붙인다. 열 순서는Decision ID | Decision | Status | Owner | Affected FE-OC | Evidence / rationale | Revisit trigger | Supersedes`.

FE-D034 행의 Supersedes 열은 `FE-D019` 다. 나머지 10행은 .

  • Step 3: §3.2 의 기존 2행 갱신

FE-D019 행 — Status`conditional-default``superseded` 로 바꾼다. 행을 삭제하지 않는다 (hub §3.3 5단계).

FE-D018 행 — Decision 셀을 route/API-operation/env/storage/error/query/telemetry/release token은 8개 registry로 관리route/API-operation/env/storage/error/query/telemetry/release/capability token은 9개 registry로 관리 로 바꾼다.

  • Step 4: §6.1 에 DEC-… 11행 추가

| \DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SAMPLE-FIXTURE-001` | …행 다음에 spec §7.2 의 표 11행을 붙인다. 열 순서는Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence, Owner는 전부raw/project-notes/ca-skeleton-frontend-operational-contract`.

Summary 셀 11개는 아래 문자열을 그대로 쓴다. 조사 앞 공백 없음:

신규 runtime capability 6종은 FE-REG-CAPABILITY flag로 default OFF이며 활성화는 owner·gate·runbook을 동반한다
로컬 바이너리 backend는 IndexedDB를 default로 하고 OPFS는 대용량 순차 write에 opt-in, Cache Storage는 service worker 호스팅 response cache 전용이다
탭 간 무효화는 BroadcastChannel 우선에 storage event fallback을 쓰고 leader election 없이 무효화 key만 전파한다
presigned URL 획득은 shared client를 경유하고 실제 byte 전송은 session credential을 첨부하지 않는 transfer adapter가 수행한다
재개 가능 전송은 part size·병렬도·part 재시도 상한을 registry로 고정하고 part 상태를 BlobStorePort에 보존한다
transport default는 REST이고 GraphQL·gRPC-Web·Connect-Web은 FE-REG-API의 protocol 필드로 opt-in하며 미지원 환경은 REST gateway로 fallback한다
실시간 transport는 SSE를 우선하고 양방향이 필요하면 WebSocket, 둘 다 불가할 때만 최소 간격·backoff·visibility gating을 갖춘 bounded polling을 쓴다
실시간 연결은 full jitter backoff와 30초 cap을 쓰고 재시도 상한 후 terminal 상태로 전이하며 resume은 Last-Event-ID 또는 cursor로 수행하고 unmount 시 구독을 해제한다
service worker는 역할을 분리해 release asset precaching은 default off로 유지하고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용하며 update UX 계약을 요구한다
background sync 재생은 idempotency keyed operation만 허용한다
Web Worker 작업은 structured-clone 또는 Transferable로만 통신하고 timeout과 terminate를 계약하며 worker 안에서 application port를 재구현하지 않는다
  • Step 5: §6.1 의 기존 2행 개정

DEC-…-OFFLINE-CACHE-001 행 — Revision 12, Summary 를 아래로 교체:

  • 교체 전: service worker와 offline asset cache는 default off다
  • 교체 후: service worker의 release asset precaching은 default off이고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용한다

DEC-…-REGISTRY-001 행 — Revision1 유지, Summary 를 아래로 교체:

  • 교체 전: route, API operation, env, storage, error, query, telemetry, release token을 8개 registry로 관리한다

  • 교체 후: route, API operation, env, storage, error, query, telemetry, release token, capability를 9개 registry로 관리한다

  • Step 6: §6.1 하단 개정 기록에 2건 추가

기존 > **개정 기록 (§3.3 protocol)** 블록의 - 2026-07-21 · \DEC-...-SUPPLY-CHAIN-001` …` 항목 다음에 아래 두 줄을 넣는다.

> - 2026-07-28 · `DEC-...-OFFLINE-CACHE-001` · `compatibility_impact: behavior-change` · revision 1→2. `FE-D034` 가 `FE-D019` 를 supersede 하면서 service worker 를 "전면 off" 에서 "precaching off + 역할별 capability opt-in" 으로 바꿨다. WebPush·Background Sync·Cache Storage 가 service worker 없이는 동작하지 않기 때문이다. behavior-change 이므로 §3.3 4단계에 따라 `FE-GATE-032`(SW update UX + rollback 시 SW 되돌림)와 `FE-RB-007` 이 migration·rollback evidence 를 담당한다. pin 을 가진 `feature-frontend-release-cache-rollback-contract` 는 `@2` 로 갱신했다.
> - 2026-07-28 · `DEC-...-REGISTRY-001` · `compatibility_impact: additive` · revision 유지(1). 9번째 registry `FE-REG-CAPABILITY` 를 추가했다. 기존 8개 registry 의 owner·schema·동작은 바뀌지 않으므로 `DEC-...-SUPPLY-CHAIN-001` 선례와 같은 판정을 적용한다. 다만 Summary 문자열이 바뀌므로 이를 복사해 둔 소비 branch 4곳(`storage-registry`·`observability-logging-trace`·`contract-registry-governance`·`contract-compatibility-governance`)의 상속 표를 함께 갱신했다.
  • Step 7: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "FE-D 신규(기대 11): $(grep -cE '^\| `FE-D0(2[6-9]|3[0-6])`' "$HUB")"
echo "DEC 신규(기대 11): $(grep -cE '^\| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-(CAPABILITY|BINARY-STORE|CROSS-TAB|TRANSFER-CREDENTIAL|RESUMABLE-TRANSFER|PROTOCOL|REALTIME-TRANSPORT|REALTIME-LIFECYCLE|SERVICE-WORKER-ROLE|BACKGROUND-SYNC|WORKER-TASK)-001`' "$HUB")"
echo "FE-D019 superseded(기대 1): $(grep -cE '^\| `FE-D019`.*`superseded`' "$HUB")"
echo "구 OFFLINE-CACHE 문자열 잔존(기대 0): $(grep -cF 'service worker와 offline asset cache는 default off다' "$HUB")"
echo "구 REGISTRY 문자열 잔존(기대 0): $(grep -cF 'release token을 8개 registry로 관리한다' "$HUB")"
echo "신규 REGISTRY 문자열(기대 1): $(grep -cF 'release token, capability를 9개 registry로 관리한다' "$HUB")"

Expected: 11, 11, 1, 0, 0, 1.

  • Step 8: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): 결정 11건 추가, FE-D019 supersede, registry 개수 개정

- FE-D026~036 / DEC-... 11건: capability default-off, 바이너리 backend
  선택, 탭 간 무효화, 전송 credential 경계, 프로토콜 opt-in, 실시간
  transport·수명주기, SW 역할 분리, background sync, worker 통신
- FE-D019 -> superseded (FE-D034 가 대체), OFFLINE-CACHE-001 revision 2
  (behavior-change)
- REGISTRY-001 은 additive 이므로 revision 유지, Summary 만 9개로 갱신
- §6.1 개정 기록 2건 추가"

Task 3: hub 위임·흐름 레지스트리 (§2.1.2, §2.1.4)

Files:

  • Modify: hub §2.1.2 Delegation Registry (현재 317324행), §2.1.4 Flow Stage Registry (현재 298307행)

Interfaces:

  • Consumes: Task 1 의 계약 ID

  • Produces: DELEG-FE-007DELEG-FE-011, FLOW-FE-EVENT-001FLOW-FE-EVENT-005. Task 10·11 이 delegates:/accepts_delegations:/imports: 에서 참조한다.

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE '^\| `DELEG-FE-0(07|08|09|10|11)`' "$HUB"
grep -cE '^\| `FLOW-FE-EVENT-00[1-5]`' "$HUB"

Expected: 둘 다 0.

  • Step 2: §2.1.2 에 위임 5행 추가

| \DELEG-FE-006` | …행 다음에 spec §7.4 의 표 5행을 붙인다. 열 순서는Delegation ID | Concern Key | Revision | Delegator | Delegate | Scope | Status, Revision1`.

Status전부 accepted 로 적는다 — Task 10 과 Task 11 에서 delegate 5곳의 accepts_delegations 를 모두 채우기 때문이다. 접수하지 않은 채 accepted 로 적으면 거짓이므로, Task 11 이 끝날 때 Step 5 의 왕복 대조로 확인한다.

  • Step 3: §2.1.2 서두 설명 갱신

기존 문단의 아래 6행은 2026-07-20 문서 간 정합성 감사에서 … 문장 뒤에 아래를 덧붙인다.

> 2026-07-28 에 `DELEG-FE-007`~`DELEG-FE-011` 5행이 추가됐다. 신규 6개 능력 도메인이 서로 또는 기존 branch 에 넘기는 관심사이며, delegate 5곳의 `accepts_delegations` 를 같은 변경에서 채워 전부 `accepted` 로 시작한다.
  • Step 4: §2.1.4 에 이벤트 흐름 5행 추가

| \FLOW-FE-RESP-008` | 8 | …행 다음에 spec §7.5 의 표 5행을 붙인다. 열 순서는Stage ID | Order | Owner | Input | Action | Output | Invariants | Revision, Order는 1~5,Revision1`.

§2.1.4 서두 문단 끝에 아래를 덧붙인다.

> `FLOW-FE-RESP-*` 는 요청/응답 한 번의 여정이고 `FLOW-FE-EVENT-*` 는 인바운드 프레임 하나의 여정이다. 두 흐름은 3~4단계에서 같은 runtime schema owner 를 공유하지만 순서를 합치지 않는다. 구독 해제(cleanup)는 어느 흐름도 소유하지 않고 `RealtimeSubscriptionPort` 계약이 소유한다.
  • Step 5: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "DELEG 신규(기대 5): $(grep -cE '^\| `DELEG-FE-0(07|08|09|10|11)`' "$HUB")"
echo "FLOW-EVENT 신규(기대 5): $(grep -cE '^\| `FLOW-FE-EVENT-00[1-5]`' "$HUB")"
echo "proposed 잔존(기대 0): $(grep -cE '^\| `DELEG-FE-0(07|08|09|10|11)`.*proposed' "$HUB")"

Expected: 5, 5, 0.

  • Step 6: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): DELEG-FE-007~011 위임과 FLOW-FE-EVENT-001~005 흐름 추가

인바운드 이벤트는 FLOW-FE-RESP-* 에 자리가 없어 별도 5단계로 고정한다.
검증 통과분만 application 에 도달하며 구독 해제는 port 계약이 소유한다."

Task 4: hub 아키텍처 (§4.2~§4.6)

Files:

  • Modify: hub §4.2 Component responsibility (현재 456465행), §4.3 Dependency matrix (현재 471488행), §4.4 Port ownership matrix (현재 492503행), §4.5 Composition root (현재 505527행), §4.6 Planned directory blueprint (현재 529582행)

Interfaces:

  • Consumes: Task 2 의 FE-D034·FE-D036 (worker/SW 규칙의 근거)

  • Produces: port 12개 이름 — CapabilityPort, FileDialogPort, BlobStorePort, CachePersistencePort, CrossTabSyncPort, UploadTransferPort, StreamingDownloadPort, RealtimeSubscriptionPort, PushSubscriptionPort, WorkerTaskPort, ServiceWorkerHostPort, BackgroundSyncPort. Task 10 의 branch-note 목표·범위가 이 이름을 참조한다.

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE '`(CapabilityPort|FileDialogPort|BlobStorePort|CachePersistencePort|CrossTabSyncPort|UploadTransferPort|StreamingDownloadPort|RealtimeSubscriptionPort|PushSubscriptionPort|WorkerTaskPort|ServiceWorkerHostPort|BackgroundSyncPort)`' "$HUB"

Expected: 0.

  • Step 2: §4.2 에 adapter 10행 추가

| \bootstrap` | config load, …행 **앞**에 spec §5.3 의 표 10행을 붙인다.bootstrap` 은 표의 마지막 행으로 남긴다 — 조립 주체이므로 조립 대상 뒤에 오는 기존 배치를 유지한다.

  • Step 3: §4.3 에 예외 2건과 worker/SW 엔트리 규칙 추가

Normative dependency summary: 목록의 마지막 항목(- bootstrap만 concrete adapter를 조립할 수 있다.) 다음에 spec §5.4 의 4개 항목을 붙인다.

  • Step 4: §4.4 에 port 12행 추가 + 설명 문단

| \ReleaseInfoPort` | …행 다음에 spec §5.1 의 표 12행을 붙인다. 열 순서는Port | Definition owner | Planned implementation | Consumer | Input / output | Failure vocabulary`.

기존 AuthSessionPort는 token 문자열을 … 문단 다음에 spec §5.2 의 두 문단(멀티프로토콜은 신규 port 0개 / Image CDN 은 application 정책)을 그대로 붙인다.

  • Step 5: §4.5 boot order 를 12단계로 교체

기존 1~10단계 목록을 spec §5.5 의 12단계로 교체하고, 그 아래 규범 2항(6단계는 실패하지 않는다 / 9단계는 정적 import 하지 않는다)을 덧붙인다. 기존 문장 2~4단계가 실패하면 product route를 mount하지 않고 boot error shell만 렌더한다. telemetry adapter 생성 실패는 console-safe fallback으로 계속 진행할 수 있다. 는 단계 번호가 바뀌지 않았으므로 그대로 둔다.

  • Step 6: §4.6 디렉터리 청사진 확장

기존 코드 블록의 adapters/ 하위를 spec §5.6 의 트리로 교체하고, application/policies/·contracts/capabilities.js·src/workers/·public/sw.js 를 추가한다. 기존 항목은 지우지 않는다.

  • Step 7: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
for p in CapabilityPort FileDialogPort BlobStorePort CachePersistencePort CrossTabSyncPort UploadTransferPort StreamingDownloadPort RealtimeSubscriptionPort PushSubscriptionPort WorkerTaskPort ServiceWorkerHostPort BackgroundSyncPort; do
  n=$(grep -c "\`$p\`" "$HUB"); [ "$n" -ge 1 ] || echo "MISSING: $p"
done
echo "port 행(기대 12): $(grep -cE '^\| `(CapabilityPort|FileDialogPort|BlobStorePort|CachePersistencePort|CrossTabSyncPort|UploadTransferPort|StreamingDownloadPort|RealtimeSubscriptionPort|PushSubscriptionPort|WorkerTaskPort|ServiceWorkerHostPort|BackgroundSyncPort)`' "$HUB")"
echo "boot 6단계(기대 1): $(grep -c 'capability 해석' "$HUB")"
echo "capabilities.js(기대 1 이상): $(grep -c 'capabilities.js' "$HUB")"

Expected: MISSING: 출력 없음, 12, 1, 1 이상.

  • Step 8: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): port 12개, adapter 책임 10행, capability boot 단계, 디렉터리 확장

- 멀티프로토콜은 기존 ResourceQueryPort/ResourceCommandPort 를 재사용해
  신규 port 0개. 프로토콜은 registry 데이터이지 타입이 아니다.
- Image CDN 은 I-O 가 없으므로 adapter 가 아니라 application 정책.
- boot 에 capability 해석 단계 삽입 — 실패하지 않고, 비활성 adapter 는
  정적 import 하지 않는다(FE-NFR-020 방어)."

Task 5: hub Contract Registries (§5.1, §5.3~§5.9, §5.11)

Files:

  • Modify: hub §5.1 Registry owner map (현재 590599행), §5.3 API operation registry (622643행), §5.4 Environment registry (645664행), §5.5 Storage registry (666686행), §5.6 Error registry (688729행), §5.7 Query key registry (731748행), §5.8 Telemetry registry (750770행), §5.9 Release token registry (772783행)
  • Modify: hub — §5.10 Registry change protocol 뒤에 §5.11 신설

Interfaces:

  • Consumes: Task 2 의 DEC-…-REGISTRY-001 갱신, Task 1 의 FE-GATE-027~033

  • Produces: FE-REG-CAPABILITY, capability ID 6개(CAP_FE_BINARY_IO, CAP_FE_CACHE_PERSISTENCE, CAP_FE_LARGE_TRANSFER, CAP_FE_ALT_PROTOCOL, CAP_FE_REALTIME, CAP_FE_BACKGROUND_EXEC), error kind 26종. Task 6 의 failure matrix 가 kind 를 참조한다.

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -c 'FE-REG-CAPABILITY' "$HUB"
grep -cE '^(CAPABILITY_DISABLED|EVENT_SCHEMA_MISMATCH|BACKGROUND_SYNC_REPLAY_REJECTED)$' "$HUB"

Expected: 둘 다 0.

  • Step 2: §5.1 에 FE-REG-CAPABILITY 행 추가

| \FE-REG-RELEASE` | …` 행 다음에:

| `FE-REG-CAPABILITY` | capability 활성 조건/owner/gate/fallback | `src/contracts/capabilities.js` | `feature-frontend-env-runtime-config-contract` | registry 없이 config 를 직접 읽어 기능 분기 |
  • Step 3: §5.11 신설 — capability registry 스키마

§5.10 의 마지막 항목(8. orphan token scan이 0건이어야 merge할 수 있다.) 다음, --- 구분선 ### 5.11 Capability registry minimum schema 절을 만들고 spec §6.1 의 필드 표 7행 + 초기 행 6개를 붙인다. spec §6.1 의 "§5.11 로 뒤에 붙인다" 근거 문단도 함께 옮긴다.

  • Step 4: §5.3 API operation registry 확장

필드 표에 spec §6.2 의 신규 5필드(protocol, transferMode, operationRef, eventSchema, resumeStrategy)를 추가하고, Initial planned rows 표에 sample 3행(STREAM_SAMPLE_EVENTS, PRESIGN_SAMPLE_UPLOAD, DOWNLOAD_SAMPLE_OBJECT)을 추가한다.

표 아래에 아래 문단을 넣는다.

`timeoutMs``transferMode: stream` 행에서 **연결 수립 timeout** 을 뜻하고 스트림 총 수명에는 적용하지 않는다. 스트림 수명은 `FE-D033` 의 재연결·terminal 전이 계약이 소유한다.
  • Step 5: §5.4 Environment registry 에 15개 키 추가

| \RELEASE_MANIFEST_URL` | …행 다음에 spec §6.2 의 env 표 15행을 붙인다. capability flag 6개는 전부Default가 ``false` `` 다.

public-sensitive 설명 문단 다음에 아래를 덧붙인다.

`PUSH_PUBLIC_KEY` 는 VAPID **공개**키이므로 `public` 이다. 대응 개인키는 backend 소유이며 이 registry 에 등록할 수 없다.
  • Step 6: §5.5 Storage registry 확장

  • backend 행의 Rule 을 `memory`, `sessionStorage`, `localStorage`, `indexedDB`, `opfs`, `cacheStorage` 로 교체

  • 필드 표에 payloadClass·evictionOrder 2행 추가

  • Initial planned rows 에 spec §6.2 의 4행(UPLOAD_PART_STATE, TRANSFER_OBJECT_BUFFER, QUERY_CACHE_SNAPSHOT, SW_RESPONSE_CACHE) 추가. UPLOAD_PART_STATE 의 fallback 은 fallback 없음, evictionOrdernull 이다 — correctness 값이 조용히 memory 로 넘어가지 않게 하는 장치다.

  • Step 7: §5.6 Error registry 에 kind 26종 추가

Planned \kind` enum:코드 블록의UNKNOWN_FAILURE**앞**에 spec §6.2 의 26줄을 삽입한다.UNKNOWN_FAILURE` 는 catch-all 이므로 목록 끝에 유지한다.

코드 블록 다음에 아래 문단을 넣는다.

`TRANSFER_ABORTED` 는 만들지 않고 기존 `REQUEST_ABORTED` 를 재사용한다. `SUBSCRIPTION_LEAKED` 는 사용자에게 보이는 실패가 아니라 `FE-GATE-031` 이 잡는 결함이므로 kind 가 아니다. `SW_UPDATE_PENDING` 도 실패가 아니라 §9.7 의 surface state 다.
  • Step 8: §5.7·§5.8·§5.9 확장

  • §5.7 규칙 표에 persistenceTier·crossTabScope·version partition 3행 추가 (spec §6.2)

  • §5.8 Initial planned events 표에 7행 추가 (spec §6.2). forbiddenAttributes 필드 Rule 에 , 파일명, object key, presigned URL, 구독 endpoint 를 덧붙인다

  • §5.9 표에 serviceWorkerVersion 1행 추가

  • Step 9: 체크 명령을 다시 돌려 통과 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "FE-REG-CAPABILITY(기대 3 이상): $(grep -c 'FE-REG-CAPABILITY' "$HUB")"
echo "§5.11(기대 1): $(grep -c '^### 5.11 Capability registry minimum schema' "$HUB")"
echo "capability ID(기대 6): $(grep -cE '^\| `CAP_FE_(BINARY_IO|CACHE_PERSISTENCE|LARGE_TRANSFER|ALT_PROTOCOL|REALTIME|BACKGROUND_EXEC)`' "$HUB")"
echo "capability flag 키(기대 6): $(grep -cE '^\| `CAPABILITY_[A-Z_]+_ENABLED`' "$HUB")"
echo "신규 error kind(기대 26): $(grep -cE '^(CAPABILITY_DISABLED|CAPABILITY_UNSUPPORTED|FILE_PICKER_DISMISSED|FILE_REJECTED|BLOB_STORE_UNAVAILABLE|BLOB_STORE_QUOTA_EXCEEDED|CACHE_PERSISTENCE_FAILURE|CROSS_TAB_CHANNEL_UNAVAILABLE|PRESIGN_EXPIRED|UPLOAD_PART_FAILED|TRANSFER_INTEGRITY_MISMATCH|STREAM_INTERRUPTED|PROTOCOL_STATUS_MISMATCH|CODEC_DECODE_FAILURE|PARTIAL_RESULT_FAILURE|REALTIME_CONNECT_FAILED|REALTIME_DISCONNECTED|REALTIME_RESUME_GAP|EVENT_SCHEMA_MISMATCH|PUSH_PERMISSION_DENIED|PUSH_SUBSCRIPTION_EXPIRED|WORKER_UNAVAILABLE|WORKER_TASK_TIMEOUT|SW_REGISTRATION_FAILED|BACKGROUND_SYNC_UNSUPPORTED|BACKGROUND_SYNC_REPLAY_REJECTED)$' "$HUB")"
echo "opfs/cacheStorage backend(기대 1): $(grep -c 'indexedDB`, `opfs`, `cacheStorage' "$HUB")"
echo "금지 kind 오입력(기대 0): $(grep -cE '^(TRANSFER_ABORTED|SUBSCRIPTION_LEAKED|SW_UPDATE_PENDING)$' "$HUB")"

Expected: 3 이상, 1, 6, 6, 26, 1, 0.

  • Step 10: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): FE-REG-CAPABILITY 신설(8->9)과 기존 8개 registry additive 확장

- §5.11 capability registry — envFlagKey 는 FE-REG-ENV 행 포인터이며
  키의 타입·검증은 env registry 가 계속 소유(재진술 금지)
- FE-REG-API 에 protocol/transferMode/operationRef/eventSchema/
  resumeStrategy. 실시간 구독은 별도 장부가 아니라 stream operation 이다
- FE-REG-STORAGE 에 opfs/cacheStorage backend, payloadClass, evictionOrder.
  UPLOAD_PART_STATE 는 correctness 값이라 quota fallback 없음
- error kind 26종. TRANSFER_ABORTED/SUBSCRIPTION_LEAKED/SW_UPDATE_PENDING
  은 각각 기존 kind 재사용/gate 결함/surface state 라 제외"

Task 6: hub 실패 매트릭스·surface state·NFR (§8.2, §9.5~§9.7, §14.2)

Files:

  • Modify: hub §8.2 Failure matrix (현재 11161150행), §9 절 끝(현재 1251행 뒤)에 §9.5~§9.7 신설, §14.2 Initial target matrix (14951512행)

Interfaces:

  • Consumes: Task 5 의 error kind 26종

  • Produces: FE-NFR-016~FE-NFR-020. Task 7 의 gate Covered FE-NFR 열이 참조한다.

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE '^\| `FE-NFR-0(1[6-9]|20)`' "$HUB"
grep -c '^### 9.5 ' "$HUB"

Expected: 둘 다 0.

  • Step 2: §8.2 Failure matrix 에 신규 kind 행 추가

| unknown thrown value | \UNKNOWN_FAILURE` | …행 **앞**에 26개 kind 행을 추가한다. 열 순서는Trigger | Normalized kind | Auto retry | Fallback | User UX | Telemetry rule`. spec §10.2 의 특기 사항을 반드시 반영한다.

  • FILE_PICKER_DISMISSED — Auto retry no, User UX error surface 없음, Telemetry rule event 금지 (사용자 취소는 실패가 아니다)

  • CAPABILITY_DISABLED / CAPABILITY_UNSUPPORTED — Auto retry no, Fallback 은 FE-REG-CAPABILITYdisabledFallback 을 따름

  • PRESIGN_EXPIRED — Auto retry presign 재획득 후 1회, User UX 자동 재개, 실패 시 retry action

  • REALTIME_DISCONNECTED — Auto retry no (재시도 상한 소진 뒤 도달하는 terminal), User UX 사용자 주도 retry

  • BACKGROUND_SYNC_REPLAY_REJECTED — Auto retry no, User UX contact-support, 중복 write 방지 우선

  • Step 3: §9.5 실시간 surface state 신설

§9.4 Storage behavior 의 마지막 항목 다음, --- ### 9.5 실시간 surface state 를 만들고 spec §9.2 의 표 5행 + 마지막 설명 문단을 붙인다.

  • Step 4: §9.6 전송 진행 surface state 신설

바로 이어서 ### 9.6 전송 진행 surface state 를 만들고 spec §9.3 의 표 5행 + telemetry 주의 문단을 붙인다.

  • Step 5: §9.7 Service Worker 갱신 surface state 신설

바로 이어서 ### 9.7 Service Worker 갱신 surface state 를 만들고 spec §9.4 의 표 4행을 붙인다. sw-update-pending 행의 자동 skipWaiting 금지 규범을 빠뜨리지 않는다.

  • Step 6: §14.2 에 NFR 5행 추가

| \FE-NFR-015` | INP field p75 | …행 다음에 spec §9.1 의 표 5행을 붙인다.Current evidence는 전부none`.

표 아래 Field Web Vitals는 … 문단 다음에 아래를 덧붙인다.

`FE-NFR-020``FE-NFR-001`(initial JS gzip ≤ 200 KiB) 예산을 신규 capability 가 잠식하지 않음을 수치로 방어하는 항목이다. capability 를 켜면 번들이 늘어나는 것은 정상이며, 이 NFR 이 막는 것은 **끄고도 늘어나는** 경우다.
  • Step 7: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "FE-NFR 신규(기대 5): $(grep -cE '^\| `FE-NFR-0(1[6-9]|20)`' "$HUB")"
echo "§9.5~9.7(기대 3): $(grep -cE '^### 9\.[567] ' "$HUB")"
echo "skipWaiting 금지(기대 1): $(grep -c 'skipWaiting' "$HUB")"
echo "failure matrix 신규 kind(기대 26): $(grep -cE '^\| .* \| `(CAPABILITY_DISABLED|CAPABILITY_UNSUPPORTED|FILE_PICKER_DISMISSED|FILE_REJECTED|BLOB_STORE_UNAVAILABLE|BLOB_STORE_QUOTA_EXCEEDED|CACHE_PERSISTENCE_FAILURE|CROSS_TAB_CHANNEL_UNAVAILABLE|PRESIGN_EXPIRED|UPLOAD_PART_FAILED|TRANSFER_INTEGRITY_MISMATCH|STREAM_INTERRUPTED|PROTOCOL_STATUS_MISMATCH|CODEC_DECODE_FAILURE|PARTIAL_RESULT_FAILURE|REALTIME_CONNECT_FAILED|REALTIME_DISCONNECTED|REALTIME_RESUME_GAP|EVENT_SCHEMA_MISMATCH|PUSH_PERMISSION_DENIED|PUSH_SUBSCRIPTION_EXPIRED|WORKER_UNAVAILABLE|WORKER_TASK_TIMEOUT|SW_REGISTRATION_FAILED|BACKGROUND_SYNC_UNSUPPORTED|BACKGROUND_SYNC_REPLAY_REJECTED)`' "$HUB")"

Expected: 5, 3, 1 이상, 26.

  • Step 8: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): failure matrix 26행, surface state 3종, NFR 5개 추가

- 실시간은 reconnecting 과 disconnected 를 구분해야 한다. 전자를 terminal
  로 보이면 불필요한 새로고침, 후자를 refreshing 으로 보이면 오지 않는
  데이터를 기다린다.
- sw-update-pending 은 자동 skipWaiting 금지 — 열린 탭이 release 를
  갈아타면 FE-OC-016 coherence 가 깨진다.
- FE-NFR-020 은 capability 를 끄고도 번들이 늘어나는 경우를 막는다."

Task 7: hub Acceptance Gate·승급·readiness (§15.1~§15.3, §18.1, §18.2)

Files:

  • Modify: hub §15.1 Gate ownership (현재 15541586행), §15.2 Negative fixture (15921602행), §15.3 Promotion rule (16081617행), §18.1 Formula (19491955행), §18.2 Current scorecard (19591980행)

Interfaces:

  • Consumes: Task 1 의 FE-GATE-027033 typed 행, Task 6 의 FE-NFR-016020

  • Produces: NOT_APPLICABLE 상태 개념, FE-RDY-017

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE '^\| `FE-GATE-(027|028|029|030|031|032|033)` \|' "$HUB"
grep -c 'NOT_APPLICABLE' "$HUB"

Expected: 둘 다 0. (Task 1 이 §2.1.1 에 넣은 gate 행은 | \FE-GATE-027` | `fe.gate…형태라 위 패턴` |` 와 다르다. §15.1 행만 센다.)

  • Step 2: §15.1 에 gate 7행 추가

| \FE-GATE-026` | lab performance | …행 다음에 spec §8.3 의 표 7행을 붙인다. 열 순서는Gate ID | Gate | Blocking scope | Covered FE-OC | Covered FE-NFR | Required fixtures | Pass condition | Evidence artifact | Current, Current는 전부 ``FAIL_UNVERIFIED` ``.

  • Step 3: §15.1 서두 개수 갱신

현재 stable gate registry는 26개 row이며현재 stable gate registry는 33개 row이며

  • Step 4: §15.2 에 negative fixture 7행 추가

표 끝에 spec §8.4 의 7행을 붙인다.

  • Step 5: §15.3 Promotion rule 코드 블록 교체

기존 블록을 spec §8.5 의 블록으로 교체하고 그 아래에 아래 문장을 넣는다.

`FE-GATE-033``NOT_APPLICABLE` 을 취할 수 없으므로 항상 `MERGE_READY` 에 무조건 포함된다. capability 를 하나도 쓰지 않는 프로젝트도 "쓰지 않는다"를 증명해야 한다.

기존 문장 현재는 \PROJECT_READY = false`, 즉 `NOT_READY`다.` 는 유지한다.

  • Step 6: §18.1 Formula 교체

기존 코드 블록을 spec §8.1 의 블록으로 교체하고, 기존 PASS_SCOPED는 … 문단 다음에 아래 3개 규범 항목을 붙인다.

- `NOT_APPLICABLE``FE-GATE-027`~`FE-GATE-032` **만** 취할 수 있다. `FE-GATE-033` 자신은 취할 수 없다.
- `FE-GATE-033` 이 PASS 가 아니면 모든 `NOT_APPLICABLE` 은 무효이며 `FAIL_UNVERIFIED` 로 강등된다.
- "안 쓴다"는 주장은 선언이 아니라 **번들에 그 adapter 가 없다는 증거**로만 성립한다.
  • Step 7: §18.2 scorecard 갱신

FE-RDY-009 행의 Blocking question 8 registry가 single owner로 구현됐는가9 registry가 single owner로 구현됐는가

FE-RDY-016 행 다음에:

| `FE-RDY-017` | 비활성 capability가 번들에서 실제로 부재한가 | capability bundle report | `FAIL` | build evidence `UNVERIFIED` |
  • Step 8: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "§15.1 gate 행(기대 7): $(grep -cE '^\| `FE-GATE-(027|028|029|030|031|032|033)` \|' "$HUB")"
echo "33개 row(기대 1): $(grep -c '33개 row이며' "$HUB")"
echo "26개 row 잔존(기대 0): $(grep -c '26개 row이며' "$HUB")"
echo "NOT_APPLICABLE(기대 4 이상): $(grep -c 'NOT_APPLICABLE' "$HUB")"
echo "FE-RDY-017(기대 1): $(grep -c 'FE-RDY-017' "$HUB")"
echo "8 registry 잔존(기대 0): $(grep -c '8 registry가 single owner' "$HUB")"

Expected: 7, 1, 0, 4 이상, 1, 0.

  • Step 9: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): gate 7개와 조건부 차단(NOT_APPLICABLE) 개념 추가

capability 가 OFF 인 프로젝트에서 gate 를 PASS 라 하면 거짓말이고 FAIL
이라 하면 영원히 배포할 수 없다. NOT_APPLICABLE 을 도입하되 FE-GATE-033
이 번들 부재를 증명했을 때만 유효하게 묶었다.
FE-GATE-033 자신은 NOT_APPLICABLE 을 취할 수 없다."

Task 8: hub 범위·runbook·증거·리스크·답변경계 (§0.5, §16, §17.1, §19, §22)

Files:

  • Modify: hub §0.5 범위 (현재 110129행), §16 (1621행 이후 — §16.5 뒤에 §16.6·§16.7 신설), §17.1 Evidence records (19001914행), §19.1 Risk register (19882001행), §19.2 Open questions (20052019행), §22.2·§22.3 (22552280행)

Interfaces:

  • Consumes: Task 2 의 FE-D034(FE-Q-009 해소 근거), Task 7 의 gate

  • Produces: FE-RB-006·FE-RB-007, FE-EV-014·FE-EV-015, FE-RISK-013018, FE-Q-011014

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE 'FE-RB-00[67]|FE-EV-01[45]|FE-RISK-01[3-8]|FE-Q-01[1-4]' "$HUB"

Expected: 0.

  • Step 2: §0.5 범위 갱신

In scope: 목록 끝에 spec §10.1 의 6개 항목을 추가한다.

Out of scope: 목록 끝에 spec §10.1 의 2개 항목을 추가한다. 첫 항목은 아래 문장을 그대로 쓴다 — 이 문서가 어디까지 계약하는지의 경계다.

- 위 6개 도메인의 use case, domain model, business rule — 이 skeleton 은 port 와 adapter 계약까지만 제공한다
  • Step 3: §16.6·§16.7 runbook 신설

§16.5 FE-RB-005 의 마지막 줄 다음, --- ### 16.6 \FE-RB-006` — 실시간 연결 장애### 16.7 `FE-RB-007` — 백그라운드 실행 장애` 를 만든다. 각각 §16.1~§16.5 와 동일한 형식을 따른다.

필드 표 (Primary owner / Technical escalation / Activation condition / Conditional window / Evidence path) + **Trigger** / **Immediate containment** / **Diagnosis evidence** / **Mitigation options** / **Escalation** / **Recovery assertions** / **Evidence** 소제목 순서.

내용은 spec §9.5 의 두 문단에서 가져오되, 위 소제목 구조로 펼친다.

  • FE-RB-006 — Primary owner feature-frontend-operational-runbook-contract, Technical escalation feature-frontend-realtime-subscription-lifecycle-contract → backend API owner, Evidence path artifacts/runbooks/FE-RB-006/<release-id>/
  • FE-RB-007 — Primary owner feature-frontend-operational-runbook-contract, Technical escalation feature-frontend-background-execution-worker-contractfeature-frontend-release-cache-rollback-contract, Evidence path artifacts/runbooks/FE-RB-007/<release-id>/

두 runbook 모두 Conditional window 는 기존 5개와 같은 planned conditional default 이며 measured SLO 가 아님을 §16 서두가 이미 밝히고 있으므로 따로 반복하지 않는다.

  • Step 4: §17.1 에 evidence 2행 추가

표 끝에 spec §10.3 의 2행을 붙인다.

  • Step 5: §19.1 에 risk 6행, §19.2 에 open question 4행 추가

각 표 끝에 spec §10.5 의 행을 붙인다. risk 의 Resolution condition·Status 열을 빠뜨리지 않는다(Status 는 전부 `open`).

FE-Q-009 행의 Resolution condition`FE-D019` retained or superseded`FE-D034` 로 해소(2026-07-28) — superseded 로 바꾼다.

  • Step 6: §22.2·§22.3 갱신

§22.2 목록 끝에:

- 6개 opt-in capability 의 port 이름·기본값·gate 구조

§22.3 목록 끝에:

- 이 adapter 들이 동작한다는 주장
- 실시간·전송·worker 의 성능이나 안정성 수치를 측정했다는 주장
- 특정 storage·CDN·push vendor 와의 통합을 검증했다는 주장
  • Step 7: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "runbook 절(기대 2): $(grep -cE '^### 16\.[67] `FE-RB-00[67]`' "$HUB")"
echo "FE-EV 신규(기대 2): $(grep -cE '^\| `FE-EV-01[45]`' "$HUB")"
echo "FE-RISK 신규(기대 6): $(grep -cE '^\| `FE-RISK-01[3-8]`' "$HUB")"
echo "FE-Q 신규(기대 4): $(grep -cE '^\| `FE-Q-01[1-4]`' "$HUB")"
echo "FE-Q-009 해소(기대 1): $(grep -c 'FE-D034` 로 해소' "$HUB")"
echo "out of scope 못박기(기대 1): $(grep -c 'port 와 adapter 계약까지만 제공한다' "$HUB")"

Expected: 2, 2, 6, 4, 1, 1.

  • Step 8: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): 범위·runbook 2개·evidence·risk·open question·답변경계

- §0.5 out of scope 에 '6개 도메인의 use case/domain model/business rule'
  을 명시. 이 skeleton 은 port 와 adapter 계약까지다.
- FE-RB-006 실시간 연결 장애, FE-RB-007 백그라운드 실행 장애
- FE-Q-009(service worker 필요한가)는 FE-D034 로 해소"

Task 9: hub 실행계획·branch 분해·Cluster·체크리스트·tail (§8.0, §20, §21.2, §23.1, §25, §26, frontmatter)

Files:

  • Modify: hub frontmatter (133행), §8.0 실행계획 (20252053행), §20 Branch Decomposition (20592089행), §21.2 브랜치 (21582216행), §23.1 (22972310행), §25 Next Steps (23652404행), §26 (24092418행)

Interfaces:

  • Consumes: Task 1~8 의 모든 ID

  • Produces: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028~033, branch slug 6개. Task 10 의 branch-note frontmatter 가 이 WI ID 를 pin 한다.

  • Step 1: 체크 명령을 돌려 아직 없음을 확인

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
grep -cE 'WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-0(2[89]|3[0-3])' "$HUB"
grep -c 'feature-frontend-binary-file-io-store-contract' "$HUB"

Expected: 둘 다 0.

  • Step 2: §8.0 에 Work Item 6행 추가 + 기존 1행 보강

| \WI-…-027` | `feature-frontend-ci-quality-gates-contract` | … 행 다음에 spec §11.1 의 표 6행을 붙인다. **ID 는 축약 없이 전체 문자열**(WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028등)로 쓴다.Status는 전부 ``planned` ``.

WI-…-004(feature-frontend-env-runtime-config-contract) 행의 완료 조건에 ; capability registry와 default-off 번들 검증이 통과한다 를 덧붙이고, Applies DecisionsDEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1 을 추가한다.

  • Step 3: §20 에 branch 6행 추가 + 서두 갱신

표 끝에 spec §11.2 의 6행을 붙인다. Measurable completion 은 §8.0 완료 조건과 같은 취지로 적고, Priority 는 전부 P4.

서두 문장 아래 27개 branch-note는 2026-07-18 \/branch` scaffolding으로 생성되어아래 33개 branch-note 중 27개는 2026-07-18 scaffolding으로, 6개는 2026-07-28 runtime capability 확장으로 생성되어`

Priority 열 설명을 표 아래에 추가한다.

`P4` 는 2026-07-28 에 추가한 계층이다. P1~P3 의 핵심 skeleton 이 완성된 뒤 착수하는 **opt-in capability** 를 뜻하며, 이 계층의 branch 가 미완이어도 `MERGE_READY``FE-GATE-033` 만으로 성립한다(§15.3).
  • Step 4: §21.2 Cluster 에 6항 추가

<!-- GENERATED: branches:start --> 블록 안의 알파벳 순서에 맞춰 6개 wikilink 를 삽입한다. feature-frontend-b…feature-frontend-auth-session-integration-contractfeature-frontend-browser-security-boundary-contract 사이 등, 정렬을 실제로 맞춘다.

블록 아래 수기 목록에도 6항을 추가한다(설명 포함).

- [[raw/branch-notes/feature-frontend-binary-file-io-store-contract]] — 바이너리/파일 I-O·로컬 대용량 저장 contract
- [[raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract]] — 캐시 계층·탭 간 무효화 contract
- [[raw/branch-notes/feature-frontend-large-object-transfer-contract]] — 대용량 객체 전송 contract
- [[raw/branch-notes/feature-frontend-multi-protocol-api-transport-contract]] — 멀티프로토콜 API transport contract
- [[raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract]] — 실시간 구독 수명주기 contract
- [[raw/branch-notes/feature-frontend-background-execution-worker-contract]] — 백그라운드 실행 contract
  • Step 5: §23.1·§25·§26 갱신

§23.1 — - [x] route/API-operation/env/storage/error/query/telemetry/release 8개 registry owner가 있음9개 registry owner가 있음 (뒤에 /capability 추가). - [x] runbook 5종이 있음- [x] runbook 7종이 있음.

§25 — ### P3 — Release readiness 절 다음, ### Promotion 앞에 신설:

### P4 — Opt-in runtime capability

- [ ] `feature-frontend-binary-file-io-store-contract` 설계·depth gate
- [ ] `feature-frontend-cache-tier-cross-tab-invalidation-contract` 설계·depth gate
- [ ] `feature-frontend-large-object-transfer-contract` 설계·depth gate
- [ ] `feature-frontend-multi-protocol-api-transport-contract` 설계·depth gate
- [ ] `feature-frontend-realtime-subscription-lifecycle-contract` 설계·depth gate
- [ ] `feature-frontend-background-execution-worker-contract` 설계·depth gate
- [ ] 6개 도메인의 근거 raw 자료 수집 (`FE-Q-011`)

§26 — 표 끝에:

| opt-in runtime capability | `planned` | 설계와 계약만 존재; adapter·gate evidence `UNVERIFIED` |
  • Step 6: frontmatter 갱신

last_reviewed: 2026-07-18last_reviewed: 2026-07-28 project_revision: 1project_revision: 2

imports: 배열은 손대지 않는다. 이 배열은 hub 가 다른 문서에서 가져온 계약의 pin 이고, 신규 FE-OC-027032·FE-GATE-027033 은 hub 가 정의하는 것이지 가져오는 것이 아니다. §21 가져온 프로젝트 계약 표도 같은 이유로 Task 11 이후 branch-note 가 생긴 뒤에 다루며, 이번 변경에서는 건드리지 않는다.

  • Step 7: 체크 명령을 다시 돌려 통과 확인
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "WI 신규(기대 6): $(grep -cE '^\| `WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-0(2[89]|3[0-3])`' "$HUB")"
echo "branch slug 6종 등장: $(for s in binary-file-io-store cache-tier-cross-tab-invalidation large-object-transfer multi-protocol-api-transport realtime-subscription-lifecycle background-execution-worker; do grep -q "feature-frontend-$s-contract" "$HUB" || echo "MISSING $s"; done; echo ok)"
echo "33개 branch(기대 1): $(grep -c '33개 branch-note' "$HUB")"
echo "9개 registry owner(기대 1): $(grep -c '9개 registry owner가 있음' "$HUB")"
echo "runbook 7종(기대 1): $(grep -c 'runbook 7종이 있음' "$HUB")"
echo "P4 절(기대 1): $(grep -c '^### P4 — Opt-in runtime capability' "$HUB")"
echo "last_reviewed(기대 1): $(grep -c '^last_reviewed: 2026-07-28' "$HUB")"

Expected: 6, MISSING 없이 ok, 1, 1, 1, 1, 1.

  • Step 8: hub 전체 참조 무결성 검사
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
CONTRACT_STABLE_ID_RE='FE-D[0-9]{3}|FE-(SC|OC|NFR|GATE|RB|EV|RDY|RISK|Q)-[0-9]{3}|FE-NFR-C[0-9]{2}|FE-REG-[A-Z]+(-[A-Z]+)*'
comm -23 \
  <(grep -oE "$CONTRACT_STABLE_ID_RE" "$HUB" | sort -u) \
  <(grep -nE '^\| `FE-|^### 16\.[0-9]+ `FE-RB-' "$HUB" | grep -oE "$CONTRACT_STABLE_ID_RE" | sort -u)

Expected: 출력 없음. 출력이 있으면 그 ID 는 참조만 되고 정의 행이 없다는 뜻이니, 해당 Task 로 돌아가 정의 행을 추가한다.

  • Step 9: 커밋
git add raw/project-notes/ca-skeleton-frontend-operational-contract.md
git commit -m "docs(hub): Work Item 6건, branch 분해 6행, Cluster, P4 계층, tail 정합

- WI-...-028~033 과 §20 branch 행. P4 = P1~P3 완료 후 착수하는 opt-in
  capability 계층이며 미완이어도 MERGE_READY 는 FE-GATE-033 으로 성립
- §23.1 체크리스트 8->9 registry, runbook 5->7종
- project_revision 2, last_reviewed 2026-07-28
- frontmatter imports 는 손대지 않음(hub 가 정의하는 계약이지 가져온 것이
  아니다)"

Task 10: 신규 branch-note 6개 생성

Files:

  • Create: raw/branch-notes/feature-frontend-binary-file-io-store-contract.md
  • Create: raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract.md
  • Create: raw/branch-notes/feature-frontend-large-object-transfer-contract.md
  • Create: raw/branch-notes/feature-frontend-multi-protocol-api-transport-contract.md
  • Create: raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract.md
  • Create: raw/branch-notes/feature-frontend-background-execution-worker-contract.md
  • Read (템플릿): templates/branch-note-template.md

Interfaces:

  • Consumes: Task 2 의 DEC-… Summary 문자열(글자 단위 복사), Task 3 의 DELEG-FE-*·FLOW-FE-EVENT-*, Task 9 의 WI-…-028~033
  • Produces: branch-note 6개. Task 11 의 위임 왕복 대조가 이 파일들의 delegates:/accepts_delegations: 를 참조한다.

작성 원칙: templates/branch-note-template.md 의 절 구조를 그대로 따른다. ## 구현 가이드헤딩과 R1/R2/R3 안내만 남기고 비운다 — 근거 raw 없이 채우면 전부 UNSUPPORTED_IMPL_DECISION 이 되므로(CLAUDE.md §15.5) 다음 단계(/branch-spec 상당 작업)로 미룬다. 이 사실을 각 파일의 해당 절에 한 줄로 적는다.

  • Step 1: 템플릿을 읽고 절 구조를 확인
grep -nE '^#{1,3} |^<!-- section-id' templates/branch-note-template.md | head -40

# branch: {{branch-name}} 부터 ## 완료 후 정리 까지가 1벌이다. 파일 후반(334행 이후)은 축약 예시이므로 전반부 구조를 쓴다.

  • Step 2: 파일 1 — feature-frontend-binary-file-io-store-contract.md

frontmatter:

---
title: branch / feature-frontend-binary-file-io-store-contract
source_type: branch-note
status: raw
id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028
kind: project-work-item
project: ca-skeleton-frontend-operational-contract
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BINARY-STORE-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001@1]
refines: []
overrides: []
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-002, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011]
imports: [FE-GATE-027@1, FE-OC-002@1, FE-OC-013@1, FE-OC-022@1]
delegates: []
accepts_delegations: [DELEG-FE-008]
contract_packet: 1
branch: feature-frontend-binary-file-io-store-contract
parent_branch:
related_projects: [ca-skeleton-frontend, ca-skeleton]
tags: [branch, ca-skeleton-frontend, storage, binary, file-io]
created: 2026-07-28
target_merge:
status_label: in-progress
---

본문 핵심:

  • ## 부모[[raw/project-notes/ca-skeleton-frontend-operational-contract]]

  • ## 브랜치 계약 패킷 — 생성 시 프로젝트 개정 2, 완료 조건은 hub §8.0 WI-…-028 셀과 같은 문장

  • ### 상속한 프로젝트 결정 — 3개 pin, Summary 는 Task 2 Step 4 의 문자열을 글자 단위로 복사, 각 행에 branch 적용점 1줄

  • ## 목표FileDialogPortBlobStorePort 를 정의하고 IndexedDB·OPFS·Cache Storage adapter 와 object URL 수명 계약을 고정한다

  • ### 포함 범위 — 파일 선택/저장 dialog, Blob·File descriptor, object URL 생성·해제, IndexedDB/OPFS/Cache Storage backend, quota 매핑과 eviction, FE-REG-STORAGE 신규 4행

  • ### 제외 범위use case·domain model·business rule, 파일 형식별 처리(이미지 리사이즈·트랜스코딩·문서 파싱), 실제 전송(= feature-frontend-large-object-transfer-contract 소유)

  • ## 근거[[docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design]] §5.1·§6.2, 그리고 project-local default, 외부 source claim 아님 명시. 근거 raw 수집은 FE-Q-011

  • ## 검증해야 할 주장FE-GATE-027 의 fixture 5종을 claim 으로 전개(picker 취소·거부, quota 초과 fallback, OPFS 순차 write, Cache Storage 버전 파티션, object URL 해제)

  • ## 구현 가이드 — 헤딩만 두고 아래 한 줄: > 근거 raw 자료(FE-Q-011) 수집 전까지 비워 둔다. 지금 채우면 모든 cell 이 UNSUPPORTED_IMPL_DECISION 이 된다.

  • Step 3: 파일 2 — feature-frontend-cache-tier-cross-tab-invalidation-contract.md

frontmatter 차이:

id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-029
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-029
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CROSS-TAB-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVER-STATE-001@1]
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-010, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011]
imports: [FE-GATE-028@1, FE-OC-012@1, FE-OC-013@1, FE-OC-023@1]
delegates: [DELEG-FE-009]
accepts_delegations: []
tags: [branch, ca-skeleton-frontend, cache, server-state, cross-tab]

본문 핵심:

  • ## 목표CachePersistencePortCrossTabSyncPort 를 정의하고 memory↔session↔local↔IndexedDB 계층과 탭 간 무효화를 고정한다

  • ### 포함 범위 — persistence tier, version partition(releaseId·configSchemaVersion·apiContractVersion), BroadcastChannel + storage event fallback, 무효화 key 전파

  • ### 제외 범위 — use case·domain model·business rule, QueryCachePort 정책 자체(= feature-server-state-caching-contract 소유), physical storage key·classification(= DELEG-FE-009feature-frontend-storage-registry-contract 에 위임), offline-first 충돌 해결

  • ## 검증해야 할 주장FE-GATE-028 fixture 3종

  • DEC-…-SERVER-STATE-001@1 Summary 는 hub §6.1 의 기존 문자열을 그대로 복사한다: application-owned QueryCachePort와 TanStack Query adapter를 사용하고 client store에 server state를 복제하지 않는다

  • Step 4: 파일 3 — feature-frontend-large-object-transfer-contract.md

frontmatter 차이:

id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-030
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-030
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TRANSFER-CREDENTIAL-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-RESUMABLE-TRANSFER-001@1]
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-005, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-028]
imports: [FE-GATE-029@1, FE-OC-006@1, FE-OC-019@1, FE-OC-027@1]
delegates: [DELEG-FE-008]
accepts_delegations: []
tags: [branch, ca-skeleton-frontend, transfer, upload, streaming]

본문 핵심:

  • ## 목표UploadTransferPort·StreamingDownloadPort 정의, presigned 획득과 byte 전송의 credential 경계 고정, MediaUrlPolicy 명세

  • ### 포함 범위 — presign 획득(shared client 경유), credential-less 전송, part 분할·병렬·재시도·무결성, 진행 보고, range/resume 다운로드, Image CDN URL 파생 정책

  • ### 제외 범위 — use case·domain model·business rule, backend presign endpoint 설계, object storage vendor 선택, File/Blob handle 수명(= DELEG-FE-008 로 위임)

  • ## 검증해야 할 주장FE-GATE-029 fixture 5종. credential 첨부 negative fixture 를 반드시 포함한다

  • Step 5: 파일 4 — feature-frontend-multi-protocol-api-transport-contract.md

frontmatter 차이:

id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-031
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-031
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-PROTOCOL-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-VALIDATION-001@1]
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-005, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-006, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-007]
imports: [FE-GATE-030@1, FE-OC-006@1, FE-OC-007@1, FE-OC-008@1, FLOW-FE-RESP-004@1, FLOW-FE-RESP-005@1, FLOW-FE-RESP-006@1]
delegates: [DELEG-FE-010]
accepts_delegations: []
tags: [branch, ca-skeleton-frontend, api, protocol, graphql, grpc-web]

본문 핵심:

  • ## 목표 — GraphQL·gRPC-Web·Connect-Web adapter 가 기존 ResourceQueryPort/ResourceCommandPort 를 구현하도록 고정하고, protocol 별 성공/실패 판정을 정규화한다

  • ### 포함 범위FE-REG-API.protocol·operationRef 소비, codec, gRPC status ↔ 정규화 kind 매핑, GraphQL 200 + errors[] 처리, REST gateway fallback

  • ### 제외 범위 — use case·domain model·business rule, 신규 port 정의(0개가 이 branch 의 설계 결론이다), GraphQL 스키마·protobuf 서비스 정의, 스키마 생성 파이프라인(FE-Q-013), 디코드 후 payload 검증(= DELEG-FE-010 로 위임)

  • ## 검증해야 할 주장FE-GATE-030 fixture 4종

  • DEC-…-VALIDATION-001@1 Summary 는 hub 기존 문자열 복사: boundary runtime validation은 Zod schema로 수행한다

  • Step 6: 파일 5 — feature-frontend-realtime-subscription-lifecycle-contract.md

frontmatter 차이:

id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-032
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-032
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-TRANSPORT-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-LIFECYCLE-001@1]
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-006, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-007, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-013]
imports: [FE-GATE-031@1, FE-OC-007@1, FE-OC-008@1, FE-OC-011@1, FE-OC-025@1, FLOW-FE-EVENT-003@1, FLOW-FE-EVENT-004@1, FLOW-FE-EVENT-005@1]
delegates: [DELEG-FE-007]
accepts_delegations: []
tags: [branch, ca-skeleton-frontend, realtime, sse, websocket, push]

FLOW-FE-EVENT-001·002 는 이 branch 가 소유하므로 import 하지 않는다. 003·004(runtime-schema owner)와 005(error-classification owner)만 import 한다.

본문 핵심:

  • ## 목표RealtimeSubscriptionPort·PushSubscriptionPort 정의, 연결·재연결·재개·이벤트 검증·해제 계약 고정

  • ### 포함 범위 — SSE/WebSocket/bounded polling adapter, full jitter backoff + 30s cap + terminal 전이, Last-Event-ID/cursor resume, 프레임 디코드(FLOW-FE-EVENT-001·002), 구독 해제, §9.5 surface state, WebPush 등록, FE-RB-006

  • ### 제외 범위 — use case·domain model·business rule, 이벤트의 도메인 의미와 상태 병합 정책, service worker 등록·수명주기(= DELEG-FE-007 로 위임), push 발송 서버·VAPID 개인키(FE-Q-014)

  • ## 검증해야 할 주장FE-GATE-031 fixture 4종 + FE-NFR-016·FE-NFR-017

  • Step 7: 파일 6 — feature-frontend-background-execution-worker-contract.md

frontmatter 차이:

id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-033
work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-033
inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVICE-WORKER-ROLE-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BACKGROUND-SYNC-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-WORKER-TASK-001@1]
depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-005, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-024]
imports: [FE-GATE-032@1, FE-OC-009@1, FE-OC-016@1, FE-OC-017@1, FE-OC-025@1]
delegates: [DELEG-FE-011]
accepts_delegations: [DELEG-FE-007]
tags: [branch, ca-skeleton-frontend, worker, service-worker, background-sync]

본문 핵심:

  • ## 목표WorkerTaskPort·ServiceWorkerHostPort·BackgroundSyncPort 정의, FE-D034 의 SW 역할 분리를 구현 계약으로 내린다

  • ### 포함 범위 — worker 생성·통신·timeout·terminate, SW 등록·갱신 상태·§9.7 surface state(자동 skipWaiting 금지), background sync 큐(keyed only), serviceWorkerVersion 토큰 산출, FE-RB-007

  • ### 제외 범위 — use case·domain model·business rule, release asset precaching(FE-D034 에 의해 default off 유지), rollback 판정 자체(= DELEG-FE-011 로 위임), push 발송 서버

  • ### 선언한 예외FE-D019FE-D034 가 supersede 했음을 명시하고, 이 branch 가 DEC-…-OFFLINE-CACHE-001@2 의 소비자임을 적는다

  • ## 검증해야 할 주장FE-GATE-032 fixture 4종 + FE-NFR-019

  • Step 8: 6개 파일 정합 검사

BN=raw/branch-notes
NEW="feature-frontend-binary-file-io-store-contract feature-frontend-cache-tier-cross-tab-invalidation-contract feature-frontend-large-object-transfer-contract feature-frontend-multi-protocol-api-transport-contract feature-frontend-realtime-subscription-lifecycle-contract feature-frontend-background-execution-worker-contract"
for f in $NEW; do
  p="$BN/$f.md"
  [ -f "$p" ] || { echo "MISSING FILE: $p"; continue; }
  grep -q "^source_type: branch-note$" "$p" || echo "BAD source_type: $f"
  grep -q "^contract_packet: 1$" "$p" || echo "BAD contract_packet: $f"
  grep -q "^created: 2026-07-28$" "$p" || echo "BAD created: $f"
  grep -q "^parent_branch:$" "$p" || echo "BAD parent_branch(비어야 함): $f"
  grep -q "\[\[raw/project-notes/ca-skeleton-frontend-operational-contract\]\]" "$p" || echo "MISSING 부모 링크: $f"
  grep -q "use case" "$p" || echo "MISSING 제외범위 use case: $f"
done
echo "--- 결정 Summary 문자열 hub 대조 ---"
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
while IFS= read -r s; do
  n=$(grep -lF "$s" $BN/*.md "$HUB" 2>/dev/null | wc -l)
  [ "$n" -ge 2 ] || echo "고아 Summary(hub 에만 있음): $s"
done <<'EOF'
신규 runtime capability 6종은 FE-REG-CAPABILITY flag로 default OFF이며 활성화는 owner·gate·runbook을 동반한다
로컬 바이너리 backend는 IndexedDB를 default로 하고 OPFS는 대용량 순차 write에 opt-in, Cache Storage는 service worker 호스팅 response cache 전용이다
탭 간 무효화는 BroadcastChannel 우선에 storage event fallback을 쓰고 leader election 없이 무효화 key만 전파한다
presigned URL 획득은 shared client를 경유하고 실제 byte 전송은 session credential을 첨부하지 않는 transfer adapter가 수행한다
재개 가능 전송은 part size·병렬도·part 재시도 상한을 registry로 고정하고 part 상태를 BlobStorePort에 보존한다
transport default는 REST이고 GraphQL·gRPC-Web·Connect-Web은 FE-REG-API의 protocol 필드로 opt-in하며 미지원 환경은 REST gateway로 fallback한다
실시간 transport는 SSE를 우선하고 양방향이 필요하면 WebSocket, 둘 다 불가할 때만 최소 간격·backoff·visibility gating을 갖춘 bounded polling을 쓴다
실시간 연결은 full jitter backoff와 30초 cap을 쓰고 재시도 상한 후 terminal 상태로 전이하며 resume은 Last-Event-ID 또는 cursor로 수행하고 unmount 시 구독을 해제한다
service worker는 역할을 분리해 release asset precaching은 default off로 유지하고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용하며 update UX 계약을 요구한다
background sync 재생은 idempotency keyed operation만 허용한다
Web Worker 작업은 structured-clone 또는 Transferable로만 통신하고 timeout과 terminate를 계약하며 worker 안에서 application port를 재구현하지 않는다
EOF
echo done

Expected: MISSING/BAD/고아 Summary 출력 없이 done.

  • Step 9: 커밋
git add raw/branch-notes/feature-frontend-binary-file-io-store-contract.md \
        raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract.md \
        raw/branch-notes/feature-frontend-large-object-transfer-contract.md \
        raw/branch-notes/feature-frontend-multi-protocol-api-transport-contract.md \
        raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract.md \
        raw/branch-notes/feature-frontend-background-execution-worker-contract.md
git commit -m "docs(branch): 런타임 capability branch-note 6개 스캐폴딩

WI-...-028~033 에 대응하는 FE-OC-027~032 owner 노트.
각 노트의 제외 범위에 'use case·domain model·business rule' 을 명시해
이 skeleton 이 port 와 adapter 계약까지임을 못박았다.
구현 가이드 절은 근거 raw(FE-Q-011) 수집 전까지 비워 둔다."

Task 11: 기존 branch-note 7개 정합 수정

Files:

  • Modify: raw/branch-notes/feature-frontend-release-cache-rollback-contract.md (9행 inherits:, 50행 상속 표)
  • Modify: raw/branch-notes/feature-frontend-storage-registry-contract.md (48행 상속 표)
  • Modify: raw/branch-notes/feature-frontend-observability-logging-trace-contract.md (50행 상속 표)
  • Modify: raw/branch-notes/feature-frontend-contract-registry-governance.md (49행 상속 표)
  • Modify: raw/branch-notes/feature-frontend-contract-compatibility-governance.md (48행 상속 표)
  • Modify: raw/branch-notes/feature-runtime-schema-validation-contract.md (frontmatter)
  • Modify: raw/branch-notes/feature-frontend-env-runtime-config-contract.md (frontmatter + 본문)

Interfaces:

  • Consumes: Task 2 의 개정된 Summary 문자열, Task 3 의 DELEG-FE-*, Task 5 의 FE-REG-CAPABILITY, Task 7 의 FE-GATE-033

  • Produces: 위임 5건 전부 accepted 성립

  • Step 1: 체크 명령을 돌려 불일치를 확인

BN=raw/branch-notes
echo "구 REGISTRY 문자열(기대 4): $(grep -lF 'release token을 8개 registry로 관리한다' $BN/*.md | wc -l)"
echo "구 OFFLINE-CACHE 문자열(기대 1): $(grep -lF 'service worker와 offline asset cache는 default off다' $BN/*.md | wc -l)"
echo "OFFLINE-CACHE @1 pin(기대 1): $(grep -c 'DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001@1' $BN/feature-frontend-release-cache-rollback-contract.md)"

Expected: 4, 1, 1.

  • Step 2: REGISTRY-001 문자열 4곳 일괄 교체
BN=raw/branch-notes
for f in feature-frontend-storage-registry-contract \
         feature-frontend-observability-logging-trace-contract \
         feature-frontend-contract-registry-governance \
         feature-frontend-contract-compatibility-governance; do
  python3 - "$BN/$f.md" <<'PY'
import sys, pathlib
p = pathlib.Path(sys.argv[1])
old = "route, API operation, env, storage, error, query, telemetry, release token을 8개 registry로 관리한다"
new = "route, API operation, env, storage, error, query, telemetry, release token, capability를 9개 registry로 관리한다"
t = p.read_text(encoding="utf-8")
assert old in t, f"old string not found in {p}"
p.write_text(t.replace(old, new), encoding="utf-8")
print("ok", p)
PY
done

feature-frontend-contract-registry-governanceBranch 적용 셀은 8개 registry의 owner·schema·impact·snapshot governance를 집행한다 이므로 9개 registry의 … 로 함께 고친다(이 셀은 Summary 가 아니라 적용점이라 문자열 제약은 없지만, 숫자가 어긋난 채 남으면 문서가 자기모순이다).

  • Step 3: feature-frontend-release-cache-rollback-contract.md 개정

  • frontmatter 9행: DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001@1…@2

  • frontmatter accepts_delegations:DELEG-FE-011 추가 (키가 없으면 imports: 다음에 추가)

  • 상속 표 50행: pin 을 @2 로, Summary 를 service worker의 release asset precaching은 default off이고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용한다 로 교체

  • 같은 행 Branch 적용 셀을 service worker registration과 offline cache 기본 정책에 적용한다release asset precaching 은 off 로 유지하고, capability opt-in 된 service worker 의 버전을 release·rollback coherence 에 연결한다 로 갱신

  • Step 4: feature-runtime-schema-validation-contract.md 위임 접수

frontmatter accepts_delegations:DELEG-FE-010 을 추가한다. ## 수신한 위임 절에 아래 행을 추가한다.

| `DELEG-FE-010` | `feature-frontend-multi-protocol-api-transport-contract` | codec 디코드 이후 payload 의 runtime schema 검증 | accepted |

FLOW-FE-EVENT-003·FLOW-FE-EVENT-004 를 이 branch 가 소유한다는 사실을 ## 범위 / 포함 범위 에 한 줄로 추가한다.

  • Step 5: feature-frontend-env-runtime-config-contract.md owner 취득 반영

  • frontmatter inherits:DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1 추가

  • frontmatter imports:FE-GATE-033@1 추가

  • ### 상속한 프로젝트 결정 표에 CAPABILITY-001@1 행 추가 (Summary 는 Task 2 Step 4 첫 문자열 그대로)

  • ## 범위 / 포함 범위FE-REG-CAPABILITY registry owner 와 FE-GATE-033 gate owner 역할을 추가

  • ## 검증해야 할 주장FE-GATE-033 의 claim 2개(기본 config build 에 비활성 adapter 부재 / FE-NFR-020 initial JS 증가 0) 추가

  • Step 6: 위임 왕복 대조

BN=raw/branch-notes
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
for d in DELEG-FE-007 DELEG-FE-008 DELEG-FE-009 DELEG-FE-010 DELEG-FE-011; do
  delegator=$(grep -c "delegates: \[.*$d" $BN/*.md 2>/dev/null | grep -v ':0' | wc -l)
  delegate=$(grep -c "accepts_delegations: \[.*$d" $BN/*.md 2>/dev/null | grep -v ':0' | wc -l)
  [ "$delegator" -ge 1 ] || echo "$d: delegator 없음"
  [ "$delegate" -ge 1 ] || echo "$d: delegate 미접수(UNACCEPTED_DELEGATION)"
  grep -qE "^\| \`$d\`.*accepted \|$" "$HUB" || echo "$d: hub Status 가 accepted 아님"
done
echo "--- 문자열 잔존 확인 ---"
echo "구 REGISTRY(기대 0): $(grep -lF 'release token을 8개 registry로 관리한다' $BN/*.md 2>/dev/null | wc -l)"
echo "구 OFFLINE-CACHE(기대 0): $(grep -lF 'service worker와 offline asset cache는 default off다' $BN/*.md 2>/dev/null | wc -l)"
echo "OFFLINE-CACHE @1 잔존(기대 0): $(grep -c 'OFFLINE-CACHE-001@1' $BN/*.md 2>/dev/null | grep -v ':0' | wc -l)"
echo done

Expected: 경고 출력 없이 0, 0, 0, done.

  • Step 7: 커밋
git add raw/branch-notes/
git commit -m "docs(branch): 기존 7개 노트를 개정 결정·신규 위임에 정합

- REGISTRY-001 Summary 문자열 4곳 (additive, revision 은 1 유지)
- OFFLINE-CACHE-001 pin @1->@2 와 Summary (behavior-change)
- DELEG-FE-007~011 delegate 5곳 접수 완료 — 미접수 위임 0건
- env-runtime-config 가 FE-REG-CAPABILITY registry 와 FE-GATE-033 gate
  owner 를 취득"

Task 12: 전체 정합 검증과 마무리

Files:

  • Read-only 검증. 필요 시 앞선 Task 의 파일을 수정.
  • Modify: docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design.md (실행 결과 반영이 필요할 때만)

Interfaces:

  • Consumes: Task 1~11 전부

  • Produces: 없음 (검증 종결)

  • Step 1: hub 참조 무결성

HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
CONTRACT_STABLE_ID_RE='FE-D[0-9]{3}|FE-(SC|OC|NFR|GATE|RB|EV|RDY|RISK|Q)-[0-9]{3}|FE-NFR-C[0-9]{2}|FE-REG-[A-Z]+(-[A-Z]+)*'
echo "--- 정의 없는 참조 (비어야 함) ---"
comm -23 \
  <(grep -oE "$CONTRACT_STABLE_ID_RE" "$HUB" | sort -u) \
  <(grep -nE '^\| `FE-|^### 16\.[0-9]+ `FE-RB-' "$HUB" | grep -oE "$CONTRACT_STABLE_ID_RE" | sort -u)
echo "--- 끝 ---"

Expected: 두 --- 사이가 비어 있음.

  • Step 2: 단일 소유자 검사 — 한 계약에 owner 가 둘 이상이면 안 됨
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
echo "--- FE-OC 중복 정의 (비어야 함) ---"
grep -oE '^\| `FE-OC-[0-9]{3}`' "$HUB" | sort | uniq -c | awk '$1 != 2 {print "개수 이상:", $0}'
echo "--- FE-GATE 중복 정의 (비어야 함) ---"
grep -oE '^\| `FE-GATE-[0-9]{3}`' "$HUB" | sort | uniq -c | awk '$1 != 2 {print "개수 이상:", $0}'

FE-OC-*FE-GATE-* 는 각각 정확히 2회(§2.1+§2.1.1, §2.1.1+§15.1) 정의 행으로 나타나야 한다. 다른 개수면 어느 표에서 누락됐거나 중복이다.

  • Step 3: 개수 정합 총점검
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
BN=raw/branch-notes
cat <<EOF
FE-OC 고유 ID    (기대 32): $(grep -oE '^\| `FE-OC-[0-9]{3}`' "$HUB" | sort -u | wc -l)
FE-GATE 고유 ID  (기대 33): $(grep -oE '^\| `FE-GATE-[0-9]{3}`' "$HUB" | sort -u | wc -l)
FE-D 정의 행     (기대 36): $(grep -cE '^\| `FE-D[0-9]{3}`' "$HUB")
DEC 정의 행      (기대 36): $(grep -cE '^\| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-' "$HUB")
FE-REG 정의 행   (기대  9): $(grep -cE '^\| `FE-REG-[A-Z]+`' "$HUB")
FE-NFR 정의 행   (기대 20): $(grep -cE '^\| `FE-NFR-[0-9]{3}`' "$HUB")
FE-RB 절         (기대  7): $(grep -cE '^### 16\.[0-9]+ `FE-RB-' "$HUB")
WI 정의 행       (기대 33): $(grep -cE '^\| `WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-' "$HUB")
프로젝트 소속 노트 (기대 33): $(grep -l 'ca-skeleton-frontend-operational-contract' $BN/*.md | wc -l)
Cluster 링크     (기대 33): $(sed -n '/GENERATED: branches:start/,/GENERATED: branches:end/p' "$HUB" | grep -c '^- \[\[raw/branch-notes/')
EOF

산식: FE-OC 26+6=32, FE-GATE 26+7=33, FE-D 25+11=36, DEC 25+11=36, FE-REG 8+1=9, FE-NFR 15+5=20, FE-RB 5+2=7, WI 27+6=33, 프로젝트 소속 branch-note 27+6=33.

FE-OC·FE-GATEsort -u고유 ID 를 센다. 각 ID 가 두 표에 정의 행을 갖기 때문에 단순 grep -c 는 두 배가 나온다. 기대값과 다르면 해당 Task 로 돌아간다.

  • Step 4: 금지 표현 검사
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
BN=raw/branch-notes
echo "신규 영역 과장 등급(기대 0):"
grep -nE '(actually-implemented|locally-verified|prod-verified)' "$HUB" \
  | grep -vE '§0\.2|§6|17\.2|허용|금지|이상 evidence|등급' | head
echo "TBD/TODO(기대 0): $(grep -cE '\bTBD\b|\bTODO\b' "$HUB" $BN/feature-frontend-binary-file-io-store-contract.md 2>/dev/null | grep -v ':0' | wc -l)"

Expected: 첫 명령은 등급 정의·게이트 설명 맥락 외 출력 없음, 둘째는 0.

  • Step 5: wikilink 유효성
HUB=raw/project-notes/ca-skeleton-frontend-operational-contract.md
BN=raw/branch-notes
echo "--- 깨진 wikilink (비어야 함) ---"
grep -ohE '\[\[[^]|]+\]\]' "$HUB" $BN/feature-frontend-{binary-file-io-store,cache-tier-cross-tab-invalidation,large-object-transfer,multi-protocol-api-transport,realtime-subscription-lifecycle,background-execution-worker}-contract.md \
  | sed 's/^\[\[//; s/\]\]$//' | sort -u \
  | while read -r l; do [ -f "$l.md" ] || echo "BROKEN: $l"; done
echo "--- 끝 ---"

Expected: 비어 있음. 설계문서 링크(docs/superpowers/specs/…)도 실제 파일이므로 통과해야 한다.

  • Step 6: 전체 diff 를 사람 눈으로 확인
git diff --stat 4533122..HEAD
git log --oneline 4533122..HEAD

파일 14개(hub 1 + 신규 6 + 기존 7)와 커밋 11개가 보여야 한다.

  • Step 7: spec 과의 최종 대조

spec §12.1 의 41개 항목을 하나씩 읽으며 hub 에서 확인한다. 실행 중 spec 과 다르게 처리한 항목이 있으면 spec 을 갱신하고 그 사유를 §14 승인 이력에 한 줄 남긴다. 계획서가 아니라 spec 이 SSOT 다.

  • Step 8: 커밋 (spec 갱신이 있을 때만)
git add docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design.md
git commit -m "docs(spec): 실행 결과 반영

<무엇이 어떻게 달라졌고 왜인지>"

Self-Review

1. Spec coverage — spec §12.1 의 41개 편집 항목이 Task 1~9 에 모두 배정됐다.

spec §12.1 항목 Task
1 frontmatter 9
2 §0.5 8
3 §2.1 / 4 §2.1.1 1
5 §2.1.2 / 6 §2.1.4 3
7 §3.2 / 8 §6.1 2
9 §4.2 ~ 13 §4.6 4
14 §5.1 ~ 22 §5.11 5
23 §8.2 / 24 §9.5~9.7 / 25 §14.2 6
26 §15.1 ~ 28 §15.3 / 31 §18.1 / 32 §18.2 7
29 §16 / 30 §17.1 / 33 §19.1 / 34 §19.2 / 38 §22 8
35 §8.0 / 36 §20 / 37 §21.2 / 39 §23.1 / 40 §25 / 41 §26 9
spec §11.3 신규 파일 6개 10
spec §12.3 기존 파일 7개 11

spec §13(알려진 drift)은 편집 항목이 아니라 제약이므로 Global Constraints 에 반영했다.

2. Placeholder scan — "적절히", "필요 시 처리", "비슷하게" 류 없음. 각 Step 은 정확한 파일·행 위치·문자열·명령·기대 출력을 갖는다. 표 내용은 spec 절 번호로 지시하되, 오타가 곧 문서 간 모순이 되는 §6.1 Summary 11개 문자열은 Task 2 Step 4 에 그대로 인라인했다.

3. Type consistency — port 12개 이름은 Task 4 정의 → Task 10 branch-note 목표에서 동일 철자로 사용. capability ID 6개는 Task 5 정의 → Task 5 Step 9 검증에서 동일. WI-…-028033 은 Task 9 정의 → Task 10 frontmatter 에서 전체 문자열로 사용. DELEG-FE-007011 은 Task 3 정의 → Task 10·11 에서 delegator/delegate 양쪽에 대응 등록 후 Task 11 Step 6 이 왕복 대조. FLOW-FE-EVENT-001~005 는 Task 3 정의 → Task 10 파일 5가 003·004·005 만 import(001·002 는 소유).

4. 알려진 한계 — 이 계획의 검증은 전부 grep 기반 구조 검사다. 문장의 의미가 옳은지, 표의 셀 내용이 spec 과 같은 뜻인지는 기계가 판정하지 않는다. Task 12 Step 7 의 사람 대조가 그 역할을 한다.


Execution Handoff

계획을 docs/superpowers/plans/2026-07-28-ca-skeleton-frontend-runtime-adapter-features.md 에 저장했다.