Skip to content

Keep queued user turns after Telegram supersedes#83790

Closed
VACInc wants to merge 1 commit into
openclaw:mainfrom
VACInc:fix-telegram-topic-followup-queue
Closed

Keep queued user turns after Telegram supersedes#83790
VACInc wants to merge 1 commit into
openclaw:mainfrom
VACInc:fix-telegram-topic-followup-queue

Conversation

@VACInc

@VACInc VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Detach queued user_request followups from the source-channel abort signal once they have been accepted into the reply queue.
  • Keep room_event followups tied to their source abort signal so ambient/current-event work can still be canceled by the admission fence.
  • Stop the followup runner from reintroducing the original source opts.abortSignal when executing a queued item; queued execution now uses only the abort metadata carried on that queued item.

Root Cause

Queued followups were built with opts.abortSignal unconditionally. In Telegram topics, a later user turn can supersede the source reply fence while an earlier turn is still active. That made an already accepted user_request followup look aborted before it drained. The followup runner also fell back to the captured source opts.abortSignal, so omitting the signal on the queued object alone was not sufficient.

Real behavior proof

Behavior addressed: Telegram topic user messages accepted while another turn is active should remain queued and run after the active turn, even if the source reply fence is later superseded.

Real environment tested: temp worktree /tmp/openclaw-topic-followups.hEwtrg for the patch and focused tests; current live local Telegram gateway for current-chat proof; real local gateway runtime logs reviewed from /tmp/openclaw/openclaw-2026-05-18.log and topic session trajectories under ~/.openclaw/agents/main/sessions.

Exact steps or command run after this patch: node scripts/run-vitest.mjs src/auto-reply/reply/get-reply-run.media-only.test.ts src/auto-reply/reply/followup-runner.test.ts src/auto-reply/reply/queue.collect.test.ts extensions/telegram/src/bot-message-dispatch.test.ts; jq -r 'select((.message // "") | test("topic:8185|threadId=8185")) | select(.time >= "2026-05-18T19:40:00") | [.time, .message] | @tsv' /tmp/openclaw/openclaw-2026-05-18.log; and redacted runtime-log review of the original Telegram-topic failure window.

Evidence after fix: focused regression proof shows old code failed and PR head passed. On old code with only the new regression tests applied, node scripts/run-vitest.mjs src/auto-reply/reply/get-reply-run.media-only.test.ts src/auto-reply/reply/followup-runner.test.ts failed with Test Files 2 failed (2) and Tests 2 failed | 110 passed (112), including expected AbortSignal { aborted: true } to be undefined and expected AbortSignal { aborted: false } to be undefined. On PR head 695478dc167f6cd54cfe318fe037837494bf832a, the same command passed with Test Files 2 passed (2) and Tests 112 passed (112).

Current live Telegram topic proof from the active patched gateway shows the current chat receiving topic messages and sending replies back into the same Telegram topic after the patch:

2026-05-18T19:41:31.880-04:00  Inbound message telegram:group:-<redacted>:topic:8185 -> @vacs_tars_bot (group, 12 chars)
2026-05-18T19:41:51.482-04:00  telegram outbound send ok accountId=default chatId=-<redacted> messageId=100708 operation=sendMessage deliveryKind=text threadId=8185 chunkCount=1
2026-05-18T19:43:23.393-04:00  Inbound message telegram:group:-<redacted>:topic:8185 -> @vacs_tars_bot (group, 42 chars)
2026-05-18T19:46:27.188-04:00  telegram outbound send ok accountId=default chatId=-<redacted> messageId=100749 operation=sendMessage deliveryKind=text threadId=8185 chunkCount=1
2026-05-18T19:46:28.027-04:00  telegram outbound send ok accountId=default chatId=-<redacted> messageId=100750 operation=sendMessage deliveryKind=text threadId=8185 chunkCount=1

The active live runtime also contains the patched abort contract:

dist/get-reply-DqVR3pSa.js: queuedFollowupAbortSignal = inboundEventKind === "room_event" ? opts?.abortSignal : void 0
dist/agent-runner.runtime-CAMJHMX1.js: upstreamAbortSignal: queued.abortSignal
dist/agent-runner.runtime-CAMJHMX1.js: abortSignal: queued.abortSignal

Redacted runtime log excerpt from the original real OpenClaw Telegram-topic failure window showed multiple topic inbounds while active queued work was present, followed by prompt-stage app-server closures and queued topic diagnostics:

2026-05-18T17:42:08.017-04:00  Inbound message telegram:group:-<redacted>:topic:24 -> <redacted>
2026-05-18T17:43:07.782-04:00  Inbound message telegram:group:-<redacted>:topic:24 -> <redacted>
2026-05-18T17:43:28.862-04:00  Inbound message telegram:group:-<redacted>:topic:5907 -> <redacted>
2026-05-18T17:43:43.340-04:00  embedded run failover decision runId=11c4451e-4ab6-4dad-b6ef-edfde684a0cd stage=prompt aborted=false rawErrorPreview="codex app-server client closed before turn completed"
2026-05-18T17:43:43.379-04:00  embedded run failover decision runId=df0003ed-4b49-4be0-8a12-71e1b450eee7 stage=prompt aborted=false rawErrorPreview="codex app-server client closed before turn completed"
2026-05-18T17:44:55.514-04:00  liveness warning ... active=...topic:24(processing/embedded_run,q=2,...)|...topic:5907(processing/embedded_run,q=1,...) queued=...topic:24(processing/embedded_run,q=2,...)
2026-05-18T17:59:02.652-04:00  long-running session ... topic:8428 state=processing queueDepth=1 reason=queued_behind_active_work classification=long_running

Additional redacted trajectory evidence showed repeated Telegram topic abort endings matching the loss mode this patch removes for queued user requests:

externalAbort=true / "Reply operation aborted by user" counts by Telegram topic trajectory:
11 topic:24
9  topic:26866
6  topic:5907
4  topic:8428
4  topic:22684
4  topic:10174

Observed result after fix: queued user_request followups no longer carry or inherit the supersedable source abort signal; queued room_event followups still preserve their abort signal and continue to be skipped when that signal is already aborted. Focused regression tests pass, and the current live Telegram topic chat shows post-patch inbound topic messages receiving outbound threadId=8185 replies from the active patched gateway.

What was not tested: Mantis Telegram Desktop visible proof did not capture because the Telegram bot connection was conflicted and proof messages did not reach OpenClaw. No video/artifact proof from Mantis or Crabbox is attached. Discord was not retested beyond the reporter's confirmation that a Discord server channel was not reproducing the same issue. The current live Telegram log proof is from the operator's active gateway, not a controlled baseline/candidate A/B desktop recording.

Verification

  • pnpm install --frozen-lockfile to install dependencies in the temp worktree only after the Vitest wrapper could not resolve vitest/package.json.
  • git diff --check
  • node scripts/run-vitest.mjs src/auto-reply/reply/get-reply-run.media-only.test.ts src/auto-reply/reply/followup-runner.test.ts src/auto-reply/reply/queue.collect.test.ts extensions/telegram/src/bot-message-dispatch.test.ts -> Test Files 4 passed (4), Tests 220 passed (220).
  • Rebased onto current origin/main (d761b98adc6ff2c824b95d0b2a7a54dfa1177d18) and reran the same focused test command -> Test Files 4 passed (4), Tests 220 passed (220).
  • Current live gateway log inspection for topic 8185 showed inbound Telegram topic messages followed by outbound threadId=8185 replies from the active patched runtime.
  • AUTOREVIEW_AUTO_TESTS=0 .agents/skills/autoreview/scripts/autoreview --mode local reported findings against untouched files (src/auto-reply/inbound-debounce.ts, extensions/telegram/src/sequential-key.ts). I rejected those as not applicable after git diff --name-only showed this branch only touches reply-runner files. Manual review did find the followup-runner fallback path, which is fixed here. A second autoreview rerun was stopped after about five minutes because it again expanded into broad unrelated GitHub search instead of completing a local-diff review.

What was not tested

  • Mantis Telegram Desktop visible proof / Crabbox proof was attempted but blocked by a conflicted Telegram bot connection.
  • Broad pnpm check was not run from this Codex worktree.

@openclaw-barnacle openclaw-barnacle Bot added size: S triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 18, 2026
@clawsweeper

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Workflow note: Future ClawSweeper reviews update this same comment in place.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Summary
The PR detaches accepted queued user-request followups from the source abort signal while preserving room-event abort metadata and adds focused regression coverage.

Reproducibility: yes. at source level: current main attaches opts.abortSignal to queued user followups and the queued runner reuses that source signal when queued.abortSignal is absent. I did not run tests because this review is read-only, but the PR supplies focused before/after regression output for the same path.

PR rating
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🦞 diamond lobster
Summary: The patch is focused and well tested at source level, but merge readiness is capped by insufficient real Telegram behavior proof for the exact queue/supersede race.

Rank-up moves:

  • Add redacted Telegram topic logs or a short recording showing a queued user request accepted while another turn is active and then draining after a later superseding turn.
  • Include diagnostics that show the queue/supersede/drain path while redacting chat IDs, phone numbers, tokens, non-public endpoints, and message contents.
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

PR egg
🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature, rarity, or ASCII portrait is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

Real behavior proof
Needs stronger real behavior proof before merge: The PR includes redacted patched-runtime Telegram logs, but they do not demonstrate the exact queued-after-supersede path; add redacted logs, terminal output, or a recording that shows that path and update the PR body for re-review.

Mantis proof suggestion
A native Telegram proof can directly show whether the queued topic user message is preserved and answered after a later superseding turn. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

telegram desktop proof: verify that a queued Telegram topic user message drains after a later superseding turn, with room-event cancellation still aborting ambient work.

Risk before merge
Why this matters: - The live proof currently shows same-topic inbound and outbound messages from a patched gateway, but not an accepted queued user turn draining after a later superseding turn.

  • The change affects generic queued CLI and embedded followup abort propagation, so maintainers should verify both user-request survivability and room-event cancellation before merge.

Maintainer options:

  1. Require exact Telegram queue proof (recommended)
    Ask for redacted logs, terminal output, or a short recording from the patched branch showing a queued Telegram topic user request accepted while another turn is active and then drained after a later superseding turn.
  2. Accept source and focused-test proof
    Maintainers can choose to merge on the source-level fix and before/after regression tests while explicitly accepting that the exact live Telegram race was not captured.
  3. Pause until Mantis or live lane is available
    If exact proof cannot be captured from the contributor setup, pause the PR until Mantis, Crabbox, or another live Telegram lane can exercise the queue/supersede path.

Next step before merge
The remaining action is exact live Telegram proof and maintainer review, not a safe automated code repair.

Security
Cleared: The diff only changes in-process abort propagation and focused tests; it does not touch secrets, dependencies, CI, install scripts, package metadata, or external code execution paths.

Review details

Best possible solution:

Land the focused abort-metadata fix after redacted live Telegram proof shows queued user turns drain after supersede while room-event cancellation still skips aborted ambient work.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main attaches opts.abortSignal to queued user followups and the queued runner reuses that source signal when queued.abortSignal is absent. I did not run tests because this review is read-only, but the PR supplies focused before/after regression output for the same path.

Is this the best way to solve the issue?

Yes, the code direction is the narrowest maintainable fix: carry abort metadata only on queued room events and stop queued execution from falling back to the captured source signal. The remaining gap is exact live Telegram proof, not a different implementation shape.

Label justifications:

  • P1: The PR addresses a reported Telegram topic message-loss path where accepted queued user turns can be aborted before they drain.
  • merge-risk: 🚨 message-delivery: Merging changes queued followup abort semantics across CLI and embedded reply execution, which can affect whether channel messages are delivered or canceled.

What I checked:

  • Current main builds every followup with the source abort signal: On current main, runPreparedReply constructs followupRun with abortSignal: opts?.abortSignal regardless of inbound event kind, so queued user_request turns inherit Telegram's supersedable reply-fence signal. (src/auto-reply/reply/get-reply-run.ts:1047, 87aa31956840)
  • Current main re-inherits the captured source signal at queued execution: createFollowupRunner falls back from queued.abortSignal to opts?.abortSignal when creating the reply operation and when dispatching CLI or embedded queued followups, which matches the PR's reported loss mode. (src/auto-reply/reply/followup-runner.ts:422, 87aa31956840)
  • PR diff narrows abort metadata to room events and removes fallback: The PR commit changes get-reply-run.ts to attach queued abort metadata only for room_event followups and changes followup-runner.ts to use queued.abortSignal directly, with tests for detached queued user requests and preserved room-event cancellation. (src/auto-reply/reply/get-reply-run.ts:1047, 695478dc167f)
  • Telegram source signal is the reply fence that supersedes older turns: Telegram dispatch creates a per-dispatch replyAbortController, registers it with the reply fence, and passes its signal to replyOptions; newer user requests supersede that fence while queued room-event lifecycle keeps ambient work abortable. (extensions/telegram/src/bot-message-dispatch.ts:465, 87aa31956840)
  • Maintainer review standard requires real Telegram proof: The Telegram maintainer note says behavior PRs touching topics need real Telegram proof, preferably bot-to-bot QA or an equivalent live probe; the PR logs show patched topic replies but not the exact queued-after-supersede path. (.agents/maintainer-notes/telegram.md:37, 87aa31956840)
  • History points to followup queue and routing owners: Recent history on the relevant files includes followup delivery seam extraction, debounce/followup ordering preservation, queue callback fixes, and originating-channel followup routing. (src/auto-reply/reply/followup-runner.ts:1, 43e6c923ded1)

Likely related people:

  • steipete: Authored recent followup delivery, ordering, and routing-hardening work in the auto-reply/followup path touched by this PR. (role: recent area contributor; confidence: high; commits: 43e6c923ded1, 1b69d9ee1a51, ccbeb332e096; files: src/auto-reply/reply/followup-runner.ts, src/auto-reply/reply/get-reply-run.ts)
  • vincentkoc: Authored recent followup queue callback and singleton-state fixes adjacent to the queued followup drain behavior. (role: recent queue maintainer; confidence: medium; commits: 02e07a157d22, a35dcf608e8e, dc2013aae59f; files: src/auto-reply/reply/followup-runner.ts, src/auto-reply/reply/queue)
  • jalehman: Introduced originating-channel routing for queued followups, which is the delivery surface that drains replies back to the source chat/topic. (role: adjacent routing owner; confidence: medium; commits: 9d50ebad7d33; files: src/auto-reply/reply/followup-runner.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 87aa31956840.

@VACInc VACInc force-pushed the fix-telegram-topic-followup-queue branch from af605ff to 56b6731 Compare May 18, 2026 22:24

VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

Rebased the draft branch onto current origin/main after opening.

  • Head SHA: 56b6731d2290c19413863c52e5adf73bc8a0f4b1
  • Change after rebase: no code changes beyond replaying the same queued-followup fix onto latest main
  • Focused validation rerun: node scripts/run-vitest.mjs src/auto-reply/reply/get-reply-run.media-only.test.ts src/auto-reply/reply/followup-runner.test.ts src/auto-reply/reply/queue.collect.test.ts extensions/telegram/src/bot-message-dispatch.test.ts -> Test Files 4 passed (4), Tests 220 passed (220)

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 18, 2026
@VACInc VACInc force-pushed the fix-telegram-topic-followup-queue branch from 56b6731 to 695478d Compare May 18, 2026 22:28

VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

Refreshed the draft branch head after the proof-body update so the PR gets a clean check set.

  • Head SHA: 695478dc167f6cd54cfe318fe037837494bf832a
  • Code tree change from prior head: none; commit was amended only to refresh SHA after updating the PR body
  • Focused validation rerun: node scripts/run-vitest.mjs src/auto-reply/reply/get-reply-run.media-only.test.ts src/auto-reply/reply/followup-runner.test.ts src/auto-reply/reply/queue.collect.test.ts extensions/telegram/src/bot-message-dispatch.test.ts -> Test Files 4 passed (4), Tests 220 passed (220)

VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

Queue-mode and before/after proof for the queued-followup fix.

Queue mode is still respected

  • src/auto-reply/reply/get-reply-run.ts resolves resolvedQueue.mode first, derives activeRunQueueMode, and calls resolveActiveRunQueueAction(...) before a busy turn can be enqueued.
  • src/auto-reply/reply/agent-runner.ts only calls enqueueFollowupRun(...) when activeRunQueueAction === "enqueue-followup", and it passes the original resolvedQueue into enqueueFollowupRun(...) unchanged.
  • This patch only changes the abort metadata carried by an already accepted queued followup. It does not make interrupt, drop, steer, followup, or collect choose a different queue action.

Before proof

Setup: checked out parent d761b98adc6ff2c824b95d0b2a7a54dfa1177d18 in a separate temp worktree, applied only the new regression tests, and ran:

node scripts/run-vitest.mjs src/auto-reply/reply/get-reply-run.media-only.test.ts src/auto-reply/reply/followup-runner.test.ts

Result on old code:

Test Files  2 failed (2)
Tests  2 failed | 110 passed (112)

FAIL ... followup-runner.test.ts > does not inherit source abort signals for queued user followups
AssertionError: expected AbortSignal { aborted: true } to be undefined

FAIL ... get-reply-run.media-only.test.ts > detaches queued user requests from superseded source abort signals
AssertionError: expected AbortSignal { aborted: false } to be undefined

After proof

Ran the same command on PR head 695478dc167f6cd54cfe318fe037837494bf832a:

Test Files  2 passed (2)
Tests  112 passed (112)

This proves the pre-patch behavior both attached the source abort signal to queued user requests and re-inherited an already-aborted source signal during queued execution; the PR head removes both while leaving the queue-mode decision path intact.

@clawsweeper clawsweeper Bot added the rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. label May 18, 2026

VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels May 18, 2026

VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

Updated the PR body with redacted current live Telegram topic proof from the active patched gateway (topic:8185 inbound messages followed by outbound threadId=8185 replies) and noted that the Mantis proof lane was blocked by a conflicted Telegram bot connection.

@clawsweeper re-review

VACInc commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels May 18, 2026
@VACInc

VACInc commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #83827. Refiled with the RCA, before/after regression proof, queue-mode proof, live Telegram-topic log proof, blocked Mantis proof, and the later topic 22684 client-close classification consolidated in the new PR body.

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

Labels

mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant