Skip to content

Tidy Usage page and recover from disconnected gateway - #508

Merged
shanselman merged 2 commits into
openclaw:masterfrom
bkudiess:usage-page
May 22, 2026
Merged

Tidy Usage page and recover from disconnected gateway#508
shanselman merged 2 commits into
openclaw:masterfrom
bkudiess:usage-page

Conversation

@bkudiess

@bkudiess bkudiess commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Cleans up the Usage page and fixes the "page not loading / no values" report.

Layout (openclaw-design + winuxe)

  • Removed 📊 emoji from the page title (no emoji on WinUI surfaces); updated 5 resw locales.
  • Switched the 3 stat cards from a horizontal StackPanel to a 3-column Grid (equal widths) so they share available width cleanly.
  • Replaced raw FontSize/FontWeight with Fluent typography styles (TitleLargeTextBlockStyle for the hero Total Cost, SubtitleTextBlockStyle for the small stats) per winuxe Critical Rule Fix WinUI tray menu crash with invisible anchor window pattern #4.
  • Kept MaxWidth=900 to match Permissions/Connection/Settings.

Bug fix: page not loading

Root cause: OpenClawGatewayClient.RequestUsage* calls silently no-op when !IsConnectedToGateway. Navigating while the WebSocket was reconnecting left the progress rings spinning forever and after Fail() the visual helpers hid loading, content, and empty — leaving completely blank cards.

  • Treat client == null || !client.IsConnectedToGateway as disconnected in Initialize and SelectPeriod.
  • Subscribe to client.StatusChanged so the page self-heals when the gateway comes online later (re-fires the three requests on the UI thread); unsubscribe in Unloaded.
  • Surface a "Couldn't load. Check your gateway connection." message when loading state is failed-and-never-loaded.

Validation

  • ./build.ps1
  • Tray tests: 1178 passed ✅
  • Shared tests: 1890 passed ✅ (29 skipped)
image

Layout:
- Drop the emoji from the page title (no emoji on WinUI surfaces per
  openclaw-design skill); update en-us/fr-fr/nl-nl/zh-cn/zh-tw resw.
- Switch 3 stat cards from horizontal StackPanel to a 3-column Grid
  with equal widths so they share available width cleanly.
- Replace raw FontSize/FontWeight with Fluent typography styles
  (TitleLarge for the hero Total Cost, Subtitle for the small stats)
  per winuxe Critical Rule #4 — also gives the page proper hierarchy.

Bug fix (page not loading / no values):
- OpenClawGatewayClient.RequestUsageAsync/CostAsync/StatusAsync silently
  no-op when !IsConnectedToGateway, so navigating while the gateway
  was reconnecting left the progress rings spinning forever.
- Treat (client == null || !client.IsConnectedToGateway) as
  disconnected in Initialize and SelectPeriod.
- Subscribe to client.StatusChanged so the page self-heals when the
  gateway comes online later (re-fires the three requests on the UI
  thread). Unsubscribe in Unloaded.
- After Fail() the loading state is !IsRefreshing && !HasLoaded, which
  hid loading + content + empty all at once. Surface a 'Couldn't load.
  Check your gateway connection.' message in that state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge.

Latest ClawSweeper review: 2026-05-22 22:19 UTC / May 22, 2026, 6:19 PM ET.

Workflow note: Future ClawSweeper reviews update this same comment in place.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Summary
This PR updates the WinUI Usage page layout/localized title resources and adds disconnected-gateway handling, reconnect refresh logic, and usage-cost response handling.

Reproducibility: yes. by source inspection: current main can enter Usage with a non-null but disconnected GatewayClient, while RequestUsageAsync returns early when the WebSocket is not connected. I did not run the WinUI app, so this is source-reproducible rather than runtime-reproduced.

PR rating
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Summary: The PR addresses a real bug, but insufficient runtime proof and multiple blocking Usage page correctness issues keep it below merge-ready quality.

Rank-up moves:

  • Fix the selected-period race caused by the implicit 30-day usage.cost request.
  • Handle operator-client replacement while the Usage page remains open and keep new messages localized.
  • Add redacted screenshot, recording, terminal output, or logs showing the disconnected state and values reloading after reconnect.
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

Real behavior proof
Needs stronger real behavior proof before merge: The attached screenshot shows the loaded connected Usage page layout, but it does not show the disconnected state or recovery after gateway reconnect. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A visible desktop proof would materially help verify the Usage page disconnected message and reconnect reload behavior. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

visual task: verify the Usage page shows a disconnected message while gateway is offline and reloads selected-period usage values after reconnect.

Risk before merge

  • The Usage page can still remain attached to a disposed/replaced operator client after an explicit reconnect, setup-code apply, settings reconnect, or gateway switch while the page is open.
  • Because RequestUsageAsync still sends an implicit 30-day usage.cost request, accepting and syncing to any returned days value can override the user's selected 7-day period depending on response ordering.
  • The new empty/failure messages overwrite localized x:Uid text with English strings in non-English locales.
  • The screenshot proves the connected layout only; it does not prove the disconnected and reconnect recovery path this PR is meant to fix.

Maintainer options:

  1. Decide the mitigation before merge
    Route Usage refresh through the connection manager/AppState so client swaps and status changes both reload the selected period, keep all visible strings resource-backed, and require proof of the offline-to-reconnected Usage flow.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge
The PR needs contributor or maintainer code changes plus real behavior proof; ClawSweeper repair should not be requested while the proof gate remains unsatisfied.

Security
Cleared: The diff is limited to WinUI page code and localized resource text, with no concrete credential, permission, dependency, build, or supply-chain concern found.

Review findings

  • [P2] Do not let the implicit 30-day refresh override the period — src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:175-178
  • [P2] Reattach when the operator client changes — src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:45
  • [P2] Keep Usage empty text localized — src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:263-273
Review details

Best possible solution:

Route Usage refresh through the connection manager/AppState so client swaps and status changes both reload the selected period, keep all visible strings resource-backed, and require proof of the offline-to-reconnected Usage flow.

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

Yes by source inspection: current main can enter Usage with a non-null but disconnected GatewayClient, while RequestUsageAsync returns early when the WebSocket is not connected. I did not run the WinUI app, so this is source-reproducible rather than runtime-reproduced.

Is this the best way to solve the issue?

No. The branch points in the right direction, but the maintainable fix needs to avoid the implicit 30-day response race, observe operator-client replacement, and use localized resources for new visible text.

Label changes:

  • add proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The attached screenshot shows the loaded connected Usage page layout, but it does not show the disconnected state or recovery after gateway reconnect.

Label justifications:

  • P2: This is a normal-priority WinUI Usage page bugfix/polish PR with blocking review issues but limited blast radius.
  • rating: 🧂 unranked krab: Current PR rating is 🧂 unranked krab because proof is 🧂 unranked krab, patch quality is 🦐 gold shrimp, and The PR addresses a real bug, but insufficient runtime proof and multiple blocking Usage page correctness issues keep it below merge-ready quality.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The attached screenshot shows the loaded connected Usage page layout, but it does not show the disconnected state or recovery after gateway reconnect. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The attached screenshot shows the loaded connected Usage page layout, but it does not show the disconnected state or recovery after gateway reconnect.

Full review comments:

  • [P2] Do not let the implicit 30-day refresh override the period — src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:175-178
    RequestRefresh still calls RequestUsageAsync(), and that method sends a usage.cost request for 30 days before the page sends the selected period request. Since this patch now accepts any returned cost.Days and syncs the selector to it, a normal 7-day load can flip to 30 days when that implicit response arrives last; avoid the extra 30-day cost request or only accept mismatched days when no selected-period response is in flight.
    Confidence: 0.87
  • [P2] Reattach when the operator client changes — src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:45
    This attaches the page only to the CurrentApp.GatewayClient instance present during Initialize(). The connection manager replaces the operator client on explicit reconnects, setup-code apply, and gateway switches via OperatorClientChanged, so an open Usage page can stay subscribed to the old disposed client and never reload when the replacement connects; subscribe to the manager/client-change path or reinitialize from that signal.
    Confidence: 0.86
  • [P2] Keep Usage empty text localized — src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:263-273
    These assignments replace the x:Uid-provided localized text with English constants every time the loading visuals update. In fr/nl/zh locales, both normal empty states and the new disconnected list message display English despite existing resource entries; use resource-backed strings for the defaults and add localized keys for the new failure message.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.86

What I checked:

  • Current-main reproduction path: Current main initializes Usage with any non-null GatewayClient and immediately calls RequestUsage* even when the WebSocket is disconnected, while OpenClawGatewayClient.RequestUsageAsync returns early when !IsConnected; this supports the reported spinner/no-values bug by source inspection. (src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:37, 8560086ebeae)
  • PR period race: At the synthetic merge commit, RequestRefresh calls RequestUsageAsync and RequestUsageCostAsync(_currentPeriodDays), and UpdateUsageCost now syncs the selector to any returned days value; current main's RequestUsageAsync always asks usage.cost for 30 days, so a default 7-day view can be flipped by the implicit 30-day response. (src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:127, d19026d6aeb5)
  • Client swap architecture: Current main routes operator-client replacement through GatewayConnectionManager.OperatorClientChanged and App.OnOperatorClientChanged/GatewayService.AttachClient; the PR page only AttachClient()s the client present during Initialize, so it can miss replacement clients while the page stays open. (src/OpenClaw.Tray.WinUI/App.xaml.cs:1552, 8560086ebeae)
  • Localized resource regression: The merge commit preserves x:Uid-backed Usage page resource keys, and current main has localized fr-fr values, but the PR assigns English constants to DailyEmptyText and ProviderEmptyText on every visual update. (src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:263, d19026d6aeb5)
  • Proof artifact inspected: The attached screenshot shows the connected Usage page layout and values, but it does not show the disconnected state or automatic reload after gateway reconnect.
  • Feature history: UsagePage current behavior is concentrated in recent commits for async loading states, localization, and period-specific usage requests; GatewayService/App client-swap wiring is also recent and explicit. (src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs:32, 8560086ebeae)

Likely related people:

  • bkudiess: Prior merged history touched the same Usage page period selector, localization resources, and App operator-client wiring, so they are a strong routing candidate beyond authoring this PR. (role: recent area contributor; confidence: high; commits: 650f2203eea8, d4b35d4941c0, 139002cbc9d3; files: src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs, src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml, src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw)
  • Scott Hanselman: Introduced the current async list loading/disconnected state behavior for UsagePage and recently touched the same loading visuals. (role: recent area contributor; confidence: high; commits: 1fe8e5216ca7, 0b31e210; files: src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs, src/OpenClaw.Tray.WinUI/Services/GatewayService.cs)
  • Ranjesh Jaganathan: Blame shows the original UsagePage Initialize/UpdateUsageCost structure and GatewayService AttachClient implementation came from recent work under this name. (role: feature origin and adjacent owner; confidence: medium; commits: 8dea8acbae8f, d7d7661ac28c; files: src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs, src/OpenClaw.Tray.WinUI/Services/GatewayService.cs, src/OpenClaw.Tray.WinUI/App.xaml.cs)
  • Mike Harsh: The connection manager/client lifecycle path is tied to recent V2 setup and GatewayConnectionManager work in the history search around OperatorClientChanged. (role: connection lifecycle contributor; confidence: medium; commits: 58315446796e; files: src/OpenClaw.Connection/GatewayConnectionManager.cs, src/OpenClaw.Tray.WinUI/App.xaml.cs)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 8560086ebeae.

@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 priority bug or improvement with limited blast radius. labels May 22, 2026
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

The Usage page fires two usage.cost requests per refresh: one indirectly
via RequestUsageAsync() (always days=30) and one directly via the period
selector (default 7). UpdateUsageCost rejected any response where
cost.Days != _currentPeriodDays, so when the gateway only replied to one
of the two -- or didn't honor the days request param -- valid data was
silently thrown away and the Daily Cost spinner ran forever.

Now:
- Accept any usage.cost response and apply its data.
- If cost.Days is a valid selector value (7 or 30) but doesn't match the
  user's current pick, silently snap the SelectorBar to that period so
  the header isn't lying about what data is on screen.
- Clear ConnectionInfoBar on a successful UpdateUsageCost/UsageStatus so
  late replies after a disconnect recover the UI.
- Remove the hardcoded 284.5K fake value from TokenCountText: it had
  x:Uid='TokenCountText' bound to a resw entry that hardcoded '284.5K'
  across all five locales, masking the real loading bug by making it
  look like Tokens had populated when no usage.cost reply ever arrived.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@clawsweeper clawsweeper Bot added the proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. label May 22, 2026
@shanselman
shanselman merged commit e67f5c2 into openclaw:master May 22, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants