Skip to content

Latest commit

 

History

History
246 lines (227 loc) · 66.9 KB

File metadata and controls

246 lines (227 loc) · 66.9 KB

OpenClaw Windows node - architecture ledger

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.

How to use this document

  1. Before editing a file named in the ledger, read its row(s). Do not add back anything a row marks closed.
  2. 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.
  3. Prefer behavioral/golden guards. Use source-shape guards only for a concrete prohibited pattern (a banned helper signature, a forbidden direct constructor call), never for broad architectural wishes, and always with a retirement_condition.

Ownership rules

  • 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 - no Microsoft.UI.Xaml, no Application.Current, no Window/Frame/Brush/Color, no concrete SettingsManager. 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.

Single-source owners

These are the canonical homes. Do not reintroduce private copies elsewhere.

Concern Canonical owner Status
Test temp directories OpenClaw.TestSupport.TempDirectory 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
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
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
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
Exact Gateway wizard terminal-restart compatibility and bounded retry policy GatewayWizardRestartRecoveryPolicy authoritative
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
Hub notification banner severity and action projection AppNotificationInfoBarPresenter 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
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
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
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
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

When you touch file X, extract toward Y

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/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/OpenClawChatTimeline.cs ReactorChatTimeline (production ItemsView / ItemContainer), ChatBubbleRenderer, ToolCallCardRenderer, PermissionRequestCard, AttachmentBubbleRenderer
src/OpenClaw.Tray.WinUI/Chat/OpenClawComposer.cs ComposerViewModel, SlashCommandPalette, AttachmentPreviewStrip, VoiceComposerController (legacy FunctionalUI surface; the production path is ReactorChatComposer.cs below)
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, 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

Ledger

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 | closed
  • guard_type: behavioral | golden | source-shape | review-only
  • For authoritative/closed rows, guard_test must name a test as Type.Method (validated for format), OR guard_type must be review-only with a real rationale in guard_test (placeholders like -/none are rejected).
  • For behavioral/golden rows, the named guard_test must actually exist in the tests/ source tree - the consistency test scans for it, so renaming or deleting a guard without updating the ledger fails CI.
  • source-shape rows must set a concrete retirement_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
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-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
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 -
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 -
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; current-user IPC, oversized-payload rejection, and confirmation/redaction semantics are preserved ActivationRouterTests.ForwardThenListen_DispatchesRouteFromForwardedDeepLink 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
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
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 src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs production chat message virtualization, row realization, and imperative scroll follow ReactorChatTimeline through OpenClawReactorChatRoot and ReactorHostControl OpenClawChatTimeline remains a legacy focused-test surface while its runtime route is migrated 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 review-only: user explicitly deferred new tests for this migration; required build and existing shared/tray suites still run review-only when Reactor timeline proof coverage replaces the legacy focused UI host coverage
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 -
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/FunctionalChatHostExtensions.cs mounting the FunctionalUI chat tree as the default ChatPage or ChatWindow surface ReactorChatHostExtensions and OpenClawReactorChatRoot legacy FunctionalUI chat files may remain for focused compatibility coverage only ChatPage and ChatWindow mount the Reactor root directly into their existing ChatHost Borders; no FunctionalUI component mounts or nests Reactor on the default path review-only: user explicitly deferred new tests for this migration; required build and existing shared/tray suites still run review-only when legacy FunctionalUI chat surfaces are removed
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 notification subscription, bell reconciliation, 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 -
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 -
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; ChatComposerViewModel never subscribes to IChatDataProvider every observable mutation is dispatched through IUiDispatcher, ChatComposerInputs is applied only when its revision strictly increases, 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 only builds ChatComposerInputs and forwards it plus a bound SelectThread handoff to the composer session ChatRootComposerClosureTests.Root_DoesNotReintroduceComposerMutableState source-shape when OpenClawReactorChatRoot is replaced by a different root/composer boundary

Deferred test builders

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.