diff options
| author | Adam Malczewski <[email protected]> | 2026-06-12 02:25:57 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-12 02:25:57 +0900 |
| commit | 86b5137c4f7f2bcc08f0580f1edaa05d14015e63 (patch) | |
| tree | 20215a5dccf1b76cf9cf95fceec1eca450aa8559 /tasks.md | |
| parent | 839f5c02676a0b7def27ace7125fbec3aa08bda5 (diff) | |
| download | dispatch-86b5137c4f7f2bcc08f0580f1edaa05d14015e63.tar.gz dispatch-86b5137c4f7f2bcc08f0580f1edaa05d14015e63.zip | |
feat(turns): detached turns + multi-client live view
A turn no longer dies when its WebSocket connection closes. The turn-broadcast
hub moves into the core (session-orchestrator): turns run detached, persist at
seal regardless of clients, and fan out AgentEvents to N subscribers per
conversation with in-flight buffer replay for late-joiners. transport-ws stops
aborting turns on socket close and gains chat.subscribe/chat.unsubscribe so a
second device (or a reloaded browser) can watch a running turn.
- @dispatch/transport-contract 0.6.0->0.7.0: chat.subscribe/chat.unsubscribe WS ops
- session-orchestrator: startTurn/subscribe/isActive; persistent subscribers +
per-turn buffer (two-map model); handleMessage = convenience wrapper (no signal)
- transport-ws: per-connection chat-subscription fan-out; no turn-abort-on-close
- transport-http: test fakes updated for the widened interface (runtime unchanged)
- design notes/turn-continuity-design.md; FE courier frontend-turn-continuity-handoff.md
Live-verified vs flash (2-client WS): sender disconnect mid-turn -> other client
streams to done + turn persists; late-join replays turn from turn-start. 891 vitest
+ transport bun green; tsc -b EXIT 0; biome clean.
Diffstat (limited to 'tasks.md')
| -rw-r--r-- | tasks.md | 31 |
1 files changed, 30 insertions, 1 deletions
@@ -5,7 +5,7 @@ > Keep this lean and current; do not let it re-accrete a step-by-step changelog. ## Status (current) -`tsc -b` EXIT 0 · biome clean · **881 vitest + 135 bun = 1016 tests**. +`tsc -b` EXIT 0 · biome clean · **891 vitest + transport bun green**. Built and verified live (full-fidelity: every feature is a manifest-loaded extension through the host): @@ -254,6 +254,35 @@ persisted `TurnMetrics`. - [x] **FE courier handoff:** `frontend-context-size-handoff.md` (user couriers to `../dispatch-web`). +## Turn continuity — detached turns + multi-client live view (DONE) +Design: `notes/turn-continuity-design.md`. FE courier: `frontend-turn-continuity-handoff.md`. +Problem (code-traced): a turn's lifetime was bound to the WS connection — `transport-ws` aborted +the in-flight turn on socket close, so a backgrounded/reloaded mobile browser killed generation. +Principle enforced: **the FE is only a control interface; the AI runs independent of it**, and +**multiple clients may watch the same conversation** (multi-device handoff). +- **Decisions (locked):** broadcast hub lives in the CORE (`session-orchestrator`), not a + transport; additive `SessionOrchestrator` handle (keep `handleMessage`); persist-at-seal kept, + per-step R1 deferred; late-join served by an in-memory in-flight buffer; subscribers persist + per-conversation independent of turns; no concurrent-send arbitration; no explicit stop op. +- **Contract (orchestrator):** `@dispatch/transport-contract` `0.6.0→0.7.0` — additive WS ops + `chat.subscribe`/`chat.unsubscribe` on `WsClientMessage` (events still arrive as `chat.delta`). +- **Wave 1 — `session-orchestrator`:** detached per-conversation turn ownership + broadcast; + `startTurn`/`subscribe`/`isActive` added to the handle; `handleMessage` → convenience wrapper + (dropped `signal`). **Two-map model** (`subscribers` persistent + `activeTurns` buffer) — the + fix for the live-found bug where pre-turn subscribers were dropped. 63 tests. +- **Wave 2 (parallel) — `transport-ws`** (fan-out: per-connection chat-subscription map; + `chat.send` auto-subscribes sender + `startTurn`; new ops in pure `router.ts`; `close` drops + subs but NEVER aborts a turn; removed the turn `AbortController`) + **`transport-http`** (only + test fakes updated for the 3 new methods; runtime unchanged). host-bin untouched. +- **LIVE-VERIFIED against flash** (2-client WS test, `/tmp/ws_multi.ts`): (S1) two clients both + stream a turn; closing the SENDER mid-turn → the other keeps receiving through `done` and the + turn persists (1197 chars) — AI kept going independent of the interface; (S2) a client joining + mid-turn gets `turn-start` replayed + the rest live. `RESULT OVERALL: OK`. +- **Recovery (scar tissue):** first Wave-1 impl stored listeners INSIDE the per-turn hub and + `startTurn` made a fresh empty-listener hub → every pre-turn subscriber dropped; live test got + zero deltas though the turn ran+persisted. Caught by live-verify (unit test had subscribed + AFTER start, masking it). Fixed via the persistent-subscribers / per-turn-buffer split. + ## Open items - **Context window LIMIT (next, sibling of context size):** expose the selected model's max context-window token limit so the FE can render `contextSize / limit` (e.g. `1286 / 200000`). |
