Skip to content

refactor(tray): extract App-owned surface lifetimes - #1085

Merged
karkarl merged 2 commits into
mainfrom
bkudiess-app-surface-owners
Aug 13, 2026
Merged

refactor(tray): extract App-owned surface lifetimes#1085
karkarl merged 2 commits into
mainfrom
bkudiess-app-surface-owners

Conversation

@bkudiess

@bkudiess bkudiess commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Moves concrete tray and non-tray window lifetimes out of App.xaml.cs into two focused App-owned services. This is layer 3 of the App architecture stack and depends on #1082 and #1075.

What changed

  • Add TrayController as the authoritative owner of tray icon, tray menu, live toggle/control references, event subscriptions, popup coordination, status/tooltip application, and dispose-once behavior.
  • Add WindowManager as the authoritative owner of concrete keep-alive, Hub, Chat, connection-status, and Setup window creation/reuse/focus/theme/close lifetime plus App-level Canvas routing.
  • Add typed surface request records and narrow App callbacks instead of moving connection/setup/activation policy into the window owner.
  • Preserve A1 TrayMenuPresenter/TrayMenuRenderer/ConnectionTogglePresenter; TrayController does not interpret menu semantics.
  • Preserve TrayMenuWindow ownership of HWND, DPI/monitor positioning, focus/light-dismiss, keyboard navigation, cascade, and measurement mechanics.
  • Preserve NodeService ownership of the actual Canvas window.
  • Keep App as composition root and owner of startup ordering, settings/activation/routing policy, service lifetime, tray action semantics, setup completion/restart, and final shutdown sequencing.
  • Preserve A0 MCP-only capability refresh and all A0/A1 ownership closures.
  • Update the architecture ledger and source/behavior guards for the two transferred owners.

Ownership transfer

  • Old owner: App.xaml.cs concrete tray/window fields, construction, subscriptions, show/hide/focus/theme/close, and disposal mechanics.
  • New owners: App-owned ITrayController/TrayController and IWindowManager/WindowManager.
  • App residue: immutable snapshot/request construction, route and policy decisions, action callbacks, startup/shutdown call positions, service ownership, and final Exit orchestration.
  • Preserved invariant: surfaces are created/reused/closed exactly once; callbacks unsubscribe before disposal; Hub navigation scope resets once; Setup cleanup completes; no owner is DI-disposed.

Validation

Audited at exact head 7d5f24587a67c7af704d0b90c18c3f7e8dc148c2:

  • ./build.ps1: all 5 projects passed
  • OpenClaw.Shared.Tests: 3,415 passed, 32 skipped, 0 failed
  • OpenClaw.Tray.Tests: 2,205 passed, 0 skipped, 0 failed
  • Focused owner/navigation/lifecycle tests: 36 passed
  • Architecture ledger consistency: 6 passed
  • Real-process accessibility (win-x64): 19/19 passed
  • Enabled integration tests: 19 passed
  • Worktree remained clean; the audit made no source changes

Hosted exact-head checks

  • Default CodeQL run 30868745921: passed at exact head for Actions, C#, and Python.
  • Advanced CodeQL gate 30868708316: passed at exact head; advanced jobs were skipped because repository default setup is active.
  • Safe workflow-dispatch probe 30983100202: restored and built the exact C# head successfully. Query evaluation and SARIF generation/upload completed, but GitHub rejected processing with CodeQL analyses from advanced configurations cannot be processed when the default setup is enabled. This is a default/advanced CodeQL configuration conflict, not an A2 build or source failure.
  • The repository Build and Test workflow has no workflow_dispatch entry and its pull-request trigger targets main/master, so this feature-based stack layer cannot safely manufacture that hosted check. Maintainer retargeting or merge-queue execution is still required for that signal.

Real behavior proof

Current-head isolated runtime proof showed:

  • MCP discovery exposed 51 tools.
  • app.status and app.menu returned the expected disconnected/idle surface state.
  • Hub navigated Connection, Settings, Permissions, Chat, and Diagnostics while reusing one HWND.
  • Closing/reopening Hub exercised navigation-scope reset behavior.
  • Connection status and Setup windows created, reused, closed, and recreated.
  • canvas.present and canvas.hide succeeded; unpaired Canvas visibly routed to Connection while real Canvas ownership remained in NodeService.
  • openclaw://menu forwarded successfully and created the tray-menu window.
  • Light/Dark theme application was exercised across live Hub/Setup surfaces.
  • Clean product Close logs showed WindowManager, tray menu, service provider, and tray icon disposal exactly once and in order.

Current-head Permissions visual proof

Sanitized Permissions surface proof at 7d5f2458

This image was captured from the isolated Dev app at exact PR head 7d5f24587a67c7af704d0b90c18c3f7e8dc148c2 after MCP app.navigate visibly opened Permissions. Privacy crop/redaction only; UI state unchanged. Unrelated desktop content was cropped away and the machine identifier was covered with a solid opaque mask. The original screenshot was not published.

  • Sanitized PNG SHA-256: 810DD5042F3F8808B4AA039F9406D651885179E934FE4A463AFADC75EFB3BE1F
  • Original capture SHA-256: 1690F62072B97300767016DAFE4D6AB34CB37374308EE81F95A6150D4EFD5835
  • Proof manifest

The raw PNG and manifest URLs returned HTTP 200. The downloaded PNG was 1234x804 and matched the local sanitized derivative byte-for-byte.

Reproduction:

./run-app-local.ps1 -Isolated
$env:OPENCLAW_TRAY_DATA_DIR = '<isolated-data-dir-printed-by-run-app-local>'
winnode --command app.navigate --params '{"destination":"permissions"}'

Confirm the isolated Companion window visibly routes to Permissions and retains the expected disconnected/local-MCP surface state.

Warning

Tray/menu media: Not verified / blocked. The only privacy-safe crop removed the tray menu, so no image is published or claimed as tray/menu proof. Runtime transcript, Win32/source contracts, presentation matrices, accessibility tests, and clean shutdown logs cover those paths, but current-head public tray/menu media remains unavailable.

No success is claimed for a paired Canvas dependency that was unavailable in the isolated MCP-only host.

Review

  • Rubber-duck review found one Setup shutdown race: an already-closed Setup window could skip CleanupCompleted. The close path now always awaits cleanup and has a regression guard.
  • GPT-5.6 Sol full-diff review: no actionable findings, 94% overall confidence.
  • Claude Sonnet 5 independent full-diff review: no actionable findings, 90% overall confidence.
  • Claude Opus 4.8 review: no high-confidence actionable defect, 88% overall confidence. Its 35%-confidence concern about ShowHubChatAndStartVoice was rejected after tracing synchronous WinUI Frame.Navigate/Navigated behavior; Sonnet independently reached no-regression confidence of 80% for that specific path.
  • ClawSweeper audit remains 4/6 with zero findings/security findings and proof 5/6. The remaining gaps are hosted Build/Test availability for a feature-based stack layer and public current-head tray/menu media, not verified source defects.
  • The project autoreview helper refused the complete bundle due its 180 KB size cap; no truncated result was used.

Deferred work

Activation routing, settings-change coordination, startup/bootstrap ownership, and final shutdown orchestration remain in App for the next stack layer. Pairing workflow and actual Canvas lifetime remain with their existing owners.

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. labels Aug 4, 2026
@clawsweeper

clawsweeper Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed August 13, 2026, 2:02 AM ET / 06:02 UTC.

ClawSweeper review

What this changes

This PR moves native tray and companion-window creation, reuse, theming, callbacks, and shutdown from App into dedicated App-owned services.

Merge readiness

⚠️ Ready for maintainer review - 4 items remain

Keep open. Current main still keeps the tray and companion-window lifetime code in App, while this collaborator PR is dirty against main and needs conflict resolution plus exact-current-head proof before merge. Likely related people: bkudiess, high confidence from the two preceding merged tray layers.

Priority: P2
Reviewed head: 378197f764476b869b03500b2420ce535e5149d5
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) PR readiness rating was derived from proof quality, review findings, security review, and reviewer confidence.
Proof confidence 🌊 off-meta tidepool Not applicable: Real behavior proof is not required for maintainer- or bot-authored pull requests.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: Real behavior proof is not required for maintainer- or bot-authored pull requests.
Evidence reviewed 7 items Current main still has the requested owner boundary in App: App currently owns tray fields, concrete companion-window fields, tray initialization, and Hub construction, so the central A2 extraction is not already implemented on main.
Architecture ledger calls for this extraction: The current ledger explicitly directs App.xaml.cs toward IWindowManager and ITrayController, with both ownership moves still marked planned.
Stack provenance on current main: Current main contains the preceding merged Permissions and presentation layers, but not this A2 surface-lifetime extraction.
Findings None None.
Security None None.

How this fits together

The WinUI tray app coordinates native notification-area UI and companion windows with gateway, settings, and local-MCP services. App receives user and MCP actions, then routes them to the tray and window owners.

flowchart LR
  Actions[Tray and MCP actions] --> App[Application root]
  App --> Tray[Tray surface owner]
  App --> Windows[Window surface owner]
  Tray --> Menu[Tray icon and menu]
  Windows --> Surfaces[Hub chat setup windows]
  App --> Runtime[Connection settings and node services]
Loading

Decision needed

Question Recommendation
Should this stacked A2 layer be rebased and revalidated by its current owner, or should a maintainer take ownership of resolving the current-main conflicts? Rebase and reprove on current main: Update the branch onto current main, resolve the A0/A1 overlap, and attach exact-head runtime proof before normal review resumes.

Why: The branch is not mergeable against current main, and resolving the overlap determines who verifies the combined lifecycle behavior.

Before merge

  • Resolve merge risk (P1) - The branch is conflict-dirty against current main, so merging it without a resolved integration could regress the newly merged A0/A1 tray behavior.
  • Resolve merge risk (P1) - The supplied visual proof targets a different revision and shows Permissions rather than the tray/window lifetime paths, leaving current-head lifecycle and shutdown behavior unproven.
  • Complete next step (P2) - A maintainer must choose the conflict-resolution owner before an exact current-main diff and runtime proof can be reviewed safely.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Change surface 70 files, +11,059/-3,593 lines The stack-sized refactor crosses tray, window, permissions, and test surfaces, making an exact current-main integration necessary.

Merge-risk options

Maintainer options:

  1. Resolve the stack on current main (recommended)
    Rebase or reconstruct the branch on current main and re-run lifecycle validation before merge because current GitHub state is conflict-dirty.
  2. Pause for a narrower replacement
    Pause this branch if the conflict resolution cannot preserve the intended A2 seam without reintroducing merged A0/A1 code.

Technical review

Best possible solution:

Rebase or reconstruct the A2 extraction on current main, preserve the merged A0/A1 ownership boundaries, then validate real tray, window reuse, routing, and shutdown behavior from the resulting exact head.

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

Not applicable as a bug report. The remaining question is whether the refactor preserves existing behavior after current-main conflict resolution.

Is this the best way to solve the issue?

Unclear. The requested ownership direction matches the architecture ledger, but the current dirty branch and non-current-head proof prevent confirming this exact implementation as the best landing path.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against bc518f7bd158.

Labels

Label changes:

  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit. Replaced prior rating: 🦐 gold shrimp.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.

Label justifications:

  • P2: This is a bounded architecture refactor with normal priority, but it affects common companion-window behavior.
  • merge-risk: 🚨 compatibility: The PR replaces App-owned creation and reuse paths that existing tray and companion-window workflows depend on.
  • merge-risk: 🚨 availability: The refactor changes shutdown and disposal sequencing for native UI surfaces.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit. Replaced prior rating: 🦐 gold shrimp.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: Real behavior proof is not required for maintainer- or bot-authored pull requests.

Evidence

What I checked:

  • Current main still has the requested owner boundary in App: App currently owns tray fields, concrete companion-window fields, tray initialization, and Hub construction, so the central A2 extraction is not already implemented on main. (src/OpenClaw.Tray.WinUI/App.xaml.cs:52, bc518f7bd158)
  • Architecture ledger calls for this extraction: The current ledger explicitly directs App.xaml.cs toward IWindowManager and ITrayController, with both ownership moves still marked planned. (docs/ARCHITECTURE.md:86, bc518f7bd158)
  • Stack provenance on current main: Current main contains the preceding merged Permissions and presentation layers, but not this A2 surface-lifetime extraction. (src/OpenClaw.Tray.WinUI/App.xaml.cs:44, bc518f7bd158)
  • Release check: v2026.7.1 points to 4206611 and git tag --contains bc518f7... returned no release tag, so the current main presentation layer is newer than the latest release and this PR is not shipped. (4206611f2b2e)
  • Merge state blocks landing: GitHub context reports the PR head 378197f as dirty against current main bc518f7, so a three-way integration has not been established. (378197f76447)
  • Prepared visual proof is not exact-head lifecycle proof: The inspected PNG visibly shows the Permissions surface, but its cited revision is 7d5f245 rather than the current PR head 378197f and it does not show tray/menu or surface-lifetime behavior.

Likely related people:

  • bkudiess: The related merged layers for Permissions and Hub/tray presentation were authored in current-main history by Barbara Kudiess and are attributed to bkudiess in the supplied PR metadata. (role: introduced and recently maintained the preceding tray architecture layers; confidence: high; commits: f4e1cf3a9894, bc518f7bd158; files: src/OpenClaw.Tray.WinUI/App.xaml.cs, docs/ARCHITECTURE.md)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Tighten the PR description with what changed, how it was validated, and any remaining risk.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
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.

Workflow

  • 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.

History

Review history (22 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-07T21:27:31.090Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-08T14:24:35.831Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-08T15:40:15.079Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T00:06:22.731Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T03:16:59.127Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T09:28:22.191Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T12:00:14.415Z sha 378197f :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T14:51:51.832Z sha 378197f :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Aug 4, 2026
@bkudiess
bkudiess marked this pull request as draft August 5, 2026 06:23
@bkudiess

bkudiess commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

@clawsweeper

clawsweeper Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added the proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. label Aug 5, 2026
@bkudiess
bkudiess force-pushed the bkudiess-app-surface-owners branch from 7d5f245 to 378197f Compare August 5, 2026 20:42
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Aug 5, 2026
@bkudiess
bkudiess marked this pull request as ready for review August 5, 2026 22:22
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. labels Aug 6, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. labels Aug 7, 2026
Base automatically changed from bkudiess-presentation-models to main August 13, 2026 05:58
@karkarl karkarl added the status: 🚢 actively landing A maintainer or agent is actively driving this item through implementation, validation, or merge. label Aug 13, 2026
bkudiess and others added 2 commits August 12, 2026 23:04
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ed0ab729-86e9-48b1-a0e4-57eeadaa99c3
@karkarl
karkarl force-pushed the bkudiess-app-surface-owners branch from 378197f to 6501249 Compare August 13, 2026 19:03
@karkarl

karkarl commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Current-head UI proof

Captured from the isolated Dev-identity app at commit 6501249b1003692dbf657df2b401db99afea99b6 with local MCP-only mode enabled.

Connection Hub

Connection Hub

Setup window

Setup window

The Setup deep link was invoked twice and UI Automation confirmed that exactly one Setup window remained, demonstrating window reuse.

Permissions Hub

Permissions Hub

The existing Hub window navigated from Connection to Permissions. The local device name was blurred before upload, and all unredacted screenshot files were deleted.

@clawsweeper

clawsweeper Bot commented Aug 13, 2026

Copy link
Copy Markdown

ClawSweeper status: review started.

I am starting a fresh review of this pull request: refactor(tray): extract App-owned surface lifetimes This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@karkarl
karkarl merged commit 3a097bc into main Aug 13, 2026
22 checks passed
@karkarl
karkarl deleted the bkudiess-app-surface-owners branch August 13, 2026 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 🚢 actively landing A maintainer or agent is actively driving this item through implementation, validation, or merge. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants