Commit Graph

5 Commits

Author SHA1 Message Date
LZH-YS1998 b8202bbe9e fix: unify company runtime recovery lifecycle 2026-07-14 14:35:43 +08:00
LZH-YS1998 4bc18dcd27 fix(ui): stabilize workplace chat scrolling 2026-07-13 23:02:39 +08:00
LZH-YS1998 818189a1cc fix: guarantee engine replies reach the UI channel and stop same-scope duplicate rows
Project 000, 19:21/20:27: the engine recorded its assistant reply in
session_messages, but the post-turn transcript sync never surfaced it in the
ui_state channel, and nothing reconciled afterwards — the user watched an
empty conversation while the reply sat in the DB. And at 19:13 the same reply
was persisted twice in one channel under `<id>` and `<id>::<project>::<channel>`.

Two fixes:
- _ensure_reply_projected: after the transcript sync, if the session's newest
  persisted top_level_reply row is absent from the chat store (checked by
  transcript message id, so nothing user-visible is ever duplicated or leaked),
  insert and broadcast it directly. Reproduced by test: with the sync disabled
  the reply previously never reached the channel.
- backfill_messages: a live insert racing the backfill snapshot now merges into
  the existing same-scope row (new _merge_into_same_scope_row, also used by the
  IntegrityError fallback) instead of minting a `::`-scoped alias id in the
  message's own channel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 22:59:53 +08:00
LZH-YS1998 3a2c935025 fix: deduplicate re-delivered session sends on the client message id
Typed-3-shown-5 forensics (project 000): the WS client queues session_send
payloads while disconnected and flushes the queue after a reconnect, and the
server minted a fresh row id per delivery — so one typed message could land
as several user turns, each dispatched to the engine.

Every send now carries a client-generated ui_message_id (dispatchSessionSend
injects one when the caller didn't). The handler persists the user row under
that id and answers any later delivery in the same channel with an idempotent
ack instead of inserting and dispatching again. Because the row id now equals
the optimistic bubble's ui_message_id, the echo also merges with the local
message even after the transcript sync rewrites row metadata.

Same text intentionally sent again gets a fresh id and still starts a new turn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 22:47:00 +08:00
LZH-YS1998 d78931979d Initial commit 2026-07-01 17:56:31 +08:00