Skip to content

feat(#197-B2): WS 프로토콜 + 채널 매니페스트 + 클라이언트 브리지#199

Merged
pdw96 merged 6 commits into
masterfrom
feat/197-B2-ws-protocol
Jul 3, 2026
Merged

feat(#197-B2): WS 프로토콜 + 채널 매니페스트 + 클라이언트 브리지#199
pdw96 merged 6 commits into
masterfrom
feat/197-B2-ws-protocol

Conversation

@pdw96

@pdw96 pdw96 commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Part of #197 (Phase B · B2). 체크포인트 2·2-R Codex 승인판 구현.

무엇

Electron IPC 를 WebSocket 으로 교체하기 위한 전송층 계약 + 클라이언트 브리지를 도입한다. 코어 엔진·renderer·승인 게이트는 그대로 두고, IPC 4대 시맨틱(요청/응답 correlation · 응답 보장 · 푸시 구독 · 재접속 커서)을 WS 프레임으로 재현한다. 아직 미배선window.fleet 폴백 배선은 B4, 서버 핸들러는 B3.

변경

  • src/shared/transport/protocol.tsreq/res/push/hello 프레임 타입 + makeOkFrame(void=value 생략 정책)·makeErrFrame(스택 미노출)·decodeFrame(와이어 안전 파싱)·hasEventGap(rotation 폐기 gap 판정 — B1 store.eventCursor 소비). hellomaxEventSeq+minRetainedEventSeq.
  • src/shared/transport/channels.ts — 전 44채널 매니페스트(kind: invoke|push · scope: both|desktop). 파생 타입 BothInvokeChannel(B3 핸들러 satisfies 강제용)·invokeChannels/pushChannels 필터.
  • src/shared/transport/fixtures.tsboth invoke 33채널 직렬화 계약 fixture. satisfies Record<BothInvokeChannel, …> 로 완전성을 tsc 가 강제(채널 신설 시 fixture 누락=컴파일 에러).
  • src/renderer/bridge/ws-bridge.ts — FleetBridge WS 구현(WebSocket 팩토리 주입식 → DOM 없이 node vitest 검증). correlation(pending Map)·close 시 pending 전원 reject·per-request timeout(기본 무제한=IPC 동형·runProject 보존)·리스너 채널별 Set 멱등·재접속 지수 백오프(1s→30s cap)·onConnectionState 훅·후행 undefined 트림·desktop 전용(update) 채널은 로컬 no-op/idle 스텁(reject 아님).
  • AppInfo.runtime: 'electron'|'web' 선행 반영 — 데스크톱 fleet:app:info'electron' 스탬프(서버는 B3 에서 'web').

preload/main 채널 리터럴은 무변경(기존 ipc-parity.test.ts 전제 보존·데스크톱 무회귀).

계약 테스트

  • bridge-parity(src/main) — 매니페스트↔preload(전 채널)·ws-bridge↔매니페스트(both만) 3면 대조 + 데스크톱 runtime:'electron' 스탬프. 표류 주입 시 RED 확인 완료.
  • serialization — 33 fixture JSON 왕복 불변 + void=value 생략 + 가드 유효성(Date·NaN 검출).
  • protocol(9)·channels(7)·ws-bridge(24) 동작 계약.

비범위 (후속 phase)

서버 핸들러 테이블 satisfies 대조·ESLint 순수성 게이트 src/server·src/shared/transport 확장 → B3. renderer 웹모드 배선·표면 게이팅·재하이드레이션 wiring → B4. 보안층(Origin/JWT/nonce) → B5.

적대 자가리뷰 (find → 독립 refute)

체크포인트 2 승인 후 6렌즈 적대 리뷰(fleet-finder → 별도 fleet-refuter)로 확정 7건 반영:

  • [P2] decodeFrame 신뢰경계 완성 — 판별자 t만 검사하던 것을 프레임별 필드 불변식까지 검증(res: id/ok/error.message · push: ch · hello: seq 정수). 불량 프레임을 null 로 폐기해 handleMessage 의 무검증 error.message 역참조 TypeError + pending 영구 hang(타임아웃 백스톱 무력)을 제거. hello 비수치 seq → missed-gap 오판(B1 방어 재개방) 경로도 차단.
  • [P3] terminal closed hanginvoke 가드를 disposed || state==='closed' 로 확장(재접속 없는 close 후 요청 즉시 reject).
  • [P3] sendQueue 고아 — 큐를 {id,data} 태그화, flush 시 pending 인 요청만 전송(타임아웃/취소된 죽은 프레임 미전송).
  • [P3] 리스너 예외 격리 — push 콜백 dispatch try/catch(한 리스너 throw 가 소켓 루프·타 리스너 무영향).
  • [P3] 메서드↔채널 바인딩 가드bridge-parity 의 채널 '집합' 검사가 놓치는 동일-시그니처 채널 스왑·인자 순서 drift 를 테이블 구동 테스트로 차단(스왑 주입 시 RED 실측).
  • defense-in-depthopenCliDocshttp(s) 스킴만 window.open(javascript:/data: 차단).

refute 11건(중간 undefined 트림·fixtures result:[]·openCliDocs allowlist=서버 신뢰모델·재접속 double-onclose 등)은 근거와 함께 기각.

게이트

npm run verify GREEN — 순차 전체 1424 통과 · coverage 93.24 / 86.34 / 92.95 / 94.82 (floor 상회). (병렬 실행 시 Windows 프로세스-트리-킬/npm-spawn 테스트가 부하로 간헐 flake — B2 무관·기존 환경성, 격리·순차 green 확인.)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD

Summary by CodeRabbit

  • New Features
    • WebSocket 기반 브리지 연결이 추가되어 더 다양한 환경에서 연동이 확장됩니다.
    • 애플리케이션 정보에 실행 환경(electron/web) 식별값이 포함됩니다.
  • Bug Fixes
    • 브리지 채널/전송 규약의 일치 검증이 강화되어 연결 오류 가능성이 줄었습니다.
    • 요청 타임아웃, 재접속, 구독 해제 및 에러 처리 안정성이 개선되었습니다.
    • 연결 상태 전환과 이벤트 커서 흐름이 더 정확해졌습니다.

pdw96 and others added 2 commits July 3, 2026 23:39
Part of #197 (Phase B). Electron IPC 4대 시맨틱을 WebSocket 프레임으로 재현하는
전송층 — 코어/renderer/승인 게이트 재사용, 전송층만 교체(문 ② 브라우저 오케스트레이션 UI).

- src/shared/transport/protocol.ts: req/res/push/hello 프레임 + makeOk/Err(void=value 생략)
  + decodeFrame(와이어 안전 파싱) + hasEventGap(rotation 폐기 gap 판정, B1 커서 소비)
- src/shared/transport/channels.ts: 전 44채널 매니페스트(kind invoke|push · scope both|desktop)
  + 파생 타입(BothInvokeChannel — B3 핸들러 satisfies 강제용)
- src/shared/transport/fixtures.ts: both invoke 33채널 직렬화 계약 fixture(satisfies 완전성 강제)
- src/renderer/bridge/ws-bridge.ts: FleetBridge WS 구현(WebSocket 팩토리 주입식·미배선)
  correlation(pending Map)·close 전원 reject·per-request timeout(기본 무제한=IPC 동형)
  ·리스너 채널별 Set 멱등·재접속 지수 백오프·후행 undefined 트림·desktop(update) no-op 스텁
- AppInfo.runtime 'electron'|'web' 선행 반영(desktop app:info 가 'electron' 스탬프)

계약 테스트: bridge-parity(매니페스트↔preload 전체·ws-bridge↔매니페스트 both) ·
serialization(JSON 왕복·void 정책) · protocol · channels · ws-bridge 동작(24). preload/main
리터럴 유지(ipc-parity 전제 보존·데스크톱 무회귀). 서버 핸들러↔매니페스트 대조는 B3.

체크포인트 2·2-R Codex 승인 반영판. verify GREEN(coverage 93.2/86.3/93.0/94.8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD
체크포인트 후 6렌즈 적대 자가리뷰(find→독립 refute) 확정 7건 중 실결함 반영:

- P2 decodeFrame 신뢰경계 완성: t 판별자만 검사하던 것을 프레임별 필드 불변식까지
  검증(res: id number·ok boolean·ok=false면 error.message string / push: ch string /
  hello: seq 정수). 불량 프레임은 null 로 폐기 → handleMessage 의 무검증 error.message
  역참조 TypeError + pending 영구 hang(타임아웃 백스톱 무력) 제거. hello 비수치 seq 가
  missed-gap 오판(B1 방어 재개방)하던 경로도 차단.
- P3 terminal closed hang: invoke 가드를 disposed → disposed||state==='closed' 로 확장
  (autoReconnect=false close 후 큐에 갇혀 영구 hang 하던 요청 즉시 reject).
- P3 sendQueue 고아: 큐를 {id,data} 태그로 바꿔 flush 시 pending 인 요청만 전송
  (타임아웃/취소된 프레임이 재접속 후 죽은 요청으로 전송되던 것 차단).
- P3 리스너 예외 격리: push 콜백 dispatch 를 try/catch 로 감싸 한 리스너 throw 가
  나머지·소켓 루프를 깨지 않게.
- P3 메서드↔채널 바인딩 가드(ws-bridge-binding.test.ts): bridge-parity 의 채널 '집합'
  검사가 놓치는 동일-시그니처 채널 스왑·인자 순서 drift 를 테이블 구동으로 잡음
  (getWorkspace↔selectWorkspace 스왑 주입 시 RED 실측).
- defense-in-depth: openCliDocs 가 http(s) 스킴만 window.open(javascript:/data: 차단).

refute 11건(중간 undefined 트림·fixtures result:[]·openCliDocs allowlist=서버 신뢰모델·
재접속 double-onclose 등)은 반영 안 함. verify GREEN(순차 1424 통과·coverage 93.2/86.3/93.0/94.8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@pdw96, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 499eabae-a102-45be-ad4a-3b93a0f08da2

📥 Commits

Reviewing files that changed from the base of the PR and between fdf9230 and 84a085a.

📒 Files selected for processing (7)
  • brain.md
  • src/renderer/bridge/ws-bridge-binding.test.ts
  • src/renderer/bridge/ws-bridge.test.ts
  • src/renderer/bridge/ws-bridge.ts
  • src/shared/transport/channels.test.ts
  • src/shared/transport/channels.ts
  • src/shared/transport/fixtures.ts
📝 Walkthrough

Walkthrough

공유 전송 채널 매니페스트와 WS 프레임 프로토콜이 추가되고, 이를 사용하는 WebSocket 기반 FleetBridge가 구현되었다. 채널/프로토콜/직렬화 검증 테스트가 함께 추가됐으며, AppInfo runtime 필드와 main 응답, brain.md 구조 지도도 갱신되었다.

Changes

WS 전송 계약 및 브리지 구현

Layer / File(s) Summary
채널 매니페스트 및 파생 타입
src/shared/transport/channels.ts, src/shared/transport/channels.test.ts
CHANNELS 매니페스트와 kind/scope 기반 파생 타입이 추가되고, invoke/push 분류와 정렬, 전체 집합 불변식이 테스트된다.
프레임 프로토콜 정의 및 검증
src/shared/transport/protocol.ts, src/shared/transport/protocol.test.ts
ReqFrame/ResFrame/PushFrame/HelloFrame 타입과 makeOkFrame/makeErrFrame/decodeFrame/hasEventGap이 추가되고, 생성·파싱·필드 검증 테스트가 추가된다.
채널 fixture 및 직렬화 검증
src/shared/transport/fixtures.ts, src/shared/transport/serialization.test.ts
BothInvokeChannel 전체에 대한 ChannelFixture 데이터와 JSON 왕복, void 응답 value 생략 규칙을 검증하는 테스트가 추가된다.
WsBridge 핵심 구현
src/renderer/bridge/ws-bridge.ts
ConnectionState, WsLike, WsBridgeOptions, WsBridge 타입과 pending 처리, 큐잉, 재접속, push/hello 라우팅, fleet 매핑, dispose가 구현된다.
WsBridge 동작 테스트
src/renderer/bridge/ws-bridge.test.ts
연결 상태 전이, 요청/응답 상관관계, 큐 flush, 타임아웃, 구독, 재접속, dispose 등 WS 브리지 동작이 FakeWs로 검증된다.
바인딩 테이블 및 채널 파리티 검증
src/renderer/bridge/ws-bridge-binding.test.ts, src/main/bridge-parity.test.ts
BINDINGS 기반 메서드-채널 매핑과 preload/ws-bridge/main 소스의 채널 리터럴 및 runtime 문자열이 매니페스트와 일치하는지 검증한다.
AppInfo runtime 필드 및 구조 지도 갱신
src/shared/types.ts, src/main/index.ts, brain.md
AppInfo runtime 필드와 main 응답이 갱신되고, brain.md의 메트릭과 모듈 연결 목록이 재작성된다.

Estimated code review effort: 4 (Complex) | ~60 minutes


Note

🎁 Summarized by CodeRabbit Free

The PR author is not assigned a seat. To perform a comprehensive line-by-line review, please assign a seat to the pull request author through the subscription management page by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b594c39f31

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/renderer/bridge/ws-bridge.ts Outdated
Comment thread src/renderer/bridge/ws-bridge.ts Outdated
PR#199 Codex 자동리뷰 P2 반영(둘 다 B4 배선 enabler):

- P2 접속 통지 순서(ws-bridge.ts): onopen 이 setState('connected') 를 flushQueue 보다
  먼저 호출해, 'connected' 리스너의 read 가 offline 큐잉된 write 를 앞지를 수 있었다.
  → flush 를 통지 앞으로. 또 재접속 시 이전 연결의 stale 커서를 노출하던 것을 handleClose
  에서 hello=null 로 클리어(gap 오판 방지). onConnectionState/getEventCursor 계약 문서화.
- P2 장시간 invoke 재접속(ws-bridge.ts): 소켓 드롭 시 runProject 등이 reject 되면 B4 가
  연산 실패로 오인할 수 있다(correlation 은 소켓별이라 pending 보존은 불가). → TransportError
  {reason:'disconnected'|'closed'|'timeout'} 타입을 도입해 전송 문제를 서버 연산 실패(plain
  Error)와 구분 — B4 는 이를 완료가 아닌 재접속→RunActivity 재하이드레이션으로 복구.

테스트 3종 추가(flush 선행·stale 커서 클리어·TransportError reason). verify GREEN
(B2 95통과·typecheck·lint·format·brain·build).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD
@pdw96

pdw96 commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

P2 2건 반영 완료(b0aabf0) — 접속 통지 순서(flush 선행 + 재접속 stale 커서 클리어) · 장시간 invoke 재접속(TransportError{reason} 도입으로 전송 문제↔연산 실패 구분, B4 는 재접속→RunActivity 재하이드레이션으로 복구). 앞선 자가 적대리뷰 확정 7건도 이미 반영됨. 수정분 재검증 부탁합니다.

@pdw96

pdw96 commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b0aabf040c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/renderer/bridge/ws-bridge.ts
PR#199 Codex 재리뷰(b0aabf0) P2 반영: 이전 수정으로 getEventCursor()가 hello 전까지
null 인 건 맞으나, 커서가 준비됐다는 신호가 없어 B4 가 폴링해야 했다('connected'는 open 시
발화·커서는 그 후 비동기 도착). onEventCursor(cb) 통지 콜백을 추가 — hello 수신 시 커서와
함께 발화(이 시점 getEventCursor()도 갱신). 재접속마다 새 hello 로 재발화해 B4 재하이드레이션의
실제 트리거가 된다(onConnectionState 는 전송 상태 표시용으로 역할 분리). 콜백 예외는 격리.

테스트 2종 추가(hello→onEventCursor 통지·해제·콜백 예외 격리). verify GREEN(B2 97통과).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD
@pdw96

pdw96 commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 59a8a9cce3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/renderer/bridge/ws-bridge.ts Outdated
Comment thread src/renderer/bridge/ws-bridge.ts Outdated
PR#199 Codex 재리뷰(59a8a9c) P2 2건 반영:

- 상태 리스너 예외 격리(setState): onConnectionState 콜백을 try/catch 로 감쌌다.
  scheduleReconnect 이 setState('reconnecting') 를 setTimeout(openSocket) 앞에서 부르므로,
  리스너 throw 시 재접속 타이머가 안 걸려 브리지가 멈추던 결함(push/cursor 는 이미 격리·state 만 누락).
- 미전송 큐 재접속 보존(handleClose): 소켓이 open 전에 close 되면 connecting/reconnecting 중
  큐잉된 미전송 요청까지 reject·폐기되던 것을, transient close 는 rejectSentPending 으로 **전송된
  요청만** reject 하고 미전송 큐는 다음 open flush 까지 보존하도록 분리(terminal/dispose 는 종전대로
  전원 reject). 서버 기동/재시작 시 초기 getAppInfo·listSessions 가 첫 실패에 죽지 않고 재접속에 태워진다.

테스트 2종 추가(상태 리스너 예외 격리·미전송 큐 보존→flush resolve). verify GREEN(B2 99통과).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD
@pdw96

pdw96 commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fdf9230515

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/renderer/bridge/ws-bridge.ts Outdated
Comment thread src/renderer/bridge/ws-bridge.ts Outdated
PR#199 Codex 재리뷰(fdf9230) 반영:

- P2 stale 소켓 프레임 무시(openSocket): 소켓 인스턴스를 캡처해 onopen/onmessage/onclose 가
  현재 소켓이 아니거나 disposed 면 무시. 재접속·종료로 소켓이 교체된 뒤 옛 연결의 늦은 push/hello
  가 새 커서를 옛 값으로 덮거나 중복 UI 이벤트를 내던 race 차단.
- P3 openCliDocs 클라 측 URL 도출(팝업 차단·서버 URL 신뢰 회피): 웹은 서버 왕복(await) 후
  window.open 하던 것을 shared 정적 CLI_AUTH_INSTALL_META.docsUrl 로 **동기 도출→즉시 open** 으로
  바꿔, (1) await 로 클릭 user-activation 을 잃어 팝업 차단되는 문제와 (2) 서버 반환 URL 무검증
  신뢰(앞선 자가리뷰 refuted-but-real)를 동시 제거. fleet:external:openDocs 를 desktop 전용으로
  (데스크톱은 종전 shell.openExternal). Promise<void>·데스크톱 무회귀 유지(체크포인트 §6 목표 보존).
  매니페스트/fixtures/binding/parity 일관 갱신.

테스트: stale 소켓 프레임 무시·openCliDocs 무-wire 도출. verify GREEN(B2 106통과).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kodzh3irgT2r4cE1aGhWbD
@pdw96

pdw96 commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 84a085a6b5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant