Skip to content

Control UI: reduce unnecessary gateway churn and prevent stale index caching#69454

Open
cmaldonado80 wants to merge 6 commits intoopenclaw:mainfrom
cmaldonado80:pr/control-ui-slowness-upstream
Open

Control UI: reduce unnecessary gateway churn and prevent stale index caching#69454
cmaldonado80 wants to merge 6 commits intoopenclaw:mainfrom
cmaldonado80:pr/control-ui-slowness-upstream

Conversation

@cmaldonado80
Copy link
Copy Markdown

Summary

This PR packages the local Control UI slowness fixes that materially reduced gateway churn during investigation, plus one small server-side hardening for stale bundle rollouts.

Included fixes

  • bound chat/session refresh to a recent slice instead of an effectively unbounded session universe
    • activeMinutes: 120
    • limit: 200
  • scope node polling to the Nodes tab instead of starting globally on connect
  • debounce sessions.changed reloads
  • avoid reloading sessions for sessions.changed while on Chat
  • skip eager node.list / device.pair.list preloads outside the Nodes flow
  • serve Control UI index.html with Cache-Control: no-store so browsers fetch fresh bundle references after rollouts

Why

In local runtime evidence, the biggest proven slowness driver was Control UI itself:

  • repeated sessions.list refreshes from chat/session UI state
  • global node.list polling even when Nodes was not open
  • immediate session reloads on every sessions.changed push
  • connect-time node/device preloads that were unnecessary for non-Nodes views
  • stale browser tabs continuing to hold onto older bundle behavior after rollouts

These changes are intentionally small and reversible. They reduce control-plane load without changing the overall product model.

Validation

Run on an isolated branch based on origin/main:

  • pnpm test -- --run src/gateway/control-ui.http.test.ts
  • pnpm --dir ui test -- src/ui/app-gateway.node.test.ts src/ui/app-gateway.sessions.node.test.ts src/ui/app-lifecycle.node.test.ts src/ui/app-lifecycle-connect.node.test.ts src/ui/app-settings.test.ts src/ui/app-render.helpers.node.test.ts src/ui/app-chat.test.ts
  • pnpm --dir ui build

Observed locally after rollout:

  • gateway health remained OK
  • stale high-churn Control UI behavior disappeared after reload/reconnect
  • watchdog timeout noise stayed quiet under the newer runtime budget

Notes

  • This branch intentionally excludes unrelated local Canvas work by being rebuilt cleanly from origin/main.
  • One unrelated dirty local file (ui/src/ui/views/chat.ts) was left out on purpose.

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: M labels Apr 20, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 20, 2026

Greptile Summary

This PR introduces targeted performance fixes to reduce unnecessary gateway churn in the Control UI. The changes bound chat/session refresh calls, scope node polling to the Nodes tab, debounce sessions.changed reloads, suppress session reloads while on the Chat tab, and add Cache-Control: no-store to index.html responses so browsers always fetch fresh bundle references after rollouts. The implementation is small and reversible, with unit tests covering each of the key behavioral changes.

Confidence Score: 5/5

Safe to merge — all changes are opt-in debouncing / scoping improvements with no correctness regressions and solid test coverage.

No P0 or P1 issues found. Every changed behavior (sessions debounce, tab-scoped polling, bounded session list, no-store cache header) is unit-tested and the logic is straightforward.

No files require special attention.

Reviews (1): Last reviewed commit: "Prevent control UI index caching" | Re-trigger Greptile

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 62738540dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/ui/app-gateway.ts
Comment on lines +408 to +410
host.sessionsChangedReloadTimer = window.setTimeout(() => {
host.sessionsChangedReloadTimer = null;
void loadSessions(host as unknown as SessionsState);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard deferred sessions reload against tab switches

The timeout callback always calls loadSessions even if the user has left overview/sessions before the 750ms delay elapses. In practice, if a sessions.changed event arrives on Overview and the user quickly navigates to Chat, the scheduled callback still reloads sessions on Chat, which reintroduces the gateway churn this change is meant to avoid. Re-check shouldReloadSessionsForEvent(host) (or clear the pending timer on tab change) inside the timeout callback before issuing the request.

Useful? React with 👍 / 👎.

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 29, 2026

Codex review: needs changes before merge.

What this changes:

The PR bounds Control UI chat/session session-list refreshes, scopes node and device loading and polling to the Nodes tab, debounces session-change reloads away from Chat, serves Control UI index HTML with no-store caching, and adds focused tests.

Required change before merge:

The remaining blockers are narrow and mechanical on the PR branch: guard or cancel the deferred session reload after tab changes, add a changelog entry, resolve the dirty branch, and rerun focused UI/gateway validation.

Security review:

Security review cleared: The diff does not add dependencies, workflows, package-resolution changes, secret handling, or new code-execution paths; the index no-store change is defensive for the admin UI surface.

Review findings:

  • [P2] Guard deferred session reloads after tab changes — ui/src/ui/app-gateway.ts:410
  • [P3] Add the required changelog entry — CHANGELOG.md:7
Review details

Best possible solution:

Update or replace this PR with the same narrow Control UI churn/cache improvements after adding a tab recheck or timer cancellation for deferred session reloads, adding the required Unreleased changelog credit, rebasing cleanly on current main, and keeping the broader polling-interval proposal separate in #45930.

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

Yes. A focused fake-timer test can schedule sessions.changed from Overview, switch host.tab to Chat before 750 ms, advance the timer, and assert loadSessions is not called; the PR head currently fails that behavior by calling loadSessions unconditionally inside the timeout.

Is this the best way to solve the issue?

No, not as submitted. The overall scoping/debouncing/no-store direction is narrow and maintainable, but the deferred callback needs to honor the current tab at execution time and the branch needs the required changelog/rebase cleanup before merge.

Full review comments:

  • [P2] Guard deferred session reloads after tab changes — ui/src/ui/app-gateway.ts:410
    The timeout callback always calls loadSessions after the initial tab check. If a sessions.changed event arrives on Overview and the user switches to Chat before 750 ms elapses, the delayed callback still issues sessions.list on Chat, reintroducing the churn this PR is trying to avoid. Re-check shouldReloadSessionsForEvent inside the callback or clear the pending timer on tab changes before loading sessions.
    Confidence: 0.93
  • [P3] Add the required changelog entry — CHANGELOG.md:7
    This is a user-facing Control UI performance/cache fix, but the PR does not touch CHANGELOG.md. Add an Unreleased Fixes entry with the appropriate contributor credit so the change satisfies the repo changelog policy.
    Confidence: 0.84

Overall correctness: patch is incorrect
Overall confidence: 0.88

Acceptance criteria:

  • pnpm test -- --run src/gateway/control-ui.http.test.ts
  • pnpm --dir ui test -- src/ui/app-gateway.node.test.ts src/ui/app-gateway.sessions.node.test.ts src/ui/app-lifecycle.node.test.ts src/ui/app-lifecycle-connect.node.test.ts src/ui/app-settings.test.ts src/ui/app-render.helpers.node.test.ts src/ui/app-chat.test.ts
  • pnpm --dir ui build
  • pnpm check:changed in Testbox before handoff/push if promoted

What I checked:

  • current-main unbounded chat refresh: Current main still refreshes chat session options with activeMinutes: 0 and limit: 0, matching the PR's stated high-churn source. (ui/src/ui/app-chat.ts:641, 4981ec7061ab)
  • current-main eager node/device preload: Current main loads nodes and devices on every gateway hello before refreshing the active tab, even when the Nodes tab is not active. (ui/src/ui/app-gateway.ts:471, 4981ec7061ab)
  • current-main immediate sessions.changed reload: Current main handles sessions.changed by immediately calling loadSessions, so bursty session events can trigger repeated sessions.list calls. (ui/src/ui/app-gateway.ts:733, 4981ec7061ab)
  • current-main index cache header: Current main serves resolved index.html with Cache-Control: no-cache rather than no-store, so the PR's stale-bundle hardening is not already implemented on main. (src/gateway/control-ui.ts:657, 4981ec7061ab)
  • blocking PR bug: At the PR head, scheduleSessionsReload checks the tab only before scheduling; the timeout callback clears the timer and calls loadSessions without rechecking whether the user has navigated away from Overview/Sessions. (ui/src/ui/app-gateway.ts:410, 62738540ddf5)
  • existing review comment corroborates blocker: The prior Codex review comment on the PR flags the same P2 issue: a delayed reload scheduled from Overview can still run after the user switches to Chat. (ui/src/ui/app-gateway.ts:410, 62738540ddf5)

Likely related people:

  • steipete: GitHub commit history shows recent Control UI app-gateway/app-chat/control-ui maintenance and the earlier split of app modules that owns the lifecycle/polling shape this PR changes. (role: recent maintainer and original module-split owner; confidence: high; commits: e3ff8c4d288b, f6b2ba4a10af, 9bc703213bb3; files: ui/src/ui/app-gateway.ts, ui/src/ui/app-chat.ts, ui/src/ui/app-lifecycle.ts)
  • vincentkoc: Recent commits touch the same app-gateway and app-render helper surfaces involved in session reloads, chat reconciliation, and UI runtime cleanup. (role: recent Control UI maintainer; confidence: high; commits: 02908db62b30, cff991c88d04, dbe2a97e802a; files: ui/src/ui/app-gateway.ts, ui/src/ui/app-render.helpers.ts, ui/src/ui/app-settings.ts)
  • BunsDev: Recent history shows repeated Control UI state/settings work in app.ts, app-render helpers, app-settings, and nearby chat/control UI behavior. (role: adjacent Control UI state owner; confidence: medium; commits: b1c515270eb5, c34ed90822a9, fc5920fb5134; files: ui/src/ui/app.ts, ui/src/ui/app-render.helpers.ts, ui/src/ui/app-settings.ts)
  • drobison00: Recent gateway Control UI HTTP hardening commits modified nearby server routes and auth handling around src/gateway/control-ui.ts, which is the server-side file touched by the cache-header part of this PR. (role: adjacent Gateway Control UI HTTP maintainer; confidence: medium; commits: 2321d67263bc, 2ce16e558e99; files: src/gateway/control-ui.ts)

Remaining risk / open question:

  • The PR branch currently reports dirty mergeability against main, so conflict resolution may change the reviewed diff before it can land.
  • The related sluggishness report includes broader channel/status slowness signals; this PR handles the Control UI churn subset and may not fully resolve every symptom in Bug: Control UI becomes progressively stuck after being open for a while (2026.3.12) #45698.
  • This was a read-only review, so the targeted tests listed in the PR body were inspected but not rerun locally.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 4981ec7061ab.

Copy link
Copy Markdown
Member

BunsDev commented May 2, 2026

Maintainer overlap triage after opening #75986:

This PR is complementary, not duplicate-closed or superseded by #75986.

Scope split:

I would keep this PR deferred/needs-changes, not duplicate-closed. The existing review blockers still look like the right path: guard/cancel deferred session reloads after tab changes, add the changelog entry, rebase cleanly, then rerun the focused UI/gateway validation.

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 size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants