Skip to content

fix(discord): reset progress drafts across queued turns#102341

Merged
steipete merged 14 commits into
openclaw:mainfrom
xialonglee:fix/issue-100782-tool-results-image
Jul 11, 2026
Merged

fix(discord): reset progress drafts across queued turns#102341
steipete merged 14 commits into
openclaw:mainfrom
xialonglee:fix/issue-100782-tool-results-image

Conversation

@xialonglee

@xialonglee xialonglee commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Discord progress previews could be collapsed more than once when a turn emitted repeated final payloads. The original collapse latch also remained sticky across queued turns, while receipt state was consumed before Discord confirmed delivery. Together those paths could duplicate activity receipts, lose a receipt on retry, or leave a queued turn using stopped/stale draft state.

Why This Change Was Made

This rewrite makes the lifecycle turn-scoped and commit-based:

  • collapse eligibility is consumed only after a receipt-bearing final is accepted by Discord;
  • failed delivery retains the receipt for retry;
  • a genuine queued turn resets the compositor gate, activity counters, final-delivery latches, and draft identity together;
  • Discord preview creates carry a generation, so a stale in-flight REST completion cannot adopt or stop the next turn's stream;
  • old synthetic controller tests were replaced with process-level and real draft-stream regression coverage.

This is intentionally not marked as fixing #100782. That report's image-placeholder symptom was previously attributed to the collapse latch without evidence; the behavior proven here is Discord progress receipt and queued-draft lifecycle correctness.

User Impact

Discord progress turns now produce exactly one activity receipt. A failed final can retry without losing the receipt, queued tool turns get a fresh preview and independent counters, and queued text-only turns do not receive a synthetic tool receipt. Late completion of an older preview create cannot corrupt the active turn.

Evidence

  • Exact-head sanitized AWS Crabbox (run_9e35ddfb3915): 150 focused Discord/compositor tests passed on Linux Node 24, including repeated finals, delivery retry, queued tool/text turns, cleanup, stale-create races, and block-mode preservation.
  • Fresh autoreview: clean; no accepted/actionable findings.
  • Exact-head GitHub Actions: lint, types, channel contracts, build, security, and runtime shards required by the native landing gate.

Live-proof gap: the current Discord canary verifies transport connectivity but does not drive deterministic multi-tool progress plus queued retry behavior. The regression is therefore proven at the real message-process and REST draft-stream boundaries, not claimed as a live end-to-end Discord scenario.

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord size: S labels Jul 9, 2026
@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: stale review; fresh review needed.

Summary
The latest durable ClawSweeper review was for head ab369bdd4ac7d2b4715f1c66962636a7b0cd0a70, but the PR head is now 9d19ae11ba60b3c066455209f26639f472f7ad13. Its old verdict and PR readiness labels are no longer current.

Next step
Run or wait for a fresh ClawSweeper review on the current PR head.

Review history (7 earlier review cycles)
  • reviewed 2026-07-09T01:52:17.839Z sha cbeddc7 :: needs real behavior proof before merge. :: [P1] Use supported table and chunk modes in the test helper
  • reviewed 2026-07-09T02:54:36.411Z sha cbeddc7 :: needs real behavior proof before merge. :: [P1] Use supported table and chunk modes in the test helper
  • reviewed 2026-07-09T06:32:58.582Z sha e4fba3e :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-09T06:47:59.870Z sha e4fba3e :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-09T08:57:07.126Z sha 5dd74f5 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-10T09:55:57.389Z sha 5dd74f5 :: needs real behavior proof before merge. :: [P1] Wire the guard into the current progress-collapse path
  • reviewed 2026-07-11T08:27:31.318Z sha 5dd74f5 :: needs real behavior proof before merge. :: [P1] Wire the guard into the progress-collapse path

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jul 9, 2026
@xialonglee
xialonglee marked this pull request as draft July 9, 2026 02:49
@xialonglee
xialonglee marked this pull request as ready for review July 9, 2026 08:27
@xialonglee
xialonglee marked this pull request as draft July 10, 2026 02:31
@steipete steipete self-assigned this Jul 11, 2026
xialonglee and others added 4 commits July 11, 2026 09:51
… cleaned stream

Commit 86ea382 added a progressDraftStartedBeforeFinal latch that snapshots
hasStarted at markFinalReplyStarted time. This correctly preserves collapse
eligibility when an abort cancels the compositor gate before
shouldCollapseProgressDraft runs.

However the latch was never cleared. After markPreviewFinalized turned the
draft into a summary, hasProgressDraftStarted remained true permanently. In
multi-tool turns with multiple final-payload deliveries, this caused
shouldCollapseProgressDraft to re-trigger collapse on an already-cleaned or
sealed draft stream, corrupting downstream delivery state and causing tool
results to render as image content blocks instead of text.

Fix: add a progressDraftCollapsed guard set by markPreviewFinalized that
prevents hasProgressDraftStarted from returning true after the draft has been
collapsed into a summary. Reset the guard on handleAssistantMessageBoundary
so followup/queued turns start fresh.

Per Discord channel session, all tool results rendered as image content
blocks. Model received (see attached image) placeholders instead of text.

Fixes openclaw#100782

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@steipete
steipete force-pushed the fix/issue-100782-tool-results-image branch from 5dd74f5 to 2041038 Compare July 11, 2026 08:53
@xialonglee
xialonglee marked this pull request as ready for review July 11, 2026 08:56
@clawsweeper clawsweeper Bot removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 11, 2026
@steipete steipete changed the title fix(discord): guard progress draft collapse to prevent re-collapse on cleaned stream fix(discord): reset progress drafts across queued turns Jul 11, 2026
@steipete

steipete commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Land-ready maintainer verification for final PR head 9d19ae11ba60b3c066455209f26639f472f7ad13:

Known proof gap: the passed live Discord canary does not drive deterministic multi-tool progress plus queued retry behavior. I am not claiming that narrower scenario as live E2E proof; the regression is covered at the real message-process and Discord REST draft-stream boundaries.

@steipete
steipete requested a review from a team as a code owner July 11, 2026 09:50
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: macos App: macos app: web-ui App: web-ui cli CLI command changes scripts Repository scripts commands Command implementations extensions: codex size: XL and removed size: M labels Jul 11, 2026
duplex: "half",
});
} as RequestInit & { duplex: "half" };
const upstreamRes = await fetch(upstreamUrl, upstreamInit);
@steipete
steipete merged commit ef95c5d into openclaw:main Jul 11, 2026
156 of 163 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

@xialonglee
xialonglee deleted the fix/issue-100782-tool-results-image branch July 11, 2026 10:03
vincentkoc added a commit that referenced this pull request Jul 11, 2026
* origin/main:
  fix(cron): abort superseded reconciliation hooks (#104368)
  ci(release): expose Telegram runtime preflight stage (#104387)
  fix(status): avoid false shell-wrapper audit warnings (#81778)
  fix: retry live Gateway readiness proof (#104374)
  fix(exec-approval): stop misattributing Allow Always unavailability to policy (#97740)
  fix: preserve Mac bundle during live builds (#104376)
  chore(docs): translate with GPT-5.6 xhigh
  test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface (#104361)
  fix(ui): hide group submenu separator when New group is the only entry (#104370)
  fix(discord): reset progress drafts across queued turns (#102341)
  docs(cli): clarify that exec-policy show and approvals get exclude per-session /exec overrides (#94999)
  fix(discord): single-source thread-binding default placement and guard artifact parity (#104342)
  fix(agents): add tool-activity heartbeat to keep subagent alive during tool calls (#95536)
  fix(maint): reuse recent same-PR hosted gates (#104355)
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 12, 2026
)

* fix(discord): guard progress draft collapse to prevent re-collapse on cleaned stream

Commit c23e391 added a progressDraftStartedBeforeFinal latch that snapshots
hasStarted at markFinalReplyStarted time. This correctly preserves collapse
eligibility when an abort cancels the compositor gate before
shouldCollapseProgressDraft runs.

However the latch was never cleared. After markPreviewFinalized turned the
draft into a summary, hasProgressDraftStarted remained true permanently. In
multi-tool turns with multiple final-payload deliveries, this caused
shouldCollapseProgressDraft to re-trigger collapse on an already-cleaned or
sealed draft stream, corrupting downstream delivery state and causing tool
results to render as image content blocks instead of text.

Fix: add a progressDraftCollapsed guard set by markPreviewFinalized that
prevents hasProgressDraftStarted from returning true after the draft has been
collapsed into a summary. Reset the guard on handleAssistantMessageBoundary
so followup/queued turns start fresh.

Per Discord channel session, all tool results rendered as image content
blocks. Model received (see attached image) placeholders instead of text.

Fixes openclaw#100782

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix(discord): use valid table/chunk mode literals in collapse-guard tests

* test(discord): add abort-race gate-cancellation latch survival test

* fix(discord): consume progress draft collapse once

Co-authored-by: xialonglee <[email protected]>

* fix(discord): retain progress receipt on retry

Co-authored-by: xialonglee <[email protected]>

* fix(discord): rearm queued progress drafts

Co-authored-by: xialonglee <[email protected]>

* test(discord): assert progress lifecycle outcomes

Co-authored-by: xialonglee <[email protected]>

* fix(discord): reset queued progress turn state

Co-authored-by: xialonglee <[email protected]>

* test(discord): model recreated progress drafts

Co-authored-by: xialonglee <[email protected]>

* fix(discord): serialize progress draft rotation

Co-authored-by: xialonglee <[email protected]>

* fix(discord): isolate queued draft generations

Co-authored-by: Peter Lee <[email protected]>

* test(discord): align synchronous draft rotation

Co-authored-by: Peter Lee <[email protected]>

* fix(discord): distinguish draft rotation ownership

Co-authored-by: Peter Lee <[email protected]>

* chore: keep release notes in pull request

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 12, 2026
* origin/main:
  fix(cron): abort superseded reconciliation hooks (openclaw#104368)
  ci(release): expose Telegram runtime preflight stage (openclaw#104387)
  fix(status): avoid false shell-wrapper audit warnings (openclaw#81778)
  fix: retry live Gateway readiness proof (openclaw#104374)
  fix(exec-approval): stop misattributing Allow Always unavailability to policy (openclaw#97740)
  fix: preserve Mac bundle during live builds (openclaw#104376)
  chore(docs): translate with GPT-5.6 xhigh
  test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface (openclaw#104361)
  fix(ui): hide group submenu separator when New group is the only entry (openclaw#104370)
  fix(discord): reset progress drafts across queued turns (openclaw#102341)
  docs(cli): clarify that exec-policy show and approvals get exclude per-session /exec overrides (openclaw#94999)
  fix(discord): single-source thread-binding default placement and guard artifact parity (openclaw#104342)
  fix(agents): add tool-activity heartbeat to keep subagent alive during tool calls (openclaw#95536)
  fix(maint): reuse recent same-PR hosted gates (openclaw#104355)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: macos App: macos app: web-ui App: web-ui channel: discord Channel integration: discord cli CLI command changes commands Command implementations docs Improvements or additions to documentation extensions: codex P1 High-priority user-facing bug, regression, or broken workflow. scripts Repository scripts size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants