Files
agent-desk-ng/docs/fixes/chat-realtime-recovery.md
mono 2f7a491666 feat: harden support, localize knowledge and add operator availability [skip ci]
Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.

Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.

Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.

Expected source tree: 0a4a7528e9.
2026-10-16 15:21:42 +00:00

72 lines
3.8 KiB
Markdown

# Support chat realtime recovery
This targeted change is based on canonical Gitea main snapshot
`e57610a27c556e005b9b3b68115477ba1fdd3f1b` (tree
`9cf938c2498ce6b63faaad7cf8b286c1cfe7a5ef`). That original targeted change did not import
the separate hardening-review branch. The current integration reconciles it with that branch,
preserving both realtime recovery and scoped identity/draft safeguards.
## Report and source findings
The reported scenario is opening a new chat from a previous one: sending works,
but replies appear only after a page reload. Source inspection does **not** prove
why the deployed WebSocket fails. The deployed version, reverse proxy, browser
handshake and network have not been observed or tested for this report.
The source does establish these recovery gaps:
- A socket in `CONNECTING` has no deadline; subsequent create/select/send paths
see it and return without starting a replacement.
- HTTP fallback checks end after 1.5, 3.5 and 7 seconds, so a later reply is not
retrieved while realtime remains unavailable.
- Reusing an open socket on create/select bypasses the shared status repair path.
- Initial history failure prevents bootstrap/retry from starting realtime.
- A replaced socket's late close can clear the current heartbeat/subscription
bookkeeping. A late close-conversation response can affect a newer selection.
## Changes
- Bound connection/authentication attempts to 15 seconds, invalidate abandoned
attempts, and retry using the existing exponential reconnect policy.
- Ignore close events from replaced sockets before touching current state.
- Route new/selected chats through the existing subscription/connection helper.
- Fetch late replies every 5 seconds only while the chat is open, visible, has
an active nonclosed conversation, and realtime is not connected. Never label
HTTP fallback as an online WebSocket.
- Keep latest-message refresh single-flight with a 15-second abort deadline.
Cancel previous-view requests and fence their completion before starting a new
one. Ignore stale identity/view results, stop recovery on connection, hiding,
close or teardown, and recover on focus, visibility or network return.
Background recovery failures remain quiet. The optional API AbortSignal is
backward-compatible with existing history/pagination callers.
- Connect independently of initial HTTP history success and merge history so it
cannot remove a reply already delivered by realtime.
- Restrict a close response to the conversation it actually closed.
No backend, SDK bundle, credentials, database, deployment configuration or
production data is changed.
## Validation status
Completed static checks only:
- `git diff --check`.
- Isolated strict TypeScript compile of `web/lib/realtime-connection.ts` using an
already installed TypeScript 6.0.3 compiler.
- TypeScript syntax/transpile diagnostics for the four changed production files.
- JavaScript syntax checks for the two focused regression files.
Added offline mock regressions for delayed replies beyond seven seconds, moving
from a previous chat, resubscription, stuck handshakes, late authentication and
socket close events, hidden/unmounted lifecycle, single-flight fallback,
identity/view changes, abort deadlines, stalled previous-view fetches, history
failures and late close responses.
The integrated 2026-10-16 baseline has now executed all 226 frontend Node tests,
including these recovery regressions, and the declared-dependency frontend
typecheck. Both passed. Focused backend security/setup tests and their race run
also passed; see [the current validation record](../hardening/VALIDATION.md) for
exact scope, fixture corrections and remaining build/lint/MySQL/browser gates.
No production services were started, real support messages sent, or deployment
performed. These checks are not a claim of production acceptance.