fix: recover Control UI bundle loading after gateway restart#99111
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 12:16 AM ET / 04:16 UTC. Summary PR surface: Source +73, Tests +117. Total +190 across 3 files. Reproducibility: yes. at source level: current main's Keep waiting handler only hides the fallback and rearms the same timer after the app module fails to register. I did not rerun the macOS launchd scenario locally, but the linked issue and browser proof cover the central failed-module recovery path. Review metrics: none identified. 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:
Next step before merge
Security Review detailsBest possible solution: Land the refreshed static fallback recovery after ordinary exact-head maintainer mergeability and CI gates, while keeping old-iOS/proxy compatibility and launchd/config changes separate. Do we have a high-confidence way to reproduce the issue? Yes, at source level: current main's Keep waiting handler only hides the fallback and rearms the same timer after the app module fails to register. I did not rerun the macOS launchd scenario locally, but the linked issue and browser proof cover the central failed-module recovery path. Is this the best way to solve the issue? Yes. Fetching a cache-busted current document before one bounded recovery navigation is the narrowest maintainable fix here because it avoids duplicate module-graph execution and does not add launchd or gateway config surface. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 37f96bde4d90. Label changesLabel justifications:
Evidence reviewedPR surface: Source +73, Tests +117. Total +190 across 3 files. View PR surface stats
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
Review history (3 earlier review cycles) |
06c6b5e to
18f0178
Compare
18f0178 to
d7cc641
Compare
|
Maintainer refresh complete at What changed:
Verification:
Remote proof: Blacksmith Testbox through Crabbox, The browser proof caught and led to a fix for an initial reload-loop bug in the marker guard before this refresh was pushed. Thanks @ZengWen-DT for the original diagnosis and recovery direction. Exact-head land-ready update: cd2979e is the clean current-main-plus-reviewed-patch head. Hosted CI run https://github.com/openclaw/openclaw/actions/runs/28767171169 passed at that exact SHA. The rebase changed ancestry only; the tested diff and Testbox/browser/PTY proof above are unchanged. Known proof gaps: none. |
e45c6f9 to
b1f20f8
Compare
Co-authored-by: ZengWen-DT <[email protected]>
7704374 to
cd2979e
Compare
|
Merged via squash.
|
Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Closes #99092
What Problem This Solves
Fixes an issue where users who load the Control UI while the gateway is restarting can land on the static "Control UI did not start" fallback and stay there even after the gateway becomes healthy again.
Before this change, the
Keep waitingbutton only hid the fallback and rearmed the watchdog. It did not retry the app bundle, so a failed initial module fetch still required a full page reload.Why This Change Was Made
The static fallback now performs bounded app-bundle recovery before the TypeScript app has mounted: it finds the original module script, appends a cache-busted retry script when the watchdog fires or when users click
Keep waiting, and probes the current same-origin page withHEADso the fallback can distinguish a restarting/unreachable gateway from a reachable gateway where module execution is still blocked.This keeps the fix inside the pre-mount Control UI fallback. It intentionally does not change launchd restart behavior or add new gateway config surface.
AI-assisted.
User Impact
Users no longer need to manually reload the Control UI when the only problem was a transient app-bundle fetch failure during gateway restart. The fallback copy now points at gateway restart/reachability first, while still preserving the clean-profile guidance for persistent module blocking.
Evidence
Focused tests and checks:
node scripts/run-vitest.mjs ui/src/ui/mount-fallback.test.tspassed: 1 file, 5 tests.node scripts/run-vitest.mjs src/gateway/control-ui-csp.test.tspassed: gateway CSP shard, 4 files, 60 tests.node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfopassed.node_modules/.bin/oxfmt --check --threads=1 ui/index.html ui/src/ui/mount-fallback.test.tspassed.pnpm ui:buildpassed. Vite still reports the existing large main chunk warning.Real browser proof against the final built Control UI:
dist/control-ui/index.htmlfrom a local HTTP server.503to simulate the gateway restart window.{ "mainRequests": 2, "initialFailures": 1, "retrySrcIncludesCacheBust": true, "mounted": true, "fallbackHidden": true, "navTypes": ["navigate"] }Local provider smoke requested for this issue:
pnpm openclaw agent --local --model deepseek/deepseek-v4-pro --session-key agent:default:ui-retry-proof --message "Reply exactly: OPENCLAW_UI_RETRY_PROOF_OK" --json --timeout 120returnedOPENCLAW_UI_RETRY_PROOF_OKwith providerdeepseek, modeldeepseek-v4-pro.