Repository navigation
fix: keep Linux widget replies connected and simplify Rust ownership - #139664
Conversation
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed September 6, 2026, 4:43 AM ET / 08:43 UTC. ClawSweeper reviewWhat this changesPreserves live widget replies, repairs Linux Quick Chat window placement and lifecycle handling, restores embedded Dashboard navigation, consolidates Rust ownership, and updates selected dependencies and Watch tooling. Merge readiness✅ Ready for maintainer review This PR remains useful: current main still lacks the central repairs, and no blocking introduced defect was found. The updated native reload evidence addresses the previous review’s remaining request. Priority: P2 Review scores
Verification
How this fits togetherThe Gateway converts successful tool results into chat content consumed by Linux Quick Chat and the Dashboard. The native app hosts interactive widgets in isolated child views and sends external new-window links to the system browser. flowchart LR
A[Successful tool result] --> B[Bounded Gateway widget descriptors]
B --> C[Chat progress and completion]
C --> D[Quick Chat native window]
D --> E[Isolated widget views]
F[Dashboard new-window link] --> G[Guarded system browser opening]
Before mergeNone. Agent review detailsSecurityNone. PR surfaceSource +81, Tests +305, Docs +2, Other -80. Total +308 across 26 files. View PR surface stats
Review metrics
Technical reviewBest possible solution: Keep widget descriptors in the existing Gateway projection and native children under one lifecycle owner while preserving isolation, suppression, and stored credential compatibility. Do we have a high-confidence way to reproduce the issue? Yes: current main’s text-only final projection and single-WebView ownership lookup match the supplied native before/after failure scenario. This review inspected source without executing the application. Is this the best way to solve the issue? Yes: the patch repairs the existing projection and native lifecycle owners, reuses Canvas normalization, and preserves the established security and persistence contracts. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 8bcffa7fdefa. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (5 earlier review cycles)
|
a5f9c92 to
ca841bb
Compare
ca841bb to
ec766f0
Compare
Carry bounded Canvas descriptors through live Gateway delivery, finalization and cancellation. Keep Quick Chat attached to its native window and let GTK own primary and widget geometry. Preserve external browser links while allowing Dashboard widget frames to load in the app. Consolidate Rust widget, queue, identity and RTC ownership; update safe dependencies and the pinned Watch compiler. Remove 141 production Rust lines while preserving credential serialization and the Watch C ABI. Validation: reviewed through P2; 135 desktop tests on macOS, 146 Linux test executions and native build; Gateway owner regressions and changed gates; Watch debug/release tests and four-architecture C linkage.
d98a8be to
d6661eb
Compare
|
Merged via squash.
|
…penclaw#139664) * fix(linux): keep widget replies connected and correctly placed Carry bounded Canvas descriptors through live Gateway delivery, finalization and cancellation. Keep Quick Chat attached to its native window and let GTK own primary and widget geometry. Preserve external browser links while allowing Dashboard widget frames to load in the app. Consolidate Rust widget, queue, identity and RTC ownership; update safe dependencies and the pinned Watch compiler. Remove 141 production Rust lines while preserving credential serialization and the Watch C ABI. Validation: reviewed through P2; 135 desktop tests on macOS, 146 Linux test executions and native build; Gateway owner regressions and changed gates; Watch debug/release tests and four-architecture C linkage. * fix(linux): preserve compact sizing and native browser links * fix(linux): dismiss widget replies after unhandled Escape * fix(linux): ignore stale Quick Chat blur events
What Problem This Solves
Fixes Linux replies that say Done while their widgets disappear, Quick Chat becomes Interrupted, or reopening fails with a duplicate window label. It also repairs misplaced native widgets and Dashboard frames that unexpectedly open the system browser.
This follows #139241 with the requested deeper Rust cleanup and dependency audit. The separate unanswered-onboarding shutdown repair landed in #139783.
Why This Change Was Made
The Gateway records bounded, normalized Canvas descriptors where a successful tool result arrives, then carries that fact through progress, completion and explicit cancellation. History and live delivery share normalization and deduplication. Existing run ownership, silent/heartbeat suppression and delivery hooks remain authoritative; retention is capped at 32 descriptors and 64 KiB, evicting oldest entries first.
Quick Chat uses its native window as the owner. Tauri's single-WebView lookup stops matching when child views exist; that lookup caused false disconnects and duplicate-label attempts. The pinned Linux Tauri/Wry path also puts child views in a vertical GtkBox and ignores their requested rectangles. An app-owned GtkOverlay/Fixed surface now positions the isolated child views, while a small content GtkBox subclass preserves the existing 640×92 compact size. Native placement completes before reconciliation commits. Child Escape forwards to WebKit first, preserving IME and widget handlers; an unhandled key uses the existing renderer hide/cleanup path. Linux blur admission also rechecks current toplevel focus so an old queued focus-loss event cannot hide an already refocused window.
Dashboard navigation no longer guesses that every cross-origin frame is an external link. The guarded native new-window handler remains the browser owner. Opener's default injected click handler is disabled because it consumed those links before calling renderer IPC that the app deliberately does not grant.
The Rust cleanup unifies widget state under one lifecycle lock, moves typed decoding into the socket owner, lets the operation queue own its sole worker, removes duplicate identity types and approval clones, and gives Watch RTC one fallible-operation boundary. The removed executor, copied state helpers and target-rewrite script have no parallel replacement paths.
User Impact
Completed widget replies stay connected and interactive. Dashboard widgets remain inside the app, external links open through the native browser handler, and Quick Chat returns to its compact size after hiding. Credential serialization, C ABI, native capabilities, config and persistent schemas remain unchanged.
Rust production is 60 lines smaller. Gateway Canvas production grows 81 lines, making this PR net +21 production lines. Tests/support grow 265 lines; dependency/license/docs/tooling metadata is counted separately. The GTK layout/input ownership and bounded Canvas result delivery require the positive portions; deleted inline tests and pure moves are not credited as production savings.
Dependencies
Audited all 29 direct registry dependencies across both Rust crates and dry-ran both complete Cargo graphs. Applied mdns-sd 0.21.2, crossbeam-channel 0.5.17 and crossbeam-utils 0.8.23; advanced Watch to nightly-2026-09-05 with its exact notices. GTK 0.18.2 is a new direct reference to an already-resolved package, with no additional package version.
Existing holds remain after direct source/probe checks: blocking 1.7.0 retains idle workers, and tauri-plugin-updater 2.11.0 changes Windows installer-failure behavior after cleanup. The remaining older generic-array/toml entries come from upstream constraints. No overrides or vendoring were added; no safe available update remained at audit time.
Dependency contracts personally inspected: Tauri 2.11.5
lib.rssingle-WebView lookup; runtime-wry 2.11.4 child creation; Wry 0.55.1 GtkBox packing, bounds and navigation; GTK 3.24.41 preferred-size, focus propagation and input ownership; WebKitGTK 2.52.6 asynchronous key replay; opener 2.5.5 builder and injected click handling. Installed Codex 0.153.4 was checked against its exact release source, including dynamic tool completion and app-server response decoding.Evidence
Crabbox run 34014138751, provider
blacksmith-testbox, leasetbx_01m1tk40syn8mwrdr3k0v0am0p. Native Linux Tauri/WebKitGTK, Openbox, real Gateway and model providers; synthetic user state. The independently checked runtime uses base883d4d65bad1791755c203a8dfd854e14b4f6e33plus this PR and #139783; changed-file manifests and dependency hashes are verified before each build.openai/gpt-5.6-sol, Codex harness) returned two working widgets. Text input, button state, Alpha/Beta tabs and ten fresh-composer hide/reopen cycles passed; cycles took 269–472 ms and typing still worked afterward. Widget window 640×440; compact window 640×92.ollama/qwen3:4b-instruct-2507-q4_K_M, OpenClaw harness) activated in 11.578 seconds, then completed three continuous native chat turns: 224.779 seconds cold, 5.074 and 5.883 seconds warm. The first CPU-only turn spent 220.338 seconds prefilling 10,430 tokens; warm turns reused the prompt cache. These are observed cold/warm limits, not a claim of instant cold inference.Final uninstrumented native A/B proof passed on the replacement lease
tbx_01m1tsjy758bvhjb4rpbs9g2pv(providerblacksmith-testbox): real GTK Unicode composition cancellation retained the widget and window; primary-popover Escape stayed local; ordinary widget Escape dismissed the reply. The exact original sequence then passed 100 rapid hide/reopen cycles at 277–501 ms, with the same mapping predicates and five-second phase bounds. A physical outside click still hid Quick Chat in 291 ms, and reopening accepted input. The preceding uninstrumented candidate failed at cycle 2 on two leases; diagnostic logging alone made it pass and was not counted as product proof. Final candidate contains no diagnostics.The child-alive parent reload also passed on that uninstrumented candidate. With two real child WebViews present, the test runner validated the owned PID/UID/executable and invoked WebKit's existing
webkit_web_view_reloadon the actual Quick Chat parent through the GTK widget tree. Both old children retired; the parent reopened at 640×92 and acceptedAFTER_PARENT_RELOAD. This exercised native renderer replacement without moving focus, adding production IPC or changing test-user permissions. Inspector captures remain private; normal app screenshots contain only synthetic task data. Final Crabbox run 34019002348.After rebasing onto
45213bbddbe8ec95326981367c10ba7eb4c68240, all native Rust files remain byte-identical to the live-tested candidate. The Gateway integration retained main's retry/status projection changes; its final exact-head standalone replay passed 327 tests across five files. Exact-head CI completed successfully: 153 passed, 33 skipped, includingopenclaw/ci-gate(run 34021971776).CI exposed a pre-existing browser-hash fixture depending on a shared
/tmp/workspace. Existing skill directories changed runtime hashing while the fixture expected no skill mounts. Our exact red reproduction had 26 passing cases and one failure; the isolated fixture repair plus hash siblings passed 40 tests and independent P2 review. Meanwhile #139894 landed suite-wide owned-workspace isolation in main. The rebase keeps that canonical fix and drops our duplicate test commit; production hashing and assertions remain unchanged. Existing filesystem data was preserved.Native before and after
Baseline: the completed reply loses its widget descriptors.
Candidate: both widgets are present inside Quick Chat.
Compact composer remains usable after ten hide/reopen cycles.
Three continuous local-model replies in the native Dashboard.
Review follow-through
The earlier ClawSweeper interaction, layout and dependency-proof requests are addressed by the owner-source audit and live input/tab/toggle/link/local/service results above. Final child-input Escape, real IME cancellation and 100-cycle uninstrumented stress proof are complete; child-alive renderer reload is complete on the same uninstrumented candidate. The previously reported merge conflict was resolved while preserving main's text-projection changes and both shrinking assertion baselines. The first GTK allocation adapter and direct Escape interception were rejected and removed.
Follow-up: CPU-only cold local inference remains expensive because of prompt prefill; warm behavior is measured above. A fixture-only service failure also exposed raw CLI JSON in native error text; this is recorded for a separate presentation cleanup and is not a regression introduced here.
The native source audit also identified a separate Tao queued-show/focus caveat. No distinct failing presentation case was isolated after the blur repair, so a shared native presentation change is recorded as follow-up rather than adding a second window-control path here.
Final lifecycle proof and cleanup
Uninstrumented input after 100 rapid cycles:
Input after native parent reload with live children:
Final cleanup completed before explicit lease stop: managed Gateway stopped, task authentication/state removed, QA user removed and port 18789 closed. Blacksmith confirmed the sixth lease completed at 2026-09-06 08:47:13 UTC. Earlier leases that ended through provider teardown are not claimed to have had manual home cleanup.
Presentation follow-up: an unstyled transparent synthetic widget exposes underlying content after repaint. Existing frames do not distinguish expected fixture transparency from a GTK paint issue, so no product-regression or repair claim is made for that observation.
Final local validation used a standalone checkout at the rebased head with its own frozen install. This resolved package-local dependency links missing from the review worktree. The app-lint step then used the already installed, verified SwiftLint 0.65.1; all remaining planned checks passed. No production change, assertion relaxation or timeout increase was used to repair the environment.