Skip to content

Fix chat.abort during attachment send preprocessing#84306

Closed
nxmxbbd wants to merge 13 commits into
openclaw:mainfrom
nxmxbbd:nex/84176-chat-abort-race
Closed

Fix chat.abort during attachment send preprocessing#84306
nxmxbbd wants to merge 13 commits into
openclaw:mainfrom
nxmxbbd:nex/84176-chat-abort-race

Conversation

@nxmxbbd

@nxmxbbd nxmxbbd commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes the chat.abort / chat.send race from [Bug]: chat.abort fails when called immediately after chat.send due to race condition #84176 by registering the chat run abort controller before awaited attachment/model preprocessing, so an immediate abort can find and cancel the just-started run.
  • An aborted-before/at-dispatch send now acks terminal {runId,status:"timeout"} instead of non-terminal {status:"started"}. This prevents the Control UI and agent.wait from treating an already-cancelled run as still active.
  • Post-dispatch abort detection reads this run's own AbortController signal, not the shared chatAbortedRuns marker, so stale or cross-run same-key abort markers no longer force a fresh run to report timeout or swallow its real error. The shared marker remains in place for existing abort-tail suppression.
  • Terminal non-OK chat.send ACKs now clear the Control UI's optimistic local run/stream state through the shared run lifecycle reconciler, including the queued app-chat path. New visible sends clear stale local-terminal suppression state.
  • Scope boundary: this widens the chat.send ACK status union to include terminal "timeout"/"error" values in the Control UI ACK normalizer and forwarded skills-revision ACK schema. No new RPC method, config/auth/security/network change, or channel adapter change.

AI-assisted; contributor manually reviewed and is responsible for the change.

Linked context

Real behavior proof

  • Behavior or issue addressed:

chat.abort called immediately after an attachment chat.send now cancels the in-preprocess run, and the send returns terminal {runId,status:"timeout"} rather than a non-terminal started ACK. A post-dispatch abort also leaves terminal dedupe for duplicate same-key sends / agent.wait. A fresh same-key send after an older abort is reported from its own run signal, not from a stale shared abort marker. The Control UI clears local optimistic run/stream state when chat.send itself returns terminal timeout or error, including the queued send path.

  • Real environment tested:

Current head cd4e345a12 was exercised with real local Gateway processes started from this checkout via gateway run --allow-unconfigured on loopback, using temporary HOME/state/config directories. The attachment abort proof used the real Gateway WebSocket protocol and production chat.send / chat.abort handlers with a real PNG attachment. The browser proof used the built Control UI served by that Gateway, Chromium, and CDP WebSocket frame capture; a second real Gateway WebSocket client issued the immediate abort as soon as the browser's attachment chat.send frame was observed. The model catalog was a local test-provider entry with image support and a loopback dummy base URL; the proof intentionally aborts before provider dispatch, so no provider call is part of the expected path.

  • Exact steps or command run after this patch:
node /tmp/pr84306-real-gateway-attachment-abort.mjs /tmp/pr84306-real-gateway-abort-run.lk8NqN

OPENCLAW_BUILD_ALL_NO_PNPM=1 node scripts/ui.js build
node /tmp/pr84306-real-browser-control-ui-abort-v2.mjs /tmp/pr84306-real-browser-abort-v2-run.6p5DHN

node scripts/run-vitest.mjs run src/gateway/server.chat.gateway-server-chat-b.test.ts \
  -t "chat.abort stops an attachment send while preprocessing is still pending|smoke: supports abort and idempotent completion" \
  --reporter=dot
( cd ui && node ../node_modules/vitest/vitest.mjs run \
    src/ui/controllers/chat.test.ts src/ui/app-chat.test.ts \
    src/ui/chat/run-lifecycle.test.ts --reporter=dot )
node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json \
  --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfo
./node_modules/.bin/oxfmt --check --threads=1 \
  ui/src/ui/controllers/chat.test.ts ui/src/ui/app-chat.test.ts \
  ui/src/ui/controllers/chat.ts ui/src/ui/app-chat.ts ui/src/ui/chat/run-lifecycle.ts
git diff --check a3992f4e620cb00bb0fe705689dbfeb71033f96a..HEAD
  • Evidence after fix:

Terminal capture from a real Gateway loopback WebSocket run, copied live output:

repoHead=cd4e345a12e274ddcbf53f82c1c06c76121fa0ce
gatewayReady=true
connect.ok=true
abortResponse={"ok":true,"payload":{"ok":true,"aborted":true,"runIds":["pr84306-attach-abort-e2c29a34-6248-47ee-983f-375204f412c3"]}}
sendResponse={"ok":true,"payload":{"runId":"pr84306-attach-abort-e2c29a34-6248-47ee-983f-375204f412c3","status":"timeout"}}
duplicateSendResponse={"ok":true,"payload":{"runId":"pr84306-attach-abort-e2c29a34-6248-47ee-983f-375204f412c3","sessionKey":"agent:main:main","status":"timeout","summary":"aborted","stopReason":"rpc"}}
status=pass

Terminal capture from the real Gateway-served Control UI browser run, copied live output:

repoHead=cd4e345a12e274ddcbf53f82c1c06c76121fa0ce
gatewayReady=true
backendAbortClientConnected=true
browserConnected=true
browserAction=send attachment message; backend abort fires on observed browser chat.send frame
backendAbortResult={"ok":true,"payload":{"ok":true,"aborted":true,"runIds":["d50f2f19-010e-4478-9cc8-b04ae4afd540"]},"runId":"d50f2f19-010e-4478-9cc8-b04ae4afd540","sessionKey":"agent:main:main"}
sendResponse={"ok":true,"payload":{"runId":"d50f2f19-010e-4478-9cc8-b04ae4afd540","status":"timeout"}}
afterUiState={"connected":true,"chatSending":false,"chatRunId":null,"chatStream":null,"chatStreamStartedAt":null,"chatRunStatus":{"phase":"interrupted","runId":"d50f2f19-010e-4478-9cc8-b04ae4afd540","sessionKey":"agent:main:main"},"lastLocalTerminalReconcile":{"sessionKey":"agent:main:main","runId":"d50f2f19-010e-4478-9cc8-b04ae4afd540","phase":"interrupted","sessionStatus":"killed"},"chatError":null,"lastError":null,"stopButtonCount":0,"sendButtonDisabled":false,"sendButtonTitle":"Send","textareaDisabled":false,"attachmentPreviewCount":0}
status=pass

Redacted browser WebSocket frame capture from the same browser run shows the browser's real attachment send and terminal ACK:

[
  {
    "direction": "browser->gateway",
    "method": "chat.send",
    "params": {
      "sessionKey": "agent:main:main",
      "message": "see image",
      "deliver": false,
      "idempotencyKey": "d50f2f19-010e-4478-9cc8-b04ae4afd540",
      "attachments": [{ "type": "image", "mimeType": "image/png", "fileName": "dot.png", "content": "<redacted base64 length=92>" }]
    }
  },
  {
    "direction": "gateway->browser",
    "method": "chat.send",
    "ok": true,
    "payload": { "runId": "d50f2f19-010e-4478-9cc8-b04ae4afd540", "status": "timeout" }
  }
]

Public screenshot artifact from the same browser run, hosted outside the PR diff:

Control UI idle after terminal attachment-send abort ACK

Control UI idle after abort

Artifact branch README: https://raw.githubusercontent.com/nxmxbbd/openclaw/pr-84306-route1-proof-20260606/README.md

Image sha256: ee2fc617d12bc75eeee38ffb9868bd78ed3f7a216946270e17b75761e24ed713

Supplemental current-head focused proof runs:

Gateway focused proof on cd4e345a12:
Test Files  1 passed (1)
Tests       2 passed | 35 skipped (37)

Control UI focused proof on cd4e345a12:
Test Files  3 passed (3)
Tests       222 passed (222)

UI tsgo exit 0; oxfmt --check clean; git diff --check clean; PR-range commit identity/signature verified.
  • Observed result after fix:

A real Gateway attachment chat.send can be aborted immediately while preprocessing is still pending and returns terminal {runId,status:"timeout"} to the original chat.send caller. Duplicate same-key sends and waiters observe terminal timeout instead of a stuck non-terminal state. In the real browser run, the Control UI received the terminal timeout ACK for its own attachment send and returned to idle: chatSending:false, chatRunId:null, chatStream:null, no Stop button, enabled Send button titled Send, and no chat/login error.

  • What was not tested:

No real provider call is made in the abort proofs; the target behavior is cancellation before provider dispatch. The browser proof uses a second local Gateway WS client as the immediate abort trigger so the abort lands during preprocessing; it does not claim that a human can click the Control UI Stop button before the non-terminal ACK renders. Not tested: remote/non-loopback Gateway, real model-provider dispatch after preprocessing, or a public recording.

Known trade-offs / out of scope

  • This PR preserves the existing shared abort marker for abort-tail suppression while using each run's own AbortController signal for post-dispatch decisions; a marker generation/epoch refactor is separate scope.
  • Same-key idempotency reuse can remain sticky after an earlier cancellation; this targeted fix does not redesign broader dedupe semantics or hoist all terminal writes into abortChatRunById.

Risk checklist

Did user-visible behavior change? (Yes/No) Yes. Immediate abort now reaches in-preprocess sends, aborted sends ACK terminal timeout, and terminal ACKs clear the Control UI local active run.

Did config, environment, or migration behavior change? (Yes/No) No

Did security, auth, secrets, network, or tool execution behavior change? (Yes/No) No

What is the highest-risk area?

Cancellation/idempotency timing around early abort registration, post-dispatch abort detection, dedupe caching, and Control UI optimistic run lifecycle.

How is that risk mitigated?

Abort detection uses each run's own AbortController signal, while the shared abort marker is preserved for abort-tail suppression. Non-aborted sends keep their existing started / in_flight ACK behavior. Focused gateway and UI regressions cover pre-dispatch attachment abort, post-dispatch abort terminal dedupe, stale-marker same-key behavior, terminal ACK UI clearing, queued app-chat clearing, and widened ACK schema acceptance. The added real Gateway/browser proof exercises the user-visible terminal ACK and idle UI path outside Vitest.

Tests and validation

Commands run on current proof head cd4e345a12e274ddcbf53f82c1c06c76121fa0ce:

  • Real Gateway loopback WS attachment-abort proof --- pass.
  • Real Gateway-served Control UI browser attachment-abort proof --- pass.
  • Gateway focused proof (server.chat.gateway-server-chat-b, pre-dispatch attachment abort + loopback smoke) --- 2 tests passed.
  • Control UI focused proof (controllers/chat, app-chat, run-lifecycle) --- 222 tests passed.
  • UI tsgo typecheck --- exit 0.
  • oxfmt --check over changed UI files --- clean.
  • git diff --check a3992f4e62..HEAD --- clean.
  • Commit identity/signature over the PR range --- expected noreply identity and SSH signatures.

Regression coverage added/updated in this PR: pre-dispatch attachment abort terminal ACK + dedupe, post-dispatch own-signal abort handling, Control UI terminal ACK idle clearing for direct and queued sends, ACK normalizer preservation, and forwarded skills-revision schema acceptance/rejection.

Current review state

Current head cd4e345a12e274ddcbf53f82c1c06c76121fa0ce is live on this PR. Checks were green after the last push, but the PR still carried status: needs proof; this body refresh adds real local Gateway/browser proof for the qualitative proof blocker without changing code.

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: M proof: supplied External PR includes structured after-fix real behavior proof. labels May 19, 2026
@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 6, 2026, 7:31 AM ET / 11:31 UTC.

Summary
The branch registers chat.send abort controllers before attachment preprocessing, returns terminal timeout/error ACKs, reconciles Control UI and native client run state, canonicalizes node chat subscriptions, and updates protocol/docs/tests for the widened ACK contract.

PR surface: Source +343, Tests +1400, Docs 0, Other +391. Total +2134 across 32 files.

Reproducibility: yes. source inspection gives a high-confidence reproduction path: current main awaits attachment preprocessing before registering the abort controller, so chat.abort can miss an in-preprocess chat.send. I did not run a live repro in this read-only review.

Review metrics: 2 noteworthy metrics.

  • ACK status contract: 2 terminal statuses added: timeout, error. The public/forwarded ACK shape changes, so maintainers should consciously accept strict-client compatibility impact before merge.
  • Native runtime coverage: 3 app runtimes touched: Android, iOS, macOS. The current proof should either cover these user-visible clients or the native handling should be split before merge.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Resolve the dirty merge state against current main.
  • Update proof at c5e2cf6 or newer, covering the native terminal ACK behavior or explicitly split it out.
  • Rerun the focused Gateway, Control UI, and native tests after the rebase.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The Gateway/browser proof is strong but was captured at cd4e345, while current head c5e2cf6 adds native Android/iOS/macOS behavior that is not shown in a real setup. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P2] The PR intentionally widens chat.send and forwarded Skill Workshop ACK statuses to terminal timeout/error, so strict clients or downstream consumers that assumed only started/in_flight/ok need compatibility acceptance.
  • [P1] Cancellation, idempotency, duplicate-send, and agent.wait behavior now depend on terminal dedupe writes and per-run AbortController signal checks, which is session-state-sensitive even though focused tests cover the intended paths.
  • [P1] Node chat subscription canonicalization changes how raw and canonical session keys receive chat events; that is message-delivery-sensitive and should be accepted as part of this fix, not treated as incidental churn.
  • [P1] Live GitHub reports mergeable:false and mergeable_state:dirty, so the exact merge result still needs a conflict-resolution review.
  • [P1] The supplied real Gateway/browser proof is strong for cd4e345, but current head c5e2cf6 adds Android, iOS, and macOS terminal ACK handling that is not covered by current-head real behavior proof.

Maintainer options:

  1. Refresh and land the lifecycle contract (recommended)
    Resolve conflicts, update current-head proof for the native and Control UI terminal ACK behavior, then merge if maintainers accept timeout/error as chat.send terminal ACK statuses.
  2. Split the native follow-up
    If maintainers want a smaller landing surface, keep the Gateway and Control UI race fix here and move Android/iOS/macOS terminal ACK handling into a separately proved follow-up.
  3. Pause on the public ACK shape
    If timeout/error should not be exposed from chat.send ACKs, pause this PR and redesign the client-visible terminal signal before merging.

Next step before merge

  • [P1] Human maintainer review is needed because the PR is dirty, proof is stale for the current head, and the fix changes compatibility-sensitive ACK/session/message-delivery contracts.

Security
Cleared: No concrete security or supply-chain regression was found; the diff does not change dependencies, workflows, secrets, auth, or downloaded code execution, and the new staged-media cleanup stays within a resolved workspace root.

Review details

Best possible solution:

Resolve the dirty merge, refresh real behavior proof at the current head or split out the native changes, and land only after maintainers accept the terminal ACK lifecycle contract.

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

Yes, source inspection gives a high-confidence reproduction path: current main awaits attachment preprocessing before registering the abort controller, so chat.abort can miss an in-preprocess chat.send. I did not run a live repro in this read-only review.

Is this the best way to solve the issue?

Yes, early abort registration plus terminal ACK propagation is a maintainable fix shape for the race, but the exact timeout/error ACK contract and node subscription canonicalization need maintainer acceptance before merge.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 74331f632b93.

Label changes

Label changes:

  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The Gateway/browser proof is strong but was captured at cd4e345, while current head c5e2cf6 adds native Android/iOS/macOS behavior that is not shown in a real setup. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • remove proof: sufficient: Current real behavior proof status is insufficient, not sufficient.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦪 silver shellfish, so this older rating label is no longer current.
  • remove status: 👀 ready for maintainer look: Current PR status label is status: 📣 needs proof.

Label justifications:

  • P2: This is a normal-priority race fix for chat abort/session lifecycle behavior with limited but real user-facing impact.
  • merge-risk: 🚨 compatibility: The diff widens chat.send-derived ACK statuses to timeout/error for clients and a forwarded protocol schema.
  • merge-risk: 🚨 message-delivery: The diff changes node chat subscription key canonicalization and delivery matching for chat events.
  • merge-risk: 🚨 session-state: The diff changes abort, dedupe, active-run, local-run clearing, and agent.wait terminal-state behavior.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The Gateway/browser proof is strong but was captured at cd4e345, while current head c5e2cf6 adds native Android/iOS/macOS behavior that is not shown in a real setup. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +343, Tests +1400, Docs 0, Other +391. Total +2134 across 32 files.

View PR surface stats
Area Files Added Removed Net
Source 11 445 102 +343
Tests 8 1417 17 +1400
Docs 1 1 1 0
Config 0 0 0 0
Generated 0 0 0 0
Other 12 454 63 +391
Total 32 2317 183 +2134

What I checked:

Likely related people:

  • vincentkoc: Blame and local path history for the current Gateway chat send, UI ACK normalization, and node subscription code point to Vincent Koc's recent work; the history is grafted, so this is best treated as routing signal rather than sole ownership. (role: recent area contributor; confidence: medium; commits: f94e4f85f070; files: src/gateway/server-methods/chat.ts, ui/src/ui/controllers/chat.ts, src/gateway/server-node-subscriptions.ts)
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.

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.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 19, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 19, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. P2 Normal backlog priority with limited blast radius. labels May 19, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Neon Branchling

Hatched PR egg: 🥚 common Neon Branchling

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: hums during re-review.
Image traits: location release reef; accessory green check lantern; palette coral, mint, and warm cream; mood mischievous; pose curling around a status light; shell smooth pearl shell; lighting calm overcast light; background subtle branch markers.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Neon Branchling in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@nxmxbbd

nxmxbbd commented May 24, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper hatch

@clawsweeper

clawsweeper Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper PR egg hatch requested.

I queued a comment sync for this PR. If the egg is hatchable, ClawSweeper will generate the image once and update the existing review comment.
Action: PR egg hatch queued (workflow sweep.yml, event repository_dispatch).
The ASCII egg stays as the fallback.

@RomneyDa

Copy link
Copy Markdown
Member

Heads up: this PR needs to be updated against current main before the new required Dependency Guard check can pass.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 29, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 29, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 30, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 30, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 1, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. and removed rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 1, 2026
nxmxbbd added 4 commits June 6, 2026 01:18
…spatch abort

A chat.send aborted before dispatch (during attachment preprocessing) or after
dispatch reported a non-terminal {status:"started"} for both the chat.send
response and the chat:${runId} dedupe entry. That left the Control UI adopting
an already-aborted run (stuck "busy") and agent.wait callers hanging until their
own timeout instead of observing the abort.

Report the terminal outcome instead, reusing the existing
{status:"timeout", stopReason} shape sessions.abort already writes (no new status
invented): the pre-dispatch abort branches respond terminal and write a terminal
dedupe entry, and the post-dispatch completion guard records the terminal abort
instead of skipping the dedupe write. A "rpc"/"stop" stopReason classifies as a
sticky cancellation so a late started/in_flight write cannot resurrect the run.

UI: preserve terminal ack statuses through normalizeChatSendAck (previously
coerced to "started") and gate adopt-vs-clear on the shared
isNonTerminalAgentRunStatus predicate (three-way: non-terminal adopts, "ok"
completes, terminal does nothing since the abort broadcast already drove the
lifecycle).

Related openclaw#84176.
…t terminal dedupe

Follow-up to the chat.send terminal-abort fix: skills.proposals.requestRevision
forwards the chat.send ack, so widen SkillsProposalRequestRevisionResultSchema's
status union to include the terminal "timeout"/"error" statuses the abort fix can
now return through that public method.

Also: add a schema regression test for the widened union, add a post-dispatch
abort dedupe assertion (duplicate send after a post-dispatch abort observes the
terminal outcome), and tighten the dedupe comment to note that maintenance-driven
"timeout" aborts are terminal but not sticky.

Related openclaw#84176.
…oc the abort ack

Address the remaining low-severity review follow-ups for the chat.send terminal
abort fix:

- gateway: the post-dispatch .catch handler now records the terminal abort
  outcome (and skips the redundant chat error broadcast) when the run was already
  aborted, matching the .then completion guard, so a dispatch that throws under
  abort no longer reports a spurious error instead of the cancellation.
- ui: export normalizeChatSendAck and add tests that it preserves terminal
  statuses (timeout/error) instead of coercing them to "started", plus a
  controller test that a terminal send ack is not adopted as an active run (the
  3-way adopt gate).
- docs: note the terminal {status:"timeout"} ack for sends aborted before/at
  dispatch in the Control UI send semantics.

Related openclaw#84176.
…ller signal

A reused idempotencyKey is the chat run id (clientRunId), and the shared
chatAbortedRuns marker is keyed by it. The marker lives ~60min while the
chat:<runId> dedupe lives only ~5min, and it is also reused by any prior or
concurrent same-key run. The post-dispatch completion/throw handlers read that
marker to decide whether to write a terminal abort dedupe, so a stale or
cross-run marker made a fresh same-key run report a false {status:"timeout"} and
the .catch swallow a real error as a false abort.

Fix the post-dispatch guards to read THIS run's own AbortController signal
(activeRunAbort.controller.signal.aborted) instead of the shared marker,
mirroring the pre-dispatch abort checks. Only a genuine abort of this run sets
its controller (abortChatRunById is the sole production setter), so a stale
marker no longer misclassifies it, and the shared marker is left untouched so
server-chat abort-tail suppression and concurrent same-key sends are unaffected.

Also log the swallowed error in the .catch-under-abort branch so a real failure
coinciding with an abort is not lost; skip seeding refreshSessionsAfterChat for
terminal acks since the clearing chat-state event never arrives; and tighten the
dedupe-shape comment.

Adds regression coverage: a fresh same-key run with a stale marker present
completes terminal-ok / surfaces a real error instead of a false timeout (marker
left intact), and terminal acks no longer seed the deferred session refresh.

Issue openclaw#84176.
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed proof: supplied External PR includes structured after-fix real behavior proof. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 5, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 5, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 5, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 5, 2026
@nxmxbbd
nxmxbbd marked this pull request as draft June 5, 2026 21:22
@nxmxbbd
nxmxbbd marked this pull request as ready for review June 6, 2026 05:10
@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 6, 2026
@nxmxbbd

nxmxbbd commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 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:

@nxmxbbd

nxmxbbd commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

Closing this since the original issue was fixed on main in 6ace7a6. I'll follow up separately with smaller current-main issues/PRs for any remaining terminal chat.send ACK/client-side gaps that still reproduce.

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

Labels

app: android App: android app: ios App: ios app: macos App: macos app: web-ui App: web-ui docs Improvements or additions to documentation gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XL 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.

[Bug]: chat.abort fails when called immediately after chat.send due to race condition

2 participants