Skip to content

fix(ui): keep composer on Send when run-status toast expires (#88033)#91680

Closed
tiffanychum wants to merge 3 commits into
openclaw:mainfrom
tiffanychum:fix/88033-composer-stop-toast-expiry
Closed

fix(ui): keep composer on Send when run-status toast expires (#88033)#91680
tiffanychum wants to merge 3 commits into
openclaw:mainfrom
tiffanychum:fix/88033-composer-stop-toast-expiry

Conversation

@tiffanychum

@tiffanychum tiffanychum commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #88033

AI-assisted: Yes (Codex)

What Problem This Solves

After a reply visibly completed, delayed session metadata could make the Control UI composer switch from Send back to Stop when the five-second terminal status expired. A later unrelated session update could restore the same stale active row again.

Why This Change Was Made

Gateway session projections now carry the deterministic ids of visible active runs, including direct agent lifecycle start and terminal events. The local-completion guard runs when the terminal status mask expires and whenever either session-state publication path can republish canonical rows, but it suppresses a row only when its sole active run id exactly matches the completed run. The identity is retained across missing/disconnected session results until Gateway publishes terminal state or a different run; no browser/Gateway wall-clock comparison or arbitrary expiry is involved.

This rewrites the original suggestion around one shared invariant, covers both SessionCapability subscription updates and direct sessions.changed reconciliation, and fails safe when an older Gateway does not provide run identity.

User Impact

Once a completed reply returns the composer to Send, stale poll data can no longer make it revert to Stop. Real follow-up runs still show Stop and retain their stream.

Evidence

  • Red proof on current main, Blacksmith Testbox tbx_01kwt3gy25f6vrxsven71k22mz: the Chromium scenario failed after toast expiry with one unexpected Stop control.
  • Same Testbox after the fix: focused Gateway/session projection and agent-event suites plus the surrounding chat suites (284 Gateway test executions and 248 UI assertions pass).
  • Same Testbox after the fix: repository UI E2E wrapper for ui/src/e2e/chat-run-lifecycle.e2e.test.ts (Chromium, 1/1 pass).
  • Same Testbox: corepack pnpm check:changed (pass).
  • In-app browser live proof: after the production timer plus a second exact stale-run publication beyond the former 10-second window, Send remained visible and enabled and Stop remained absent.
  • Fresh autoreview findings were accepted and fixed: canonical session republish coverage, preservation of an adopted follow-up run, removal of cross-host timestamp ordering and timeout heuristics, and retention across missing session results.
  • git diff --check (pass).

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 9, 2026
@clawsweeper

clawsweeper Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close this PR as superseded: the useful Gateway/UI active-run identity fix is now carried by the clean open replacement at #100527, while this branch still includes unrelated Swift auth, outbound action, and changelog changes that should not land with the composer-state fix.

Root-cause cluster
Relationship: superseded
Canonical: #100527
Summary: This PR is superseded by the open clean maintainer PR for the same WebChat composer stale-run identity fix; the linked issue remains the bug being fixed.

Members:

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

Canonical path: Use #100527 as the canonical landing path, preserve the contributor credit there, and leave #88033 open until a clean fix merges.

So I’m closing this here and keeping the remaining discussion on #100527 and #88033.

Review details

Best possible solution:

Use #100527 as the canonical landing path, preserve the contributor credit there, and leave #88033 open until a clean fix merges.

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

Yes at source/proof level: current main lacks the toast-expiry identity-bound reconciliation, the linked issue reports the Send-to-Stop relapse after completion, and the PR body plus proof workflow show a red/green browser/Testbox path. I did not rerun live browser proof in this read-only cleanup pass.

Is this the best way to solve the issue?

No for this branch: the identity-bound Gateway/UI design is the right fix, but this PR is no longer the best landing vehicle because the clean replacement carries the same useful work without unrelated auth, outbound, or changelog changes.

Security review:

Security review needs attention: The branch includes an unrelated security-sensitive OpenClawKit device-token retry host-trust change, so the current PR should not be used as the landing candidate.

  • [medium] Unrelated auth retry boundary change — apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift:1200
    The Swift diff changes when stored device-token retry is trusted for loopback hosts, which is auth boundary behavior unrelated to the Control UI session-state fix and not present in the clean replacement PR.
    Confidence: 0.86

AGENTS.md: found and applied where relevant.

What I checked:

  • Repository policy read: Root and scoped UI/Gateway/outbound AGENTS.md files were read; release-owned changelog, session-state merge risk, security-sensitive auth boundaries, and superseded-PR cleanup guidance shaped the review. (AGENTS.md:28, eda9b9fb1858)
  • Current main still has the underlying race surface: On current main, scheduleRunStatusClear clears chatRunStatus and requests an update without re-running stale session-state reconciliation at terminal-toast expiry. (ui/src/pages/chat/run-lifecycle.ts:184, eda9b9fb1858)
  • Current main lacks active run identity payloads: Current main's session-active-runs helper reports only booleans and does not expose activeRunIds, so the identity-bound fix is not already implemented on main. (src/gateway/server-methods/session-active-runs.ts:19, eda9b9fb1858)
  • This PR branch is polluted beyond the stated fix: Live PR file inspection shows 23 changed files, including CHANGELOG.md, two OpenClawKit Swift auth files, and two outbound message-action files that are absent from the clean replacement PR. (b039925e8c34)
  • Clean replacement PR owns the useful fix: fix(ui): bind stale run state to run identity #100527 is open, mergeable, labeled maintainer, contains the same 18 Gateway/UI run-identity files without the unrelated branch changes, and has a successful Real behavior proof check. (ba84e085e4c3)
  • Maintainer provenance for supersession: The replacement PR body says it supersedes this PR because the contributor fork could not retain clean rebased ancestry, and preserves contributor credit through co-authorship. (ba84e085e4c3)

Likely related people:

  • steipete: Authored the clean replacement commit, is assigned on this PR, and left the maintainer pass that led to the superseding PR. (role: replacement PR author and recent review owner; confidence: high; commits: ba84e085e4c3, fc9fb695dce2, eda3eb7083c7; files: ui/src/pages/chat/run-lifecycle.ts, src/gateway/server-methods/session-active-runs.ts, src/gateway/server-chat.ts)
  • MukundaKatta: Authored the merged stale active selected-session suppression PR whose run-lifecycle helper is strengthened by the identity-bound fix. (role: related fix author; confidence: high; commits: e452d16ceaa5; files: ui/src/ui/chat/run-lifecycle.ts, ui/src/ui/chat/run-lifecycle.test.ts)
  • vincentkoc: Current-main blame for the toast-clear and active-run helper areas points to a recent file-layout/current-main commit by Vincent Koc; history is noisy around path moves. (role: current-main line owner signal; confidence: medium; commits: 170150a306e3; files: ui/src/pages/chat/run-lifecycle.ts, src/gateway/server-methods/session-active-runs.ts)
  • scotthuang: Authored adjacent Gateway/UI active-run preservation work in the same run-lifecycle area. (role: recent adjacent active-run contributor; confidence: medium; commits: b3dc27403498; files: ui/src/ui/chat/run-lifecycle.ts, ui/src/ui/chat/run-lifecycle.test.ts)
  • Val Alexander: Authored the shared Control UI run-status cleanup path that this composer-state bug exercises. (role: introduced adjacent lifecycle cleanup; confidence: medium; commits: 4935e24c7a7f; files: ui/src/ui/chat/run-lifecycle.ts, ui/src/ui/views/chat.ts)

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

@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. P2 Normal backlog priority with limited blast radius. labels Jun 9, 2026
@tiffanychum

Copy link
Copy Markdown
Contributor Author

Notes on CI status and real-behavior proof

build-artifacts failure is an unrelated CI flake, not this change. This PR only edits ui/src/ui/chat/run-lifecycle.ts. The failing items in that job are unrelated infra/network paths:

  • scripts/upgrade-survivor-assertions.test.ts (ClawHub npm-pack installs)
  • gateway-cpu startup scenarios (spawn ENOENT)
  • a Chromium install failure in the Linux lane

None of those touch ui/. The owning CI workflow is intermittently red on main itself right now (recent main runs alternate failure/success), so this is environmental and should clear on a re-run against a green base.

On real-behavior proof: this fixes a non-deterministic timing race — the composer snaps back from Send to Stop when the run-status toast expires while a completed run is still briefly marked "active" due to session-poll lag. The fix re-reconciles the composer from the current session row when the toast clears (publishRunStatus: false so it does not re-arm a toast loop), guarded by a red/green unit regression in ui/src/ui/chat/run-lifecycle.test.ts.

Because the trigger depends on the precise overlap of toast-expiry and poll-lag windows, it does not reproduce deterministically even in the Playwright e2e harness (an e2e attempt passed both with and without the fix, so it was not a valid guard and was dropped). Visual before/after therefore realistically needs a maintainer environment or a proof: override. Happy to add anything further that helps.

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. label Jun 21, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 21, 2026
@tiffanychum

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Requesting a fresh review. CI has since re-run and the prior build-artifacts failure was an unrelated infra flake (paths outside ui/; the CI workflow was intermittently red on main at the time). The change is a one-line reconcile in ui/src/ui/chat/run-lifecycle.ts guarded by a red/green unit regression in run-lifecycle.test.ts, and the previous review confirmed it is not already on main or in the latest release.

@clawsweeper

clawsweeper Bot commented Jul 4, 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.

@clawsweeper clawsweeper Bot added status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 4, 2026
@steipete steipete self-assigned this Jul 5, 2026
@steipete
steipete force-pushed the fix/88033-composer-stop-toast-expiry branch from fe243ce to a637b1c Compare July 5, 2026 23:02
@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: L and removed size: XS triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jul 5, 2026
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Land-ready maintainer pass complete on a637b1c027cad92efe557504bc4f2ee261ad04da.

What changed:

  • replaced the timer-only suggestion with exact visible active-run identity across session list, history, mutation, transcript, and direct lifecycle publications;
  • retained completed-run identity across missing session results, while preserving different or ambiguous active runs;
  • removed cross-host timestamp ordering and the arbitrary suppression timeout;
  • added contributor credit in the changelog.

Proof:

  • Blacksmith Testbox tbx_01kwt3gy25f6vrxsven71k22mz (golden-lobster): corepack pnpm test src/gateway/server-chat.agent-events.test.ts src/gateway/server-methods/session-active-runs.test.ts src/gateway/server.sessions.list-changed.test.ts src/gateway/server-session-events.test.ts ui/src/pages/chat/run-lifecycle.test.ts ui/src/pages/chat/chat-gateway.test.ts ui/src/pages/chat/chat-send.test.ts ui/src/e2e/chat-run-lifecycle.e2e.test.ts — 284 Gateway tests, 248 UI tests, Chromium E2E 1/1.
  • Same Testbox: env OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 corepack pnpm check:changed — pass.
  • Same Testbox: corepack pnpm build — pass.
  • In-app live Control UI: after the five-second terminal mask and a second exact stale-run publication beyond the former 10-second window, Send remained visible/enabled and Stop remained absent.
  • Fresh full-branch Codex autoreview — no accepted/actionable findings.
  • git diff --check — pass.
  • Real behavior proof workflow: https://github.com/openclaw/openclaw/actions/runs/28758033863 — pass.

Known proof gaps: none for the changed Control UI/Gateway path. GitHub CI is still completing; the repository prepare/merge guard remains the final gate.

@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: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. labels Jul 5, 2026
@steipete
steipete force-pushed the fix/88033-composer-stop-toast-expiry branch from a637b1c to eda3eb7 Compare July 6, 2026 00:58
@clawsweeper clawsweeper Bot added 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: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. 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 Jul 6, 2026
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Landed the reviewed fix as #100527 in commit 4f8eeeaca9a9850074dfd4083f462e622dc13064.

I rebuilt the patch on current main because the fork-branch update path could not preserve clean rebased ancestry and produced an inflated unrelated diff. The landed replacement binds completed-run state to run identity across the Gateway and Control UI, retains the focused and live E2E coverage, and preserves the original contributor credit.

Thank you @tiffanychum. For future contributions, keeping Allow edits by maintainers enabled gives us the best chance of applying fixups directly, though GitHub's fork update path can still occasionally prevent a clean ancestry-preserving update.

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

Labels

app: web-ui App: web-ui gateway Gateway runtime merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. 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. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: L status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Webchat composer stays stuck on red Stop button after response completes

2 participants