Wave 2: 409 merge-retry transport, dead pendingJob code, evidence-based timing, prompt-size guard
- components/chat-transport.ts (NEW): createChatTransport(chatId) — the chat.tsx seam is now a one-line swap. Its fetch turns a 409 on POST /api/chat (a learner send racing the wake pipeline's ~1s adoption window) into: wait out the in-flight turn (poll turnInFlight, 30s cap), refetch the record, MERGE the outgoing messages onto the fresh server list, re-POST. A bare retry would clobber the steer + wake messages via the write-ahead persist (steerDelivered makes that loss permanent) — merging is the whole point. Unit-tested: pass-through, wait+merge+reorder, dedupe by id, repeated-409 loop, bounded give-up. - src/core/pending.ts: findPendingJobCall deleted (dead since wave 1 — job tools resolve server-side with an ack, nothing pends client-side). JOB_TOOLS kept (runner.ts still uses it). Header doc rewritten. - src/server/jobs.ts: GRACE_MS 1500 → 750, with the evidence in the comment: the race window is only the learner's answer→POST flight (sendAutomaticallyWhen dispatches synchronously; ~10ms localhost, <300ms realistic RTT — 750 is 2.5× worst case) and misses self-heal via the pump's gate recheck, the 409 backoff ramp, and the new transport merge-retry. POLL_MS=400 kept (sampling granularity only). - tests/jobs.test.ts: prompt-size guard — every fragment ≤8k chars, composed prompt ≤60k — the README-leak class (815 bytes ≈ 200 tokens per teacher turn before wave 1's fix) can't silently recur. Gates: typecheck, 279/279 tests, lint, build — all green.
This commit is contained in:
+14
-2
@@ -87,8 +87,20 @@ export function setJobRespawn(respawn: JobRespawn): void {
|
||||
|
||||
const POLL_MS = 400;
|
||||
/** After the gates open, wait a beat before firing — a client that just
|
||||
* answered a question is about to send its continuation; don't 409 it. */
|
||||
const GRACE_MS = 1500;
|
||||
* answered a question is about to send its continuation; don't 409 it.
|
||||
*
|
||||
* Evidence for 750: the race window is exactly the learner's answer→POST
|
||||
* flight — sendAutomaticallyWhen dispatches synchronously on addToolOutput,
|
||||
* the answer hits the record only at the write-ahead persist, and beginTurn
|
||||
* flips the turn registry immediately after, all before the grace can fire
|
||||
* (measured localhost RTT ~10ms; typical LAN/production RTT <300ms). 750ms
|
||||
* is 2.5× the worst realistic flight. A miss self-heals: the pump rechecks
|
||||
* the gates after the grace AND the wake pipeline retries 409s with a
|
||||
* backoff ramp — and since the transport's merge-retry (chat-transport.ts)
|
||||
* made client 409s non-fatal, even a pathological RTT degrades gracefully.
|
||||
* (Was 1500 — pure guess; 750 claws back 750ms of post-answer delivery
|
||||
* latency without weakening the guard.) */
|
||||
const GRACE_MS = 750;
|
||||
/** 409 backoff: capped ramp so a busy client can't spin the pump. */
|
||||
const RETRY_BACKOFF_MS = [500, 1000, 2000, 5000] as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user