diff options
Diffstat (limited to 'backend-handoff.md')
| -rw-r--r-- | backend-handoff.md | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/backend-handoff.md b/backend-handoff.md index 2ddebe1..69deebf 100644 --- a/backend-handoff.md +++ b/backend-handoff.md @@ -5,7 +5,7 @@ > **From:** dispatch-web orchestrator · **To:** arch-rewrite orchestrator · **Courier:** the user. > `lsp` does NOT span the repos (ORCHESTRATOR §5) — every cross-repo ask flows through here. -_Last updated: 2026-06-10 — "Extensions" view shipped FE-side. ONE open ask: CR-1 (Loaded Extensions as a real multi-column table). The surface is already readable today; CR-1 is the enhancement that finishes the user's "nice table" request._ +_Last updated: 2026-06-11 — **Cache-rate fix + retention + CR-3 consumed FE-side** (from `frontend-cache-warming-handoff.md`): (1) per-turn cache rate now reads true on Claude (no FE change); (2) NEW cross-turn **expected cache (retention)** metric in the chat metrics bubble (`computeExpectedCachePct`/`viewExpectedCache`); (3) **CR-3 DONE & consumed** — the countdown is now AUTHORITATIVE off the surface's `cache-warming-timer` `nextWarmAt`/`lastWarmAt` (FE guessing dropped), history keyed off `lastWarmAt`, and `WarmResponse.expectedCacheRate` headlined on "Warm now"; (4) second "cache retention" `stat` parsed. transport mirror regenerated. **Earlier (same day):** `NumberField` + conversation-scoped subscriptions + "Cache Warming" sidebar view. Open asks: CR-1 (Loaded Extensions as a real multi-column table); CR-2 (optional catalog `scope` flag). **CR-3 is RESOLVED** (see §2)._ --- @@ -26,6 +26,19 @@ Endpoints in use (HTTP **24203**, WS **24205**, CORS `*`): Mirrored in-repo for headless agents: `.dispatch/{ui-contract,wire,transport-contract}.reference.md` (regenerate on any contract bump). +**2026-06-11 re-mirror (cache-warming).** Both `ui-contract` and `transport-contract` were left at their +existing versions by the backend (`[email protected]`, `[email protected]`) but gained ADDITIVE +members; the `file:` deps already resolve them. The FE mirrors were regenerated to match: +- `ui-contract.reference.md`: `NumberField` (`kind:"number"`) + optional `conversationId?` on + `Subscribe`/`Unsubscribe`/`Invoke`/`Surface`/`SurfaceUpdate`. +- `transport-contract.reference.md`: `POST /chat/warm` (`WarmRequest`/`WarmResponse`) + the throughput + axis (`GET /metrics/throughput`, `ThroughputResponse`/`ThroughputModelStat`/`ThroughputPeriod`). +- FE consumed: generic `number` renderer; protocol keyed by `surfaceId` carrying the focused + conversationId with a staleness rule (drop a `surface`/`update` echoing a non-current conversation; + a global no-echo reply is always accepted); store auto-subscribes every catalog surface with the + focused conversationId and re-scopes on conversation switch; `warmNow()` posts `/chat/warm` with the + conversation's current model name. + ## 2. Open asks FOR THE BACKEND ### CR-1 — emit the **Loaded Extensions** surface as a true table @@ -66,6 +79,33 @@ table (e.g. `Name | Version | Trust | Scope`), listing **all** loaded extensions read `0.0.0` (unversioned). If real versions should appear in the table column, bump each extension's manifest `version` — otherwise the column is all `0.0.0`. +### CR-2 (optional, low priority) — a `scope` flag on the surface catalog entry + +The catalog (`SurfaceCatalogEntry`) carries no hint of whether a surface is GLOBAL or +CONVERSATION-SCOPED, so the FE follows the handoff's "always send the focused `conversationId`" +policy. That works (global surfaces ignore it; the FE's routing accepts the no-echo global reply), +but it means the FE **re-subscribes every surface — including global ones like `loaded-extensions` — +on every conversation switch**, which is needless churn (one redundant unsubscribe+subscribe round +trip per global surface per switch; no user-visible bug, the old spec is retained so there's no +flicker). An optional `scope?: "global" | "conversation"` on `SurfaceCatalogEntry` would let the FE +skip re-subscribing globals on switch. **Not blocking** — only raise if cheap. + +### CR-3 — next-warm timestamp + manual-warm timer reset → **RESOLVED ✅ (backend `bfbad3a`, consumed FE-side)** + +Both asks shipped by the backend (no contract bump — `custom` escape hatch) and are now consumed: +1. **`nextWarmAt` / `lastWarmAt` (epoch-ms)** arrive on the conversation-scoped `cache-warming` surface + as a `custom` field `{ rendererId: "cache-warming-timer", payload: { nextWarmAt, lastWarmAt } }`. + FE: `parseControls` reads them; the countdown is now derived straight from `nextWarmAt` + (`secondsUntilNext(nextWarmAt, now)`) and the history keys off `lastWarmAt` (`observeWarm`). The + old FE best-effort anchor/guess logic was DELETED. +2. **Manual `POST /chat/warm` now re-arms the timer + pushes a surface `update`.** FE: dropped the + workaround of recording history from the HTTP response — history is driven authoritatively by the + surface's `lastWarmAt`; the HTTP `WarmResponse` is still used for the immediate "Warm now" feedback + line (now headlining `expectedCacheRate`). The generic surface-host does NOT render + `cache-warming-timer` (no registered renderer → graceful skip); the cache-warming feature owns it. + +(The standalone courier `backend-handoff-cache-warming-timer.md` is now historical — no open asks.) + ## 3. Likely NEXT backend asks (heads-up, not yet requested) - `GET /conversations` — conversation list / sidebar (history explorer / switcher); could also expose a |
