Skip to content

fix(gateway): preserve abort after dispatch rejection#91000

Open
nxmxbbd wants to merge 45 commits into
openclaw:mainfrom
nxmxbbd:repair/post84306-abort-throw-20260607T025542
Open

fix(gateway): preserve abort after dispatch rejection#91000
nxmxbbd wants to merge 45 commits into
openclaw:mainfrom
nxmxbbd:repair/post84306-abort-throw-20260607T025542

Conversation

@nxmxbbd

@nxmxbbd nxmxbbd commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes #90999.

chat.send can receive a dispatch rejection after an explicit chat.abort has already made the run terminal. In that ordering, the later rejection can replace the cached aborted result with status: "error" and send a contradictory error terminal to clients.

Why This Change Was Made

The dispatch-error path now chooses terminal ownership before asynchronous fallback work. An explicit abort marker retains its aborted result; a dispatch error retains its error result when no abort marker owns the run; and a real agent lifecycle terminal remains the sole live terminal projection. The change also keeps queued-followup and restart-safe session-admission cleanup on their existing ownership paths.

The diff is limited to five Gateway dispatch/admission files and their regression coverage. It does not change provider routing, authentication, protocol schemas, or client APIs.

User Impact

Clients observing an explicitly aborted chat.send no longer receive a later contradictory error terminal when the original dispatch rejects. The error-first path remains an error, and a signal-only lifecycle interruption still exposes its lifecycle terminal without a duplicate client-visible error.

Related: #84176 and #84306.

Evidence

Full E2E: partial. The proof starts a real local Gateway server and connects a real WebSocket RPC client. It exercises production chat.send / chat.abort handling, runtime lifecycle event subscription, WebSocket transport, and client-visible chat broadcasts. Dispatch rejection is the controlled boundary; no live provider/model, browser UI, or native client was used.

Refresh head: adc576fd19e1c40f08cbb2549a906209e63c0238.

Current main at preparation: f6653d1127820c202a8f9cb0b0b8685c20fe84b2. The merge tree for current main plus this head is clean (f9af0f067d6b70ef71511183d4ca73cd45c20c60), and the PR-style diff contains only:

src/gateway/server-methods/chat-send-admission.ts
src/gateway/server-methods/chat-send-attachments.ts
src/gateway/server-methods/chat-send-dispatch-errors.test.ts
src/gateway/server-methods/chat-send-dispatch-errors.ts
src/gateway/server.chat.gateway-server-chat-b.test.ts

Commands run against the refresh head:

node_modules/.bin/oxlint <the five files above>
node_modules/.bin/oxfmt --check <the five files above>
git diff --check f6653d1127820c202a8f9cb0b0b8685c20fe84b2...adc576fd19e1c40f08cbb2549a906209e63c0238
OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server.chat.gateway-server-chat-b.test.ts
OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/pr91000-adc576-websocket-proof.diagnostic.test.ts

Observed results:

oxlint: 0 warnings, 0 errors
oxfmt --check: all matched files correctly formatted
git diff --check: no output
Gateway B: 89 passed
Real Gateway/WebSocket: 3 projects, 9 passed
abort-first terminal: ["aborted"]
error-first late-abort terminal: ["error"]
signal-only lifecycle terminal after observed dispatch rejection: ["aborted"]

The exact-head WebSocket proof uses a real Gateway server and WebSocket RPC client. It verifies that an abort-first rejection has no error terminal, an error-first late abort remains error, and a signal-only lifecycle terminal remains the only client-visible terminal after the controlled dispatch rejection.

What was not tested: live provider/model execution, browser UI, and native clients.

@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 Jun 6, 2026
@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 15, 2026, 10:05 PM ET / July 16, 2026, 02:05 UTC.

Summary
The PR updates Gateway admission, attachment preparation, dispatch-rejection handling, and regression coverage so abort, dispatch error, and agent-lifecycle races retain a single terminal result.

PR surface: Source +92, Tests +1402. Total +1494 across 5 files.

Reproducibility: yes. —the source-level reproduction deterministically starts dispatch, aborts the same run, and then rejects dispatch; the supplied after-fix real Gateway/WebSocket proof exercises the corresponding observable terminal results. The current exact merge result still needs rerunning because the branch is behind main.

Review metrics: 1 noteworthy metric.

  • Terminal race scenarios: 3 real Gateway/WebSocket orderings proven. The proof separately covers abort-first rejection, error-first late abort, and signal-only lifecycle interruption rather than demonstrating only the happy path.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #90999
Summary: This PR is the active candidate fix for the linked post-dispatch rejection bug; adjacent abort and dispatch-lifecycle items share surfaces but do not replace the exact fix.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

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

Rank-up moves:

  • Obtain Gateway owner confirmation of the terminal-owner precedence and its relationship to the canonical agent terminal-outcome path.
  • Rebase onto current main and rerun the focused Gateway suite plus the three real WebSocket orderings against the exact merge result.

Risk before merge

  • [P1] Merging the wrong terminal precedence could replace an explicit abort or observed lifecycle terminal with a contradictory dispatch error, affecting dedupe results, session status, and client-visible terminal broadcasts.
  • [P1] The branch is behind current main, so its clean historical merge tree and proof do not settle whether the exact current merge result still preserves queued-followup, restart-safe admission, transcript, and lifecycle cleanup ownership.
  • [P1] The patch implements Gateway-local terminal-owner selection near a repository-wide canonical terminal-outcome invariant; owner review should confirm this is the correct boundary rather than a second precedence implementation.

Maintainer options:

  1. Confirm invariant and refresh proof (recommended)
    Have the Gateway owner approve the terminal precedence, rebase onto current main, and validate the exact merge result with focused tests and the three WebSocket orderings.
  2. Centralize terminal precedence
    Refactor the ownership choice through the canonical terminal-outcome path if Gateway-local state would otherwise duplicate cancellation and error precedence.
  3. Pause if ownership remains disputed
    Do not merge until maintainers agree which layer owns abort, lifecycle, and dispatch-error terminal selection.

Next step before merge

  • [P2] No narrow mechanical defect remains; a Gateway owner must confirm terminal precedence and require exact current-main merge-result validation before merge.

Maintainer decision needed

  • Question: Should Gateway dispatch rejection use this precedence on current main—an explicit abort or established lifecycle terminal retains ownership, while dispatch error owns only runs without either terminal owner?
  • Rationale: Green tests cannot choose the product-level terminal semantics when abort, agent lifecycle, dedupe, session persistence, and restart-safe admission race; the relevant Gateway owner must confirm the invariant and its ownership boundary.
  • Likely owner: jesse-merhi — Their merged dispatch-failure lifecycle work is the closest current-main provenance for the terminal session behavior this PR changes.
  • Options:
    • Approve and validate precedence (recommended): Confirm this terminal-owner ordering, rebase onto current main, and rerun the focused Gateway plus real WebSocket scenarios against the exact merge result.
    • Refactor through shared outcome logic: Require the Gateway decision to consume or extend the canonical agent terminal-outcome helper before merge so precedence cannot drift across projections.
    • Pause for broader ownership design: Hold the PR if abort, lifecycle, and dispatch-error terminals need a wider redesign spanning Gateway dedupe and persisted session state.

Security
Cleared: The five-file Gateway and test diff adds no dependency, workflow, permission, secret, install, package-resolution, or external code-execution surface.

Review details

Best possible solution:

Use one explicitly approved terminal-owner invariant—preferably shared with the canonical agent terminal-outcome normalization where practical—then rebase and prove abort-first, error-first, lifecycle-terminal, queued-followup, and restart-safe paths on the exact merge result.

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

Yes—the source-level reproduction deterministically starts dispatch, aborts the same run, and then rejects dispatch; the supplied after-fix real Gateway/WebSocket proof exercises the corresponding observable terminal results. The current exact merge result still needs rerunning because the branch is behind main.

Is this the best way to solve the issue?

Unclear—the bounded patch and proof are convincing, but repository policy favors canonical terminal-outcome normalization, so the Gateway owner should confirm that this local ownership layer is the narrowest maintainable boundary.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 154d53c4f6fc.

Label changes

Label justifications:

  • P2: This is a bounded Gateway correctness fix for contradictory terminal state with limited but real client and session impact.
  • merge-risk: 🚨 message-delivery: An incorrect precedence can emit a contradictory late error terminal after an abort or duplicate the client-visible terminal projection.
  • merge-risk: 🚨 session-state: The changed path controls dedupe payloads, persisted lifecycle terminalization, active-run cleanup, and restart-safe session admission.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR supplies after-fix live output from a real local Gateway and WebSocket RPC client for all three relevant terminal orderings; the later head change is test typing only and does not alter runtime behavior.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR supplies after-fix live output from a real local Gateway and WebSocket RPC client for all three relevant terminal orderings; the later head change is test typing only and does not alter runtime behavior.
Evidence reviewed

PR surface:

Source +92, Tests +1402. Total +1494 across 5 files.

View PR surface stats
Area Files Added Removed Net
Source 3 125 33 +92
Tests 2 1569 167 +1402
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 5 1694 200 +1494

What I checked:

Likely related people:

  • jesse-merhi: Their merged work in Fix WebChat dispatch failure session status #84352 established the session terminalization and sessions.changed behavior that the current dispatch-error owner logic must preserve. (role: introduced adjacent dispatch-failure lifecycle behavior; confidence: high; commits: 92c10d4edcad; files: src/gateway/server-methods/chat.ts, src/gateway/server-methods/chat-send-dispatch-errors.ts, src/gateway/server.chat.gateway-server-chat-b.test.ts)
  • nxmxbbd: Beyond authoring this proposal, they previously contributed the merged structured abort-marker ordering in fix(gateway): ignore stale abort markers for fresh chat events #91013, which is directly adjacent to the terminal-owner invariant. (role: recent abort-marker and Gateway lifecycle contributor; confidence: high; commits: cd98f195a709; files: src/gateway/server-chat-state.ts, src/gateway/server-chat.ts, src/gateway/server-close.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.
Review history (9 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-05T07:40:02.876Z sha 7e05517 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T08:01:53.389Z sha 7e05517 :: needs real behavior proof before merge. :: [P2] Fix the broadcast mock typing in the new Gateway test
  • reviewed 2026-07-05T08:07:52.017Z sha 5e2378a :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T08:14:25.808Z sha 5e2378a :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T09:56:05.552Z sha 5e2378a :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T10:09:11.008Z sha 5e2378a :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T11:48:23.263Z sha 5c2e32c :: needs maintainer review before merge. :: none
  • reviewed 2026-07-10T20:11:29.301Z sha c0d19fe :: needs maintainer review before merge. :: none

@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. P2 Normal backlog priority with limited blast radius. 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. labels Jun 6, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. 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. and removed 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. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 14, 2026
@clawsweeper clawsweeper Bot added the rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. label Jul 10, 2026
nxmxbbd added 25 commits July 14, 2026 00:16
@openclaw-barnacle openclaw-barnacle Bot added size: XL and removed app: web-ui App: web-ui size: L labels Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime 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: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: post-dispatch chat.send rejection can overwrite terminal abort

2 participants