ticket: refine websocket proxy planning
This commit is contained in:
parent
15abcf6782
commit
471dc5bc52
|
|
@ -1,91 +1,127 @@
|
||||||
---
|
---
|
||||||
title: 'worker-runtimeにWebSocket event stream serverを追加する'
|
title: 'Runtime/Backend WebSocket observation proxyを実装する'
|
||||||
state: 'ready'
|
state: 'planning'
|
||||||
created_at: '2026-06-25T14:44:02Z'
|
created_at: '2026-06-25T14:44:02Z'
|
||||||
updated_at: '2026-06-25T20:10:54Z'
|
updated_at: '2026-06-25T20:25:52Z'
|
||||||
assignee: null
|
assignee: null
|
||||||
---
|
---
|
||||||
|
|
||||||
## 背景
|
## 背景
|
||||||
|
|
||||||
Runtime command は REST/HTTP でよいが、Worker output / status / transcript update を Backend が追うには observation transport が必要になる。Runtime から Backend へ能動接続する相互型は v0 では採用せず、Backend が Runtime の event stream に接続する形にする。Browser は Runtime event stream に直接接続せず、Backend が proxy / projection する。
|
Runtime command は REST/HTTP でよいが、Worker output / status / transcript update を Backend / Web / future TUI が追うには observation transport が必要になる。Runtime から Backend へ能動接続する相互型は v0 では採用せず、Backend が Runtime の event stream に接続し、Client は Backend に接続する形にする。
|
||||||
|
|
||||||
この Ticket では `worker-runtime` process に WebSocket based observation server を追加する。SSE は将来追加してよいが、v0 の実装対象は Backend-owned WebSocket client が接続する Runtime event stream とする。command API とは分離する。
|
この Ticket では `Runtime -> Backend -> Client` の WebSocket observation proxy を実装する。`worker-runtime` process は Worker event stream を WebSocket で公開し、Backend は登録済み Runtime handle に対する WS client として購読し、Browser / future TUI は Backend-owned client-facing WS に接続する。Backend は Runtime endpoint / token / socket path / session path を Client に渡さない。
|
||||||
|
|
||||||
## 目的
|
## 目的
|
||||||
|
|
||||||
- Backend が Runtime 内 Worker の output / status / transcript update を購読できる。
|
- Backend が Runtime 内 Worker の output / status / transcript update を購読できる。
|
||||||
|
- Backend が購読した Runtime event を Client-facing WS として proxy できる。
|
||||||
- Runtime WS は新しい Worker output model を作らず、既存 `crates/protocol` の `protocol::Event` を observation payload として流す。
|
- Runtime WS は新しい Worker output model を作らず、既存 `crates/protocol` の `protocol::Event` を observation payload として流す。
|
||||||
- Runtime WS は command channel ではなく、Backend-facing observation channel とする。
|
- Client は `runtime_id + worker_id` を authority として Backend WS に接続し、Runtime endpoint / credential / raw socket path を扱わない。
|
||||||
- Browser / Web UI へは Backend が proxy / projection し、Runtime endpoint / token / socket path / session path を直接渡さない。
|
- Runtime WS / Backend WS は command channel ではなく observation channel とする。
|
||||||
- 後続の Web 権限制御で、Web origin からの操作や観測を Backend 側で block / redact / project できる境界を明示する。
|
- 後続の Web 権限制御は、Backend proxy/projection layer に observe/filter/redact/command-forward policy を差し込める seam を作るに留める。
|
||||||
|
|
||||||
## 要件
|
## 要件
|
||||||
|
|
||||||
### Feature / server boundary
|
### Overall proxy model
|
||||||
|
|
||||||
|
- v0 の主対象は WebSocket proxy path とする。
|
||||||
|
- `Runtime -> Backend`: Runtime-owned Worker event stream。
|
||||||
|
- `Backend -> Client`: Backend-owned Worker observation stream。
|
||||||
|
- Backend は登録済み Runtime handle / endpoint capability から Runtime WS に接続する。
|
||||||
|
- Remote Runtime から event を受け取り Client-facing WS に流す経路までをこの Ticket の実装対象に含める。
|
||||||
|
- Embedded Runtime の登録・接続実装そのものはこの Ticket の主対象にしない。ただし Backend proxy 型は embedded / remote のどちらの Runtime handle にも後続で接続できる形にする。
|
||||||
|
- Runtime process discovery / remote process lifecycle / dynamic registration はこの Ticket の scope 外とし、既に Registry から接続可能な Runtime handle が得られる前提でよい。
|
||||||
|
|
||||||
|
### Runtime WS server
|
||||||
|
|
||||||
- `worker-runtime` に `ws-server` feature を追加する。
|
- `worker-runtime` に `ws-server` feature を追加する。
|
||||||
- Feature disabled 時、core library は stream server dependency を強制しない。
|
- Feature disabled 時、core library は stream server dependency を強制しない。
|
||||||
- Runtime process が Worker observation event を WebSocket endpoint で公開できる。
|
- Runtime process が Worker observation event を WebSocket endpoint で公開できる。
|
||||||
- Runtime WS endpoint は Backend-internal API として扱い、Browser-facing protocol ではない。
|
|
||||||
- Runtime WS は user input / command / mutation を受け付けない。
|
|
||||||
- Runtime WS 上に `protocol::Method` tunnel や arbitrary operation frame を作らない。
|
|
||||||
|
|
||||||
### Endpoint shape
|
|
||||||
|
|
||||||
- v0 required endpoint は worker-scoped stream とする。
|
- v0 required endpoint は worker-scoped stream とする。
|
||||||
- `GET /v1/workers/{worker_id}/events/ws?cursor=...`
|
- `GET /v1/workers/{worker_id}/events/ws?cursor=...`
|
||||||
- Runtime-wide stream は v0 non-goal とする。ただし型や event id 設計は将来の runtime-wide stream を妨げない。
|
- Runtime-wide stream は v0 non-goal とする。ただし型や event id 設計は将来の runtime-wide stream を妨げない。
|
||||||
|
- Runtime WS endpoint は Backend-facing internal API として扱い、Browser-facing protocol ではない。
|
||||||
|
- Runtime WS は user input / command / mutation を受け付けない。
|
||||||
|
- Runtime WS 上に `protocol::Method` tunnel や arbitrary operation frame を作らない。
|
||||||
- Connect 時に対象 Worker の initial projection として `protocol::Event::Snapshot` 相当を最初に送る。
|
- Connect 時に対象 Worker の initial projection として `protocol::Event::Snapshot` 相当を最初に送る。
|
||||||
- Snapshot 後の live update は Runtime / Worker の broadcast event から生成される `protocol::Event` payload を送る。
|
- Snapshot 後の live update は Worker event bus が publish する `protocol::Event` payload を forward する。
|
||||||
|
|
||||||
### Wire envelope / protocol payload
|
### Runtime WS envelope / payload
|
||||||
|
|
||||||
- WebSocket frame は Runtime-local envelope を持ち、payload として `protocol::Event` を含める。
|
- Runtime WS frame は Runtime-local envelope を持ち、payload として `protocol::Event` を含める。
|
||||||
- Envelope は少なくとも以下を持つ。
|
- Envelope は少なくとも以下を持つ。
|
||||||
- opaque event id / cursor。
|
- Runtime-local opaque event id / cursor。
|
||||||
- worker id。
|
- worker id。
|
||||||
- `protocol::Event` payload。
|
- `protocol::Event` payload。
|
||||||
- optional diagnostic / stream control kind。
|
- optional diagnostic / stream control kind。
|
||||||
- `protocol::Event` は `crates/protocol` を authority とし、Runtime WS 専用の並行 event model を作らない。
|
- `protocol::Event` は `crates/protocol` を authority とし、Runtime WS 専用の並行 event model を作らない。
|
||||||
- Runtime WS は `protocol::Event` の variant allowlist / subset を定義しない。Worker event bus が publish する `protocol::Event` payload を Runtime observation stream として forward する。
|
- Runtime WS は `protocol::Event` の variant allowlist / subset を定義しない。
|
||||||
- Runtime WS が Web 表示可否を判断しない。Browser / Web UI 向けの filter / redact / projection は Backend projection layer の責務とする。
|
- Runtime WS が Web 表示可否を判断しない。Browser / Web UI 向けの filter / redact / projection は Backend proxy/projection layer の責務とする。
|
||||||
- Runtime WS の除外境界は variant subset ではなく channel / authority 境界とする。
|
- Runtime WS の除外境界は variant subset ではなく channel / authority 境界とする。
|
||||||
- `protocol::Method` tunnel を作らない。
|
- `protocol::Method` tunnel を作らない。
|
||||||
- user input / command / mutation frame を受け付けない。
|
- user input / command / mutation frame を受け付けない。
|
||||||
- raw provider trace / raw full session log / local filesystem paths / runtime credentials を authority payload として送らない。
|
- raw provider trace / raw full session log / local filesystem paths / runtime credentials を authority payload として送らない。
|
||||||
- Method-specific reply を Runtime WS が passive event として合成しない。Worker event bus に publish された `protocol::Event` を forward する。
|
- Method-specific reply を Runtime WS が passive event として合成しない。Worker event bus に publish された `protocol::Event` を forward する。
|
||||||
|
|
||||||
|
### Backend Runtime WS client
|
||||||
|
|
||||||
|
- Backend に Runtime WS client を実装する。
|
||||||
|
- Backend Runtime WS client は RuntimeRegistry から得た Runtime handle / connection capability を使い、Client から Runtime endpoint / credential を受け取らない。
|
||||||
|
- Backend Runtime WS client は Runtime-local envelope を読み、`runtime_id + worker_id + runtime_cursor + protocol::Event` として Backend 内部に渡す。
|
||||||
|
- Runtime unavailable、worker not found、unknown cursor、expired cursor、upstream disconnect、malformed frame を typed diagnostic として扱う。
|
||||||
|
- Backend client は upstream cursor を使って reconnect / resume できる。
|
||||||
|
- Upstream reconnect 時に exactly-once delivery は要求しない。Backend は event id / cursor で duplicate を扱えるようにする。
|
||||||
|
|
||||||
|
### Backend Client-facing WS proxy
|
||||||
|
|
||||||
|
- Backend は Client-facing Worker observation WS endpoint を公開する。
|
||||||
|
- v0 endpoint shape は実装時に既存 workspace-server routing と合わせて決めてよいが、Client-facing authority は `runtime_id + worker_id` とする。
|
||||||
|
- 例: `GET /api/runtimes/{runtime_id}/workers/{worker_id}/events/ws?cursor=...`
|
||||||
|
- Browser / future TUI は Runtime WS に直接接続せず、Backend WS に接続する。
|
||||||
|
- Backend WS frame は Backend-owned envelope を持ち、payload として `protocol::Event` を含める。
|
||||||
|
- Backend-owned envelope は少なくとも以下を持つ。
|
||||||
|
- Backend-local opaque cursor。
|
||||||
|
- runtime id。
|
||||||
|
- worker id。
|
||||||
|
- `protocol::Event` payload。
|
||||||
|
- optional diagnostic / stream control kind。
|
||||||
|
- Backend cursor は Client にとって opaque とする。実装は Runtime cursor を wrap / map してよいが、Client が Runtime-local cursor semantics に依存しないようにする。
|
||||||
|
- Backend proxy は v0 では原則 pass-through projection とし、`protocol::Event` を別 model に変換しない。
|
||||||
|
- Backend は Runtime WS event を raw tunnel せず、Backend-owned envelope / cursor / diagnostics を付与した proxy stream として出す。
|
||||||
|
|
||||||
### Cursor / backlog / ordering
|
### Cursor / backlog / ordering
|
||||||
|
|
||||||
- Event id / cursor は Runtime local opaque id とする。
|
- Runtime event id / cursor は Runtime local opaque id とする。
|
||||||
|
- Backend client-facing cursor は Backend local opaque id とする。
|
||||||
- Cursor は「最後に受け取った event id」を表し、resume 時はそれより後の event を送る。
|
- Cursor は「最後に受け取った event id」を表し、resume 時はそれより後の event を送る。
|
||||||
- Delivery semantics は at-least-once とし、duplicate はあり得る。Backend client は id で de-dup できる。
|
- Delivery semantics は at-least-once とし、duplicate はあり得る。Backend / Client は id で de-dup できる。
|
||||||
- Ordering は worker-scoped stream 内で保持する。
|
- Ordering は worker-scoped stream 内で保持する。
|
||||||
- Bounded per-worker backlog を持ち、unknown cursor / expired cursor / worker not found / worker unavailable を typed close reason または stream diagnostic として返す。
|
- Bounded per-worker backlog を持ち、unknown cursor / expired cursor / worker not found / worker unavailable を typed close reason または stream diagnostic として返す。
|
||||||
- Unknown / expired cursor 時に raw session log 全体を暗黙送信して復旧しない。Backend は fresh Snapshot から再同期する。
|
- Unknown / expired cursor 時に raw session log 全体を暗黙送信して復旧しない。Backend / Client は fresh Snapshot から再同期する。
|
||||||
- Transcript projection polling endpoint と event stream の責務を分ける。
|
- Transcript projection polling endpoint と event stream の責務を分ける。
|
||||||
|
|
||||||
### Backend proxy / permission boundary
|
### Permission seam / future policy boundary
|
||||||
|
|
||||||
- Browser direct Runtime access は想定せず、Backend client が Runtime WS を購読する。
|
- この Ticket の主目的は proxy の実装であり、full auth / permission model は実装しない。
|
||||||
- Backend は Runtime WS event を Browser / Web UI にそのまま tunnel しない。Backend-owned projection layer を通す。
|
- Backend proxy/projection layer に後続で policy を差し込める seam を作る。
|
||||||
- Backend projection layer は後続の権限制御を差し込める境界として設計する。
|
- Worker observation を許可 / 拒否する。
|
||||||
- Worker observation を許可するか。
|
- thinking / tool output / diagnostics などを表示 / redact する。
|
||||||
- thinking / tool output / diagnostics などを表示・redact するか。
|
- Web origin から利用可能な action affordance を出す / 隠す。
|
||||||
- Web origin から利用可能な action affordance を出すか。
|
- operation-capable command API への forward を許可 / 拒否する。
|
||||||
- operation-capable command API への forward を許可するか。
|
- v0 の seam は pass-through default でよい。具体的な user/role permission、multi-user auth、redaction rule set は後続 Ticket に残す。
|
||||||
- この Ticket では full auth / permission model は実装しないが、Runtime WS client / Backend proxy 型に policy hook を差し込める seam を作る。
|
- Web からの操作 block は Runtime WS ではなく Backend command API / Backend Web-facing proxy の責務とする。
|
||||||
- Web からの操作 block は Runtime WS ではなく Backend command API / Backend Web-facing proxy の責務とする。Runtime WS はそのための観測入力と projection boundary を提供する。
|
|
||||||
|
|
||||||
## Non-goals
|
## Non-goals
|
||||||
|
|
||||||
- REST command server implementation。
|
- REST command server implementation。
|
||||||
- Browser-facing WebSocket protocol の完成。
|
- Embedded Runtime registration / direct-call implementation。
|
||||||
- Backend Web UI implementation。
|
- Remote Runtime process lifecycle / discovery / dynamic registration。
|
||||||
|
- Browser-facing Web Console UI implementation。
|
||||||
|
- Full auth / permission model。
|
||||||
|
- Concrete redaction policy implementation。
|
||||||
- Runtime-initiated Backend push connection。
|
- Runtime-initiated Backend push connection。
|
||||||
- Full exactly-once delivery。
|
- Full exactly-once delivery。
|
||||||
- Full auth / permission model。
|
|
||||||
- Runtime-wide multi-worker stream implementation。
|
- Runtime-wide multi-worker stream implementation。
|
||||||
- Raw provider trace streaming。
|
- Raw provider trace streaming。
|
||||||
- Raw session storage migration。
|
- Raw session storage migration。
|
||||||
|
|
@ -95,16 +131,21 @@ Runtime command は REST/HTTP でよいが、Worker output / status / transcript
|
||||||
- `worker-runtime` に optional `ws-server` feature がある。
|
- `worker-runtime` に optional `ws-server` feature がある。
|
||||||
- Feature disabled でも `worker-runtime` core が compile できる。
|
- Feature disabled でも `worker-runtime` core が compile できる。
|
||||||
- Runtime process exposes worker-scoped WebSocket observation endpoint。
|
- Runtime process exposes worker-scoped WebSocket observation endpoint。
|
||||||
- WebSocket frame envelope includes opaque event id / cursor, worker id, and `protocol::Event` payload。
|
- Runtime WS frame envelope includes Runtime-local opaque event id / cursor, worker id, and `protocol::Event` payload。
|
||||||
- Connect sends initial `protocol::Event::Snapshot` projection for the target Worker。
|
- Runtime WS connect sends initial `protocol::Event::Snapshot` projection for the target Worker。
|
||||||
- Live stream forwards Worker event bus `protocol::Event` payloads rather than a parallel Worker output model or Runtime-side event subset。
|
- Runtime WS live stream forwards Worker event bus `protocol::Event` payloads rather than a parallel Worker output model or Runtime-side event subset。
|
||||||
- Runtime WS does not create `protocol::Method` tunnel / command / mutation channels or synthesize request/reply events。
|
- Runtime WS does not create `protocol::Method` tunnel / command / mutation channels or synthesize request/reply events。
|
||||||
- Backend client can reconnect with cursor / last event id semantics at the protocol level。
|
- Backend Runtime WS client can connect to a registered remote Runtime handle and receive Worker events。
|
||||||
- Unknown cursor / expired cursor / worker not found are typed errors or stream diagnostics。
|
- Backend Runtime WS client can reconnect with Runtime cursor / last event id semantics at the protocol level。
|
||||||
- Backend-facing Runtime WS is not Browser-facing authority and does not expose Runtime endpoint / credential / raw socket / session path to Browser。
|
- Backend exposes Client-facing worker observation WS keyed by `runtime_id + worker_id`。
|
||||||
- Backend proxy / projection boundary has an explicit seam for later observe/command permission checks and redaction policy。
|
- Client-facing WS frame envelope includes Backend-local opaque cursor, runtime id, worker id, and `protocol::Event` payload。
|
||||||
- WebSocket event stream tests cover connect, initial Snapshot, live event delivery, cursor resume, duplicate-safe ids, expired/unknown cursor diagnostics, and worker-scoped filtering。
|
- Client-facing WS can proxy initial Snapshot and live Worker events received from upstream Runtime WS。
|
||||||
|
- Backend cursor is opaque to Client and does not expose Runtime endpoint / credential / raw socket / session path。
|
||||||
|
- Unknown cursor / expired cursor / worker not found / upstream runtime unavailable are typed errors or stream diagnostics。
|
||||||
|
- Backend proxy/projection layer has an explicit seam for later observe/command permission checks and redaction policy, with pass-through default in this Ticket。
|
||||||
|
- WebSocket proxy tests cover Runtime WS connect, initial Snapshot, live event delivery, Backend upstream consumption, Client-facing proxy delivery, cursor resume, duplicate-safe ids, expired/unknown cursor diagnostics, upstream disconnect diagnostics, and worker-scoped filtering。
|
||||||
- `cargo test -p worker-runtime --features ws-server` が通る。
|
- `cargo test -p worker-runtime --features ws-server` が通る。
|
||||||
|
- `cargo test -p yoi-workspace-server` が通る。
|
||||||
- `cargo check -p yoi` が通る。
|
- `cargo check -p yoi` が通る。
|
||||||
- `git diff --check` が通る。
|
- `git diff --check` が通る。
|
||||||
- `nix build .#yoi --no-link` が通る。
|
- `nix build .#yoi --no-link` が通る。
|
||||||
|
|
|
||||||
|
|
@ -77,4 +77,26 @@ Marked ready by `yoi ticket state`.
|
||||||
Marked ready by `yoi ticket state`.
|
Marked ready by `yoi ticket state`.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: state_changed author: "yoi ticket" at: 2026-06-25T20:24:40Z from: ready to: planning reason: cli_state field: state -->
|
||||||
|
|
||||||
|
## State changed
|
||||||
|
|
||||||
|
State changed to `planning`.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: decision author: hare at: 2026-06-25T20:25:52Z -->
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
STJT の主目的を Runtime WS server 単体から `Runtime -> Backend -> Client` の WebSocket observation proxy に広げる。Remote Runtime から Backend Runtime WS client が `protocol::Event` を受け取り、Backend-owned client-facing WS で `runtime_id + worker_id` keyed stream として流すところまでをこの Ticket の実装対象に含める。
|
||||||
|
|
||||||
|
Backend proxy は v0 では pass-through projection を基本にし、`protocol::Event` を別 output model へ変換しない。一方で Browser / future TUI は Runtime WS に直接接続せず、Backend-owned cursor/envelope/diagnostic を持つ stream だけを見る。Runtime endpoint / credential / socket path / session path は Client-facing authority に出さない。
|
||||||
|
|
||||||
|
権限系はこの Ticket で full auth / permission / redaction rule を実装しない。Backend proxy/projection layer に、後続で observe allow/deny、thinking/tool output/diagnostic redaction、action affordance、command API forwarding allow/deny を差し込める seam を作るに留める。
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user