fix(webchat): sessions persist after reconnects#89017
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 22, 2026, 12:30 AM ET / 04:30 UTC. Summary PR surface: Source +86, Tests +225, Docs +1. Total +312 across 18 files. Reproducibility: yes. at source level: current main still treats stale daily/idle entries as non-reusable, and Control UI currently forwards only the visible Review metrics: 2 noteworthy metrics.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this PR only after maintainers explicitly accept the one-shot Control UI freshness exception, while keeping public Gateway protocol and Plugin SDK surfaces closed and leaving archive/history discovery to separate work. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main still treats stale daily/idle entries as non-reusable, and Control UI currently forwards only the visible Is this the best way to solve the issue? Yes, with maintainer approval: this is a focused candidate because it keeps the public protocol and Plugin SDK closed, requires a matching current AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a594d2ce7325. Label changesLabel justifications:
Evidence reviewedPR surface: Source +86, Tests +225, Docs +1. Total +312 across 18 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
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
|
be6817c to
475ae44
Compare
475ae44 to
70afe9d
Compare
70afe9d to
71f4579
Compare
|
Update on the latest revision:
Reasoning: The linked bug is user-visible session loss after a Control UI reconnect or sleep/resume. A general Validation run for this revision:
|
Summary
What problem does this PR solve?
sessionId, while Gateway freshness handling treated the next send like an ordinary stale send and rotated that matching transcript into a reset archive before the resumed turn landed.chat.sendresume contract or Plugin SDK reply-options surface.Why does this matter now?
chat.send.resumeSession, but that made the fix look like a new public Gateway protocol feature and required a broader product/session-policy decision.What is the intended outcome?
sessionIdwhen policy requires it.chat.send.resumeSessionis not part of the public Gateway protocol schema, generated Swift model, or docs.requestedSessionId/resumeRequestedSessionstay on the internal Gateway/reply path and are not part of exported Plugin SDKGetReplyOptions.What is intentionally out of scope?
What does success look like?
resumeSessionas an extrachat.sendproperty.reply-runtimekeepsGetReplyOptionsfree of the private reconnect resume controls.What should reviewers focus on?
sessionId; ordinary stale sends still rotate.Summary guidance
This PR description is the contributor's durable explanation of the change. Write it for human maintainers first; ClawSweeper and Barnacle use the same text to understand intent, proof, risk, and current review state.
Describe the intent and outcome in 2-5 bullets. Avoid restating the diff; reviewers and bots can read the changed files.
If this PR fixes a plugin beta-release blocker, title it
fix(<plugin-id>): beta blocker - <summary>and link the matchingBeta blocker: <plugin-name> - <summary>issue labeledbeta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.Linked context
Which issue does this close?
Closes #87700
Which issues, PRs, or discussions are related?
Related #89017
Was this requested by a maintainer or owner?
No direct maintainer request; ClawSweeper requested maintainer/product review for the public protocol shape, so this update narrows the shape to avoid a public API decision.
Linked context guidance
Link the issue, PR, discussion, maintainer request, or owner request that explains why this PR should exist. Maintainer context helps reviewers and automation distinguish intended work from drive-by churn.
Real behavior proof (required for external PRs)
Behavior or issue addressed: Control UI reconnect send preserves the matching visible session without exposing a public
chat.send.resumeSessionfield.Real environment tested: Foreground Gateway websocket RPC from the current checkout, using real Control UI and public WebChat client identities with browser-origin and device-identity handshake requirements enabled.
Exact steps or command run after this patch:
chat.sendwebsocket RPCs for Control UI reconnect, public WebChat with the private marker, and ordinary stale Control UI send.Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): Validation
live-control-ui-reconnect-proof(pass, exit_code=0, 103436ms):Observed result after fix:
chat.sendvalidation.resumeSessionremains outside the publicchat.sendprotocol contract.What was not tested: None for the scoped Gateway/session behavior covered by this proof.
Proof limitations or environment constraints: The live proof targets the runtime session boundary that caused [Bug]: Control UI webchat session silently resets after network disconnect / sleep — previous session file renamed to .jsonl.reset.* and lost from sessions tab #87700; Control UI marker construction is covered by the supplemental controller regression tests below.
Before evidence (optional but encouraged): Before the scoped reconnect handling, a stale send with the displayed matching session was handled like an ordinary stale send and rotated instead of preserving the visible reconnect session.
Real behavior proof guidance
External contributors must show after-fix evidence from a real OpenClaw setup. Unit tests, mocks, lint, typechecks, snapshots, and CI are supplemental only.
Screenshots are encouraged even for CLI, console, text, or log changes. Terminal screenshots, copied live output, redacted runtime logs, recordings, and linked artifacts count.
If your environment cannot produce the ideal proof, explain that under
Proof limitations or environment constraintsso reviewers and ClawSweeper can direct the next step properly.Be mindful of private information like IP addresses, API keys, phone numbers, non-public endpoints, or other private details when providing evidence.
Tests and validation
Which commands did you run?
pnpm lint --threads=8(pass, exit_code=0, 206428ms)node scripts/run-vitest.mjs packages/gateway-protocol/src/index.test.ts src/plugins/contracts/plugin-sdk-subpaths.test.ts src/gateway/server.chat.gateway-server-chat-b.test.ts ui/src/ui/controllers/chat.test.ts(pass, exit_code=0, 139848ms)pnpm exec oxfmt --check src/auto-reply/dispatch.ts src/auto-reply/reply/dispatch-from-config.types.ts src/auto-reply/reply/get-reply.types.ts src/plugins/contracts/plugin-sdk-subpaths.test.ts(pass, exit_code=0, 2584ms)git diff --check(pass, exit_code=0, 1276ms)TMPDIR=<isolated temp dir> NODE_OPTIONS=--max-old-space-size=8192 OPENCLAW_VITEST_MAX_WORKERS=2 node scripts/run-vitest.mjs run --config test/vitest/vitest.full-core-support-boundary.config.ts(pass, exit_code=0, 9189ms)NODE_OPTIONS=--max-old-space-size=8192 pnpm build:ci-artifacts(pass, exit_code=0, 178580ms)What regression coverage was added or updated?
resumeSessionis not a publicchat.sendparameter.openclaw/plugin-sdk/reply-runtimedoes not exposerequestedSessionId/resumeRequestedSessionthroughGetReplyOptions.What failed before this fix, if known?
check-lintfailed because the controller regression test read__controlUiReconnectResumewith dot syntax, triggeringno-underscore-dangle; the assertion now checks property absence without relaxing lint rules.build-artifactsboundary failure was tied to the stale pre-sync checkout; after syncing with currentmain, the same core-support boundary suite passes.If no test was added, why not?
Testing guidance
List focused commands, not every incidental check. CI is useful support, but external PRs still need real behavior proof above when behavior changes.
Risk checklist
Did user-visible behavior change? (
Yes/No)Yes. Control UI reconnect sends can preserve the matching visible session once; this is the intended fix for the linked session-loss path.
Did config, environment, or migration behavior change? (
Yes/No)No.
Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)Yes, in the limited sense that Gateway request validation now has an internal Control UI-only marker. Non-operator/public clients are rejected by validation coverage.
What is the highest-risk area?
Session-state and protocol boundary: avoiding a generic client-controlled override of idle/daily freshness.
How is that risk mitigated?
resumeSessionwas removed from the public schema and generated Swift model.requestedSessionId/resumeRequestedSessionwere removed from exportedGetReplyOptionsand kept on internal Gateway/reply option types.sessionIdmatches the current session entry.Related open PR / competition scan / contract scope:
resumeSessionproperty, and the generated Swift model no longer exposes one.Patch quality warnings / notes:
src/gateway/server.chat.gateway-server-chat-b.test.tsreturnsundefinedfrom the mocked reply only to stop the harness after capturing reply initialization options; this is test-only control flow, not a production fallback.unknowncasts are confined to UI helper/test setup where the shared UI state object is intentionally sliced down to chat-controller fields; they do not widen the runtimechat.sendpayload or relax Gateway validation.Risk guidance
Use this for author judgment that is not obvious from the diff. ClawSweeper can see touched files, but it cannot know which behavior you think is risky, why the risk is acceptable, or what mitigation reviewers should verify.
Current review state
What is the next action?
Maintainer-ready confidence: high after syncing with current
main, fixing the remaining lint failure, revalidating build-artifacts coverage, refreshing live Gateway proof, and passing ClawSweeper commit review.Review the narrowed implementation and let CI settle after this update.
What is still waiting on author, maintainer, CI, or external proof?
main.check-lintfailure is fixed without changing runtime behavior.chat.send.resumeSessionprotocol field remains.GetReplyOptions.Which bot or reviewer comments were addressed?
status: ⏳ waiting on authorlabel is addressed by this update; it should be recalculated by hosted ClawSweeper after submit.sessionId, and is backed by live Gateway proof.requestedSessionIdandresumeRequestedSessionout of exported Plugin SDKGetReplyOptions.sessionId.reply-runtimedispatch signatures and running targeted Vitest coverage for Plugin SDK subpaths, Gateway reconnect forwarding/rejection, and session freshness behavior.oxfmt --checkcommand successfully.git diff --checksuccessfully.Review state guidance
Keep this as the durable state for review progress. If useful information appears in comments, fold the current next action or blocker back here so maintainers and ClawSweeper do not need to reconstruct state from comment history.