Skip to content

fix(ui): retain queued replies across late reconnect history - #1968

Merged
schlessera merged 8 commits into
mainfrom
test/1917-queued-followup-trace-3d746bc3
Oct 15, 2026
Merged

schlessera merged 8 commits into
mainfrom
test/1917-queued-followup-trace-3d746bc3

Conversation

@schlessera

@schlessera schlessera commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Closes #1917

#1979 is merged and verified on main as cbf2bb87f8eee79f971099aa4858262888f087ae. This layer's diff is the queued-reply behavior repair below; the inherited three fixture changes are already delivered.

What changed

A reconnect history read can sample before a queued turn completes and return after its reply has reached the browser. Publishing that older transcript then removes the delivered exchange. The host now observes ordinary turn starts and terminals while a read is pending, reads again once after an overlap, and reports the existing SESSION_LOAD_ERROR if the second read also changes. Validation and publication of history, pending requests and current turn status run synchronously. This applies to explicit resume and the connect snapshot.

Client reconciliation also keeps the live assistant across exactly one missing user row inserted by fresh history, including split chunks and intervening deltas. It requires delivered progress or a known turn, so a cold connection placeholder cannot hide a restored capacity failure. Existing text, tool, turn and repeated-prefix checks still decide whether it is the same answer.

The browser fixture retains bounded lifecycle diagnostics and adds stale/fresh overlapping-history cases at both existing device/theme cells. They check queued user/assistant messages in the settled store and rendered reply after history and terminal status arrive. The original ten-drop cases remain byte-identical. The snapshot delivery oracle now expects the current turn identity; all draft, focus, selection, node-identity and no-send assertions remain, and the existing client old-status rejection tests remain unchanged.

Why this shape

Ordinary shorter and empty history must still replace the transcript. The correction prevents publication of a read known to overlap live turn transitions rather than changing those replacement semantics. Only pending reads retain tokens; there is no transcript cache or new protocol field. Same-turn deltas retain existing client reconciliation. Snapshot read failures now send the existing session-load error and current status instead of being logged only.

This repairs the controlled defect documented on #1917. The historical hosted timeout's precise cause remains unknown; passing controls and this reproduction are not relabelled as attribution of that execution. The host check does not promise freshness for a backend that stores its answer only after a result and is first sampled afterward.

Proof

Candidate 8e41b9829715767efa6127c2bf69d77e4f1b2d87 passes complete run 38783200249, attempt 1, on tested main cbf2bb87f8eee79f971099aa4858262888f087ae. All 14 selected jobs and aggregate pass. All 14 actual checkout logs agree on 76c16a49930da3192152033a462797c75ce1516b, whose immutable parents are that base/head and tree is 4a0fe6bea400e0dec6a07c27407bb545bfd375d7; API and local Git agree. Strict verification, packaging, runtime and captures pass. Unit shards pass 3080 /3163 /3449 /3637; browser shards pass 4580 /4228 with four /six existing exclusions; layouts pass 622 /428. All 14 native continuity cases pass, including both original ten-drop/IME cells and the four new stale/fresh-history cases. The current-head contract gate passes.

Main subsequently advanced to 090c8a5463effe6811742259bc27af2b5ff6e66c through documentation-only #1992. Its three worker-policy decision amendments change no product, test, harness, dependency or configuration input for this repair and introduce no citations to files moved here. Their decision scope is unrelated to chat history publication. Existing policy permits this unrelated advancement without rebasing/repeating long proof. A scoped check of the actual combined documentation/product state passes all 44 citation tests /113 assertions. Expected final combined tree is 23abbfe4ff695cc0f7c51f11ed5c5357b39faf57; the full CI receipt retains its actual older base/tree and is not relabelled as testing the newer documentation.

Original local receipts below retain their actual prepared source. The native fixture's later shared-gate projection correction and client's empty-placeholder guard are independently proved in the preserved failure sections. Independent read-only review found no blocker in the final guard or authorization/cancellation behavior.

  • Current-main reproduction of the published stale-history recipe: original Noted wait times out after 675 assertions (122919.02 ms case / 176.96 s invocation). Its lifecycle JSON shows backend four messages, client two, drained queue and replay/streaming false. Source 2c88134, based on 9274b8a; temporary recipe restored.
  • Durable native stale-history regression with the guard disabled: original queued-reply wait fails after seven assertions (42.13 s case / 90.63 s invocation); backend four/client two. Guard restored; the subsequent cancellation-order correction is independently mutation-tested below. No setup failure is offered as failing-first evidence.
  • Final focused and related server/client batch: 146 pass / zero fail / 843 assertions across six files. The new real-host file contributes 12 cases / 42 assertions, including no catalog persistence, bounded retry/refusal/recovery, cancellation-before-result, cleanup-idle deduplication, empty history, session isolation, same-turn deltas, authorization loss and current snapshot status.
  • Server mutations fail the named stale-history equality, missing load-error and cancellation-order assertions. All mutations are restored.
  • Original prepared-source full guarded native continuity file: 14 pass / zero fail / 1661 assertions, 397.58 s, including all four stale/fresh cells and both original ten-drop/IME cases. The initial run with only the host correction passes 13 and fails the original newer-answer streaming assertion; it is preserved. Four full/split × legacy/proven client controls then fail on lost answer identity before the client correction and pass after it; changed-prefix, conflicting-turn and distinct-tool controls remain rejecting.
  • Renewed combined-base bun run check:pr --base origin/main: 852 pass / zero fail / 5459 assertions across 43 files and all local gates.
  • Original repair-only local bun run check:pr --base origin/main: 502 pass / zero fail / 2974 assertions across 24 files and all local gates. Final exact-host guard mutation fails on missing queued messages (three assertions); restoring it passes all 12 focused cases / 42 assertions.
  • Original local behavioral runs used the working tree committed as prepared candidate 2c9477aaead747c8048f7f0d92686ef4cb362f5f, with runner HEAD 2c88134afedf22581522d588258b4bdebbc1250e. Frozen host SHA-256 395bba54b02567d9ad89d45d7d8a8cc6073c4e09f01eb3c7b0a3bea6d4b27d3f and chat-state SHA-256 81143ed4543ea6334c8311b019b03a41ebe2aeda8fe1e1b1d0d2afc7ef557e5e match that prepared candidate. These are local source receipts, not current-head hosted proof.
  • Pending changeset package references validate; the full Changesets plan keeps all 18 packages in the existing minor fixed group with no major bump.

The original failed run 38607535922 and earlier diagnostic qualifications retain their identities and limits in the issue body and reproduction receipt. They are not current-candidate qualification.

Diagnosed strict-type failure and correction

Run 38779448425, attempt 1, verification job 116575872719, checks head 1db612bb2a8b82f2a9b8ddcbd28cfd9cb4cdfe9b on main b4609b961084268309287fff807b1dbd2687d607. Actual checkout 92d7f870c1c9a5585ea49ea400c401567e3584de has those parents and tree 8ac8aee4bd434606898b26bc18bef296dbf7253a; API and Git agree. Strict types report TS2345 at the fixture's shared history gate: spreading the late-history probe also supplies stale/fresh mode to a failed/empty mode type. The correction passes only the promise/release/read fields that this gate needs; its false hold predicate and runtime sequence remain unchanged. Local bun run typecheck and renewed preflight (852 pass / 5459 assertions) pass.

The diagnosed invalid candidate was superseded with this changed source; unfinished categories are cancelled, never passing evidence. The superseded run ends cancelled: metadata and packaging pass, verification fails as above, ten executing categories and the unexecuted aggregate are cancelled. Cancelled executing jobs consumed 65.27 aggregate runner-minutes (70.10 across all completed jobs). No cancelled result is qualification. No unchanged failed job was retried. Fresh complete qualification of this corrected head is required.

Diagnosed capacity-handoff regression and correction

Run 38780399184, attempt 1, checks older head 5b340c7c20fcd0d38015c4b2fc1eb2d27d7a7fc4 / base b4609b961084268309287fff807b1dbd2687d607, actual checkout f02eee279b2adb9b8edf3ca9481e9519b47b3c00, tree 94e60086b4daf5dcb99bf10b15f93aa60543031c. API, Git and retained browser artifact 11995832339 agree. Browser 1 fails four session-capacity handoff cases (4576 pass /four existing exclusions), browser 2 fails the remaining two fine-pointer cells (4226 pass /six existing exclusions). The original action lookup fails because the insertion guard reuses an empty connection placeholder as a streaming answer, hiding the completed failure's handoff action. This is a diagnosed regression, not timing recovery.

The unchanged complete native working-session file reproduces all six capacity failures: 195 pass /six fail /six existing exclusions, 36.11 s. Two new cold full/split-history controls fail first on spurious streaming. Requiring actual progress or turn correlation fixes the guard; the unchanged browser file then passes all 201 cases /six existing exclusions, 33.10 s. Five positive controls preserve text, thinking, tools, turnId and streamTurnId. Combined server/client proof passes 153 tests /882 assertions across six files. Original full/split identity and rejection controls remain. Local strict types and renewed preflight (852 pass /5459 assertions) pass. Moved citations are adjusted; the existing patch changeset covers the corrected client behavior.

This diagnosed failed candidate is superseded by changed source: seven jobs pass, both browser jobs fail, four unfinished executing jobs and the aggregate are cancelled. Cancelled job wall time is 81.20 aggregate runner-minutes (154.42 across all completed jobs). Its failure receipt and final states are preserved; it is never called passing evidence. Fresh complete qualification of 8e41b9829715767efa6127c2bf69d77e4f1b2d87 is run 38783200249, attempt 1, completed successfully as recorded above. Final client SHA-256 is 97b9165f1199859c722b4430fb04a29272919226394d4164e9d95e5633687af2; earlier local native and mutation receipts remain attributed to their actual prepared source.

Checklist

  • Focused local preflight and complete selected current-head hosted proof pass.
  • ui-react: late reconnect history removes a delivered queued reply #1917 criteria are met; PR and issue milestone 0.44.0 are read back before merge.
  • Meaningful native and server failing-first receipts are preserved; mutations restored.
  • Patch changeset for @schlessera/brain-ui-server and @schlessera/brain-ui-react; no package version or dependency change.
  • Moved documentation citations updated.
  • No machine-contract or wire-shape change.
  • Existing offline/security guards and continuity coverage retained.

Anything left open

The controlled #1917 defect and regression are corrected and qualified. Original historical attribution remains unknown and is stated separately from that demonstrated bug class. #1979 delivery is verified. Separate main-push Playwright GUID/cross-case failures are retained in #1993; this fresh candidate passes the parallel-session file, without claiming to diagnose that independent failure. #1764's own implementation and required proof remain its separate scope.

@schlessera schlessera added this to the 0.44.0 milestone Oct 15, 2026
@schlessera schlessera added type: test Coverage, harness or proof work with no behaviour change. area: ui-server Hono app factory: turn coordinator, auth, session catalog, routes, cron. area: ui-react React chat/files/voice components, stores, WebSocket transport. area: ci CI workflows, the gates they run, release scripts, packaging. labels Oct 15, 2026
@schlessera
schlessera force-pushed the test/1917-queued-followup-trace-3d746bc3 branch from 10ed3d7 to 4557ce2 Compare October 15, 2026 08:46
@schlessera
schlessera marked this pull request as draft October 15, 2026 09:22
@schlessera
schlessera force-pushed the test/1917-queued-followup-trace-3d746bc3 branch 2 times, most recently from 3ed9d4a to 2c9477a Compare October 15, 2026 17:13
@schlessera schlessera added type: fix Something is broken and must behave the way it is documented. and removed type: test Coverage, harness or proof work with no behaviour change. labels Oct 15, 2026
@schlessera schlessera changed the title test(ui-react): retain queued follow-up lifecycle evidence fix(ui): retain queued replies across late reconnect history Oct 15, 2026
@schlessera
schlessera force-pushed the test/1917-queued-followup-trace-3d746bc3 branch from 2c9477a to 1db612b Compare October 15, 2026 17:39
@schlessera
schlessera marked this pull request as ready for review October 15, 2026 17:41
@schlessera
schlessera merged commit 66c370b into main Oct 15, 2026
19 checks passed
@schlessera

Copy link
Copy Markdown
Owner Author

Delivered by merged #1968 / 66c370b54e65151c6b56a0466347b609b31571b1, verified on fetched main. Current-candidate run 38783200249 attempt 1 passes all 14 selected jobs/aggregate, with every actual checkout 76c16a49930da3192152033a462797c75ce1516b matching tested base cbf2bb87f8eee79f971099aa4858262888f087ae, head 8e41b9829715767efa6127c2bf69d77e4f1b2d87, tree 4a0fe6bea400e0dec6a07c27407bb545bfd375d7. All 14 native continuity cases pass, including original ten-drop/IME and four new stale/fresh cells. Main's later #1992 is documentation only; combined citations pass 44 tests. Actual squash parent 090c8a5463effe6811742259bc27af2b5ff6e66c / tree 23abbfe4ff695cc0f7c51f11ed5c5357b39faf57 match the separately inspected combined state, not the older full-CI tree. Issue closure and PR/issue milestone 0.44.0 are read back. Original historical attribution and separate #1993/#1978 causal gaps remain explicit; no failed/cancelled candidate is relabelled green.

@schlessera

Copy link
Copy Markdown
Owner Author

Post-merge verification is complete: automatic main-push run 38787444974, attempt 1, passes all fourteen selected jobs and aggregate on squash 66c370b54e65151c6b56a0466347b609b31571b1. Every actual job checkout log independently agrees on that exact SHA; its parent/tree remain 090c8a5463effe6811742259bc27af2b5ff6e66c / 23abbfe4ff695cc0f7c51f11ed5c5357b39faf57. This is a fresh main receipt for the documentation-adjusted final state, separate from the earlier PR qualification. It supersedes the prior pending-main status. Passing native PDF/parallel-session executions do not diagnose the independent historical causes on #1978 or #1993, which remain open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, the gates they run, release scripts, packaging. area: ui-react React chat/files/voice components, stores, WebSocket transport. area: ui-server Hono app factory: turn coordinator, auth, session catalog, routes, cron. type: fix Something is broken and must behave the way it is documented.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui-react: late reconnect history removes a delivered queued reply

1 participant