summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-27 18:43:25 +0900
committerAdam Malczewski <[email protected]>2026-06-27 18:43:25 +0900
commit93b6ac11a83b8f4ec38bb957a5be5cfefa2b1240 (patch)
tree6e23d9f798a84df57c53fb636e6ede0a796d37c0
parente81df4c4936549fa674584c076e9e59fa4c920d5 (diff)
downloaddispatch-web-93b6ac11a83b8f4ec38bb957a5be5cfefa2b1240.tar.gz
dispatch-web-93b6ac11a83b8f4ec38bb957a5be5cfefa2b1240.zip
docs(handoff): CR-13 — per-conversation 'queued' status for the concurrency queue
A small UX ask (queued chat -> loading ring, generating -> loading dots, in the tab + composer corner) needs a backend change: there is no FE-derivable per- conversation 'queued' signal (turn-start sets generating before the queue wait; concurrency status is per-provider aggregate; background tabs only get the conversation.statusChanged broadcast). Add 'queued' to ConversationStatus (@dispatch/wire) + emit it from the concurrency extension when acquire() blocks. Sent to backend agent e1d7; FE side fully designed, blocked on the wire bump. Header notes the dev merge (e81df4c, 921 tests green).
-rw-r--r--backend-handoff.md48
1 files changed, 42 insertions, 6 deletions
diff --git a/backend-handoff.md b/backend-handoff.md
index db3df12..c6d5165 100644
--- a/backend-handoff.md
+++ b/backend-handoff.md
@@ -5,13 +5,12 @@
> **From:** dispatch-web orchestrator · **To:** `../backend` orchestrator · **Courier:** the user.
> `lsp` does NOT span the repos (AGENTS.md § Backend seam) — every cross-repo ask flows through here.
-_Last updated: 2026-06-26 (§2j ADDED — Provider concurrency limits: per-provider in-flight caps with oldest-agent-first
-queueing + 429-pause backoff. New `concurrency` REST surface (`GET`/`PUT`/`DELETE /concurrency/limits[/:id]`,
-`GET /concurrency/status`) + `[email protected]` bump (5 concurrency types). FE re-pinned + re-mirrored; new
-`features/concurrency` feature library + AppStore wiring + a sidebar "Concurrency" view. typecheck 0/0, 914 tests
-green, biome clean, build OK. §2i/§2h/§2g/§2f unchanged.)_
+_Last updated: 2026-06-26 (dev merged — sidebar-tabs tab rework into feature/provider-concurrency; merge commit e81df4c,
+clean auto-merge, 921 tests green. CR-13 OPEN: per-conversation `"queued"` ConversationStatus for the concurrency
+queue — sent to backend agent `e1d7`; FE side designed + blocked on the `wire` bump.) §2j concurrency unchanged._
**FE is current on `[email protected]` / `[email protected]` / `[email protected]`.** Open asks: **CR-9**
-(`system:os` should detect WSL + include Linux distro — backend behavior change, no contract bump). The SSH-divergence
+(`system:os` should detect WSL + include Linux distro — backend behavior change, no contract bump) + **CR-13**
+(add `"queued"` to `ConversationStatus` + emit from the concurrency extension — `wire` bump). The SSH-divergence
(§2d) is RESOLVED.
Backend shipped CR-10 (workspace id on `conversation.open` / `conversation.statusChanged`), CR-11
(per-conversation model persistence), and CR-12 (`GET /conversations/:id/mcp`); FE has consumed all three.
@@ -93,6 +92,43 @@ No wire/transport-contract/ui-contract change needed — this is a backend behav
how the `system:os` variable is resolved (the type shape is unchanged: it's still a `string`).
The FE is unaffected (it only inserts `[system:os]` into the template; the backend resolves it).
+### CR-13 — Per-conversation `"queued"` status for the concurrency queue → **OPEN** (sent to backend agent `e1d7`)
+
+Small UX ask: when a conversation's request is WAITING in the per-provider concurrency queue (not yet
+generating tokens), the FE should show the loading **RING** (spinner) on that tab + in the composer
+corner, instead of the loading **DOTS** (dots = actively generating). Currently both states show dots.
+
+**Why a backend change is needed (no FE-derivable signal):**
+- The FE tab spinner keys off the `conversation.statusChanged` broadcast (`ConversationStatus`:
+ `active`/`idle`/`closed`). There is no per-conversation `"queued"` state.
+- `GET /concurrency/status` is per-PROVIDER aggregate (`inFlight`/`queued` counts) — it can't tell
+ which SPECIFIC conversation is queued.
+- `turn-start` is emitted at turn entry (`run-turn.ts:617`) BEFORE `provider.stream()` → concurrency
+ `acquire()` (which may block). So the FE's `generating` flag is already `true` during the queue wait
+ — there is no `active && !generating` window to derive `"queued"` from.
+- Background tabs (not the active conversation) only receive the `conversation.statusChanged`
+ broadcast (the FE does not subscribe to every tab's chat event stream), so the queued signal MUST
+ flow through that broadcast — not a transient `AgentEvent`.
+
+**The change requested:**
+1. Add `"queued"` to the `ConversationStatus` type in `@dispatch/wire` (a wire version bump — additive
+ enum value; no `transport-contract` or `ui-contract` change). The `conversation.statusChanged` WS
+ message already carries `workspaceId` (CR-10); only the `status` value set widens.
+2. The `concurrency` extension: when a request BLOCKS on `acquire()` (enqueued in the per-provider
+ queue awaiting a slot), emit `conversation.statusChanged` with `status: "queued"` (carrying
+ `workspaceId`). When the slot is GRANTED and generation begins, flip to `"active"`. The existing
+ `"idle"` on turn seal is unchanged.
+ - Net lifecycle for a queued request: `queued` (waiting for slot) → `active` (generating) → `idle`
+ (turn sealed). A request that gets a slot immediately never emits `"queued"` (goes straight to
+ `active`) — fine.
+ - Edge: the FE opens a tab only on `"active"` (store handler), not on `"queued"`; in practice a
+ queued conversation is already an open tab, so `"queued"` just updates the status map.
+
+**FE side (BLOCKED on the wire bump — will implement the moment it ships):** re-pin `@dispatch/wire` →
+re-mirror `.dispatch/wire.reference.md` → accept `"queued"` in the WS parser (`adapters/ws/logic.ts`) →
+`TabList`: loading-ring for `status === "queued"`, loading-dots for `"active"` → Composer corner
+`status` gains `"queued"` → loading-ring, derived from the active conversation's `conversationStatus`.
+
### CR-7 — Workspace cwd fallthrough bug + relative-path resolution → **RESOLVED ✅ (backend shipped; FE code unchanged)**
Fixed backend-side (reply from arch-rewrite agent ab13). **No wire/transport-contract/ui-contract