feat(#197-B2): WS 프로토콜 + 채널 매니페스트 + 클라이언트 브리지#199
Conversation
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
|
Warning Review limit reached
Next review available in: 38 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthrough공유 전송 채널 매니페스트와 WS 프레임 프로토콜이 추가되고, 이를 사용하는 WebSocket 기반 FleetBridge가 구현되었다. 채널/프로토콜/직렬화 검증 테스트가 함께 추가됐으며, AppInfo runtime 필드와 main 응답, brain.md 구조 지도도 갱신되었다. ChangesWS 전송 계약 및 브리지 구현
Estimated code review effort: 4 (Complex) | ~60 minutes Note 🎁 Summarized by CodeRabbit FreeThe 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 |
There was a problem hiding this comment.
💡 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".
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
|
@codex review |
There was a problem hiding this comment.
💡 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".
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
|
@codex review |
There was a problem hiding this comment.
💡 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".
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
|
@codex review |
There was a problem hiding this comment.
💡 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".
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
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
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.ts—req/res/push/hello프레임 타입 +makeOkFrame(void=value생략 정책)·makeErrFrame(스택 미노출)·decodeFrame(와이어 안전 파싱)·hasEventGap(rotation 폐기 gap 판정 — B1store.eventCursor소비).hello는maxEventSeq+minRetainedEventSeq.src/shared/transport/channels.ts— 전 44채널 매니페스트(kind: invoke|push·scope: both|desktop). 파생 타입BothInvokeChannel(B3 핸들러satisfies강제용)·invokeChannels/pushChannels필터.src/shared/transport/fixtures.ts—bothinvoke 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건 반영:decodeFrame신뢰경계 완성 — 판별자t만 검사하던 것을 프레임별 필드 불변식까지 검증(res: id/ok/error.message · push: ch · hello: seq 정수). 불량 프레임을null로 폐기해handleMessage의 무검증error.message역참조 TypeError + pending 영구 hang(타임아웃 백스톱 무력)을 제거. hello 비수치 seq → missed-gap 오판(B1 방어 재개방) 경로도 차단.closedhang —invoke가드를disposed || state==='closed'로 확장(재접속 없는 close 후 요청 즉시 reject).sendQueue고아 — 큐를{id,data}태그화, flush 시 pending 인 요청만 전송(타임아웃/취소된 죽은 프레임 미전송).try/catch(한 리스너 throw 가 소켓 루프·타 리스너 무영향).bridge-parity의 채널 '집합' 검사가 놓치는 동일-시그니처 채널 스왑·인자 순서 drift 를 테이블 구동 테스트로 차단(스왑 주입 시 RED 실측).openCliDocs가http(s)스킴만window.open(javascript:/data:차단).refute 11건(중간 undefined 트림·fixtures
result:[]·openCliDocs allowlist=서버 신뢰모델·재접속 double-onclose 등)은 근거와 함께 기각.게이트
npm run verifyGREEN — 순차 전체 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