Skip to content

fix(transcript): collapse a missed-reconcile prompt on session reentry - #1334

Closed
yexisu wants to merge 1 commit into
vastsa:mainfrom
yexisu:fix/dedupe-replayed-prompt
Closed

yexisu wants to merge 1 commit into
vastsa:mainfrom
yexisu:fix/dedupe-replayed-prompt

Conversation

@yexisu

@yexisu yexisu commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Problem

After sending a prompt, switching away and back could show the same question twice (issue #1308, repro confirmed by the reporter: 回答完切换会话再切回能复现).

Root cause: the optimistic user row lives in the renderer transcript cache under its temporary id. The user_message_persisted reconcile event re-keys it to the durable id, but if that reconcile is missed (session switched away during dispatch), the orphan row survives with the temporary id. Reselecting the session merges the durable page with the live cache and the id-based merge cannot collapse the two rows of the same prompt.

Fix

mergeLiveSessionMessages grants each durable completed user row one collapse credit keyed by text: an orphan live user row (no durable id match, not in-flight) with equal text consumes one credit and is dropped. A genuinely repeated prompt stays visible because two real sends persist two durable rows while each live orphan only consumes one credit.

Content-equality is only used as a fallback for live-only rows; id-based dedupe remains the primary mechanism, and the credit accounting keeps legitimate repeated prompts intact.

Validation

  • session-transcript.test.mjs 15/15 (incl. two new tests: orphan collapses into its durable echo; genuinely repeated prompt survives the merge)
  • session-transcript-updates + session-transcript-empty-read 10/10
  • desktop tsc --noEmit: the only remaining errors (storage/live-voice) reproduce on the pristine main checkout and are unrelated baseline noise

Fixes #1308

Switching away right after a send could leave the optimistic user row in
the live cache under its temporary id; if the user_message_persisted
reconcile was missed, reselecting the session merged it beside the
durable echo of the same prompt and the question appeared twice (vastsa#1308).

mergeLiveSessionMessages now grants each durable completed user row one
collapse credit: an orphan live user row with equal text consumes one
credit and is dropped. A genuinely repeated prompt stays visible because
two sends persist two durable rows while each live orphan only consumes
one credit.

Validated: session-transcript tests 15/15, session-transcript-updates
and empty-read suites 10/10; the remaining desktop tsc storage errors
reproduce on the pristine main checkout and are unrelated baseline
noise.
@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Thanks for reproducing and tackling #1308. The content-credit fallback can also hide a legitimate new prompt: optimisticUserMessage() creates user rows with status "complete", while isInFlightMessage() only exempts "streaming"/running rows. If durable history already contains an identical earlier prompt, a newly submitted optimistic prompt with that text has no durable ID and can consume a credit, so the just-sent prompt disappears during the merge. The added repeated-text test has two durable sends; it does not cover one old durable prompt plus a distinct newly optimistic prompt with the same text. Please constrain the collapse to the actual persisted echo, with a regression test for that case. As written this can hide real user input, so it is not safe to merge; the branch also needs the latest main. Thanks for the work.

@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Thanks for the original contribution. The fix has been completed and merged through #1340: missed prompt echoes now match only the same prompt using the optimistic message identity and a bounded timestamp window, so older or unrelated identical text cannot hide a new prompt. I’m closing this superseded PR.

@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Superseded by merged PR #1340. Thanks again for the contribution.

@vastsa vastsa closed this Oct 3, 2026
yexisu added a commit to yexisu/PI-Desktop that referenced this pull request Oct 4, 2026
Review on vastsa#1334 flagged that optimistic rows carry status "complete", so
the in-flight exemption cannot protect a fresh prompt: if an earlier
durable prompt has the same text, the newly submitted optimistic row had
no durable id and could consume its credit, hiding the just-sent prompt
during the merge.

Each durable user row's credit is now only payable to orphan rows that
do not postdate the durable page's newest user row. A persisted echo was
created no later than the page; a just-sent prompt is strictly newer and
keeps its row. Also removes a leftover duplicate credit path in the
final live-only loop that bypassed the guarded push().

Validated: session-transcript suites 26/26 (incl. the new regression
covering one old durable prompt plus a distinct fresh prompt with the
same text).
@yexisu

yexisu commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 8edb8f8 addressing the review point:

A just-sent prompt can no longer consume an older echo's credit. Optimistic rows carry status "complete", so the in-flight exemption indeed could not protect them. The collapse credit granted by each durable user row is now only payable to orphan rows whose createdAt does not postdate the durable page's newest user row: a persisted echo was created no later than the page, while a freshly submitted optimistic prompt is strictly newer than every durable row and always keeps its row.

Also removed a leftover duplicate credit-consumption path in the final live-only loop that bypassed the guarded push() — it was the actual unguarded swallow path for the case you described.

New regression test covers exactly that scenario: one old durable prompt plus a distinct newly-submitted optimistic prompt with the same text — the fresh row survives. Full suite: 26/26 across session-transcript, -updates, and -empty-read.

Rebased check: the branch already contains the latest main (afe0fe4b0 at rebase time; verified with merge-base --is-ancestor), ready for a landing review.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 提问重复出现

2 participants