fix(telegram): skip duplicate final emit when preview already covers chunks (#87624)#87686
fix(telegram): skip duplicate final emit when preview already covers chunks (#87624)#87686sweetcornna wants to merge 1 commit into
Conversation
openclaw#87624) In partial/block streaming.mode the draft preview can end at a tighter boundary than the lane chunker (e.g. HTML rendering caps the preview a few characters short of the first chunk's raw-text boundary, or stop() failed before the firstChunk update lands). The finalizer rejected those shorter-but-still-prefix snapshots and fell through to sendPayload(finalText), which re-chunked the full reply via deliverReplies. Any retained overflow preview pages stayed visible while the final pass spawned fresh duplicates of each chunk, so a >4096-char reply landed twice on Telegram. Generalize the after-stop prefix check: if the delivered stream text is any prefix of the final text, hand off from that boundary so we only emit the missing suffix. Drop the previous "must exceed firstChunk" guard that only covered multi-preview chains.
|
Codex review: needs real behavior proof before merge. Reviewed May 29, 2026, 1:09 AM ET / 05:09 UTC. Summary PR surface: Source +3, Tests +64. Total +67 across 2 files. Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Review detailsBest possible solution: Retry the Codex review after fixing the execution failure. Do we have a high-confidence way to reproduce the issue? Unclear. The review failed before ClawSweeper could establish a reproduction path. Is this the best way to solve the issue? Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model gpt-5.5, reasoning high; reviewed against 0e86ca135225. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +3, Tests +64. Total +67 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Summary
What problem does this PR solve?
partialandblockstreaming modes. The user sees the same reply rendered twice.Why does this matter now?
regression/P1/impact:message-loss. The bug deterministically corrupts every long Telegram reply in the documented-defaultstreaming.mode: "partial"and in"block"; only"progress"is clean.What is the intended outcome?
What is intentionally out of scope?
What does success look like?
partialmode: a >4096-char reply lands inceil(reply_length / textChunkLimit)Telegram messages instead of roughly twice that.blockmode: the first chunk shown as a preview is reused as final chunk 0 instead of being re-sent alongside chunks 1..N.progressmode: unchanged.What should reviewers focus on?
extensions/telegram/src/lane-delivery-text-deliverer.ts:405: the relaxed prefix-detection check now also coversdeliveredStreamTextAfterStop.length <= firstChunk.lengthas long as the delivered text is a real prefix offinalText.Linked context
Which issue does this close?
Closes #87624
Which issues, PRs, or discussions are related?
Related #84885 (adjacent retained-preview cluster, per ClawSweeper review on #87624).
Was this requested by a maintainer or owner?
ClawSweeper review on #87624 marked it
clawsweeper:source-repro+clawsweeper:queueable-fix+clawsweeper:fix-shape-clearand pointed at this exact handoff path.Real behavior proof (required for external PRs)
extensions/telegram/src/lane-delivery-text-deliverer.ts:405rejected the after-stop prefix unlessdeliveredText.length > firstChunk.length, so when the draft preview ended on a tighter boundary (HTML rendering caps the preview, orstop()failed before the firstChunk update lands) the finalizer fell through toparams.sendPayload(applyTextToPayload(payload, text))— sending the full final text again — while the preview / retained overflow pages stayed visible.pnpm install --frozen-lockfilenode scripts/run-vitest.mjs extensions/telegram/src/lane-delivery.test.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/bot-message-dispatch.test.tsnode scripts/run-vitest.mjs extensions/telegram(full plugin suite)length > firstChunkguard: the new testhands off from a shorter streamed prefix when stop ends below the first chunk boundaryfailed withexpected 'sent' to be 'preview-finalized'(lane fell through tosendPayload(finalText)andclearDraftLane).finalizeDeliveredPrefix(deliveredStreamTextAfterStop, messageId)for any prefix snapshot, so the preview / retained pages remain the active delivery and only the missing suffix is sent viaparams.sendPayload(followUpPayload(...)).streaming.mode: "partial"+textChunkLimit: 3800and a >6000-char prompt. The fix path is exercised by unit tests but a live roundtrip is recommended before landing — cited underclawsweeper:source-repro.clawsweeper:source-reprolabel on [Bug]: Telegramstreaming.mode: "partial"and"block"duplicate the full preview when reply >4096 chars #87624.Tests and validation
Which commands did you run?
pnpm install --frozen-lockfilenode scripts/run-vitest.mjs extensions/telegram/src/lane-delivery.test.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/bot-message-dispatch.test.ts→ 161 tests passednode scripts/run-vitest.mjs extensions/telegram→ 1919 tests passedpnpm format:check extensions/telegram/src/lane-delivery-text-deliverer.ts extensions/telegram/src/lane-delivery.test.ts→ cleannode scripts/run-oxlint.mjs extensions/telegram/src/lane-delivery-text-deliverer.ts extensions/telegram/src/lane-delivery.test.ts→ exit 0pnpm tsgo --noEmit -p extensions/telegram/tsconfig.json→ cleanWhat regression coverage was added or updated?
extensions/telegram/src/lane-delivery.test.ts:does not duplicate the first chunk when block mode finalizes a long replycovers the block-mode variant (preview shows first chunk, final must reuse it for chunk 0 and only emit chunks 1..N).extensions/telegram/src/lane-delivery.test.ts:hands off from a shorter streamed prefix when stop ends below the first chunk boundarycovers the partial-mode variant where the preview'slastDeliveredTextis a real prefix shorter thanfirstChunk— the failure mode that caused the dispatcher to fall through tosendPayload(finalText)and duplicate retained pages.What failed before this fix, if known?
length > firstChunkguard restored, the newhands off from a shorter streamed prefix...test failed atexpectPreviewFinalizedwithexpected 'sent' to be 'preview-finalized'— i.e., the lane fell through to fullText delivery instead of finalizing in place.If no test was added, why not?
Risk checklist
Did user-visible behavior change? (
Yes)partial/blockmode change from "preview + full duplicated final pass" to "preview + suffix only". This is the bug fix and matches the documented behavior already shipped forprogressmode.Did config, environment, or migration behavior change? (
No)Did security, auth, secrets, network, or tool execution behavior change? (
No)What is the highest-risk area?
finalizeDeliveredPrefixeven when the delivered preview is shorter thanfirstChunk. Ifstream.lastDeliveredTextever returned a non-prefix prefix-like string (e.g., the stream had been reset to fresh state with stale content), we already bail out via theisDeliveredPrefixguard. The new branch only fires whenfinalText.startsWith(deliveredText)is true, so it cannot leak unrelated content.How is that risk mitigated?
Current review state
What is the next action?
clawsweeper:source-reprobefore landing.What is still waiting on author, maintainer, CI, or external proof?
Which bot or reviewer comments were addressed?
streaming.mode: "partial"and"block"duplicate the full preview when reply >4096 chars #87624 (comment): applied the suggestedBest possible solution— fix in the existing Telegram draft/lane delivery path, with partial and block regression tests; live Telegram proof is the remaining gap called out underProof limitations.