This document is the living source of truth for the architecture refactor that decomposes the repository's god objects. It is required reading before you touch any file listed in the ledger below.
Its job is to stop the refactor from silently regressing: when a PR moves a responsibility out of a god object, it records the move here and (for high-regression closures) adds a guard test. A later PR that tries to move the work back then shows up as either a visible ledger edit or a failing test.
See AGENTS.md → "Architecture Guardrails" for the hard rules, and the full
multi-PR refactor plan for the reasoning behind each boundary.
- Before editing a file named in the ledger, read its row(s). Do not add
back anything a row marks
closed. - When you extract a responsibility, in the same PR:
- Flip/add the ledger row for the new owner to
authoritative. - Mark the vacated responsibility in the old owner as
closed. - Update the "when you touch file X, extract toward Y" guidance below.
- Add a guard test for the closure when a silent revert would be dangerous.
- Flip/add the ledger row for the new owner to
- Prefer behavioral/golden guards. Use
source-shapeguards only for a concrete prohibited pattern (a banned helper signature, a forbidden direct constructor call), never for broad architectural wishes, and always with aretirement_condition.
- View (XAML + code-behind): layout, named-control wiring, lifecycle event forwarding, minimal WinUI-only adapters. No gateway JSON parsing, no polling loops, no settings mutation, no imperative row factories.
- ViewModel / Presenter (
OpenClaw.Tray.WinUI/ViewModels,.../Presentation): observable state, commands, pure projection. WinUI-free where practical - noMicrosoft.UI.Xaml, noApplication.Current, noWindow/Frame/Brush/Color, no concreteSettingsManager. Unit-tested. - Service: IO, gateway calls, registry/settings persistence, timers, process execution, WebSocket/MCP hosting. No UI types. No background work started from constructors.
- App (
App.xaml.cs): composition root and top-level lifecycle only. - Shared mutable domains: one observable service/store owns each persisted domain. View models consume snapshots and field-scoped or compare-and-swap mutations; they never own backing files, concrete managers, file observers, or parallel mutable caches.
These are the canonical homes. Do not reintroduce private copies elsewhere.
The tray icon's primary activation opens or focuses Workspace chat for configured
profiles, including while disconnected. TrayController invokes its chat callback and
App composes that callback with the WindowManager chat route. Explicit
Connection menu actions retain their settings route; opening Workspace does
not bypass chat authorization or pairing requirements.
StartupSetupState owns first-run eligibility from saved gateway configuration
or local MCP mode, independently of current connectivity and node pairing.
WindowManager applies the same eligibility to Workspace activation, including
forwarded launches and tray clicks: an unconfigured profile opens or refocuses
setup instead of creating Workspace behind it. Explicit companion routes remain
available for advanced connection setup.
Workspace footer text follows the macOS-hosted Control UI at
bda22f8:
the current user's name, then email, then localized Owner; the second line is
connection status. WorkspaceIdentitySource reads users.self profile fields
(displayName, first emails entry), never an agent identity or Windows account.
sessions.changed with reason profile-identity invalidates the profile through
GatewayService/AppState; ordinary session updates do not trigger profile RPCs.
The window owns the display source lifetime, and stale results cannot survive
disconnect, replacement, or close. This cache is not used for authorization.
| Concern | Canonical owner | Status |
|---|---|---|
| Test temp directories | OpenClaw.TestSupport.TempDirectory |
authoritative |
| Bounded audio child-process wait and disposal | BoundedProcessWait owns the supplied Process, including deferred disposal after its kill worker finishes; callers must not dispose it on bounded cancellation return |
authoritative |
| Test env var save/restore | OpenClaw.TestSupport.EnvironmentScope |
authoritative |
| CLI stdout/stderr/env capture | OpenClaw.TestSupport.CliHarness |
authoritative |
| Loopback MCP server for tests | OpenClaw.TestSupport.FakeMcpServer |
authoritative |
| Authenticated MCP HTTP client for app fixtures | OpenClaw.TestSupport.McpClient |
authoritative |
| Synthetic Gateway protocol/scenarios | OpenClaw.TestSupport.Gateway.FixtureGatewayServer + GatewayScenario |
authoritative |
| Fixture-backed app profile/process lifetime | OpenClaw.GatewayFixtureHost.GatewayFixtureProfile + GatewayFixtureRun |
authoritative |
| Explicit fixture context and host-effect isolation gate | OpenClaw.Shared.GatewayFixtureIsolation |
authoritative |
| Passive fixture chat-render acknowledgement | GatewayFixtureRenderObservation (pure metadata) + ReactorChatComposer (UI applicator) |
authoritative |
| External chat session selection without remounting | MountedReactorChat forwards to ChatComposerController's existing root selection handoff; ChatPage retains initial-mount fallback for an unready or replaced provider |
authoritative |
| Workspace agent creation | AgentCreationDialog owns inputs and feedback; AgentCreationService owns permission checks and response-aware gateway creation |
authoritative |
| Workspace owner display identity | WorkspaceIdentitySource reads the current operator's users.self profile; WorkspaceWindow applies name/email/Owner fallback and live connection status |
authoritative |
| Shared native command-catalog inputs | HubCommandCatalog adapts app state/settings/localization for HubPageRegistry; HubWindow and MCP search share it without requiring a companion window |
authoritative |
| Companion-only command-catalog input adaptation | Closed in HubWindow; delegate to HubCommandCatalog so Workspace-first MCP searches use the same inputs |
closed |
| Gateway record test data | OpenClaw.Connection.Tests.GatewayRecordBuilder |
authoritative |
| Settings test data | OpenClaw.TestSupport.SettingsDataBuilder |
authoritative |
JSON JsonElement coercion (non-nullable fallback family) |
JsonReadHelpers |
authoritative |
| Ollama node command risk taxonomy | OllamaNodeCommandPolicy |
authoritative |
| WSL/POSIX shell quoting | WslShellQuoting |
authoritative |
| UI-thread marshaling for presentation code | IUiDispatcher |
authoritative |
| Page view-model activation/deactivation + disposal lifetime | NavigationScopeManager |
authoritative |
| Presentation-layer DI composition root | AppServiceRegistration (root ServiceProvider, owned by App) |
authoritative |
| Settings snapshot read + field-scoped save + origin-aware change notification | ISettingsStore |
authoritative |
| Hosted setup settings writes | SetupSettingsWriter through ISettingsStore; SetupWindow and the pipeline supply only reviewed field patches |
authoritative |
| Cooperating JSON persistence coordination | PersistenceFileLease; registry expected-snapshot Save and settings loaded-JSON CAS hold it through atomic replacement |
authoritative |
| Settings persistence conflict state and visible recovery | SettingsManager owns typed CAS rejection; SettingsPersistenceNotification owns dispatched, deduplicated restart guidance; App composes/disposes it |
authoritative |
| V2 exec-approvals snapshot/CAS persistence + observation | ExecApprovalsStore through IExecApprovalsPresentationStore |
authoritative |
| Settings page load/persist view logic | SettingsPageViewModel |
authoritative |
| Native tool identity, display arguments, payload extraction, and flattened-history projection | NativeToolProjector |
authoritative |
| Managed-local listener provenance and strong-credential authorization | ManagedLocalGatewayPortProvenanceService |
authoritative |
| Native Gateway fixed-product WinGet installation from Microsoft Store and bounded App Installer bootstrap | NativeGatewayMsixInstaller |
authoritative |
| Trusted Store and existing development Gateway registration identities | NativeGatewayPackageIdentity |
authoritative |
| Current-user Gateway package registration, health and package-qualified alias discovery | NativeGatewayPackageResolver |
authoritative |
| Prospective Companion-to-native-Gateway state/config/workspace path mapping | NativeGatewayDataPathMapper; NativeGatewayPackageResolver supplies package and known-folder context. Independent of existing-log resolution |
authoritative |
| Missing-package acquisition, one installation attempt and bounded registration verification | NativeGatewayPackageAcquisition |
authoritative |
| Shared Windows capability and permission selection, with runtime-specific install review | CapabilitiesPage |
authoritative |
| Native profile draft creation and canonical state/config launch paths | NativeGatewaySetupService + NativeGatewayPaths |
authoritative |
| Native onboarding capability admission and default/remembered gateway choice policy | NativeGatewaySetupEligibility, consuming MxcAvailability session probe metadata |
authoritative |
| Package-contract runtime selection and lifetime | NativeGatewayRuntimeRouter selects IsolatedGatewayRuntime or the recognized legacy NativeGatewayRuntime |
authoritative |
| Isolated package control and listener/process-sequence verification | NativeGatewayPackageClient, IsolatedGatewayRuntime and WindowsProcessSequenceSnapshot |
authoritative |
| Retained package-launcher identity, live same-user ancestry and lifetime attribution | WindowsPackagedProcessAncestry, anchored by WindowsNativeGatewayProcessHost |
authoritative |
| Native setup staged-record runtime, reload restoration, config/health and exact-AI gates, publication | NativeGatewaySetupSession |
authoritative |
| Staged native setup operator connection, pairing, per-handshake/request provenance and bound AI transport | NativeGatewaySetupConnection borrowing the runtime from NativeGatewaySetupSession |
authoritative |
| Setup completion authority across native runtime contracts | GatewayDashboardBinding includes the package family and non-null runtime contract; NativeGatewaySetupSession rechecks agent configuration without reading a host config for isolated sessions |
authoritative |
| Native operator connection construction inside the classic wizard page | WizardPage.ConnectNativeClientAsync delegates to NativeGatewaySetupConnection |
closed |
| Published native AI transport and restart verification | GatewayAiSetupTransport.BorrowNativeAsync + GatewayConnectionManager.RequireNativeSetupClientAsync + SetupNativeCompletionVerifier |
authoritative |
| Reviewed native Local AI installation continuation | LocalAiInstallAndUseIntent binds single-use consent to Gateway/endpoint/model/port; LocalAiOnboardingUse retains mutation outcome and drain ownership. SetupWindow transfers the intent after artifact acquisition; AiSetupPage applies progress and exact-model verification without provider rediscovery |
authoritative |
| Native Local AI explicit running intent | LocalAiNativeBindingStore persists automatic-recovery intent separately from ownership; LlamaServerRuntimeService serializes explicit Start/Stop, guarded Resume, withdraw-only reconciliation and explicit release under its operation gate. LocalAiGatewayLifecycle never converts connection notifications into explicit Start; it drains recovery before shutdown withdraws through the still-authorized manager |
authoritative |
| Existing-native Local AI Settings entry | SetupAccessDraft.SelectExistingNativeGateway binds the existing record and preserves Settings ownership; WindowManager initializes only a newly created setup window, and SetupWindow applies the native route without WSL finalization or unrelated settings writes |
authoritative |
| Hosted Gateway onboarding RPC and provider/auth/model rendering for WSL and native | WizardPage |
authoritative |
| Audited optional onboarding defaults shared by native, WSL and headless setup | WizardOnboardingPolicy |
authoritative |
| Optional-tail cancellation acknowledgement and saved-config/authenticated-health gates | WizardOptionalSetupHandoff |
authoritative |
| Native terminal TUI onboarding and pre-wizard registry publication | NativeGatewaySetupHost / NativeGatewaySetupService |
closed |
| Native Gateway credential preflight and retry authorization | NativeGatewayEndpointSecurity owns the bounded native readiness allowance and sanitized startup-timeout classification; GatewayConnectionManager applies that allowance without changing non-native handoff deadlines or authority fences |
authoritative |
| HTTP/dashboard/web-chat credential handoff routing and fresh native inspection | InteractiveGatewayEndpointAuthorizer, borrowing the manager-owned runtime |
authoritative |
| Local AI gateway-record ownership and WSL distro binding | LocalAiGatewayDistroResolver |
authoritative |
| Local AI provider policy and configuration execution | LocalAiGatewayProviderCoordinator owns publication/fallback; ILocalAiGatewayConfigurationTransport separates execution, with WslLocalAiGatewayConfigurationTransport retaining pinned-distro commands |
authoritative |
| Native Local AI admission, publication and reconnect ownership | NativeLocalAiGatewayTarget admits the exact authenticated isolated record; LocalAiGatewayLifecycle binds the single runtime to that owner, borrows authorized connections and journals guarded RPC changes through LocalAiNativeBindingStore; the provider coordinator retains publication/fallback policy |
authoritative |
| Native Local AI recovery discovery | LocalAiGatewayLifecycle.ObserveOwnershipAsync reads current-profile binding and authenticated configuration without mutation or credential access; SetupLocalAiHost supplies evidence to LocalAiOnboardingSnapshot. Only a usable same-owner managed choice replaces a detected model; AiSetupPage renders guidance and retains the existing explicit Use path |
authoritative |
| Native Local AI setup, cancellation and staged handoff | SetupLocalAiHost admits explicit Use; LocalAiOnboardingUse.Expected supplies the explicit managed-use requirement carried by GatewayAiSetupCompletion through fresh verification and restart. NativeGatewaySetupSession retains its verification/publication gate; SetupWindow wires Local AI reconciliation only for that managed choice. Ordinary detected use never gains runtime/reconciliation requirements from matching receipts; setup cancellation withdraws only its selected route |
authoritative |
| Optional managed llama API authentication substrate | LocalAiApiCredentialStore protects a stable key with current-user DPAPI; LlamaServerRuntimeService supplies LLAMA_API_KEY only in the child environment; health/inference clients use Bearer headers and the process host redacts echoed keys |
authoritative |
| Native Local AI artifact-only acquisition | SetupStepFactory.BuildNativeLocalAiAcquisitionSteps reuses Windows hardware, receipt, runtime and model owners without WSL, inference, provider publication or Gateway restart; caller-owned target admission and explicit Use remain required |
authoritative |
| Local AI model cache acquisition, explicit legacy migration, and active-path receipt selection | HuggingFaceModelInstaller + LocalAiManifestStore + LocalAiInstallReconciler |
authoritative |
| Exact Gateway wizard terminal-restart compatibility and bounded retry policy | GatewayWizardRestartRecoveryPolicy |
authoritative |
| Interactive onboarding routes and installation-step selection | OnboardingFlowPolicy |
authoritative |
| Setup-lifetime capability/profile/explicit Custom intent/consent draft and ordered installation requirements | SetupAccessDraft + SetupCapabilityProfiles, owned by SetupWindow |
authoritative |
| Setup provider artwork resolution and bounded page-owned download lifetime | GatewayAiSetupPresentation + ProviderArtworkSession + ProviderArtworkLoader, rendered by ProviderArtwork |
authoritative |
| Native setup editor mounting and committed-result routing | SetupWindow through ISetupNativeConnectionHost + SetupNativeConnectionPage |
authoritative |
| Setup-only Windows privacy preview and probing | Retired; current Permissions settings and runtime consent retain their existing owners | closed |
| Setup Local AI and Tailscale control lifetimes | LocalAiSetupControl in GatewaySetupDetailPage; TailscaleSetupControl inline in GatewaySetupPage with a compatibility detail route |
authoritative |
| Per-setup-window CUDA probe reuse and incomplete/faulted-result refresh | LocalAiHardwareProbeCache; SetupWindow composes it for Welcome and LocalAiSetupControl |
authoritative |
| Temporary setup operator connection, captured identity and endpoint provenance | SetupGatewaySession + SetupGatewaySessionBinding |
authoritative |
| Expected AI restart admission during missing live handshake | GatewayAiSetupController bounds the wait; transports use the existing binding owner to validate persisted authority, then the client requires a fresh exact authenticated route |
authoritative |
| Native setup verify-only connection and isolated validation identity/tunnel | GatewayConnectionValidator + GatewayValidationIdentity |
authoritative |
| Native setup connection input and host transaction adapter | SetupNativeConnectionInputResolver + SetupNativeConnectionHost through GatewayDirectConnectService |
authoritative |
| Committed Existing/Remote Gateway through capability review and AI admission | GatewayDirectConnectService captures endpoint binding; SetupAccessDraft retains it; SetupGatewaySession / borrowed native transport reject drift before credentials or RPC |
authoritative |
| Focused AI setup protocol state and provider progress polling | GatewayAiSetupClient + GatewayAiSetupController |
authoritative |
| Verified AI completion intent and opaque pending restart handoff | GatewayAiSetupClient + GatewayAiSetupCompletion + SetupDashboardHandoffStore + SetupDashboardHandoff |
authoritative |
| Native verified destination choice and selection-time read-only verification | SetupNativeCompletionCoordinator + SetupNativeCompletionVerifier; AiReadyPage renders, SetupWindow composes finalization |
authoritative |
| Native pending launch and bound Chat/Channels/Skills entry | SetupNativeHandoffLauncher + SetupNativeNavigationRequest; SetupNativeSkills owns response-bound read-only skills loading; WindowManager and pages apply the selected route |
authoritative |
| Verified native setup Chat window boundary | SetupNativeNavigationRequest projects the exact Workspace session; WindowManager awaits WorkspaceWindow and its retained ChatPage before activation and receipt consumption. Channels/Skills remain typed companion routes |
authoritative |
| Verified setup Chat hosting in the Settings companion | Closed in HubWindow; typed native Chat requests must use Workspace without dropping endpoint, identity, agent or session verification |
closed |
| Settings Chat rail action | HubWindow forwards a non-selecting item invocation through WorkspaceNavigation to the existing Workspace; Settings never mounts Chat |
authoritative |
| Gateway dashboard management card | ConnectionPage owns the visible card and forwards to the existing GatewayDashboardLauncher path; ChatPage has no management banner |
authoritative |
| In-flight native chat navigation identity | SetupNativeChatBinding holds the exact request reference; WorkspaceWindow invalidates it at admitted agent/session navigation intent, before asynchronous creation. ChatPage checks identity and cancellation on ready and waiting paths; SetupNativeHandoffLauncher fences receipt consumption with the linked timeout |
authoritative |
| Setup-bound Chat warning and recovery presentation | SetupNativeChatPresentation retains the exact verified target through failed mounts; temporary unavailability and provider-confirmation waits hide but retain the host/draft and cannot satisfy handoff readiness. SetupNativeChatRefresh observes the existing manager with activation/request/manager fences and operator-only coalescing. ChatPage applies the InfoBar, releases the binding for composer navigation through ChatComposerHostActions as well as foreign-session queues, and performs the unchanged authority check before reuse. Hidden hosts cancel capture; pending voice starts only after successful evaluation |
authoritative |
| Native receipt acquisition classification and restart recovery settlement | SetupDashboardHandoffStore distinguishes acquired/busy/invalid/unavailable; SetupNativeHandoffLauncher retains recovery on busy/unavailable and clears it only after consumption or definitive rejection |
authoritative |
| Native completion startup readiness | SetupNativeCompletionTiming defines finite phase budgets; SetupNativeCompletionVerifier enforces both borrows, the existing Local AI recovery join and exact-model proof; SetupDashboardHandoffStore keeps five-minute unused admission and persists one non-renewable execution start/deadline under its exclusive lease; SetupNativeHandoffLauncher enforces navigation and total execution deadlines and does not redisplay settled retry failures on automatic activation |
authoritative |
| Pre-acquisition restart recovery deletion | App.OpenNativeSetupCompletion; deletion is delegated to the receipt outcome owner |
closed |
| Setup startup availability | WindowManager supplies app identity availability; SetupWindow gates presentation and persisted preference |
authoritative |
| Setup registration outcome and fallback admission | WindowsStartupTaskRegistration classifies completed numeric HRESULT; SetupStartupPolicy still requires strict task absence for rejected-operation Run-key fallback |
authoritative |
| Pipeline failure plus failed registry settlement | SetupPipeline.RunWithSettlementAsync and SetupPipelineSettlementException retain both outcomes; ProgressPage renders/logs them without declaring reconciliation success |
authoritative |
| Setup HWND sizing and DPI-aware minimum | SetupWindow applies OverlappedPresenter constraints; SetupWindowSizing projects DIP dimensions to physical pixels |
authoritative |
| Verified setup authority across fresh clients | OpenClawGatewayClient.AuthenticatedSigningDeviceId + SetupCompletionAuthority + SetupGatewaySessionBinding; accepted signing identity and exact session survive completion, disk reads only detect drift |
authoritative |
| Native startup versus ordinary update prompt | ActivationRouter.CheckOrdinaryStartupUpdateAsync; App retains startup composition and receipt dispatch |
authoritative |
| Credential-recovery transport admission | GatewayCredentialRecoveryPolicy; normal connection recovery and disposable native validation retain their endpoint-provenance checks |
authoritative |
| User-requested Dashboard launch and visible retry | GatewayDashboardLauncher; dialog lifetime remains in WindowManager; no setup receipt or intent |
authoritative |
| Experimental browser setup-completion handoff | Removed; all completion activation goes through the native receipt owner, including visible rejection of obsolete handles | closed |
| Explicit AI preparation continuation, fresh auth-URL admission and bounded restart wait | GatewayAiSetupController |
authoritative |
| Continuous AI provider dialog visibility and exact row-command admission | AiSetupPage |
authoritative |
| Focused AI discovery display grouping | AiSetupPresentationModel |
authoritative |
| Setup installation three-phase overview and exact step-count projection | SetupInstallationProgress; SetupPhaseStatus renders native status icons/text; ProgressPage retains logs and real download progress |
authoritative |
| Onboarding Local AI readiness, fresh-unsupported visibility projection and cancellable read-only observation | LocalAiOnboardingSnapshot + LocalAiOnboardingObservation |
authoritative |
| Same-window Local AI admission and runtime action bridge | ISetupLocalAiHost + SetupLocalAiHost; route inspection shared with Settings through LocalAiSetupRouteResolver |
authoritative |
| Explicit Local AI mutation drain and retained Gateway/model verification binding | LocalAiOnboardingUse; SetupWindow retains the setup lock through its drain |
authoritative |
| Focused provider prompt controls and input clearing | ProviderSetupDialog, owned by AiSetupPage |
authoritative |
Inline provider wizard rendering in AiSetupPage |
ProviderSetupDialog replaces the inline WizardPanel; page retains request/lifetime ownership |
closed |
| AI provider list selection plus a duplicate page-footer Continue | Explicit native row command or inline API Connect, bound to the exact choice | closed |
| Managed-local automatic repair eligibility and orchestration | ManagedLocalGatewayAutoRepairMonitor + ManagedLocalGatewayRepairCoordinator |
authoritative |
| Permissions page state, settings commands, and exec-approvals presentation | PermissionsPageViewModel |
authoritative |
| Permissions runtime status projection | PermissionsPageRuntimeSource |
authoritative |
| Hub navigation tags, page mapping, command catalog/search, and gateway-page classification | HubPageRegistry |
authoritative |
| Workspace Home/Notifications and exact session-key identity, deprecated-link fallback, back/forward history, and companion boundaries | WorkspaceNavigation + WorkspaceNavigationHistory; WorkspaceWindow restores the selected agent/session on the retained chat host; WindowManager routes pending session links directly without an intermediate Home entry |
authoritative |
| Workspace-versus-companion dispatch and rejection of unknown prefixed routes before window side effects | WorkspaceNavigation.Dispatch; WindowManager and HubWindow supply native window actions; AppCapability propagates navigation error payloads as tool errors |
authoritative |
| Unvalidated Workspace-prefix forwarding and companion fallback | Closed in HubWindow.NavigateTo and WindowManager.ShowHub; delegate boundary dispatch to WorkspaceNavigation |
closed |
| Workspace agent/session identity, background-session filtering, and explicit assistant-selection readiness for conversation creation | WorkspaceProjection; WorkspaceWindow applies readiness to Sessions + and guards the mutation |
authoritative |
| Workspace sidebar session context menu: entries, patch payloads, fork request; flyout, dialogs, and gateway dispatch | WorkspaceSessionMenu (pure entries/patches/fork request), WorkspaceSessionMenuController (flyout, dialogs, gateway dispatch); WorkspaceWindow applies active rows and owns session creation/navigation |
authoritative |
| Archived session browsing and restoration | Settings SessionsPage owns the Archived section and response-confirmed Unarchive action; ArchivedSessionsSource owns the lazy, connection-bound snapshot |
authoritative |
| Archived dropdown, archived row cache, and archive-list fetching in the Workspace sidebar | Removed by design; archived conversations are managed from Settings Sessions, not WorkspaceWindow |
closed |
| Workspace response-confirmed patch/delete and dialog ownership | WorkspaceSessionOperation binds the original operator client and authenticated transport epoch; OpenClawGatewayClient uses PendingRequestRegistry for matching replies; the menu controller reports errors and refreshes accepted changes |
authoritative |
| Explicit Workspace conversation removal | WorkspaceNavigationHistory.RemoveSession prunes removed destinations; ChatPage.ClearRemovedSession disposes the mounted host and invalidates pending surface work; ordinary Home retains its draft-preserving behavior |
authoritative |
| Canonical background-session classification for Workspace sidebar and latest agent session | SessionDisplayResolver.IsBackground, consumed by WorkspaceProjection; nullable gateway flags must not bypass classification/key fallback |
authoritative |
| Native Workspace pane visibility, non-overlapping reopen row, and toggle focus handoff | WorkspaceWindow |
authoritative |
| Speculative Workspace management cards and responsive grids | removed with Home/Sessions-only navigation | closed |
| Foreground Workspace and separate Settings companion lifetime | WindowManager |
authoritative |
| Chat-visible notification suppression | ChatVisibilityPolicy owns the pure visibility decision; WorkspaceWindow supplies current destination, AppWindow visibility and minimized state; WindowManager.IsChatVisible includes compact chat |
authoritative |
| Inferring chat visibility from any existing main window | Closed in App.ShouldShowNotification; use IWindowManager.IsChatVisible, retaining chat/per-type notification toggles |
closed |
| Readiness-gated, single-use native chat voice launch | PendingVoiceActivation |
authoritative |
| Hub notification banner severity and action projection | AppNotificationInfoBarPresenter |
authoritative |
| Compact notification list reconciliation and dismissal | NotificationFlyoutContent |
authoritative |
| Gateway/operator/node status flyout controls | GatewayStatusContent |
authoritative |
| Tray-menu semantic composition and connection-toggle state | TrayMenuPresenter + ConnectionTogglePresenter |
authoritative |
| App-owned non-tray window creation, reuse, focus, theme, and lifetime | IWindowManager + WindowManager |
authoritative |
| Tray icon, popup coordination, live status, and callback lifetime | ITrayController + TrayController |
authoritative |
| Deep-link/protocol/toast/forwarded activation normalization, current-user IPC, and semantic activation plans | ActivationRouter |
authoritative |
| Packaged activation-kind preservation | App.GetLaunchActivation adapts Windows AppLifecycle metadata into LaunchActivationInput; ActivationRouter shares candidate selection for initial/secondary launches and reserves implicit foreground navigation for interactive Launch |
authoritative |
| Post-save settings change effect ordering, detached snapshot comparison, and concurrent save serialization | SettingsChangeCoordinator |
authoritative |
| Exactly-once ordered app shutdown sequencing | AppShutdownCoordinator |
authoritative |
| App composition-root startup sequencing | AppBootstrapper (planned) |
planned |
| Inno migration records, preparation, and pre-start completion guard | MigrationRecordCodec, MigrationPreparation, MigrationInventory, InnoMigrationStartupGuard |
authoritative |
| Cross-session migration exclusion and source activity inspection | MigrationOperationLock, InnoSourceActivityVerifier (App only retains the runtime handle through process exit) |
authoritative |
| Store migration startup admission and finalization | InnoInstallationDetector, InnoSourceRemovalVerifier, MigrationStartupRecordReader, MigrationInventoryCapture, StoreMigrationStartupCoordinator, StoreMigrationFinalizationCoordinator, StoreMigrationStartupGuard |
authoritative |
| Windows node connection generation, cancellation, start ordering, recovery, events, and telemetry | NodeConnectionCoordinator |
authoritative |
| Bootstrap/shared/device credential handoff, durable clear gate, and operator token recovery timing | BootstrapTokenLifecycle |
authoritative |
| Device role-upgrade approval, confirmation, and bounded node reconnect queue | DevicePairApprovalCoordinator |
authoritative |
Gateway wire protocol range, minimal hello-ok validation, and sanitized compatibility state |
GatewayProtocolContract + GatewayProtocolCompatibility |
authoritative |
| Capability UI metadata | NodeCapabilityUiCatalog (planned) |
planned |
| Capability registration/gating | NodeCapabilityRegistrationPolicy (planned) |
planned |
| Local MCP exposure policy | McpCapabilityPolicy (planned) |
planned |
| Gateway connect envelope | ConnectEnvelopeBuilder |
authoritative |
| Gateway request tracking | PendingRequestRegistry |
authoritative |
| Chat atomic runtime transaction lock and cross-domain commits | ChatConversationState |
authoritative |
| Chat queue collections, echo correlation, drain and retry commit mechanics | ChatQueueState under the ChatConversationState lock |
authoritative |
| Pending chat bubble presentation | ReactorChatTimeline projects the selected-thread queue after the current turn, using the normal user bubble and existing controller cancellation |
authoritative |
| Pending chat preview list inside the composer | Closed in ReactorChatComposer; the composer contains only the unsubmitted draft and attachments |
closed |
| Chat reset generations, gates, echoes and backfill state | ChatResetState under the ChatConversationState lock |
authoritative |
| Chat history identity, revisions and connection-generation tokens | ChatHistoryState under the ChatConversationState lock |
authoritative |
| Chat sessions, models, catalog and snapshot projection inputs | ChatPresentationState under the ChatConversationState lock |
authoritative |
| Chat run, abort and terminal lifecycle state | ChatLifecycleState under the ChatConversationState lock |
authoritative |
| Chat approval identity correlation and dedupe state | ChatApprovalState under the ChatConversationState lock |
authoritative |
| Chat send admission/retry decision policy | ChatSendQueuePolicy with atomic commits coordinated by ChatConversationState |
authoritative |
| Chat history request/retry/rebuild mechanics | ChatHistoryLoader with token acceptance coordinated by ChatConversationState |
authoritative |
| Gateway agent event to chat event mapping | ChatEventMapper |
authoritative |
| Chat snapshot projection | ChatSnapshotProjector |
authoritative |
| Tool and attachment metadata cache lifecycle | ChatMetadataStore |
authoritative |
| Aborted IDs and last-chat-state persistence | ChatStatePersistence |
authoritative |
| Sensitive instant-capture ordering | SensitiveCaptureExecutor + SensitiveCapturePlans |
authoritative |
Windows deploys the MSIX. The current Gateway package owns its isolated session
and Gateway service; Companion owns setup, connection and credential handoff;
upstream OpenClaw supplies onboarding over RPC. The known legacy proof package
instead uses Companion's same-user process supervisor. Package installation,
a listening port, and successful onboarding are not
interchangeable readiness signals. App remains the composition root; do not
move package resolution, process inspection or setup finalization back into it.
Isolated runtime inspection and lifecycle ownership are separate. Verification is cached per record and is always checked against fresh listener snapshots; probing another package cannot transfer stop ownership. Only starts issued by Companion are stopped on detach, and failed authorization rolls back only a start issued by that same call. Explicit wizard restart uses a separate runtime operation and preserves a pre-existing service's leave-running policy. Ownership inspection, including the fresh check before credential handoff, has a five-second deadline. Package inspection failures, including WinRT deployment errors and an explicit unknown service state, deny handoff as unavailable inspection rather than claiming a conflicting listener. Authentication recovery classifies these unavailable probes as network failures.
NativeGatewayMsixInstaller.InstallAsync invokes the signed-in user's App Installer
alias (%LOCALAPPDATA%\Microsoft\WindowsApps\winget.exe) through the existing
CommandRunner, without a shell or elevation. The fixed command is
install --id 9NV70LV3D6XC --source msstore --silent --accept-package-agreements --accept-source-agreements --disable-interactivity --no-upgrade.
The native review explains that selecting Set up gateway authorizes installation
and accepts the package and Store source agreements. Microsoft Store still owns
architecture/package selection, signature validation and deployment. There is no
automatic Store-page fallback: missing WinGet, policy/source failures and nonzero
exit codes produce explicit retry/repair guidance with sanitized, bounded output.
Command success is not package readiness. There is no local source path,
environment override, direct download, certificate-trust change, or ARM64-only gate.
NativeGatewayPackageResolver.ResolveAsync subsequently requires exactly one
matching current-user package registration, verifies package health, and resolves
its package-qualified openclaw.exe and clawctl.exe execution aliases. Never
substitute a generic PATH/npm command, copied executable or guessed WindowsApps
installation path. NativeGatewayPackageClient probes clawctl status --json
for integration.kind: "isolated-session" and version 1. An unversioned
response that already describes a session is unsupported, not a legacy
fallback. Only the known 0.0.0.0 and 0.0.0.1 proof packages retain the
same-user path.
NativeGatewaySetupHost invokes clawctl setup --json and requires a ready
isolated session before configuring it; that command does not perform
Gateway onboarding.
NativeGatewayPackageIdentity accepts the Store manifest's exact pair:
OpenClawFoundation.OpenClawGateway and
CN=4BA40A7A-B719-4C40-BF91-84AF4F1136FC
(packaging manifest).
The original OpenClaw.Gateway / OpenClaw Foundation development publisher pair
remains accepted for already installed packages and saved profiles. Names and
publishers cannot be mixed. New setup with both identities installed produces an
explicit duplicate-registration error, not an implicit migration or preferred-package
fallback. The runtime resolver selects the saved profile's exact family, so an
existing Gateway remains usable when both packages are installed. Runtime records
remain pinned to their saved package family; Store
installation does not rewrite a development profile's identity. Package-family
syntax checks admit both names, while registration and exact family matching
remain mandatory before launching. An existing same-user record is not silently
migrated to a newly installed isolated package; it requires new setup.
scripts\NativeGatewaySourceBuild.psm1 owns the source-build safety boundary:
machine-wide build/unregister serialization, protected creation of work directories,
read-only validation of existing tree and ancestor ACLs, and prebuilt metadata/hash
validation before cache selection. Existing unsafe permissions are rejected, not
silently repaired. This protects loose-package code without changing Store resolution.
Developers opt in to a source-built Gateway with
OPENCLAW_NATIVE_GATEWAY_DEV_PATCH=<patch>. scripts\Build-NativeGatewayFromSource.ps1
builds an openclaw/openclaw ref and registers it with the packaging repo's
Deploy-LocalPackage.ps1 -Patch as the side-by-side loose registration
OpenClawFoundation.OpenClawGateway-<patch> under the Store publisher, with
package-qualified aliases openclaw-<patch>.exe and clawctl-<patch>.exe. While the
variable is set, new setup selects only that patched package
(NativeGatewayPackageIdentity.IsSelectable) and a missing patch is an explicit error,
never NativeGatewayPackageNotInstalledException, so WinGet never runs. Saved profiles
bound to a patched family resolve only while the variable names that patch
(IsResolvable); otherwise the resolver reports which value to set. With the variable
unset, selection, resolution and aliases are identical to the Store path.
After native capability/permission review, NativeGatewaySetupPage starts
automatically. It rechecks device support, then calls
NativeGatewayPackageAcquisition.EnsureAsync. Only the typed
NativeGatewayPackageNotInstalledException starts WinGet installation, once per attempt.
Healthy registration skips installation; duplicate registration, unhealthy packages
and missing aliases fail explicitly instead of triggering reinstall loops.
The cancellable acquisition deadline is five minutes including installation and
registration verification, with one-second polling after WinGet completes.
Cancellation reaches CommandRunner, which stops its WinGet process tree;
Windows may still finish an already submitted deployment. No installed package
is removed, and retry starts by resolving registration again.
The page uses the shared OnboardingMascot, native SettingsCard rows with
SetupPhaseStatus, and SetupProgressIndicator for support, package readiness,
profile preparation and verified runtime startup. Completed rows get checkmarks.
Its Install stage leads to the same focused AI and Ready stages as WSL, with six
native stages (WSL has an additional installation review). Progress sits above wrapping navigation actions on
both pages so narrow windows do not overlay buttons on the indicator.
It automatically transfers the staged session to AiSetupPage; no separate
Install, Check again or Open Gateway setup actions remain. Retry is error/cancel
recovery only. Preview never installs or starts a Gateway.
Native and WSL use the same CapabilitiesPage profiles and toggles. Native
installation consent stays on that page, without a separate review or
WSL/Local AI/Tailscale probes. Cancelling returns to capabilities without
automatically restarting a runtime.
On finalization, the session applies selected command IDs to the Gateway's
gateway.nodes.commands.allow through the upstream CLI before config/health
verification. The isolated path applies this inside the agent account, not
under Companion's Windows profile; legacy profiles retain the local writer.
Focused completion explicitly restarts through the selected runtime owner and
reverifies the exact model before publication. The isolated runtime preserves
whether a pre-existing service should be left running on detach. Focused setup
drains its operator before finalization and does not call isolated Stop before
Restart, which would otherwise discard stop ownership for a setup-started service.
The shared setup settings owner then saves the reviewed capability, transport
and startup choices without overwriting unrelated settings. Settings write
failure stays retryable before releasing the session. Completion shows the
verified model and three destinations, not a running or paired Windows node.
The normal connection owner still performs node connection/pairing; Windows
permission and exec-approval gates are unchanged.
Native package setup uses the shared AiSetupPage and AiReadyPage flow.
Only an explicit unsupported-method result offers WizardPage compatibility
setup. Authentication failures, timeouts and uncertain writes do not enter that
fallback. Healthy native and WSL AI/Ready screens use the same presentation:
providers, verified model and the three destination choices, without a native-only
summary. Gateway and permission details remain in Connection and Permissions.
Native recovery actions and output appear only for actionable errors or uncertain
outcomes on the AI page/provider dialog, and hide again during normal progress or
after recovery. Their native ownership and cancellation guards are unchanged.
The 2026-09-18 onboarding decision removed the separate "not isolated" warning/checkbox. General security consent and exact-identity pairing remain. Capability eligibility alone does not establish the Gateway's runtime account: the package-qualified versioned integration check selects the isolated package path, while the known legacy proof remains same-user.
On Welcome, NativeGatewaySetupEligibility consumes the actual
wxc-exec --probe result probes.isolationSessionAvailable exposed by
MxcAvailability.IsolationSessionCapability. It must not infer session capability
from IsolationProxy.exe, a process-containment tier or a Windows build alone.
Windows Server/unknown SKU suppression remains in the shared probe. Missing or
invalid session metadata does not invalidate a usable process sandbox, but it
cannot authorize native onboarding.
A positive result enables and initially selects the first Install a local native gateway card with the accent highlight and Recommended badge. A negative capability result leaves that recommended choice visible but disabled after WSL and Connect to an existing gateway, with Windows Update guidance directly below the choice list; reopening the page rechecks support. The pinned SDK documents Insider build 26340.9212 as its baseline. This is update guidance, not a hardcoded admission floor or a promise that a particular feature is enabled. The native boolean cannot distinguish every OS API failure from missing support. Missing executables, malformed results and probe errors instead offer retry or Companion repair, not an assertion that Windows must be updated.
The Welcome page presents WSL, Connect to an existing gateway, then disabled native
Gateway while support is being checked or unavailable. A positive result moves native
to the first position, followed by WSL and the existing-Gateway choice. WSL is visible
and selectable during the native probe and for every probe outcome, without an expander.
There is no Welcome-page Check again button.
WSL/Local AI discovery starts on page load; fresh WSL readiness and
destructive-replacement confirmation still run before its capabilities page.
WSL is never selected implicitly after a failed native probe. A late probe
result preserves explicit WSL and existing-gateway selections, including choices
restored on Back navigation. Re-entering the
page rechecks support, stale results cannot mutate an unloaded page, and native
package setup rechecks capability before preparing a profile.
ms-settings:windowsupdate only opens Settings; Companion does not enroll the
device in an Insider channel or change Windows feature flags.
NativeGatewaySetupService creates or resumes a credential-free draft descriptor
containing a Gateway ID, preferred loopback port, package family, and runtime
contract. The draft is not yet a published GatewayRegistry record. Companion
keeps its device identity under its own data directory, but an isolated package
keeps OpenClaw configuration, credentials and workspace under the agent account.
For an isolated package, clawctl companion prepare --port <preferred> --json
reads the agent's default openclaw.json and invokes upstream
openclaw config patch inside the recorded session. It preserves an existing
local port and token plus unrelated settings and rejects incompatible mode,
bind and authentication settings. Companion records the returned effective
port and token; it does not create a host-side openclaw.json, forward its
profile paths or install its own Gateway supervisor. Package
gateway-service start/status/stop owns the service lifetime. A cancelled
draft can resume without replacing the agent's credential. Finalization
checks that the returned port and token still match before publishing.
If an unpublished same-user draft survives an upgrade to an isolated package,
Companion shows an explicit replacement choice. Discarding removes only the
Companion draft descriptor, then starts isolated setup with a new identity.
Existing configuration, credentials and workspace files remain untouched, even
if a previously published connection was removed from the registry. Like
StoreMigrationRecoveryDiscard, native recovery discards intent, not user data;
the Inno-specific receipts and installation checks are not shared with native setup.
It never reuses host configuration as agent configuration. A published
same-user profile remains blocked and directs the user through Connections to
remove it and create a new isolated profile. It never adopts a foreign listener
or session, and it does not modify WSL or other package paths.
The following same-user profile and port-rotation path applies only to the
recognized legacy proof package. It creates a separate profile at
<Companion data>\gateways\<gateway-id>\native-gateway, with its own
openclaw.json, generated authentication token and workspace.
Retry re-reads the draft instead of keeping a stale in-memory port. If an
unpublished draft's port is occupied, NativeGatewaySetupService selects another
loopback port and updates only the port in the descriptor and configuration.
Gateway ID, identity, authentication token and provider settings are preserved.
A durable PreviousPort intent in the descriptor allows either interrupted
write to finish on the next attempt. Published records are never rotated by
this recovery. Runtime ownership checks still reject listeners that race startup;
no conflicting process is adopted or terminated.
For that legacy path, NativeGatewayPaths supplies explicit OPENCLAW_STATE_DIR and
OPENCLAW_CONFIG_PATH for package commands, rather than using the user's default
Gateway profile. Launch paths are mapped through ResolveDataPath to physical
locations because Companion and Gateway can have different MSIX filesystem
views; canonical registry paths are unchanged. External-supervisor/service-repair
flags and disabled automatic updates preserve Companion's lifecycle ownership.
NativeGatewaySetupSession owns cancellation, pairing and final publication
gates for both paths. Only legacy setup backs up and suspends the reload setting
in its host-owned profile; the isolated path leaves the agent's existing
reload setting intact. Stopping either runtime does not delete its configuration.
After a successful package start acknowledgement, IsolatedGatewayRuntime
allows up to three minutes, including the start command, for its own start to
become ready. A late successful acknowledgement retains ten seconds for status
confirmation, extending the start/status ceiling to at most 190 seconds. This
allowance remains subordinate to caller deadlines; the outer 210-second connection
budget also includes preflight, inspection and handshake work. It polls status
every two seconds without issuing another start.
starting or unhealthy with no listener is only a pending observation, never
credential authority. A listener racing the pending observation permits one fresh
status recheck, but only running plus full port/process attribution can pass.
Unknown/terminal states, persistently unattributed listeners and failed
ownership checks fail closed. Cancellation/deadline failure retains the existing
owned-start rollback rules; pre-existing pending services are not adopted.
See native startup contract limitations
for the older package's ambiguous failed-start response, which is not admitted.
The pending-start fixtures are conditional client-contract tests, not proof that
the installed package can acknowledge a pending launch.
IsolatedGatewayRuntime accepts a running Gateway only after a fresh
package-qualified clawctl gateway-service status --json attributes its
listener process IDs, creation times, and OS sequence numbers to the
recorded isolated session and agent SID. Companion compares that
attribution to two complete IPv4/IPv6 loopback snapshots and
SystemBasicProcessInformation process-sequence snapshots. It does not
open the isolated agent's process handle: Windows denies that cross-account
query. Windows 11 build 26100.4770 or newer is required for that
process-sequence API; unsupported builds fail closed with update guidance.
A port alone, a stale process ID, an unrelated listener, or a
replaced listener is denied. Its
synchronous browser credential callback uses the last attributed identity
plus fresh OS snapshots; it never starts a Gateway on the UI thread.
The process-job and ancestry checks below describe only the legacy same-user runtime. They are not an MXC session ownership proof.
The installed package's launcher owns a separate kill-on-close job for Node. Observed ownership with the development package was:
Companion-owned Windows lifecycle job
Packaged Gateway launcher
Package-owned Windows lifecycle job
Node process hosting the Gateway TCP listener
The original requirement that the TCP listener itself belong to Companion's job rejected this valid arrangement: the launcher was in Companion's job, but Node was not. A longer timeout, direct executable launch or an open loopback port could not establish ownership. The exact Windows job-inheritance mechanism behind that separation was not established.
WindowsNativeGatewayProcessHost now creates the package launcher suspended,
assigns it to Companion's kill-on-close job, retains its process handle, then
resumes it. Assignment/resume failures terminate the created process. Atomic
job-list creation had failed while the package was already active; suspended
creation and assignment worked with the existing Gateway still running.
NativeGatewayRuntime accepts the listener through direct job membership or
WindowsPackagedProcessAncestry: a live same-user descendant chain anchored to
that exact, still-job-owned launcher with the expected package family. Retained
process handles, parent/child creation ordering and bounded ancestry checks
prevent cached PIDs or executable names from being treated as ownership proof.
The runtime also requires complete IPv4/IPv6 inspection, loopback-only listeners,
the requested address, matching process creation times and two consistent TCP
snapshots. Unknown or replaced listeners are rejected, not adopted.
No new cross-package process-handle protocol was added to the packaging repo.
An explicit authenticated handle-handoff contract was considered; the implemented
solution uses local retained-handle attribution with the existing package.
Companion owns the launcher lifetime, while the launcher owns Node cleanup.
NativeGatewayEndpointSecurity and setup authorization use this verification
before credential-bearing connections, including reconnects.
InteractiveGatewayEndpointAuthorizer routes dashboard and web-chat HTTP
credential handoffs to the same runtime's fresh, double-snapshot inspection.
Its synchronous UI callback never starts a Gateway or waits for a busy lifecycle
gate; busy, stopped, disposed or replaced workloads fail closed. It does not
trust cached proof or connected status. App only composes this non-owning adapter;
process inspection stays in NativeGatewayRuntime. Non-native handoffs retain
ManagedLocalGatewayPortProvenanceService authorization. Typed native listener
conflicts retain LocalPortConflict classification instead of becoming generic
network failures.
The legacy path is same-user supervision, not an MXC sandbox or a security boundary against malicious same-user code. There is a narrow crash window between suspended creation and job assignment that can leave a suspended launcher; kill-on-close cleanup applies after assignment, and no launcher code has resumed before then.
This section describes the explicit compatibility path only. The normal native
path uses the same detected providers, activation, exact-model verification and
Chat/Channels/Skills chooser as WSL. NativeGatewaySetupConnection owns the
temporary operator socket in both paths; it never owns or replaces the native
runtime. SetupWindow retains NativeGatewaySetupSession across AI/Ready navigation.
The compatibility page retains the native wrapper with its exact client binding. All wizard RPCs, including progress, cancellation and the optional-policy config/health checks, pass through the generation-fenced request helper and native per-request authorization. Replaced bindings cannot send through a newer client. Page teardown cancels/drains requests and disposes the captured socket wrapper; only the window releases the native session/runtime after page cleanup.
NativeGatewaySetupPage prepares the session and passes it to the shared
WizardPage. The page owns RPC/rendering; the session owns the profile/runtime.
There is no second provider UI or normal terminal-based onboarding path.
- Validate initial configuration, start the package-owned service or legacy runtime as appropriate, and verify its listener before sending credentials.
- Connect using the per-Gateway identity and prefer its stored device token.
When pairing is required,
ApproveWizardPairingAsyncmatches the handshake request ID against that identity's device ID and public key, rechecks endpoint ownership/configuration, and approves only the exact request via the package CLI. Never approve the latest unrelated request or bypass onboarding consent. The package omits listener ownership details if Windows cannot supply process-sequence evidence. Gateway health remains independent, but Companion refuses credential handoff until running on Windows 11 build 26100.4770 or later. Re-runningclawctl setupcannot add this OS capability. - For the legacy profile, clear inherited URL overrides, pin the port and
supply the token in the child environment, not argv. The isolated path
uses package-qualified
openclaw devices listandopenclaw devices approve <request-id>. These commands run in the agent context and use its Gateway config; Companion checks that its saved port and token still match the agent config before each command. It does not pass the token or host profile paths to the CLI. The CLI budget includes slow package startup. Dispose the failed-handshake client before one bounded retry; disconnect alone does not stop its reconnect loop. - Call
wizard.startwithmode=localandinstallDaemon=false; render upstream steps and submit answers throughwizard.next.wizard.cancelends the session. Companion does not install a competing Gateway service.
WizardOnboardingPolicy supplies the same audited optional skip/keep answers to
native, WSL and headless onboarding. Consent, provider/auth/model choices,
permissions, unknown prompts and errors are not silently answered.
For isolated setup, WizardConsoleTail uses the authenticated operator's
upstream logs.tail RPC to project only root-logger console.log entries
after listener verification. The initial cursor is captured before
wizard.start, and later polls are byte/line bounded and already redacted
by OpenClaw. A gap or failure surfaces recovery-terminal guidance rather
than silently discarding an OAuth prompt. No package log-file path or host
profile is passed to the agent; legacy profile and WSL tail modes remain
separate.
The focused path admits only GatewayAiSetupCompletion bound to the same
Gateway endpoint/package family, persisted signing identity, agent, canonical
session and verified primary model. Showing the chooser publishes nothing.
Each destination freshly verifies through the staged native owner, then
CompleteVerifiedAsync stops the setup runtime, restores reload, applies selected
capabilities, validates configuration and health, and performs another exact-model
verification on the restarted runtime before publishing the record. It does not
set the classic wizard-completed flag. Publication reloads unrelated Gateway edits
and uses an expected registry snapshot; an already occupied draft ID is rejected.
After Companion restarts, verification borrows the normal connection manager's
native-authorized operator connection. It rechecks provenance on every request
and never starts a parallel native runtime or disposes that borrowed connection.
The generic SetupGatewaySession rejects native records. Windows-node WSL
workspace finalization never runs for this route.
At the Optional apps checkpoint, WizardOptionalSetupHandoff explicitly cancels
the remaining optional wizard tail, requires cancellation acknowledgement, and
checks config.get validity and authenticated health. The native session records
optional setup as deferred, not upstream wizard completion. Arbitrary errors or
user cancellation cannot take this success path.
After real wizard completion or the validated optional handoff,
NativeGatewaySetupSession.CompleteAsync performs:
Stop setup-owned Gateway -> apply capability policy (and restore legacy reload)
-> validate endpoint/auth and config -> restart with verified ownership
-> authenticated health -> stop setup-owned runtime
-> save and activate GatewayRegistry record -> release setup ownership
Only then does the existing setup-completion restart path hand normal operation
to GatewayConnectionManager and its App-composed
NativeGatewayRuntimeRouter. The isolated branch delegates lifecycle to
clawctl gateway-service; it leaves a pre-existing package service running
when Companion detaches. The legacy branch retains Companion-owned process
supervision. Reconnect verifies package/agent listener identity again rather
than adopting an unrelated port. Failed/cancelled setup
must not publish an unverified Gateway record.
Disconnect stops a Gateway that Companion started, but preserves its data; an already-running package-owned service is not stopped merely because Companion detached. Removing the saved Gateway in Connection settings removes the registry entry, not the agent's OpenClaw configuration or a legacy Companion-owned profile. Windows Installed apps owns MSIX uninstallation and package-managed agent data; Companion's device identity is separate. Back up configuration, credentials, workspace and conversation state before destructive cleanup. The broader Companion/WSL uninstall flow is not a native-Gateway-only uninstaller.
Gateway health alone does not prove AI-provider authentication, required
model-runtime availability or a usable default chat. The focused native path
requires live exact-model verification as well; the compatibility wizard retains
its narrower configuration/health summary. Real-package/provider E2E proof and
MXC isolation remain separate gates. See
Gateway setup responsibilities for the
investigation, production-backed proof and local-only recovery workarounds, and
onboarding wizard for the user flow. Regression coverage
lives in NativeGatewayRuntimeTests, NativeGatewayWindowsProcessHostTests,
NativeGatewaySetupTests, WizardOptionalSetupHandoffTests and
NativeGatewaySetupUxContractTests.
| If you are editing… | Do not grow it. Extract toward… |
|---|---|
src/OpenClaw.Tray.WinUI/App.xaml.cs |
use the authoritative IWindowManager, ITrayController, ActivationRouter, SettingsChangeCoordinator, and AppShutdownCoordinator; the remaining A3 extraction target is startup sequencing into AppBootstrapper (planned/deferred) |
src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs |
navigation/catalog policy → HubPageRegistry; notification banner projection → AppNotificationInfoBarPresenter; keep Frame, NavigationView, back-stack mutation, control application, and route side effects in the view |
src/OpenClaw.Tray.WinUI/Windows/WorkspaceWindow.xaml.cs |
route/history policy → WorkspaceNavigation; agent/session projection → WorkspaceProjection; window lifetime → WindowManager; session context menu → WorkspaceSessionMenuController; keep named-control application and existing page hosting in the view |
src/OpenClaw.Tray.WinUI/Services/TrayMenuRenderer.cs |
semantic composition → TrayMenuPresenter; connection toggle projection → ConnectionTogglePresenter; keep WinUI control construction and callback application in the renderer |
src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs |
Keep as the IChatDataProvider facade; atomic runtime coordination → ChatConversationState, lock-internal state mechanics → its queue/reset/history/presentation/lifecycle/approval substates, queue decisions → ChatSendQueuePolicy, history IO → ChatHistoryLoader, mapping → ChatEventMapper, native tool projection → NativeToolProjector, snapshots → ChatSnapshotProjector, metadata → ChatMetadataStore, persistence → ChatStatePersistence |
src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs |
ChatBubbleRenderer, PermissionRequestCard, AttachmentBubbleRenderer; tool rendering stays in ToolCallCardRenderer |
src/OpenClaw.Tray.WinUI/Chat/OpenClawReactorChatRoot.cs |
Keep as the provider-subscription/selection/timeline-composition root only; composer state → ChatComposerViewModel, composer workflow → ChatComposerController, composer view → ReactorChatComposer.cs |
src/OpenClaw.Tray.WinUI/Chat/ReactorChatComposer.cs |
Declarative view only; workflow/state changes go in ChatComposerViewModel/ChatComposerController, not new Reactor UseState/refs here |
src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs |
ConnectionPagePlan (pure), ConnectionPageViewModel, GatewayDirectConnectService, gateway row models |
src/OpenClaw.Tray.WinUI/Pages/SettingsPage.xaml.cs |
settings read/persist → SettingsPageViewModel + ISettingsStore; keep gateway-uninstall, uptime timer, saved-indicator, and app-info in the view |
src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs |
state/commands → PermissionsPageViewModel; runtime projection → PermissionsPageRuntimeSource; persistence → ISettingsStore and IExecApprovalsPresentationStore; keep exact WinUI rendering, clipboard/privacy actions, and save-hint timer in the view |
src/OpenClaw.Tray.WinUI/Services/NodeService.cs |
McpServerHost, CanvasWindowManager, MediaCapabilityHost, RecordingConsentService, SensitiveCaptureExecutor, NodeCapabilityRegistry |
src/OpenClaw.Shared/OpenClawGatewayClient.cs |
GatewayMessageRouter, per-domain API facades |
src/OpenClaw.Shared/Models.cs |
per-domain model files + *Mapper classes |
src/OpenClaw.Shared/Capabilities/SystemCapability.cs |
ExecApprovalService |
src/OpenClaw.SetupEngine/SetupSteps.cs |
one file per step (done for the steps still referencing this file); WslShellClient and GatewayConfigScriptBuilder remain pending. WSL/POSIX quoting is done - use WslShellQuoting, never a local ShellEscape. Setup-time keepalive process ownership is authoritative in KeepaliveProcessManager (see setup-keepalive-process-manager). |
src/OpenClaw.Connection/GatewayConnectionManager.cs |
The three connection-domain owners are authoritative. Keep only the public lifecycle facade, manager-owned operator/state/tunnel orchestration, typed source/sink/security ports, and event forwarding. |
| Any test hand-rolling a temp dir / env save-restore / CLI capture | OpenClaw.TestSupport fixtures |
The ledger is machine-readable and validated by
OpenClaw.Shared.Tests/Architecture/ArchitectureLedgerConsistencyTests.cs.
Rows live between the BEGIN/END markers, one per line, pipe-delimited, with a
leading and trailing pipe. Columns, in order:
id | status | old_owner | closed_responsibility | new_owner | allowed_residue | invariant | guard_test | guard_type | retirement_condition
status:planned|authoritative|closedguard_type:behavioral|golden|source-shape|review-only- For
authoritative/closedrows,guard_testmust name a test asType.Method(validated for format), ORguard_typemust bereview-onlywith a real rationale inguard_test(placeholders like-/noneare rejected). - For
behavioral/goldenrows, the namedguard_testmust actually exist in thetests/source tree - the consistency test scans for it, so renaming or deleting a guard without updating the ledger fails CI. source-shaperows must set a concreteretirement_condition.- No literal
|characters inside a cell (they break the pipe-delimited parse). - Use
-for a genuinely empty cell (except where a value is required above).
| id | status | old_owner | closed_responsibility | new_owner | allowed_residue | invariant | guard_test | guard_type | retirement_condition |
|---|---|---|---|---|---|---|---|---|---|
| setup-chat-warning-recovery | authoritative | src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml.cs | setup warning lifetime and refresh admission | SetupNativeChatPresentation + SetupNativeChatRefresh | page applies localized InfoBar state, forwards dispatcher/lifecycle/composer navigation events and calls existing authority and renderer owners | clearing a binding clears only presentation; same-client recovery retains draft after full authority checks; composer /new releases the setup target before async creation; node-only events do not remount; visual recheck never retries or settles receipts | SetupNativeChatPresentationTests.SameClientRecoveryRetainsHostAndHealthyRefreshDoesNotReseed | behavioral | - |
| setup-installation-overview | authoritative | src/OpenClaw.SetupEngine.UI/Pages/ProgressPage.xaml.cs | overview phase inference from visual row order | SetupInstallationProgress | page retains logs, download detail, dispatcher forwarding and pipeline lifetime; SetupPhaseStatus applies localized icon/text state | every real installation step has an explicit phase; failed state outranks running; skipped work is not claimed as installed | SetupInstallationProgressTests.EveryActualStep_HasAnExplicitPhaseInPipelineOrder | behavioral | - |
| setup-native-window-lifetime | authoritative | src/OpenClaw.SetupEngine.UI/SetupWindow.xaml.cs | implicit classic Settings handoff for native routes | SetupNativeConnectionPage + ISetupNativeConnectionHost | SetupWindow owns typed mounting, same-draft routing, cancellation and drain; AdvancedSetupRequested remains explicit classic fallback only | only committed native results advance to access/privacy then AI; departed native pages drain before the setup lock is released | OnboardingPresentationContractTests.NativeEditor_IsTypedAndDrainedBeforeTheRunLockIsReleased | source-shape | when native setup mounting and close ordering have mounted UI lifecycle tests |
| setup-access-draft | authoritative | src/OpenClaw.SetupEngine.UI/Pages/CapabilitiesPage.xaml.cs | capability preset detection and per-visit setup defaults | SetupAccessDraft + SetupCapabilityProfiles | page applies typed projections and forwards input; SetupWindow owns the draft lifetime | only bundled all-on placeholder defaults once; explicit profiles, consent and independent transports survive navigation without persistence | SetupAccessDraftTests.BundledPlaceholder_DefaultsOnlyAtDraftCreation | behavioral | - |
| setup-capabilities-review-closed | closed | src/OpenClaw.SetupEngine.UI/Pages/CapabilitiesPage.xaml.cs | Local AI probing, Tailscale probing, OS privacy probing and installation review | LocalAiSetupControl + TailscaleSetupControl + GatewaySetupPage; OS privacy stays outside setup | capability page owns transport/profile/Fine-tune controls only | ordinary capabilities must not reabsorb probe lifetimes or consent; only the window draft retains profile intent and disclosure | OnboardingPresentationContractTests.SetupOwnership_ClosesCombinedCapabilitiesReview | source-shape | when setup no longer presents capability and installation choices |
| setup-windows-access-preview-closed | closed | src/OpenClaw.SetupEngine.UI/SetupWindow.xaml.cs | obsolete permissions preview, dedicated control, probe helper and observation policy | removed; native Permissions settings retain their existing owners | no setup privacy probes, preview route or extra stage | removing the developer-only screen must not reintroduce OS probing in capabilities or change runtime consent | OnboardingPresentationContractTests.RetiredWindowsAccessPreview_CannotReintroduceProbesOrAnExtraSetupStage | source-shape | when setup no longer has a preview router |
| setup-browser-completion-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | experimental browser-completion issuer, event payload and activation fallback | SetupNativeHandoffLauncher + SetupDashboardHandoffStore | ordinary Dashboard opening and classic chat/settings/connection restart targets remain | only native receipts can complete setup; obsolete or invalid handles fail visibly without opening a browser | NativeCompletionPresentationTests.CompletionActivation_HasNoSupersededBrowserFallback | source-shape | when setup no longer uses restart receipts |
| setup-instance-admission | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | forwarding an expiring native handoff to a shutting-down primary | NativeRestartAdmission + NativeRestartRecoveryStore | App applies synchronous mutex admission before starting services; ordinary secondary forwarding remains | bounded same-thread waits retain the private handle until authoritative admission; no failed-forward exit discards it | NativeRestartAdmissionTests.DelayedOldOwnerIsNeverForwardedToAndMutexAcquisitionStaysOnOneThread | behavioral | - |
| direct-connect-rollback-observation | authoritative | src/OpenClaw.Tray.WinUI/Services/GatewayDirectConnectService.cs | reasserting stale candidate after rollback CAS conflict | GatewayRegistry.ReplaceSnapshotAndSave/AdoptPersistedSnapshot | only observed persisted active state can reconcile settings; unknown state reports attention | concurrent saved/live authority is preserved, candidate commit requires actual active equivalence, and later normal saves remain possible | GatewayDirectConnectServiceTests.RollbackConflictAdoptsActualNewerSavedSelectionNotStaleCandidate | behavioral | - |
| strict-startup-registration-proof | authoritative | src/OpenClaw.Tray.WinUI/Services/SetupStartupPolicy.cs | interpreting ambiguous registration failure as absence | WindowsStartupTaskRegistration.RegisterForSetup/InspectStrict | old best-effort API stays separate | uncertain registration cannot create duplicate Run-key fallback; only exact enabled task proof may complete it | SetupStartupPolicyTests.AmbiguousRegistrationNeverCreatesRunKey | behavioral | - |
| registry-shared-persistence | authoritative | src/OpenClaw.Connection/GatewayRegistry.cs | per-instance-only compare/write ordering | PersistenceFileLease + persisted snapshot CAS | instance lock precedes path lease; Changed events are outside both | all registry writers reject stale authority and coordinate final compare through replacement; LastConnected merges only for unchanged authority | GatewayRegistryPersistenceTests.OtherInstanceCannotWriteBetweenFinalCheckAndReplacement | behavioral | - |
| setup-settings-owner | authoritative | src/OpenClaw.SetupEngine.UI/SetupWindow.xaml.cs | hosted direct settings-file merging | SetupSettingsWriter + ISettingsStore | standalone merging remains under the shared path lease | background app.settings.set and setup serialize through one owner, preserve unrelated fields and reject same-field conflicts | SettingsStoreTests.HostedSetupSerializesWithBackgroundSettingsMutationWithoutLosingUnrelatedFields | behavioral | - |
| setup-strict-startup | authoritative | src/OpenClaw.Tray.WinUI/Services/AutoStartManager.cs | treating legacy best-effort return as setup success | SetupStartupPolicy + AutoStartSettingsApplier | native strict application uses the existing mutation gate; classic startup failure warns before restart continues | failed removal/fallback never marks native startup applied; classic optional failure does not lose durable setup | SetupStartupPolicyTests.DisableRequiresBothRunKeyRemovalAndSuccessfulTaskRemoval | behavioral | - |
| setup-completion-stable-authority | authoritative | src/OpenClaw.SetupEngine/GatewayAiSetupCompletion.cs | original signing identity and exact session ownership across fresh clients | OpenClawGatewayClient.AuthenticatedSigningDeviceId + SetupCompletionAuthority + SetupNativeVerification | domain-separated identity hash and exact session persist without path or token contents; server echo remains diagnostics only | accepted connect signing identity supplies authority; missing/rotated disk identity rejects without regeneration or relabeling the live client | OpenClawGatewayClientTests.AuthenticatedSigningIdentity_ComesFromConnectNotOptionalHelloEcho | behavioral | - |
| setup-completion-effective-endpoint | authoritative | src/OpenClaw.Connection/GatewayDashboardBinding.cs | stable persisted endpoint ownership including SSH forwarding port | GatewayClientEndpointResolver + GatewayDashboardBinding | temporary validation listener allocation remains separate | only-local-port drift rejects the original receipt before a new connection | SetupCompletionAuthorityTests.PersistedPortDrift_IsRejectedBeforeFreshSessionCanConnect | behavioral | - |
| setup-native-revoked-token-recovery | authoritative | src/OpenClaw.Connection/GatewayConnectionValidator.cs | typed, one-shot saved operator-token mismatch recovery | GatewayValidationIdentity + GatewayCredentialRecoveryPolicy | shared/bootstrap requires renewed endpoint authorization; normal device-token precedence remains | Check never changes saved identity; recovery preserves keypair and original CAS baseline; authenticated bootstrap replacement survives Next | GatewayConnectionValidatorTests.RevokedDeviceToken_RecoversOnceInCopyAndPreservesKeypairThroughCheckAndNext | behavioral | - |
| setup-startup-update-admission | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | ordinary startup update prompt ordering versus expiring native receipt | ActivationRouter.CheckOrdinaryStartupUpdateAsync | App composes startup and dispatch; ordinary startup update behavior is retained | a shaped native handle bypasses update prompting, not receipt verification; installer exit cannot skip that handoff | SetupDashboardHandoffTests.NativeStartup_DoesNotWaitForUpdatePromptOrExitForInstaller | behavioral | - |
| setup-snapshot-bookkeeping | authoritative | src/OpenClaw.Connection/GatewayRegistry.cs | setup baseline admission during LastConnected Update/Save gap | GatewayRegistry.CapturePersistedSnapshot | canonical memory snapshot is returned unchanged | only LastConnected differences are ignored; authority and configuration edits still reject | GatewayRegistryTests.CapturePersistedSnapshot_AcceptsOnlyPendingConnectionBookkeeping | behavioral | - |
| setup-native-progress | authoritative | src/OpenClaw.SetupEngine.UI/Pages/SetupNativeConnectionPage.xaml | route progress and nonoverlapping narrow-window actions | SetupProgressIndicator + SetupWindow.RefreshFlowProgress | separate progress and wrapping action rows | native connection has the Gateway stage announcement without overlaying Back/Cancel/Check/Next | NativeCompletionPresentationTests.NativeConnectionProgress_HasItsOwnRowAboveWrappableActions | source-shape | when the native editor footer is no longer XAML |
| setup-local-ai-review | authoritative | src/OpenClaw.SetupEngine.UI/Pages/CapabilitiesPage.xaml.cs | Local AI hardware/model readiness and generation-fenced recheck | LocalAiSetupControl | GatewaySetupDetailPage forwards lifecycle; SetupWindow keeps hardware probe cache | unknown is not unsupported; pinned recovery cannot silently opt out; global WSL consent is explicit and retained | SetupReviewOwnershipTests.LocalAiReview_PreservesGenerationEligibilityAndPinnedRecovery | source-shape | when the setup Local AI control has mounted hardware-probe tests |
| setup-tailscale-review | authoritative | src/OpenClaw.SetupEngine.UI/Pages/CapabilitiesPage.xaml.cs | Windows Tailscale read-only readiness probe and draft options | TailscaleSetupControl + SetupTailscaleReadiness | GatewaySetupPage binds inline and detaches on navigation/unload; GatewaySetupDetailPage retains compatibility hosting | bounded generation-fenced status probe precedes selected Tailscale installation; off does not probe; rebind cancels before changing drafts; auth key and identity trust remain separate | SetupReviewOwnershipTests.TailscaleReview_PreservesBoundedReadOnlyProbeAndGenerationFence | source-shape | when mounted injected-probe lifecycle tests have authorized native execution proof |
| setup-wsl-route-guard | authoritative | src/OpenClaw.SetupEngine.UI/SetupWindow.xaml.cs | installation eligibility for alternate routes and reviewed replacement | SetupAccessDraft | SetupWindow checks CanInstall before navigating; engine retains destructive ownership guard | only ManagedWsl installs and replacement consent binds to the exact inspected distro | SetupAccessDraftTests.AlternateRoutes_NeverInstallWsl | behavioral | - |
| workspace-navigation | authoritative | HubWindow.xaml.cs | main landing and chat route ownership | WorkspaceNavigation and WorkspaceWindow | HubPageRegistry remains the companion catalog and command search owner | Workspace is the landing page; companion destinations never replace it | WorkspaceNavigationTests.CompanionRoutes_DoNotReplaceWorkspace | behavioral | - |
| hub-chat-hosting | closed | HubWindow.xaml.cs | hosting Chat as a Settings navigation page | WorkspaceWindow with existing ChatPage | legacy chat route redirects to Workspace | Settings remains a separate window and cannot destroy the composer draft | WorkspaceWindowProofTests.DefaultLaunchAndCompanionRefocus_PreserveNativeComposerDraft | behavioral | - |
| workspace-window-lifetime | authoritative | HubWindow.xaml.cs | one shared foreground surface for chat and settings | WindowManager | App composes callbacks only; companion navigation scope stays independent | companion deep links reuse a separate window while Workspace survives | WorkspaceWindowProofTests.NativePagesAndOwnerLinks_KeepCompanionIndependent | behavioral | - |
| workspace-card-renderer | closed | WorkspaceContentPage.xaml.cs | speculative management-page cards and rows | removed per Home/Sessions-only Workspace correction | real management pages remain in the Settings companion | removed pages cannot return through navigation history or deprecated links | WorkspaceNavigationTests.DeprecatedWorkspaceLinks_ReturnHomeAndCannotResurrectRemovedPages | behavioral | - |
| workspace-agent-projection | authoritative | WorkspaceWindow.xaml.cs | ad hoc agent and session identity projection | WorkspaceProjection | view applies projected values | no fixture agents and no background-session selection | WorkspaceNavigationTests.Projection_DoesNotSelectBackgroundSessionsForAssistantChat | behavioral | - |
| chat-voice-readiness | authoritative | ChatPage.xaml.cs | timed retries for cold voice launch | PendingVoiceActivation | ChatPage forwards native readiness and cancels on unload or legacy surface | one explicit request is consumed once when ready, never after page exit | PendingVoiceActivationTests.DelayedComposer_ConsumesExactlyOnceWhenReady | behavioral | - |
| test-temp-dir | authoritative | scattered test files | hand-rolled Path.GetTempPath temp dirs in migrated tests | OpenClaw.TestSupport.TempDirectory | pre-existing un-migrated tests until adopted | temp dirs are created unique and best-effort deleted | TestSupportFixtureTests.TempDirectory_CreatesAndDeletes | behavioral | when all temp-dir tests are migrated |
| test-env-scope | authoritative | scattered test files | hand-rolled env var save/restore in migrated tests | OpenClaw.TestSupport.EnvironmentScope | pre-existing un-migrated tests until adopted | env vars set in a test are restored on dispose | TestSupportFixtureTests.EnvironmentScope_RestoresOriginal | behavioral | when all env-mutating tests are migrated |
| test-cli-harness | authoritative | CLI test projects | duplicated stdout/stderr/env capture tuples | OpenClaw.TestSupport.CliHarness | - | stdout/stderr/env lookup are captured consistently | TestSupportFixtureTests.CliHarness_CapturesAndLooksUp | behavioral | when CLI tests adopt the harness |
| test-fake-mcp | authoritative | OpenClaw.WinNode.Cli.Tests | private internal FakeMcpServer copy | OpenClaw.TestSupport.FakeMcpServer | - | one loopback MCP server captures method/body/auth and returns canned/timeout responses | TestSupportFixtureTests.FakeMcpServer_CapturesRequest | behavioral | when all MCP-round-trip tests share it |
| test-app-mcp-client | authoritative | tests/OpenClaw.Tray.IntegrationTests/McpClient.cs | authenticated MCP request/response helper | OpenClaw.TestSupport.McpClient | original app tests retain the same API through a shared namespace import | fixture-host and original MCP integration consumers share request correlation, bearer handling and tool-error parsing without changing original fixture defaults | GatewayFixtureAppTests.RealOperatorPopulatesSessionsWithoutEnablingNodeExecution | behavioral | - |
| gateway-fixture-isolation | authoritative | App startup and service boundaries | implicit isolated-profile safety assumptions | OpenClaw.Shared.GatewayFixtureIsolation | composition-root validation and narrow service checks | explicit fixture mode requires valid absolute profile and setup-local overrides; ordinary isolated mode is unchanged | GatewayFixtureIsolationTests.Get_MissingOrRelativeRoot_ThrowsWithoutFallback | behavioral | - |
| test-gateway-builder | authoritative | OpenClaw.Connection.Tests | per-file MakeRecord(id,url) helpers | OpenClaw.Connection.Tests.GatewayRecordBuilder | pre-existing MakeRecord until migrated | gateway record test data has one builder | TestSupportFixtureTests.GatewayRecordBuilder_BuildsRecord | behavioral | when MakeRecord helpers are removed |
| test-settings-builder | authoritative | scattered test files | ad hoc SettingsData construction in migrated tests | OpenClaw.TestSupport.SettingsDataBuilder | pre-existing un-migrated tests until adopted | settings test data starts from production defaults | TestSupportFixtureTests.SettingsDataBuilder_StartsFromDefaults | behavioral | when settings tests adopt the builder |
| json-read-helpers | authoritative | OpenClaw.Shared (multiple files) | duplicate non-nullable fallback-returning JsonElement getters | JsonReadHelpers | null-sentinel / non-negative / whitespace-absent / trimming variants stay separate | canonical non-nullable fallback JSON coercion; divergent-contract helpers are not blindly routed here | JsonReadHelpersTests.GetString_ReturnsNull_WhenPropertyMissing | behavioral | when the non-nullable fallback getters are all routed here |
| ollama-node-command-policy | authoritative | src/OpenClaw.Shared/Models.cs | Ollama read-only and sensitive command taxonomy | OllamaNodeCommandPolicy | Models consumes the focused command sets when projecting Command Center health | ollama.models remains optional read-only inventory, ollama.chat remains sensitive, and neither becomes a platform parity requirement | OllamaNodeCommandPolicyTests.ClassifiesCommands | behavioral | - |
| wsl-posix-quoting | authoritative | OpenClaw.SetupEngine/SetupSteps.cs | ad hoc ShellEscape with divergent wrap semantics | WslShellQuoting | - | WSL command lines use POSIX single-quote quoting via WslShellQuoting not cmd/PowerShell quoting | WslShellQuotingTests.QuotePosixSingleQuote_WrapsAndEscapesEmbeddedQuote | behavioral | when no code builds WSL command lines outside WslShellQuoting |
| setup-shellescape-closed | closed | src/OpenClaw.SetupEngine/SetupSteps.cs | private ShellEscape helpers with divergent wrap semantics | WslShellQuoting | - | OpenClaw.SetupEngine builds WSL command lines only via WslShellQuoting; no local ShellEscape helper anywhere in the project | SetupStepsShellEscapeClosureTests.SetupEngine_DoesNotReintroduce_PrivateShellEscape | source-shape | when no file under src/OpenClaw.SetupEngine builds any WSL command strings |
| setup-keepalive-process-manager | authoritative | src/OpenClaw.SetupEngine/SetupSteps.cs (StartKeepaliveStep) | setup-time WSL keepalive process discovery, start, marker read/write, command-line identity, and rollback cleanup | KeepaliveProcessManager (raw OS calls delegated to internal IKeepaliveProcessRuntime seam; StartKeepaliveStep is the only caller that reads SetupContext) | StartKeepaliveStep keeps Id/DisplayName and thin ExecuteAsync/RollbackAsync orchestration only | setup-time keepalive never hard-fails the pipeline on start failure (null PID or thrown exception both soft-fail identically); its marker path/JSON are the intentional handoff consumed by the tray keepalive service; rollback kills only wsl/wsl.exe processes whose command line matches this distro via WslCommandLineMatcher, leaves wrong-distro/unmatched command lines untouched, and deletes only its own marker/empty directory | KeepaliveProcessManagerTests.RollbackAsync_KillsOnlyMatchingDistroProcesses_LeavesOthersUntouched | behavioral | when StartKeepaliveStep contains no process/marker logic of its own |
| wsl-distro-install-path | authoritative | OpenClaw.SetupEngine/SetupSteps.cs | inline Path.Combine wsl distro install-path derivation | DistroInstallPathPolicy | - | new installs use the strict supported name grammar; teardown accepts only unambiguous single-segment names whose canonical path is an immediate child of LocalDataDir\wsl with no aliases, case or Unicode collisions, or reparse points at the root or child | SetupStepsTests.DistroInstallPathPolicy_ResolvesImmediateChild | behavioral | - |
| setup-managed-distro-ownership | authoritative | ExistingConfigDetector, CleanupStaleDistroStep, and CreateWslInstanceStep | durable ownership evidence parsing, current-user WSL registration binding, and marker lifecycle | ManagedDistroOwnership plus WindowsWslRegistrationInspector | detector and setup steps request ownership checks or scoped marker operations only | automatic unregister requires durable OpenClaw evidence plus exactly one readable current-user WSL registration whose canonical BasePath is the expected managed install path; automatic orphan-directory deletion requires a path-bound marker; missing, duplicate, malformed, unreadable, or mismatched registration metadata fails closed; exact UI or CLI destructive consent may override | SetupStepsTests.CleanupStaleDistro_PreservesUnownedRegisteredDistro | behavioral | - |
| managed-local-provenance | authoritative | scattered connection, setup, browser, and reconnect call sites | implicit loopback trust and duplicated strong-credential listener checks | ManagedLocalGatewayPortProvenanceService | callers request inspection, authorization, or conflict repair only | unknown, incomplete, conflicting, or changed Windows listener ownership never receives strong credentials or destructive remediation; relayless ownership requires a complete empty Windows snapshot, expected-distro systemd MainPID proof, and immediate complete empty revalidation | ManagedLocalGatewayPortProvenanceServiceTests.InteractiveCredentialGate_ExpectedCacheThenOwnerChanges_FailsClosed | behavioral | - |
| local-ai-gateway-distro-binding | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | hardcoded Local AI WSL distro selection | LocalAiGatewayDistroResolver | App loads the gateway registry and composes the resolver, provider coordinator, and runtime | the singleton Local AI installation binds to exactly one explicit setup-managed local no-SSH gateway record; its record ID and SetupManagedDistroName are pinned and revalidated before every WSL command, while missing, ambiguous, unavailable, or drifted ownership fails closed | LocalAiGatewayProviderCoordinatorTests.Quiesce_OwnerDriftsAfterInspection_BlocksFirstMutation | behavioral | - |
| gateway-wizard-restart-recovery | authoritative | WizardPage + SetupWizardRunner reconnect call sites | duplicated exact-version terminal-restart classification and bounded provenance retry orchestration | GatewayWizardRestartRecoveryPolicy | WizardPage and SetupWizardRunner apply hosted and headless lifecycle and consume provenance inspection results | only managed-local restart-like disconnects may retry NoListener or the typed snapshot-changed race; other unknown or conflicting ownership fails immediately, retryable startup close 1013 stays inside the existing reconnect bound, and exact Gateway 2026.7.1 final model-check close 1012 completes only after a fresh hello-ok, and a terminal hosted-wizard payload completes on the exact TUI SIGTERM termination only when the request just sent answered the authoritative final done acknowledgement step | GatewayWizardRestartRecoveryPolicyTests.Exact2026_7_1TerminalModelCheckServiceRestart_IsExpected | behavioral | when the 2026.7.1 terminal-restart compatibility path is removed |
| managed-local-repair | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs and direct reconnect callbacks | repair eligibility, restart budgets, port remediation, and reconnect verification | ManagedLocalGatewayAutoRepairMonitor + ManagedLocalGatewayRepairCoordinator | App composition and dependency callbacks only | explicit disconnect and gateway switches abort repair before restart or reconnect | ManagedLocalGatewayRepairCoordinatorTests.UserDisconnectedIntent_AbortsBeforeProbeOrRestart | behavioral | - |
| app-managed-local-repair-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | managed-local repair loops, probing, restart budgeting, and verification implementation | ManagedLocalGatewayAutoRepairMonitor + ManagedLocalGatewayRepairCoordinator | service construction, callback adapters, and lifetime wiring only | App remains the composition root and does not regain repair implementation | AppRefactorContractTests.ManagedLocalGatewayRepair_StaysDelegatedToDedicatedOwners | source-shape | when App no longer constructs the managed-local repair services directly |
| connection-page-direct-connect-closed | closed | src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs | direct-connect registry, identity-token, settings, rollback, terminal-wait, and runtime-tunnel transaction | GatewayDirectConnectService | add-form control reads, input validation, result text, and post-success visual refresh only | the page delegates one request; rollback restores the durable registry before identity and settings, reconnects a previously live gateway, and a later credential writer wins | GatewayDirectConnectServiceTests.Connect_Failure_RestoresPreviousLiveConnection | behavioral | when the Connection page no longer contains any direct-connect persistence or rollback logic |
| connection-status-direct-connect-closed | closed | src/OpenClaw.Tray.WinUI/Windows/ConnectionStatusWindow.xaml.cs | direct-connect registry, settings, rollback, terminal-wait, and runtime-tunnel transaction | GatewayDirectConnectService | diagnostics control reads, input validation, and result text only | diagnostics direct connect delegates one request and cannot report success before a terminal manager state | AppRefactorContractTests.StatusWindowDirectConnect_WaitsForManagerStateBeforeReportingConnected | source-shape | when the status window no longer contains direct-connect persistence or rollback logic |
| app-window-manager | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | Hub, Chat, status, setup, canvas request, and runtime-anchor window creation, reuse, focus, theme, owner, and lifetime mechanics | IWindowManager + WindowManager | App owns composition, typed activation-plan application through WindowManager, service-policy callback adapters, setup restart policy, pairing approval dialog workflow and shell, and shutdown-plan callback construction | distinct window types and exact routes are preserved; Hub close resets navigation scope; setup replacement waits for cleanup; shutdown closes owned windows once before provider disposal | WindowManagerTests.CloseForShutdown_GatesCreationAndClosesOwnedWindowsOnce | source-shape | when App is replaced as the WinUI composition root |
| app-window-surface-ownership-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | concrete non-tray window fields, constructors, show/hide/focus/theme/close mechanics, and window event lifetime | IWindowManager + WindowManager | interface forwarding, immutable request construction, route and policy callbacks, and setup restart dialog policy only | App cannot regain a parallel Hub, Chat, status, setup, canvas-request, or runtime-anchor owner | AppSurfaceOwnershipContractTests.App_DelegatesConcreteTrayAndWindowOwnership | source-shape | when App is replaced as the WinUI composition root |
| app-tray-controller | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | tray icon creation, tray popup coordination, click routing, tooltip and live-toggle refresh, theme, callbacks, and disposal | ITrayController + TrayController | App captures immutable snapshots, implements semantic action callbacks, triggers refresh from authoritative state, preserves startup construction order, and constructs shutdown-plan callbacks | one tray icon and root menu are reused; A1 presenters retain semantics; TrayMenuWindow retains native popup mechanics; callbacks detach and resources dispose once | TrayControllerTests.Dispose_UnsubscribesAndDisposesEachResourceOnce | source-shape | when the WinUI tray surface is replaced |
| app-tray-surface-ownership-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | concrete tray icon, root menu, weak live-control state, event subscriptions, popup build coordination, and resource disposal | ITrayController + TrayController | immutable snapshot and action callbacks plus state-change triggers only | App cannot regain tray controls or popup lifetime and TrayController cannot duplicate A1 semantic projection or TrayMenuWindow native mechanics | AppSurfaceOwnershipContractTests.App_DelegatesConcreteTrayAndWindowOwnership | source-shape | when the WinUI tray surface is replaced |
| native-tool-projector | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | pure native tool identity, allowlisted display arguments, payload extraction, and flattened-history detection/classification/summary | NativeToolProjector | ChatEventMapper and ChatHistoryLoader call the projector; ChatConversationState supplies scoped correlation plans and ChatMetadataStore owns persistence | unknown identities remain truthful Tool; title aliases are strict; display arguments are allowlisted, redacted, and bounded; live/history projection stays consistent | NativeToolProjectorTests.ExtractToolIdentity_TitleRequiresExactTrustedAlias | behavioral | - |
| provider-native-tool-projection-closed | closed | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | private static copies of native tool identity, display argument, payload, flattened-history projection, and scoped metadata upsert | NativeToolProjector + ChatEventMapper + ChatHistoryLoader + ChatConversationState + ChatMetadataStore | provider forwards typed tool metadata writes while retaining bridge IO, telemetry, and event publication only | provider does not regain native tool JSON projection, identity policy, timeline correlation, or metadata persistence | review-only: pure projection, atomic correlation, and persistence are delegated to focused owners while the provider remains the IO facade | review-only | when OpenClawChatDataProvider is retired |
| chat-conversation-state | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | provider-owned runtime gate and cross-domain state transactions | ChatConversationState | sole lock, timeline and entry metadata, connection/disposal flags, and typed orchestration across lock-free substates; provider supplies bridge context and coordinates IO, telemetry, and events | one authoritative lock atomically commits reset, reconnect, dispose, queue, history, and event transitions without duplicate shared versions | ChatRuntimeOwnershipContractTests.Root_CoordinatesCrossDomainCommitsUnderSoleGate | source-shape | when the chat runtime is replaced by a different atomic transaction boundary |
| chat-provider-state-closed | closed | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | private runtime gate and mutable conversation/queue/reset/history collections | ChatConversationState | bridge subscription, telemetry, public API/events, composition, persistence coordination, and static image preview compatibility | provider cannot regain a private state lock or duplicate runtime collections | ChatRuntimeOwnershipContractTests.Provider_DelegatesRuntimeStateWithoutPrivateGate | source-shape | when OpenClawChatDataProvider is retired |
| chat-send-queue | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs and monolithic ChatConversationState | send admission, next-drain eligibility, local echo and run correlation, deferred-admission classification/backoff, retry decisions, and queue commit mechanics | ChatSendQueuePolicy + ChatQueueState | ChatConversationState coordinates queue commits with timeline, reset, and lifecycle state; provider executes typed bridge dispatch plans and records telemetry | queue collections and mechanics live in the lock-free substate under the sole conversation lock while pure policy decisions remain separately testable | ChatRuntimeOwnershipContractTests.RuntimeSubstates_AreLockFreeAndVersionOwnershipIsUnique | source-shape | when queue state and decision policy are replaced without a lock-internal substate |
| chat-reset-state | authoritative | monolithic ChatConversationState | reset versions and cutoffs, accepted and ignored runs, submitted echoes, no-run send proof, buffered starts, and remote-backfill gates | ChatResetState | ChatConversationState supplies queue and lifecycle facts and atomically applies returned typed lifecycle transitions | reset mechanics have no private lock or duplicate version and are invoked only under the conversation lock | ChatRuntimeOwnershipContractTests.RuntimeSubstates_AreLockFreeAndVersionOwnershipIsUnique | source-shape | when reset gating is replaced without a lock-internal substate |
| chat-history-state | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs and monolithic ChatConversationState | session identity, loaded/revision state, reset-cleared identity, connection generation, activation barrier, commit-token validation, and transcript merge reconciliation | ChatHistoryState | ChatConversationState supplies reset/status/disposal facts and atomically coordinates timeline commit; no history IO lives in the substate | one authoritative connection generation and reset-aware commit token accepts or drops history under the sole conversation lock | ChatConversationStateTests.HistoryGeneration_WaitsForLoaderActivation | behavioral | - |
| chat-history-loader | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | chat.history fetch lifetime, in-flight ownership, generation cancellation, retry budget/scheduling, ordered transcript rebuild plans, and stale-result delivery filtering | ChatHistoryLoader | ChatHistoryState owns authoritative identity and generation tokens; ChatConversationState coordinates commit acceptance; provider publishes typed completion results and notifications | stale connection/reset responses cannot commit, deliver, clear a newer in-flight owner, or carry retry work/budget across generations; authoritative reload coalescing remains generation-safe | OpenClawChatDataProviderTests.LoadHistoryAsync_DelayedRetryDoesNotCrossResetGeneration | behavioral | - |
| chat-checkpoint-history-replacement | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | checkpoint-restore timeline clearing, replacement generation fencing, and replacement-over-authoritative reload priority | ChatHistoryState + ChatHistoryLoader coordinated by ChatConversationState | provider starts the typed replacement transition, publishes its immutable snapshot, and delegates gateway IO | replacement atomically clears timeline metadata, invalidates stale results, preserves post-restore live entries, and suppresses stale retries and notifications | ChatConversationStateTests.HistoryReplacement_ClearsTimelineAndAdvancesOwnedTokenAtomically | behavioral | - |
| chat-presentation-state | authoritative | monolithic ChatConversationState | sessions, usage, models, choices, command catalog/fetch epoch, pending model patches, keyless diagnostics, remembered last state, and immutable projection inputs | ChatPresentationState | ChatConversationState supplies timeline/queue/reset/history snapshots and coordinates session identity and usage timeline updates | presentation mechanics have no private lock, IO, or mutable collection exposure and snapshot values remain byte-for-byte compatible | OpenClawChatDataProviderTests.RuntimeGolden_PublicSnapshotPreservesCrossDomainState | golden | - |
| chat-lifecycle-state | authoritative | monolithic ChatConversationState | active run IDs/start sequences, pending aborts, aborted runs/threads, terminal-run dedupe, and lifecycle sequence | ChatLifecycleState | ChatConversationState coordinates lifecycle changes with reset gates, queue state, and timeline reducer events | lifecycle mechanics have no private lock and reset/reconnect/dispose remain root-coordinated atomic transitions | ChatRuntimeOwnershipContractTests.Root_CoordinatesCrossDomainCommitsUnderSoleGate | source-shape | when run lifecycle is replaced without a lock-internal substate |
| chat-approval-state | authoritative | monolithic ChatConversationState | bounded seen-approval identity order/set and alternate-ID correlation | ChatApprovalState | ChatConversationState coordinates approval identity with permission timeline transitions; ChatEventMapper remains the pure payload mapper | approval identity mechanics have no private lock, IO, or timeline callbacks | ChatRuntimeOwnershipContractTests.RuntimeSubstates_AreLockFreeAndVersionOwnershipIsUnique | source-shape | when approval correlation is replaced without a lock-internal substate |
| chat-event-mapper | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | pure agent-stream payload to ChatEvent/content mapping and terminal approval decision classification | ChatEventMapper | provider retains stateful approval dedupe and telemetry orchestration through ChatConversationState | tool, reasoning, lifecycle, command-output, job, and permission payloads map without provider-owned JSON mapping branches | ChatEventMapperTests.Map_ApprovalRequestPreservesIdentityAndActions | behavioral | - |
| chat-snapshot-projector | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | thread/compose-target/status/model/catalog/timeline-generation/history-revision/queued-message snapshot projection including flattened gateway session classification | ChatSnapshotProjector | provider supplies bridge handshake context; ChatConversationState captures immutable projection input; SessionDisplayResolver owns flattened session display mapping | public snapshots preserve defensive dictionary copies, raw session keys, flattened agent/background classification, compose readiness, synthetic pending thread behavior, model order, and render identity generations | OpenClawChatDataProviderTests.RuntimeGolden_PublicSnapshotPreservesCrossDomainState | golden | - |
| chat-content-formatting | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | content text formatting, truncation, content-block seam repair, and trace hashing | ChatContentFormatting | thin provider forwarders (TruncateForChatEntry, LooksLikeSystemControlNote, RepairContentBlockSeams, TruncateChatEvent) kept for existing test call sites; system-note, native tool, and flattened-history projection belongs to NativeToolProjector | content truncation and seam repair output is preserved byte-for-byte while tool identity/classification has one canonical owner | ContentBlockSeamRepairTests.RepairsKnownSeams | behavioral | when provider forwarders are removed and callers use focused owners directly |
| chat-metadata-store | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | live tool/attachment metadata dictionaries, scoped native-tool identity upsert, save locks/timers/versions, atomic JSON persistence, session eviction, and attachment-marker build/escape/rehydration | ChatMetadataStore | ChatConversationState supplies a typed session/reset/correlation write plan; provider retains the public static image-preview cache | metadata persistence, identity-strength upgrade, normalization, bounded eviction, marker security, and generation-aware idempotent reset eviction are owned under the metadata lock without raw attachment bytes on disk | ToolMetaCacheTests.CacheToolMeta_SameToolCallId_UpgradesSpecificIdentityWithoutDuplicate | behavioral | - |
| chat-state-persistence | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | persisted aborted-message IDs plus last-chat-state debounce/version/atomic save lifecycle | ChatStatePersistence | provider retains the nested LastChatState compatibility type and owns bridge history fetch orchestration | corrupted state fails closed, reset removes aborted IDs, stale reset generations cannot persist, and selected/snapshot state writes remain atomic | ChatStatePersistenceTests.ResetFence_RejectsStaleAbortedIds | behavioral | - |
| app-activation-router | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | deep-link/protocol/toast/forwarded activation normalization, current-user IPC, input guards, and confirmation decisions | ActivationRouter | App.ActivationRouter.cs implements IActivationPlanSink only and applies exactly one typed semantic plan through existing A2 owners and services | launch, protocol, toast, and forwarded activation resolve to the same routes; a no-argument secondary launch retries the existing IPC boundary and forwards the default Hub route; current-user IPC, oversized-payload rejection, and confirmation/redaction semantics are preserved | ActivationRouterTests.ForwardLaunchToPrimaryAsync_ListenerStartsLate_RetriesAndDispatchesDefaultHub | behavioral | - |
| app-activation-router-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | concrete deep-link IPC, toast argument routing, and single-instance forwarding production logic | ActivationRouter | App.ActivationRouter.cs implements IActivationPlanSink only, dispatching one typed plan per activation | App does not regain a parallel activation production path outside ActivationRouter | AppRefactorContractTests.ToastActivation_RoutesOnUiThread | source-shape | when App is replaced as the WinUI composition root |
| app-settings-change-coordinator | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | detached snapshot comparison, SettingsChangeClassifier use, concurrent save serialization, and the full post-save effect order | SettingsChangeCoordinator | App supplies the existing effects as delegates and triggers synchronous Apply from one explicit post-save call | browser proxy sync, reconnect, MCP, hotkey, autostart, telemetry, and surface notification order is preserved; MCP-only behavior and credential precedence are unaffected | SettingsChangeCoordinatorTests.Apply_GatewayUrlChange_PreparesBeforeReconnect | behavioral | - |
| app-settings-change-coordinator-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | OnSettingsSaved impact classification, reconnect switch, and inline effect ordering | SettingsChangeCoordinator | App.SettingsChangeCoordinator.cs wires effect delegates only; OnSettingsSaved forwards to Apply | App does not regain a parallel settings-change orchestration path outside SettingsChangeCoordinator | PresentationSeamContractTests.App_AppliesToolCallVisibilityFromPersistedSettings | source-shape | when App is replaced as the WinUI composition root |
| autostart-settings-applier | authoritative | src/OpenClaw.Tray.WinUI/App.SettingsChangeCoordinator.cs | post-save auto-start preference read and Windows write | AutoStartSettingsApplier | App supplies its shared mutation gate, live preference reader, OS setter, and background fault observer | ordinary settings-save effects read the current preference only after acquiring the toggle and reconciliation gate and hold it until the OS write completes; explicit valid fixture runs skip this background host refresh | AutoStartSettingsApplierTests.ApplyLatestAsync_QueuedSave_ReadsPreferenceAfterGateAcquisition | behavioral | - |
| autostart-settings-direct-write-closed | closed | src/OpenClaw.Tray.WinUI/App.SettingsChangeCoordinator.cs | direct ungated auto-start write from a saved SettingsData snapshot | AutoStartSettingsApplier | effect delegate wiring only; startup reconciliation and explicit toggles retain their existing shared gate | post-save effects cannot replay stale snapshots over newer toggle or reconciliation results | MsixDevelopmentSigningTests.SettingsSaveAutoStart_UsesSharedGateAndLivePreference | source-shape | when the WinUI adapter is exercised directly by behavioral tests |
| app-shutdown-coordinator | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | first-wins shared shutdown task, ordered step execution, and per-step log/catch/continue | AppShutdownCoordinator | App builds the immutable step plan from services it owns, including activation null-before-await and failure-safe captured-resource nulling, and constructs the BeginShutdown/ExitApplication actions | shutdown steps run in the same order exactly once even under concurrent callers; each step logs and continues past failure; Exit is called exactly once after all steps | AppShutdownCoordinatorTests.ShutdownAsync_RunsBeginStepsThenExit_InOrder | behavioral | - |
| app-shutdown-coordinator-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | the _isExiting bool guard, SafeShutdownStep/SafeShutdownStepAsync helpers, and inline ExitApplicationAsync body | AppShutdownCoordinator | App.AppShutdownCoordinator.cs builds the step plan only; ExitApplicationAsync forwards to ShutdownAsync | App does not regain a parallel exactly-once shutdown guard or step-execution loop outside AppShutdownCoordinator | AppRefactorContractTests.Shutdown_Order_PreservesAwaitedTeardownBeforeExit | source-shape | when App is replaced as the WinUI composition root |
| gateway-pending-requests | authoritative | src/OpenClaw.Shared/OpenClawGatewayClient.cs | request-id to method/completion tracking | PendingRequestRegistry | callers create request ids, choose timeout policy, parse and route responses, and use the transport | request ids do not leak after disconnect; the registry remains thread-safe with exactly one terminal completion | PendingRequestRegistryTests.ResponseVersusDrain_ExactlyOneTerminalOutcomeWins | behavioral | - |
| connect-envelope | authoritative | src/OpenClaw.Shared/OpenClawGatewayClient.cs + src/OpenClaw.Shared/WindowsNodeClient.cs | connect envelope wire shape, auth field mapping, and v3/v2 signing arguments | ConnectEnvelopeBuilder | callers explicitly select role, scopes, credential profile, and lifecycle/fallback state | the builder cannot infer credential precedence; exact v3/v2 signing bytes and protocol 3/4 remain unchanged | ConnectEnvelopeBuilderTests.Build_CompleteProfileMatrix_PreservesWireShapeAndSigningArguments | golden | - |
| gateway-connect-inline-closed | closed | src/OpenClaw.Shared/OpenClawGatewayClient.cs + src/OpenClaw.Shared/WindowsNodeClient.cs | anonymous connect envelope, auth dictionary, and direct signature/payload construction | ConnectEnvelopeBuilder | explicit role/scope/credential profile selection, lifecycle/fallback state and persistence, redacted logging, transport send | both clients delegate connect construction without moving credential precedence into the builder | GatewayProtocolCoreClosureTests.GatewayClients_DoNotReintroduce_InlineConnectEnvelopeConstruction | source-shape | when both clients are removed or no longer initiate gateway connect handshakes |
| gateway-pending-inline-closed | closed | src/OpenClaw.Shared/OpenClawGatewayClient.cs | pending maps and locks plus Track-Take-Clear and chat-send helper families | PendingRequestRegistry | request-id creation, timeout policy, response parsing/routing, transport | the client delegates registration, take, removal, and disconnect drain so request ids cannot leak and only one completion wins | GatewayProtocolCoreClosureTests.OpenClawGatewayClient_DoesNotReintroduce_InlinePendingRequestTracking | source-shape | when OpenClawGatewayClient is removed or no longer issues correlated requests |
| gateway-protocol-contract | authoritative | ConnectEnvelopeBuilder + src/OpenClaw.Shared/OpenClawGatewayClient.cs + src/OpenClaw.Shared/WindowsNodeClient.cs | duplicated wire-version range, ad hoc successful hello acceptance, and raw mismatch interpretation | GatewayProtocolContract + GatewayProtocolCompatibility | the builder retains exact envelope construction; clients retain credential precedence, signature fallback, generation fencing, and role-specific success side effects | Windows advertises Gateway protocols 3 through 4 and validates the minimal hello-ok shape before success side effects; after the Gateway accepts that range, an integer hello-ok protocol at or above 3 is accepted because it reports the Gateway current constant rather than a negotiated selection; structured mismatch details remain finite and sanitized relative to the advertised range | GatewayProtocolContractTests.SupportedRange_IsThreeThroughFour | behavioral | - |
| gateway-protocol-literals-closed | closed | ConnectEnvelopeBuilder | private minProtocol and maxProtocol numeric literals | GatewayProtocolContract | the builder serializes its existing envelopes using the shared constants | operator and node connect envelopes advertise the same 3-through-4 protocol range | GatewayProtocolContractTests.Clients_use_shared_contract_for_protocol_range | source-shape | when connect envelopes no longer carry a Gateway protocol range |
| ui-dispatcher | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | UI-thread marshaling abstraction for presentation code | IUiDispatcher | App and existing WinUI code may call DispatcherQueue directly until the view-model migration | presentation view models depend on IUiDispatcher not a concrete DispatcherQueue | UiDispatcherContractTests.PageViewModel_ReceivesRegisteredDispatcher | behavioral | - |
| navigation-scope | authoritative | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs | page view-model activation/deactivation and disposal lifetime | NavigationScopeManager | HubWindow keeps frame navigation back-stack and rail selection | transient page view models are activated on navigation and deactivated then disposed on navigate-away | NavigationScopeManagerTests.NavigatingAway_DeactivatesAndDisposesPreviousViewModel | behavioral | - |
| composition-root | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | presentation-layer service construction and wiring | AppServiceRegistration | App remains the composition root and owns non-DI service lifetimes | one validated root ServiceProvider; App-owned singletons registered as instances are never disposed by the container | AppServiceRegistrationTests.Dispose_DoesNotDisposeAppOwnedInstanceSingletons | behavioral | - |
| node-summary-text | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | node-summary clipboard text formatting | NodeSummaryText | App keeps the clipboard side effect (building the DataPackage and setting clipboard content) | copied node-summary text is projected only by NodeSummaryText.Build (online/offline state, display-name fallback, short id, detail text, newline join) | NodeSummaryTextTests.Build_MultipleNodes_OneLinePerNodeJoinedByNewline | behavioral | - |
| reactor-chat-timeline | authoritative | removed legacy FunctionalUI chat timeline | production chat message virtualization, row realization, and imperative scroll follow | ReactorChatTimeline through OpenClawReactorChatRoot and ReactorHostControl | - | the default chat route mounts one direct ReactorHostControl per XAML chat target; Reactor owns stable-key ItemsView and ItemContainer realization without a custom native list, collection reconciler, or scroll-layout mutation | ChatTimelinePresentationTests.ReactorTimeline_UsesNonSelectableItemsViewContainersAndAnnotatedScrollBar | source-shape | when ReactorChatTimeline is replaced as the production virtualization owner |
| chat-tool-activity-renderer | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | production standalone tool-call and grouped activity presentation, summaries, disclosures, and detail rendering | ChatToolActivityPresentation + ToolCallCardRenderer | ReactorChatTimeline projects rows and delegates realization only | consecutive invocation grouping preserves source chronology; stable group identity comes from session, generation, and first tool entry; selectable output remains capped at 240px | ChatToolActivityPresentationTests.Project_GroupsOnlyConsecutiveSpansOfAtLeastTwoTools | behavioral | - |
| chat-history-replay-projection | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | array-valued history content ordering projection | ChatHistoryReplayProjection | provider applies projected text and tool parts to the reducer | interleaved text, calls, and results replay in source order without clearing active tool correlation | OpenClawChatDataProviderTests.LoadHistoryAsync_InterleavedContentParts_PreserveChronologyAndCorrelation | behavioral | - |
| assistant-media-protocol-projection | authoritative | src/OpenClaw.Shared/OpenClawGatewayClient.cs | structured assistant media content parsing and assistant-only legacy MEDIA directive redaction/projection | AssistantMediaDirectiveParser + ChatMediaContentInfo | gateway client preserves ordered typed media while tray presentation receives only safe filenames and metadata | user text never activates media directives; accepted local sources never enter visible assistant text or notifications; media-only messages survive live and history parsing | AssistantMediaDirectiveParserTests.Project_AssistantAbsolutePath_ProducesMediaWithoutExposingPath | behavioral | - |
| assistant-media-resolver | authoritative | src/OpenClaw.Shared/OpenClawGatewayClient.cs | authenticated structured artifact and legacy assistant-media byte retrieval | OpenClawGatewayClient.AssistantMedia | chat bridge exposes only lease-bound typed resolution results; renderer never receives credentials, tickets, or arbitrary URLs | accepts only current-connection results, matching media MIME families, managed ticket paths, and payloads within the 12 MiB image or 16 MiB playback caps | OpenClawGatewayClientAssistantMediaTests.ResolveLegacyMedia_UsesBearerMetadataAndSourceBoundTicket | behavioral | - |
| provider-assistant-media-parsing-closed | closed | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | parsing legacy MEDIA directives or structured Gateway media blocks | AssistantMediaDirectiveParser + OpenClawGatewayClient | provider owns message identity, streaming reconciliation, timeline application, and safe presentation metadata orchestration | provider consumes typed content parts and never reparses model text or exposes raw media sources | ChatAssistantContentPresentationTests.Project_UsesSafeFilenameWithoutExposingLegacySource | behavioral | when assistant message ingestion leaves OpenClawChatDataProvider |
| assistant-media-renderer | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | assistant media card presentation, bounded image decode, retry, and row cancellation | ChatAssistantMediaRenderer | ReactorChatTimeline owns row placement and delegates media realization | at most four images render inline per message; unsupported or unresolved typed media remains visible as an accessible safe unavailable card; raw Gateway sources are never rendered | ChatAssistantContentPresentationTests.BuildRenderPlan_CapsImagesWithoutReorderingOtherMedia | behavioral | - |
| gateway-media-message-projection | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | gateway media-envelope parsing, safe filename/MIME normalization, attachment signatures, and provenance-safe attachment descriptors | GatewayMediaMessageProjection + ChatAttachmentPresentation | provider applies the projection to live, reset, backfill, and history ingress and owns stateful echo correlation | gateway text never becomes a private marker; gateway descriptors have no preview key; only local opaque preview keys can access image bytes | GatewayMediaMessageProjectionTests.ValidEnvelope_ProjectsSafeDescriptorAndCleanProse | behavioral | - |
| provider-gateway-media-parsing-closed | closed | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | private gateway media-envelope parsing or descriptor construction | GatewayMediaMessageProjection | provider retains stateful pending-echo queues, reset gates, sidecar matching, and reducer application | all user ingress paths call the focused projection and do not independently parse gateway media text | review-only | review-only | when user-message ingestion leaves OpenClawChatDataProvider |
| reactor-tool-rendering-closed | closed | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | per-tool and grouped activity summary/detail rendering implementation | ToolCallCardRenderer | row projection, virtualization, hover state, assistant runs, and renderer delegation only | ReactorChatTimeline contains no tool detail renderer and delegates both standalone and grouped tool rows | ChatTimelinePresentationTests.ReactorTimeline_DelegatesToolAndActivityRenderingToFocusedOwner | source-shape | when ReactorChatTimeline is replaced as the production virtualization owner |
| functional-chat-default-mount | closed | src/OpenClaw.Tray.WinUI/Chat/ReactorChatHostExtensions.cs | mounting the FunctionalUI chat tree as the default ChatPage or ChatWindow surface | ReactorChatHostExtensions and OpenClawReactorChatRoot | - | ChatPage and ChatWindow mount the Reactor root directly into their existing ChatHost Borders through ReactorChatHostExtensions | ChatToolCallsToggleContractTests.ProductionChatSurfaces_MountReactorRoot | source-shape | when ReactorChatHostExtensions is replaced as the authoritative production chat mount owner |
| settings-store | authoritative | settings and permission UI surfaces | direct SettingsManager mutation and blanket self-write suppression | ISettingsStore | non-permission legacy surfaces may read SettingsManager until migrated; direct saves publish origin null | every save publishes one versioned event; only the matching writer ignores its own origin while all other active consumers refresh | SettingsSharedStateContractTests.TwoActiveSettingsPageViewModels_IgnoreOnlyOwnWrites_InBothDirections | behavioral | when every settings surface reads and writes through ISettingsStore |
| settings-page-vm | authoritative | src/OpenClaw.Tray.WinUI/Pages/SettingsPage.xaml.cs | settings load, persist, echo-guard, and auto-save wiring | SettingsPageViewModel | code-behind keeps gateway-uninstall, gateway-info and uptime timer, saved-indicator visual, and app-info population | each settings control persists its field through the store preserving mutate-save-notify order and does not re-persist on external change | SettingsPageViewModelTests.ExternalChange_ReloadsWithoutRePersisting | behavioral | when the Settings page holds no settings persistence logic in code-behind |
| exec-approvals-store | authoritative | src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs | direct exec-approvals.json snapshot, CAS persistence, file observation, and mutable policy cache | ExecApprovalsStore through IExecApprovalsPresentationStore | SystemCapability and NodeService consume the same App-owned concrete store for runtime enforcement | pure reads create nothing; CAS rejects stale hashes; one store-owned observer publishes each distinct external replacement once and retains the last valid presentation snapshot on typed failure | ExecApprovalsStoreTests.Changed_ExternalCorruptThenValid_RaisesFailureThenRecovery | behavioral | - |
| permissions-page-vm | authoritative | src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs | permission settings state, exec-approvals mutations, node/MCP/voice status decisions, and lifecycle subscriptions | PermissionsPageViewModel plus PermissionsPageRuntimeSource | code-behind keeps exact WinUI row/card construction, localization application, colors, visibility, clipboard/token reads, privacy launch, and save-hint timer | activation is pure; field-scoped settings writes preserve save-then-notify; V2 mutations preserve unrelated fields through CAS retry; deactivate/dispose releases subscriptions | PermissionsPageViewModelTests.ExternalValidChange_UpdatesOnce_AndCorruptRetainsLastValidDisplay | behavioral | - |
| permissions-page-direct-owners-closed | closed | src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs | direct SettingsManager, ConnectionManager, and ExecApprovalsStore ownership or subscriptions | PermissionsPageViewModel plus authoritative stores | WinUI-only rendering and platform actions listed in permissions-page-vm | the page applies semantic state only; the view model is WinUI/App/SettingsManager/file-IO free and never creates a parallel mutable domain cache | PermissionsPageContractTests.PermissionsPageViewModel_StaysWinUiAndAppFree | source-shape | when PermissionsPage is replaced by a different view technology |
| shared-mutable-domain-owner | authoritative | presentation pages and view models | backing-file or concrete-manager ownership, per-VM observers, and independent mutable copies of persisted domains | one observable service/store per shared mutable domain | immutable view state projected from authoritative snapshots | different active consumers converge through versioned origin-aware events or CAS snapshots without echo storms, stale whole-snapshot replay, or lost unrelated updates | SettingsSharedStateContractTests.PermissionsPageViewModel_ReceivesOneExternalUpdate_PerDistinctAppSurfaceOrigin | behavioral | - |
| exec-reusable-binding | authoritative | src/OpenClaw.Shared/ExecApprovals/ExecCommandResolution.cs | deriving durable allowlist identities and Allow Always patterns from multi-segment shell resolution | ExecReusableCommandBinder | ExecCommandResolver.Resolve stays the singular resolution used by the state machine and prompt display | at most one identity may be durably authorized per request and it is a fully qualified existing .exe image whose arguments are pinned by the generated rule |
ExecReusableCommandBinderTests.MultiElementCarrierTail_Binds | behavioral | - |
| exec-multi-segment-allowlist-closed | closed | src/OpenClaw.Shared/ExecApprovals/ExecCommandResolution.cs | ResolveForAllowlist and ResolveAllowAlwaysPatterns feeding allowlist matching or Allow Always patterns | ExecReusableCommandBinder | the two methods remain compiled with their historical tests until removed but have no production callers | the approval pipeline derives AllowlistResolutions and AllowAlwaysPatterns only from ExecReusableCommandBinder.TryBind | ExecApprovalV2NormalizationPipelineOwnershipTests.Normalizer_DerivesDurableIdentity_OnlyFromReusableBinder | source-shape | when ResolveForAllowlist and ResolveAllowAlwaysPatterns are deleted |
| canonical-cmd-carrier | authoritative | src/OpenClaw.Shared/Mxc/MxcConfigBuilder.cs | recognizing the cmd.exe /d /s /c carrier and extracting its command payload | CanonicalCmdCarrier | MxcConfigBuilder keeps cmd command-mode switch detection and command-line construction | the approvals binder and the MXC command-line builder agree on which argv shapes are the canonical cmd carrier and what payload they carry | CanonicalCmdCarrierTests.BinderAndMxcBuilder_AgreeOnCarrierRecognition | behavioral | - |
| exec-carrier-transport-identity | authoritative | src/OpenClaw.Shared/ExecApprovals/ExecApprovalsCoordinator.cs | deciding what a trusted canonical cmd carrier executes once its inner payload is durably authorized | ExecReusableCommandBinder builds the execution argv; CanonicalCmdCarrier.PinnedCarrierMatchesRequest enforces it | the coordinator still owns prompt, policy, and persistence decisions | a durably approved carrier executes a reconstruction of the validated carrier so the MXC in-band PATH/TEMP bootstrap survives; exactly two tokens may differ from the request, argv[0] pinned to the resolved System32 or SysWOW64 cmd.exe and the payload executable token pinned to its resolved absolute path, with every other token and all interior spacing ordinal-identical so no metacharacter drift can be introduced | ExecReusableCommandBinderTests.TrustedCarrier_KeepsTransportSeparateFromIdentity | behavioral | when MXC accepts an explicit environment and the bound direct argv can be executed instead |
| cmd-payload-tokenization | authoritative | src/OpenClaw.Shared/ExecApprovals/ExecReusableCommandBinder.cs | parsing a cmd payload into tokens and rewriting its executable token | CmdPayloadTokenizer | ExecReusableCommandBinder.TryTokenizeStaticCmdPayload remains as a delegating wrapper for existing callers and tests | a payload rewrite is built from parsed token spans and is accepted only after re-parsing proves the argument list is unchanged except for the pinned executable | ExecReusableCommandBinderTests.PinnedCarrier_DoesNotRewriteArgumentsThatRepeatTheExecutableText | behavioral | - |
| exec-carrier-cwd-ambiguity-check | closed | src/OpenClaw.Shared/ExecApprovals/ExecReusableCommandBinder.cs | deciding whether a carrier payload may be durably approved when the working directory could shadow it | CanonicalCmdCarrier.TryBuildPinnedCarrier (payload executable pinning) | - | the approval-time working-directory check is deleted, not merely bypassed: ExecCommandResolver exposes no HasCurrentDirectoryCandidate, a trusted carrier's payload executable is pinned to its resolved absolute path so cmd has nothing to search for, and a post-approval shadow cannot win | ExecReusableCommandBinderTests.PinnedCarrier_IgnoresShadowInsertedAfterApproval | behavioral | - |
| exec-legacy-host-quarantine | authoritative | src/OpenClaw.Shared/ExecApprovals/ExecCommandToken.cs | deciding whether a provenance-less path-only allowlist entry authorizes an interpreter or code host | ExecAllowlistMatcher.MatchInternal via ExecCommandToken.IsLegacyQuarantinedHost | argument binding remains the security boundary for every rule this node generates | an allowlist entry with no source and no argPattern is inert when its resolved target is a command host the previous model refused, is never deleted or migrated, and is superseded only by an explicit allow-always sibling carrying source and argPattern | ExecAllowlistArgBindingTests.LegacyPathOnlyEntryForACommandHost_IsInert | behavioral | - |
| app-ssh-restart-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs and ConnectionPage.xaml.cs | stopping, starting, reconnecting, and declaring success for a user-requested SSH tunnel restart | GatewayConnectionManager.RestartSshTunnelAsync | App and ConnectionPage invoke the manager and present the result | a restart succeeds only after a fresh generation-bound hello-ok and current registry, config, tunnel generation, and owned listener verification | AppRefactorContractTests.UserSshRestart_StaysDelegatedToConnectionManager | source-shape | when App no longer owns any SSH tunnel UI actions |
| hub-page-registry | authoritative | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs and GatewayNavVisibilityDebouncePolicy | navigation aliases, page mapping, command metadata and search, and gateway-page classification | HubPageRegistry | HubWindow keeps Frame and NavigationView application, back-stack mutation, command cache lifetime, and semantic action execution; GatewayNavVisibilityDebouncePolicy keeps disconnect timing | every current direct, legacy, and agent-scoped tag resolves identically; command order, titles, actions, search caps, and gateway prune set remain stable | HubPageRegistryTests.BuildCommands_PreservesBaseOrderActionsIconsAndResourceKeys | behavioral | - |
| hub-page-registry-closed | closed | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs and GatewayNavVisibilityDebouncePolicy | private tag/page switches, command catalogs or search predicates, and gateway-page tag lists | HubPageRegistry | view-only navigation application and debounce timing listed in hub-page-registry | HubWindow and the debounce policy do not regain catalog or page-classification copies | HubPresentationContractTests.HubPageRegistry_OwnsMappingsCommandsAndGatewayClassification | source-shape | when HubWindow is replaced by a different shell and GatewayNavVisibilityDebouncePolicy is retired |
| app-notification-infobar-presentation | authoritative | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs | banner severity filtering, selected-banner fallback, notification action versus Show more, and action enabled state | AppNotificationInfoBarPresenter | HubWindow keeps banner subscription, WinUI control assignment, navigation, and dismissal side effects | Warning and Error banners retain priority and hiding semantics while action projection stays WinUI-free | AppNotificationInfoBarPresenterTests.Present_ActionableNotificationWinsOverShowMore | behavioral | - |
| shell-flyout-content | authoritative | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs | compact notification list reconciliation and gateway/operator/node flyout control application | NotificationFlyoutContent + GatewayStatusContent | windows own popup lifetime, badge/status button, and route/reconnect callbacks | Workspace bell preserves chat/history; both status entry points share the existing connection projection | WorkspaceWindowProofTests.SidebarSessions_SelectOriginalKeys_AndKeepCompanionDraft | behavioral | - |
| shell-flyout-content-closed | closed | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs and WorkspaceWindow.xaml.cs | bell list reconciliation and duplicate gateway flyout row application | NotificationFlyoutContent + GatewayStatusContent | banner and sidebar application; popup lifetime and action callbacks | windows do not regain flyout lists, row projection, or independent gateway clients | DiagnosticsPageContractTests.ShellFlyoutContent_HasFocusedOwners | source-shape | when both shells retire these flyout entry points |
| tray-menu-presentation | authoritative | TrayMenuStateBuilder and src/OpenClaw.Tray.WinUI/App.xaml.cs | tray row and flyout presence, ordering, text, formatting, icon identity, action, checked and enabled state, accelerator, accessibility names, and connection-toggle projection | TrayMenuPresenter + ConnectionTogglePresenter | App captures immutable input and owns semantic callbacks, persistence, and reconnect policy; TrayController applies live projection; TrayMenuRenderer builds WinUI controls; TrayMenuWindow owns popup mechanics | equal immutable snapshots project equal complete menus; connected and disconnected compositions, all nine permission toggles, and transient connection states preserve behavior | TrayMenuPresenterTests.Connected_ProjectsExactTopLevelAndNestedOrder | behavioral | - |
| tray-menu-state-builder-closed | closed | TrayMenuStateBuilder and src/OpenClaw.Tray.WinUI/App.xaml.cs | snapshot interpretation, semantic menu construction, and duplicated connection-toggle decisions | TrayMenuPresenter + ConnectionTogglePresenter | mechanical rendering, immutable snapshot capture, action dispatch, persistence callbacks, TrayController weak control references, and TrayMenuWindow native popup behavior | presentation owners stay WinUI/App/concrete-settings free and the renderer and controller do not interpret runtime snapshots | TrayMenuPresentationContractTests.PresentationFiles_AreWinUiAppAndConcreteSettingsFree | source-shape | when the tray menu no longer uses WinUI rendering |
| node-connection-coordinator | authoritative | src/OpenClaw.Connection/GatewayConnectionManager.cs | node generation, cancellation, start guard, connect ordering, classified token recovery, connector events, and node telemetry | NodeConnectionCoordinator | manager public node façade; node-only operator/lifecycle/tunnel preparation; typed lifecycle/state/security ports; one event-forwarding subscription set | a superseded lifecycle or node generation cannot write node snapshot state | NodeConnectionCoordinatorTests.SupersededGeneration_DoesNotWriteSnapshot | behavioral | - |
| native-gateway-runtime | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs and src/OpenClaw.Connection/GatewayConnectionManager.cs | native Gateway package resolution, process launch, job ownership, and listener verification | NativeGatewayRuntime and NativeGatewayEndpointSecurity | App composes one runtime with its registry and installed-package resolver; manager delegates start/retry authorization, explicit disconnect and switch stop, and shutdown disposal | native credentials require runtime-owned endpoint proof for both roles; no WSL or remote exemption; reconnect preserves healthy native runtime and starts a crashed owned runtime | GatewayConnectionManagerTests.NativeGateway_ReconnectRestartsCrashWithoutStoppingHealthyRuntime | behavioral | - |
| gateway-manager-node-owner-closed | closed | src/OpenClaw.Connection/GatewayConnectionManager.cs | private node generation/CTS/start workflow/recovery/telemetry implementation | NodeConnectionCoordinator | public node façade; node-only operator/lifecycle/tunnel preparation; typed lifecycle/state/security ports; one event-forwarding subscription set | the manager has no node generation, node CTS, combined node-attempt predicate, node connect core, or node telemetry names | ConnectionDomainOwnerClosureTests.GatewayConnectionManager_DoesNotReintroduceNodeGenerationOrTelemetryOwnership | source-shape | when GatewayConnectionManager no longer composes NodeConnectionCoordinator directly |
| bootstrap-token-lifecycle | authoritative | src/OpenClaw.Connection/GatewayConnectionManager.cs | bootstrap selection and durable clear timing, device-token persistence handoff, post-bootstrap reconnect, and operator token recovery | BootstrapTokenLifecycle | manager public setup/shared-token façade and save-failure rollback; operator event forwarding; typed lifecycle lease, endpoint-security, reconnect, and v2 persistence ports | bootstrap clears only after canonical operator and node role tokens are both durably readable | BootstrapTokenLifecycleTests.ClearsBootstrap_OnlyWhenBothRoleTokensDurable | behavioral | - |
| gateway-manager-bootstrap-owner-closed | closed | src/OpenClaw.Connection/GatewayConnectionManager.cs | bootstrap timing flags, durable-token clear helper, post-bootstrap scheduling, and operator mismatch recovery | BootstrapTokenLifecycle | public setup/shared-token façade and save-failure rollback; one-shot shared-token validation; operator event forwarding; typed lifecycle/reconnect/v2 ports | stale token events cannot restore timing flags, clear a newer record, or schedule an untyped reconnect callback | ConnectionDomainOwnerClosureTests.GatewayConnectionManager_DoesNotReintroduceBootstrapTimingOwnership | source-shape | when GatewayConnectionManager no longer composes BootstrapTokenLifecycle directly |
| device-pair-approval-coordinator | authoritative | src/OpenClaw.Connection/GatewayConnectionManager.cs | device role-upgrade approval, confirmation, dedupe, and one-in-flight plus one-queued bounded reconnect | DevicePairApprovalCoordinator | manager pairing-event forwarding and generation-bound operator gateway lease source | post-approval node reconnect is bounded to two attempts per request and reacquires the current operator gateway | DevicePairApprovalCoordinatorTests.PostApproveReconnect_IsBounded | behavioral | - |
| gateway-manager-device-pair-owner-closed | closed | src/OpenClaw.Connection/GatewayConnectionManager.cs | device-pair approve RPC, success dedupe, reconnect attempts, and queued retry state | DevicePairApprovalCoordinator | pairing-event forwarding, node snapshot application, and generation-bound operator gateway lease source | manager cannot regain device-pair workflow fields or approve/reconnect methods | ConnectionDomainOwnerClosureTests.GatewayConnectionManager_DoesNotReintroduceDevicePairWorkflowOwnership | source-shape | when GatewayConnectionManager no longer composes DevicePairApprovalCoordinator directly |
| chat-composer-view-model | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawReactorChatRoot.cs (nested ReactorChatComposer) | draft text/revision, pending attachment identities/presentation, slash UI state, composer busy flags, selector/queue projections, and derived enablement in the root/nested composer Reactor hooks | ChatComposerViewModel | ReactorChatComposer (view) reads projected values and applies immutable ChatComposerInputs from the root in a stable-source post-commit effect; ChatComposerViewModel never subscribes to IChatDataProvider | every observable mutation is dispatched through IUiDispatcher, ChatComposerInputs accepts only increasing revisions and semantically changed projections, rejected inputs do not notify, and no mutation is accepted after Dispose | ChatComposerViewModelTests.ApplyInputs_RejectsOutOfOrderRevision | behavioral | - |
| chat-composer-controller | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawReactorChatRoot.cs (root SendAsync/OnStop and composer callback closures) | send/stop/reset-confirmation/queue-cancel/model-set-clear/thinking/catalog/attachment-ingress-remove/paste-image/voice workflow and cancellation | ChatComposerController over IChatComposerRuntimePort and ChatComposerHostActions | root session selection (SelectThread) and view event forwarding; D1 provider remains authoritative for send admission and queue mechanics | draft revision and attachment reference identities are snapshotted at operation start and cleared only when the accepted result still matches; operations are fenced by a generation bumped on Dispose so late completions cannot mutate a disposed/superseded controller | ChatComposerControllerTests.SendAsync_EditDuringDelayedSend_DoesNotClearTheEditedDraft | behavioral | - |
| chat-composer-host-lifetime | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatHostExtensions.cs | ad hoc per-render HostCallbacks assignment and no explicit composer session lifetime | IChatComposerFactory + ChatComposerSession, owned/disposed exactly once by MountedReactorChat | ChatPage and ChatWindow each receive a separate session over the same provider; the factory is a stateless singleton with no constructor-started work | disposing a MountedReactorChat disposes its ChatComposerSession (controller then view model) exactly once, and repeated Dispose calls are a no-op | ChatComposerSessionTests.Dispose_DisposesViewModelAndControllerExactlyOnce | behavioral | - |
| reactor-chat-root-composer-closed | closed | src/OpenClaw.Tray.WinUI/Chat/OpenClawReactorChatRoot.cs | composer draft/attachment/slash/voice/send mutable state and direct composer send/model/thinking/catalog/queue-cancel provider calls | ChatComposerViewModel + ChatComposerController | provider subscription, initial load, immutable snapshot, selected/materialized/compose-only thread selection, timeline/generation/metadata projection, permission-card forwarding, checkpoint routing, #1089 scroll/follow tokens, root composition, and construction of one immutable ChatComposerInputs projection per render | the root holds no composer UseState/refs and calls no composer provider API directly; it builds ChatComposerInputs, forwards them to ReactorChatComposer for post-commit application, and binds the SelectThread handoff | ChatRootComposerClosureTests.Root_DoesNotReintroduceComposerMutableState | source-shape | when OpenClawReactorChatRoot is replaced by a different root/composer boundary |
| sensitive-capture-guard | authoritative | src/OpenClaw.Tray.WinUI/Services/NodeService.cs | ordering of consent, visible per-use indication, and sensor access for instantaneous screen, camera, and location captures | SensitiveCaptureExecutor + SensitiveCapturePlans | NodeService supplies the consent prompt, localized notification, and platform sensor delegates | every sensitive instant capture completes consent and visible indication before its sensor delegate can run; denied consent never reaches the sensor | SensitiveCaptureExecutorTests.ExecuteAsync_RequiresConsentAndIndicatorBeforeSensorAccess | behavioral | - |
| inno-migration-startup | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | migration record parsing and completed-handoff admission | MigrationRecordCodec + InnoMigrationStartupGuard | App invokes the guard before ordinary startup; explicit destructive CLI uninstall remains separate | completed migration prevents normal unpackaged startup before settings or activation; development and packaged apps are unaffected | InnoMigrationContractTests.CompletedMigrationGuard_PrecedesSettingsAndActivation | source-shape | when packaged/unpackaged migration startup is fully hosted outside App |
| store-migration-startup | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | Inno discovery, pending-record inspection, and Store migration admission policy | InnoInstallationDetector + MigrationStartupRecordReader + StoreMigrationStartupCoordinator + StoreMigrationStartupGuard | App calls the compile-time-gated adapter before instance forwarding and normal services | disabled builds perform no migration inspection; preview admission never mutates source state or enables normal startup for pending migration | StoreMigrationStartupCoordinatorTests.Disabled_DoesNotInspectInstallationOrRecords | behavioral | - |
| store-migration-startup-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | direct registry discovery and migration startup policy | StoreMigrationStartupGuard + StoreMigrationStartupCoordinator | one adapter invocation after explicit CLI uninstall and before protocol processing and instance forwarding | App does not regain installation discovery, record parsing, or admission decisions | InnoMigrationContractTests.StorePreviewGuard_PrecedesInstanceForwardingAndNormalServices | source-shape | when packaged migration bootstrap is hosted outside App |
| store-migration-workflow | authoritative | StoreMigrationStartupGuard | native message-box consent loop and inline adoption composition | StoreMigrationWorkflow + StoreMigrationOperations + StoreMigrationWindow | guard gates bootstrap and owns the pre-services window lifetime only | UI actions are serialized; explicit consent precedes shutdown and validation; only verified finalization permits normal startup | StoreMigrationWorkflowTests.ExplicitConfirmation_RecordsConsentBeforeGracefulShutdownAndCompletion | behavioral | - |
| inno-migration-handoff | authoritative | SettingsPage + App activation composition | explicit consent, Store listing policy, and migration shutdown authorization | InnoMigrationHandoff + InnoMigrationConsentStore + StoreMigrationListing | Settings forwards the action and displays its result; App supplies its existing shutdown callback | only configured production Release or explicit preview builds expose handoff; Dev stays isolated; exact same-user Inno and protected consent precede canonical graceful exit; inventory never means consent | InnoMigrationContractTests.InnoPreview_GatesHandoffAndUsesCanonicalShutdown | source-shape | when migration handoff is retired |
| migration-build-policy | authoritative | OpenClaw.Tray.WinUI.csproj | shared Inno/Store compile-time activation and fixed source floor | Migration.Build.props | the tray project imports one policy for packaged and unpackaged publishing | production requires a pinned nonzero source floor and supported Release RID; Debug and Dev cannot inherit production activation | MigrationBuildConfigurationTests.Production_InnoAndStoreShareThePinnedReleasePolicy | behavioral | - |
| migration-consent-locking | authoritative | InnoMigrationConsentStore | protected consent publication and inspection while source is running | MigrationOperationLock + InnoMigrationConsentStore | consent uses a shared preparation lease and a separate exclusive writer lock | consent remains compatible with Inno runtime readers but cannot overlap exclusive Store mutation; finalization removes the writer lock before deleting the completion receipt | InnoMigrationConsentStoreTests.RuntimeReadLease_AllowsExplicitGrantAndInspection | behavioral | - |
| chat-markdown-presentation | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | paragraph and heading typography, literal code-frame presentation and Copy | ChatMarkdownPresentation | timeline keeps sanitization, parser flags, inert links/images and the existing list-wrapping callback | presentation uses public MarkdownOptions callbacks; code content is never truncated or parsed as markup | ReactorChatLayoutProofTests.CodeBlock_PreservesLiteralContentAndCopiesExactText | behavioral | - |
| chat-model-picker-presentation | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatComposer.cs, then custom Button rows in ChatModelPicker | catalog search, provider groups, native row interaction states and model metadata presentation | NativeChatModelPicker through a generated Reactor wrapper | ChatModelPicker owns flyout lifetime; composer controller owns model mutation and authorization | native single-selection navigation never writes a model until explicit activation; filtering and resizing preserve raw provider-qualified identities | ReactorChatLayoutProofTests.ModelMenu_UsesNativeSelectionStatesAndPreservesNavigationDuringResize | behavioral | - |
| chat-model-picker-button-rows-closed | closed | src/OpenClaw.Tray.WinUI/Chat/ChatModelPicker.cs | hand-built Button rows, custom selected fill/checkmark and search-box styling | NativeChatModelPicker | declarative trigger and flyout lifetime only | native AutoSuggestBox/ListView own search and row interaction visuals; no duplicate hand-styled selection path | ReactorChatLayoutProofTests.ModelMenu_UsesNativeSelectionStatesAndPreservesNavigationDuringResize | behavioral | - |
| chat-thinking-profile | authoritative | static levels in ReactorChatComposer | advertised reasoning-profile precedence and exact identity/runtime matching | ChatThinkingProfile over immutable ThinkingContext/ThinkingProfile values | ThinkingMetadata parses and scope-fences gateway metadata; client retains session-cache ownership; ChatSnapshotProjector carries it; composer controller gates selections and clears overrides | no provider/model heuristics, missing differs from empty, unknown saved values remain truthful, and Default is explicit null | ChatThinkingProfileTests.Priority_FirstCandidateWithAnyMetadataOwnsEvenEmptyOrDefaultOnly | behavioral | - |
| reactor-markdown-presentation-closed | closed | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | inline custom typography and code-frame construction | ChatMarkdownPresentation | timeline owns sanitizer and parser safety options, the existing list-wrapping callback and public callback registration | custom block presentation is delegated, with no parser or list-measurement fork | ReactorChatMarkdownContractTests.AssistantMessages_UseSanitizedGitHubFlavoredMarkdown | source-shape | when the public MarkdownOptions presentation seam is replaced |
| chat-copy-feedback | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs and ChatMarkdownPresentation.cs | copy invocation status, temporary success/failure announcement and reset lifetime | ChatCopyButton with ClipboardHelper.TryCopyText | renderers pass immutable text/identity and keep parser, metadata and workflow ownership | only confirmed clipboard writes show Copied; content changes, repeated clicks and unmount cancel stale resets | ReactorChatLayoutProofTests.CopyFeedback_ResetsRepeatedClicksContentIdentityAndDisposal | behavioral | - |
| chat-effort-picker-presentation | authoritative | ReactorChatComposer's native reasoning menu | effort popover, discrete slider/single-stop presentation and Default affordance | ChatReasoningPicker | ChatThinkingProfile resolves advertised options; ChatComposerController validates and performs mutations; composer owns responsive trigger placement | opening a popover never writes a setting, only advertised IDs are selected, Default stays an explicit clear, and compact icons retain textual automation names | ReactorChatLayoutProofTests.ReasoningPicker_UsesConcreteWireValuesAndExplicitDefaultClear | behavioral | - |
| chat-composer-button-chrome | authoritative | ReactorChatComposer's duplicated per-button resource overrides | shared idle, hover and pressed toolbar resource overrides | ChatVisuals.ToolbarButtonResources | composer constructs the controls and applies the shared resources; native templates retain disabled and keyboard-focus behavior | compact effort stays transparent at rest and matches neighboring toolbar states across resize without replacing native templates | ReactorChatLayoutProofTests.EffortTrigger_PreservesTransparentChromeAndCenteredContent | behavioral | - |
| setup-interactive-flow | authoritative | src/OpenClaw.SetupEngine.UI/Pages/ProgressPage.xaml.cs | interactive installation-step selection and required AI setup decision | OnboardingFlowPolicy | ProgressPage applies progress events and navigation; SetupWindow supplies the selected route to the progress indicator | interactive install never runs the classic wizard or workspace finalization; Local AI still requires exact-model verification when SkipWizard is set; headless step order is unchanged | OnboardingFlowPolicyTests.InteractiveInstallation_DefersWizardAndWorkspaceFinalization | behavioral | - |
| setup-page-flow-closed | closed | src/OpenClaw.SetupEngine.UI/Pages/ProgressPage.xaml.cs | private copy of default installation filtering and implicit post-install milestone gating | OnboardingFlowPolicy | BuildSteps delegates to the policy and success applies its AI setup decision | UI must not recreate the default pipeline selection or require an extra milestone click on successful modern setup | OnboardingPresentationContractTests.SuccessfulInstallation_UsesAiSetupWithoutAMilestoneClick | source-shape | when ProgressPage no longer hosts the interactive installation pipeline |
| setup-gateway-session | authoritative | src/OpenClaw.SetupEngine.UI/Pages/WizardPage.xaml.cs | temporary setup operator client construction, registry identity, endpoint resolution, and reconnect provenance | SetupGatewaySession | setup pages own their session lifetime and render protocol state; GatewayConnectionManager still owns the normal app connection | setup uses the active registry record and SSH-resolved endpoint with device-token precedence and managed-local provenance before sending strong credentials | AppRefactorContractTests.WizardConnect_UsesActiveGatewayRecordUrl | source-shape | when setup reuses the normal connection manager rather than a temporary operator session |
| setup-page-client-construction-closed | closed | src/OpenClaw.SetupEngine.UI/Pages/WizardPage.xaml.cs | private gateway-client constructor and duplicated endpoint/credential resolution | SetupGatewaySession | ConnectClientAsync forwards to the shared setup owner and keeps the returned host-access plan | classic and focused setup cannot diverge in endpoint or credential selection | AppRefactorContractTests.WizardConnect_UsesActiveGatewayRecordUrl | source-shape | when the classic gateway wizard is removed |
| connection-validation-client | authoritative | src/OpenClaw.Connection/GatewayConnectionManager.cs | one-shot validation client construction and credential persistence policy | GatewayConnectionValidator | manager retains shared-token replacement workflow and endpoint authorization callback | validation denies reconnect, pins SSH ownership, and cannot persist handshake tokens | GatewayConnectionValidatorTests.ValidationClient_DisablesHandshakeTokenPersistence | behavioral | - |
| connection-validation-construction-closed | closed | src/OpenClaw.Connection/GatewayConnectionManager.cs | private validation-client constructor policy | GatewayConnectionValidator | CreateSharedTokenValidationClient delegates to the focused owner for compatibility | native setup and shared-token replacement share the same one-shot client policy | GatewayConnectionValidatorTests.ValidationClient_DisablesHandshakeTokenPersistence | behavioral | - |
| setup-native-transaction | authoritative | src/OpenClaw.SetupEngine.UI/Pages/AdvancedSetupPage.xaml.cs | native connection checks and commit orchestration | SetupNativeConnectionHost + GatewayDirectConnectService | SetupNativeConnectionPage edits immutable draft and renders results; WindowManager injects the existing transaction owner | Check cannot write saved gateway or live connection state; Next revalidates and cancellation restores previous state | GatewayDirectConnectServiceTests.NativeNext_CancelAfterHandshakeRestoresPreviousIdentityAndLiveConnection | behavioral | - |
| setup-native-identity-promotion | authoritative | src/OpenClaw.Tray.WinUI/Services/GatewayDirectConnectService.cs | native setup identity promotion and compare-and-swap rollback without gateway-ID replacement | DeviceIdentity.ReplaceValidatedIdentity + DeviceIdentity.RestoreValidatedIdentity | direct-connect owner sequences disconnect, promotion, registry/settings commit and rollback | same-realm setup retains logical gateway ID and sidecars; a newer credential writer is preserved and surfaced as incomplete rollback | GatewayDirectConnectServiceTests.NativeNext_ManagedGatewayRetainsLogicalIdAndLocalAiOwnership | behavioral | - |
| setup-local-ai-route | authoritative | src/OpenClaw.Tray.WinUI/Services/WindowManager.cs | Local AI Gateway inspection and first-install or recovery route resolution | LocalAiSetupRouteResolver + LocalAiSetupRoutePolicy | WindowManager composes the resolver and retains Settings window lifetime; SetupLocalAiHost consumes its same typed target | first install without a receipt uses recovery only after unique app-owned Gateway proof; ambiguous and remote targets cannot receive Windows loopback configuration | LocalAiOnboardingTests.Host_FirstInstallWithoutReceipt_AdmitsSameGatewayWithoutRuntimeMutation | behavioral | - |
| setup-local-ai-mutation-drain | authoritative | src/OpenClaw.SetupEngine.UI/Pages/AiSetupPage.xaml.cs | treating local mutation as a bounded observation request | LocalAiOnboardingUse | page cancels requests and awaits actual local mutation drain before CloseAsync completes | runtime rollback must finish before the setup lock is released; uncertain outcomes retain the exact Gateway and model without replay | LocalAiOnboardingUseTests.CancelledUse_DrainRetainsOwnershipUntilActualRollbackEnds | behavioral | - |
| setup-local-ai-registry-handoff | authoritative | src/OpenClaw.SetupEngine.UI/Pages/ProgressPage.xaml.cs | stale live registry after separate-instance pipeline writes and rollback | SetupPipeline.RunWithSettlementAsync + SetupLocalAiHost + GatewayRegistry.ReconcileSetupOutcome | settlement precedes closed-page early return and setup-lock release; notifications are outside locks | all outcomes adopt only known operation output against admitted memory; concurrent edits require explicit recovery, and stale connections are conditionally disconnected | SetupPipelineSettlementTests.FailedOrCancelledPipelineSettlesBeforeClosedOwnerFinishes | behavioral | - |
| setup-local-ai-route-inline-closed | closed | src/OpenClaw.Tray.WinUI/Services/WindowManager.cs | private Local AI route detection algorithm | LocalAiSetupRouteResolver | constructor/delegate composition and failure notification only | Settings and onboarding cannot grow divergent Gateway ownership admission | WindowManagerTests.LocalAiSetup_ChoosesRecoveryOnlyAfterManagedGatewayProof | source-shape | when both Settings and onboarding route admission have mounted host tests |
| setup-local-ai-observation | authoritative | src/OpenClaw.SetupEngine.UI/Pages/AiSetupPage.xaml.cs | hardware, receipt, runtime and ownership observation or mutation policy | LocalAiOnboardingObservation + LocalAiOnboardingSnapshot + SetupLocalAiHost | page applies localized state and forwards explicit actions; SetupWindow alone navigates existing review and recovery pipeline | observation is independent from Gateway discovery and never starts, publishes, grants consent, migrates or writes; stale and closed callbacks are discarded | LocalAiOnboardingTests.Observation_CancelsRefreshAndDiscardsStaleCallbacks | behavioral | - |
| setup-local-ai-host-boundary | closed | src/OpenClaw.SetupEngine.UI/Pages/AiSetupPage.xaml.cs | opening a second setup window or constructing a parallel Local AI runtime and provider-registration owner | ISetupLocalAiHost + SetupWindow | explicit review callback, cancellation and exact-model verification | Local AI review stays under the existing setup lock, preserves access/startup choices and verifies the exact model before completion | LocalAiOnboardingOwnershipTests.AiPage_UsesTypedSameWindowHostAndNeverOwnsRuntimeOrGatewayRegistration | source-shape | when mounted same-window Local AI navigation tests replace source guards |
| setup-ai-completion-intent | authoritative | src/OpenClaw.SetupEngine.UI/Pages/AiSetupPage.xaml.cs | implicit destination from discovery or authentication success | GatewayAiSetupClient + GatewayAiSetupCompletion | page forwards a current verified receipt; intent remains activation provenance, not the native destination | only exact main-model verification yields a completion; native destinations require explicit choice and cannot fall back to browser completion | GatewayAiSetupClientTests.Completion_UsesExplicitActivationKind_NotSetupComplete | behavioral | - |
| setup-native-final-choice | authoritative | src/OpenClaw.SetupEngine.UI/SetupWindow.xaml.cs | automatic finalization and web launch on modern AI verification | SetupNativeCompletionCoordinator + SetupNativeCompletionVerifier | window owns page mounting, existing finalization hooks and prior page drain; AiReadyPage only renders and forwards choices | showing the chooser issues no nonce and performs no finalization; every explicit choice freshly verifies the same primary-model ownership before once-only finalization and publication | SetupNativeCompletionCoordinatorTests.ShowingChooserDoesNothing_ExplicitChoiceVerifiesThenFinalizesAndPublishes | behavioral | - |
| setup-native-operator-connection | authoritative | src/OpenClaw.SetupEngine.UI/Pages/WizardPage.xaml.cs | native operator construction, exact pairing retry and credential handoff authorization | NativeGatewaySetupConnection + NativeGatewaySetupSession | pages drain their operator socket; the window retains the staged runtime and profile | focused and compatibility setup share per-handshake/request provenance, pinned signing identity and canonical agent/session; lost identities cannot be recreated mid-flow | NativeGatewaySetupConnectionTests.EveryRequestAndReconnect_RechecksNativeOwnership | behavioral | - |
| setup-native-page-client-closed | closed | src/OpenClaw.SetupEngine.UI/Pages/WizardPage.xaml.cs | native client construction and parallel handshake policy | NativeGatewaySetupConnection | classic wizard retains only compatibility RPC/rendering | pages cannot bypass the native owner with a generic loopback session or duplicate pairing policy | NativeGatewaySetupUxContractTests.NativeWizard_UsesSharedPageAndRpc_WithFailClosedStagedAuthorization | source-shape | when compatibility onboarding is removed |
| setup-native-ai-finalization | authoritative | src/OpenClaw.SetupEngine/NativeGatewaySetupSession.cs | classic-wizard-only admission to registry publication | CompleteVerifiedAsync + SetupNativeCompletionCoordinator | classic completion stays separate; focused completion requires real verification without marking the wizard complete | exact model/agent/session/identity is checked after the owned runtime restart and before registry publication; unrelated records survive, occupied draft IDs fail | NativeGatewaySetupConnectionTests.FocusedAi_AllDestinationsReverifyAfterNativeRestartBeforePublication | behavioral | - |
| setup-native-restart-verification | authoritative | src/OpenClaw.SetupEngine/SetupNativeCompletionVerifier.cs | generic native loopback verification after restart | GatewayAiSetupTransport.BorrowNativeAsync + GatewayConnectionManager.RequireNativeSetupClientAsync | App only supplies the manager; verifier never disposes the borrowed client or owns a runtime | native provenance is inspected for every request and receipt drift is rejected before navigation | NativeGatewaySetupConnectionTests.PostRestartVerification_BorrowsNormalOwnerAndRejectsUnownedOrReplacedAuthority | behavioral | - |
| setup-native-pending-launch | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | implicit browser destination for new verified onboarding | SetupNativeHandoffLauncher + SetupNativeNavigationRequest + SetupDashboardHandoffStore | App supplies composition callbacks; WindowManager mounts typed native pages; page-level metadata loading remains in ChannelsPage | native versioned records retain exact Gateway/agent/model/session and exclusive lease; failed opens require explicit retry; successful opens consume | SetupNativeHandoffTests.NativeOpenVerifiesBeforeNavigationAndKeepsFailedLaunchForExplicitRetryOnly | behavioral | - |
| dashboard-launch-owner | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | ordinary Dashboard endpoint construction, credential export policy and browser result handling | GatewayDashboardLauncher + GatewayDashboardUrlBuilder | App supplies credential, tunnel, browser and failure delegates; WindowManager owns visible error/retry lifetime | only shared credentials enter fragment auth; browser failure is visible and never automatically replayed; setup completion cannot enter this path | SetupDashboardHandoffTests.DeviceAndBootstrapTokens_NeverEnterBrowserUrl | behavioral | - |
| app-dashboard-launch-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | inline Dashboard URL construction and silent Process.Start failure handling | GatewayDashboardLauncher | composition delegates and normal Dashboard entry forwarding only | App does not regain a parallel Dashboard URL or credential policy; explicit retries keep the requested path | AppRefactorContractTests.Dashboard_SurfacesSshTunnelConfigurationFailure | source-shape | when the WinUI Dashboard adapter has injected mounted lifecycle coverage |
| setup-session-captured-authority | authoritative | src/OpenClaw.SetupEngine/SetupGatewaySession.cs | deriving client authority from a later active registry record | SetupGatewaySessionBinding | session reloads registry only to validate captured identity at admission, handshake, reconnect and request boundaries | a socket opened for Gateway A cannot be reported as Gateway B; same-ID endpoint and SSH changes fail while connection timestamps remain valid | SetupGatewaySessionBindingTests.ChangedRegistryDuringConnect_CannotRelabelAlreadyCreatedClient | behavioral | - |
| setup-dashboard-pending-proof | authoritative | src/OpenClaw.Tray.WinUI/Services/SetupDashboardHandoff.cs | accepting external serialized completion JSON as verified proof | SetupDashboardHandoffStore + SetupNativeHandoffLauncher | activation parser admits only an opaque native handle; WindowManager rechecks current observations with SetupDashboardLiveFacts | a short-lived local pending record is exclusively leased, consumed on successful native presentation and retained only for explicit failed-launch retry; unknown, expired, forged, consumed and in-flight replay fail visibly; old generation numbers are not live authority | SetupDashboardHandoffStoreTests.ForgedShapeAndUnknownHandle_AreNotVerificationAuthority | behavioral | - |
DeviceIdentityBuilder and SetupContextBuilder are intentionally not in
OpenClaw.TestSupport yet. DeviceIdentity is a stateful Ed25519 key/file
service (not a value type) and SetupContext needs setup logger/journal/command-runner
fakes. Both will be added alongside their subsystem PRs (gateway protocol and
SetupEngine, respectively) so OpenClaw.TestSupport does not take a heavy
dependency on OpenClaw.SetupEngine prematurely.