From 1afd4b707094da64e7e5e4eb317b7bcd849bd496 Mon Sep 17 00:00:00 2001 From: Mike Harsh Date: Thu, 7 May 2026 09:53:41 -0700 Subject: [PATCH 01/27] refactor(setup): remove OPENCLAW_WSL_INSTALL_LOCATION env-var binding Production code path always lands at %LOCALAPPDATA%\OpenClawTray\wsl\OpenClawGateway. The env-var was a test-only artifact ported from the prototype that no production caller ever set. Eliminating it removes orphaned-VHD risk in the upcoming uninstall flow (no need to persist install location in setup-state.json). InstanceInstallLocation field on LocalGatewaySetupOptions retained as a constructor test seam for direct injection from xUnit tests. Pre-existing failures on PR #274 base (NOT introduced by this commit): - 8 LocalizationValidationTests fail with InvalidOperationException: "Could not find repository root. Set OPENCLAW_REPO_ROOT to the repo path." This is a worktree environment issue; unrelated to env-var removal. Refs: .squad/decisions/inbox/kranz-uninstall-plan-v3.md (commit 1 of 7) Stacked on PR #274. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- scripts/validate-wsl-gateway.ps1 | 3 ++- .../Services/LocalGatewaySetup/LocalGatewaySetup.cs | 5 ----- tests/OpenClaw.Tray.Tests/LocalGatewaySetupTests.cs | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/scripts/validate-wsl-gateway.ps1 b/scripts/validate-wsl-gateway.ps1 index 711b0f996..cf73f414e 100644 --- a/scripts/validate-wsl-gateway.ps1 +++ b/scripts/validate-wsl-gateway.ps1 @@ -448,7 +448,8 @@ function Start-TrayForLocalSetup { OPENCLAW_SKIP_UPDATE_CHECK = "1" OPENCLAW_FORCE_ONBOARDING = "1" OPENCLAW_WSL_DISTRO_NAME = $DistroName - OPENCLAW_WSL_INSTALL_LOCATION = $wslInstallLocation + # TODO: OPENCLAW_WSL_INSTALL_LOCATION was removed (commit: remove OPENCLAW_WSL_INSTALL_LOCATION env-var binding). + # The install location is now derived from the distro name by the tray app. Remove this comment once uninstall support lands. OPENCLAW_WSL_ALLOW_EXISTING_DISTRO = if ($Scenario -eq "UpstreamInstall") { "1" } else { "0" } OPENCLAW_TRAY_DATA_DIR = $validationAppDataRoot OPENCLAW_TRAY_APPDATA_DIR = $validationAppDataRoot diff --git a/src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs b/src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs index 8b20808b9..9bd564654 100644 --- a/src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs +++ b/src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs @@ -90,11 +90,9 @@ public sealed class ProcessLocalGatewaySetupEnvironment : ILocalGatewaySetupEnvi public sealed record LocalGatewaySetupRuntimeConfiguration( string? DistroName, - string? InstanceInstallLocation, bool AllowExistingDistro) { public const string DistroNameVariable = "OPENCLAW_WSL_DISTRO_NAME"; - public const string InstanceInstallLocationVariable = "OPENCLAW_WSL_INSTALL_LOCATION"; public const string AllowExistingDistroVariable = "OPENCLAW_WSL_ALLOW_EXISTING_DISTRO"; public static LocalGatewaySetupRuntimeConfiguration FromEnvironment(ILocalGatewaySetupEnvironment? environment = null) @@ -106,7 +104,6 @@ public static LocalGatewaySetupRuntimeConfiguration FromEnvironment(ILocalGatewa #else null, #endif - NullIfWhiteSpace(environment.GetVariable(InstanceInstallLocationVariable)), IsTruthy(environment.GetVariable(AllowExistingDistroVariable))); } @@ -2957,7 +2954,6 @@ public static LocalGatewaySetupEngine CreateLocalOnly( NodeService? nodeService = null, #endif string? distroName = null, - string? instanceInstallLocation = null, bool allowExistingDistro = false, bool replaceExistingConfigurationConfirmed = false, string? identityDataPath = null, @@ -2996,7 +2992,6 @@ public static LocalGatewaySetupEngine CreateLocalOnly( { GatewayUrl = settings.GetEffectiveGatewayUrl(), DistroName = ResolveDistroName(runtime, distroName), - InstanceInstallLocation = string.IsNullOrWhiteSpace(instanceInstallLocation) ? runtime.InstanceInstallLocation : instanceInstallLocation, AllowExistingDistro = allowExistingDistro || runtime.AllowExistingDistro || replaceExistingConfigurationConfirmed, #if OPENCLAW_TRAY_TESTS EnableWindowsTrayNodeByDefault = settings.EnableNodeMode diff --git a/tests/OpenClaw.Tray.Tests/LocalGatewaySetupTests.cs b/tests/OpenClaw.Tray.Tests/LocalGatewaySetupTests.cs index 7cb381cd4..73d2529ae 100644 --- a/tests/OpenClaw.Tray.Tests/LocalGatewaySetupTests.cs +++ b/tests/OpenClaw.Tray.Tests/LocalGatewaySetupTests.cs @@ -70,14 +70,12 @@ public void RuntimeConfiguration_ReadsOnlyCleanWslEnvironment() var environment = new FakeSetupEnvironment(new Dictionary { [LocalGatewaySetupRuntimeConfiguration.DistroNameVariable] = "OpenClawGatewayE2E", - [LocalGatewaySetupRuntimeConfiguration.InstanceInstallLocationVariable] = @"C:\openclaw\wsl", [LocalGatewaySetupRuntimeConfiguration.AllowExistingDistroVariable] = "1" }); var config = LocalGatewaySetupRuntimeConfiguration.FromEnvironment(environment); Assert.Equal("OpenClawGatewayE2E", config.DistroName); - Assert.Equal(@"C:\openclaw\wsl", config.InstanceInstallLocation); Assert.True(config.AllowExistingDistro); } From 2682e78f63c9932d4f69d25ec49c60864b72ce68 Mon Sep 17 00:00:00 2001 From: Mike Harsh Date: Thu, 7 May 2026 09:54:57 -0700 Subject: [PATCH 02/27] refactor(scripts): extract shared uninstall helpers into _uninstall-helpers.ps1 Creates scripts/_uninstall-helpers.ps1 with five reusable helper functions: - Test-IsOpenClawOwnedDistroName: distro-name guard (only OpenClawGateway*) - Invoke-WslCommand: wsl bash -c runner returning Stdout/Stderr/ExitCode - Stop-OpenClawProcessByPid: PID-based process termination, suppresses not-found - Assert-DryRunGate: throws if dry-run mode is active - Add-Step: structured step-log appender (requires caller's array) scripts/reset-openclaw-wsl-validation-state.ps1 updated to dot-source the helpers file. No behaviour change. Refs: .squad/decisions/inbox/kranz-uninstall-plan-v3.md (commit 2 of 7) Stacked on PR #274. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- scripts/_uninstall-helpers.ps1 | 147 ++++++++++++++++++ .../reset-openclaw-wsl-validation-state.ps1 | 2 + 2 files changed, 149 insertions(+) create mode 100644 scripts/_uninstall-helpers.ps1 diff --git a/scripts/_uninstall-helpers.ps1 b/scripts/_uninstall-helpers.ps1 new file mode 100644 index 000000000..3f7976f14 --- /dev/null +++ b/scripts/_uninstall-helpers.ps1 @@ -0,0 +1,147 @@ +# _uninstall-helpers.ps1 +# +# Shared helper functions for OpenClaw uninstall and cleanup scripts. +# Dot-source this file at the top of any script that needs these utilities: +# +# . "$PSScriptRoot\_uninstall-helpers.ps1" +# +# Note: Add-Step requires a $script:steps array to be initialised in the +# calling script before use (e.g. $script:steps = @()). + +# --------------------------------------------------------------------------- +# Distro-name guard +# --------------------------------------------------------------------------- + +function Test-IsOpenClawOwnedDistroName { + param([string]$Name) + + return $Name -eq "OpenClawGateway" -or $Name.StartsWith("OpenClawGateway", [System.StringComparison]::Ordinal) +} + +# --------------------------------------------------------------------------- +# WSL command runner +# --------------------------------------------------------------------------- + +function Invoke-WslCommand { + <# + .SYNOPSIS + Runs a bash command inside WSL and returns stdout, stderr, and exit code. + .PARAMETER Command + The bash command string to execute via `wsl bash -c`. + .PARAMETER DistroName + Optional WSL distribution name. Omit to use the default distribution. + .OUTPUTS + A hashtable with keys: Stdout, Stderr, ExitCode. + #> + param( + [Parameter(Mandatory)] + [string]$Command, + [string]$DistroName + ) + + $wslArgs = if ($DistroName) { + @("-d", $DistroName, "bash", "-c", $Command) + } else { + @("bash", "-c", $Command) + } + + $stdoutLines = [System.Collections.Generic.List[string]]::new() + $stderrLines = [System.Collections.Generic.List[string]]::new() + + & wsl @wslArgs 2>&1 | ForEach-Object { + if ($_ -is [System.Management.Automation.ErrorRecord]) { + $stderrLines.Add($_.ToString()) + } else { + $stdoutLines.Add($_) + } + } + + return @{ + Stdout = $stdoutLines -join "`n" + Stderr = $stderrLines -join "`n" + ExitCode = if ($null -eq $global:LASTEXITCODE) { 0 } else { $global:LASTEXITCODE } + } +} + +# --------------------------------------------------------------------------- +# Process termination +# --------------------------------------------------------------------------- + +function Stop-OpenClawProcessByPid { + <# + .SYNOPSIS + Terminates a process by PID, suppressing "not found" errors. + .PARAMETER ProcessId + PID of the process to terminate. + .PARAMETER Force + If specified, uses -Force on Stop-Process. + #> + param( + [Parameter(Mandatory)] + [int]$ProcessId, + [switch]$Force + ) + + try { + if ($Force) { + Stop-Process -Id $ProcessId -Force -ErrorAction Stop + } else { + Stop-Process -Id $ProcessId -ErrorAction Stop + } + } catch [Microsoft.PowerShell.Commands.ProcessCommandException] { + # Process already exited — not an error. + } +} + +# --------------------------------------------------------------------------- +# Dry-run gate +# --------------------------------------------------------------------------- + +function Assert-DryRunGate { + <# + .SYNOPSIS + Throws if the caller is in dry-run mode. Intended to guard any + statement that mutates persistent state (filesystem, processes, WSL). + .PARAMETER DryRun + Boolean dry-run flag from the calling script. + .PARAMETER OperationDescription + Human-readable description of the blocked operation (used in error message). + #> + param( + [Parameter(Mandatory)] + [bool]$DryRun, + [string]$OperationDescription = "destructive operation" + ) + + if ($DryRun) { + throw "Dry-run mode is active; $OperationDescription was not executed." + } +} + +# --------------------------------------------------------------------------- +# Step logging +# --------------------------------------------------------------------------- + +function Add-Step { + <# + .SYNOPSIS + Appends a structured step entry to `$script:steps` in the calling script. + .NOTES + The calling script must declare `$script:steps = @()` before dot-sourcing + this file or before first calling Add-Step. + #> + param( + [string]$Name, + [string]$Status, + [string]$Message, + [hashtable]$Data = @{} + ) + + $script:steps += [ordered]@{ + name = $Name + status = $Status + message = $Message + data = $Data + timestamp = (Get-Date).ToString("o") + } +} diff --git a/scripts/reset-openclaw-wsl-validation-state.ps1 b/scripts/reset-openclaw-wsl-validation-state.ps1 index 04bf9fdc0..9543c314f 100644 --- a/scripts/reset-openclaw-wsl-validation-state.ps1 +++ b/scripts/reset-openclaw-wsl-validation-state.ps1 @@ -30,6 +30,8 @@ param( Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" +. "$PSScriptRoot\_uninstall-helpers.ps1" + # Production-locked WSL distro name (Phase 3 constant). This script will # refuse to act on any other distro, even via -DistroName overrides # (which are intentionally absent). From 02af308357a0ed8f78bf3695964c95803afda359 Mon Sep 17 00:00:00 2001 From: Mike Harsh Date: Thu, 7 May 2026 09:55:14 -0700 Subject: [PATCH 03/27] chore(squad): restore session artifacts (MSIX validation script + decision drop-box + agent histories) Bostick's anticipatory MSIX validation script (scripts/validate-msix-storage-paths.ps1) plus accumulated .squad/ decision-inbox files and agent history updates from the plan/review/implementation cycle. These were preserved across the re-baseline onto PR #274 head. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .squad/.first-run | 1 + .squad/agents/aaron-4/history.md | 51 + .squad/agents/aaron/charter.md | 60 + .squad/agents/aaron/history-archive.md | 206 + .squad/agents/aaron/history.md | 56 + .squad/agents/bostick/charter.md | 57 + .squad/agents/bostick/history-archive.md | 218 + .squad/agents/bostick/history.md | 98 + .squad/agents/kranz/charter.md | 57 + .squad/agents/kranz/history.md | 68 + .squad/agents/mattingly/charter.md | 56 + .squad/agents/mattingly/history-archive.md | 138 + .squad/agents/mattingly/history.md | 6 + .squad/agents/ralph/charter.md | 20 + .squad/agents/ralph/history.md | 21 + .squad/agents/scribe/charter.md | 20 + .squad/agents/scribe/history.md | 21 + .squad/casting/history.json | 13 + .squad/casting/policy.json | 39 + .squad/casting/registry.json | 52 + .squad/ceremonies.md | 69 + .squad/config.json | 7 + .squad/decisions-archive.md | 196 + .squad/decisions.md | 8407 +++++++++++++++++ .squad/decisions/archive/round-17-archive.md | 363 + .squad/decisions/decisions.md | 2479 +++++ .../aaron-bug1-bootstrap-token-fix.md | 123 + ...directive-prototype-as-bugfix-reference.md | 7 + .../round-15/kranz-bug-fixes-verdict.md | 67 + .../mattingly-bug2-stage-propagation-fix.md | 154 + .../round-17/aaron-bug1-final-gate-fix.md | 174 + .../round-17/aaron-bug1-quoting-or-ws-fix.md | 156 + .../round-17/aaron-bug1-residual-fix.md | 127 + .../aaron-bug1-retry-and-diagnosability.md | 143 + .../round-17/aaron-bug1-two-stage-approve.md | 110 + .../aaron-bug3-role-upgrade-approve.md | 208 + .../bostick-bug-fix-e2e-verification.md | 149 + .../round-17/bostick-bug1-reverify.md | 826 ++ .../mattingly-bug2-screenshot-verification.md | 89 + .../inbox/bostick-msix-validation-script.md | 148 + .squad/history.md | 143 + .squad/identity/now.md | 64 + .squad/identity/wisdom.md | 11 + ...0-00Z-wsl-gateway-clean-rebuild-kickoff.md | 36 + ...0-10-27Z-phase3-approved-and-model-swap.md | 40 + ...5-00Z-phase5-approved-and-phase6-landed.md | 35 + ...35-00Z-pr-prep-cleanup-localization-mcp.md | 37 + ...20260507-135500Z-pr274-tray-init-p0-fix.md | 27 + .squad/orchestration-log.md | 152 + .../2026-05-04T17-00-00Z-aaron.md | 14 + .../2026-05-04T17-00-00Z-bostick.md | 27 + .../2026-05-04T17-00-00Z-kranz.md | 19 + .../2026-05-04T17-00-00Z-mattingly.md | 17 + ...6-05-04T21-15-00Z-round8-spawn-outcomes.md | 17 + ...60507-135500Z-aaron-pr274-tray-init-fix.md | 7 + ...-135500Z-bostick-tray-flyout-regression.md | 7 + ...07-135500Z-bostick-tray-init-state-gate.md | 7 + .squad/prototype-reference.md | 141 + .squad/registry.md | 64 + .squad/routing.md | 38 + .squad/team.md | 32 + .squad/templates/casting-history.json | 4 + .squad/templates/casting-policy.json | 37 + .squad/templates/casting-reference.md | 104 + .squad/templates/casting-registry.json | 3 + .squad/templates/casting/Futurama.json | 10 + .squad/templates/ceremonies.md | 69 + .squad/templates/charter.md | 53 + .squad/templates/constraint-tracking.md | 38 + .squad/templates/cooperative-rate-limiting.md | 229 + .squad/templates/copilot-instructions.md | 46 + .squad/templates/history.md | 10 + .squad/templates/identity/now.md | 9 + .squad/templates/identity/wisdom.md | 15 + .squad/templates/issue-lifecycle.md | 413 + .squad/templates/keda-scaler.md | 164 + .squad/templates/machine-capabilities.md | 75 + .squad/templates/mcp-config.md | 88 + .squad/templates/multi-agent-format.md | 28 + .squad/templates/orchestration-log.md | 27 + .squad/templates/package.json | 3 + .squad/templates/plugin-marketplace.md | 49 + .squad/templates/ralph-circuit-breaker.md | 313 + .squad/templates/ralph-triage.js | 545 ++ .squad/templates/raw-agent-output.md | 37 + .squad/templates/roster.md | 60 + .squad/templates/routing.md | 39 + .squad/templates/run-output.md | 50 + .squad/templates/schedule.json | 19 + .squad/templates/scribe-charter.md | 142 + .squad/templates/skill.md | 24 + .../skills/agent-collaboration/SKILL.md | 42 + .../templates/skills/agent-conduct/SKILL.md | 24 + .../skills/architectural-proposals/SKILL.md | 151 + .../skills/ci-validation-gates/SKILL.md | 84 + .squad/templates/skills/cli-wiring/SKILL.md | 47 + .../skills/client-compatibility/SKILL.md | 89 + .../cross-machine-coordination/SKILL.md | 434 + .squad/templates/skills/cross-squad/SKILL.md | 114 + .../skills/distributed-mesh/SKILL.md | 287 + .../skills/distributed-mesh/mesh.json.example | 30 + .../skills/distributed-mesh/sync-mesh.ps1 | 111 + .../skills/distributed-mesh/sync-mesh.sh | 104 + .../templates/skills/docs-standards/SKILL.md | 71 + .squad/templates/skills/economy-mode/SKILL.md | 114 + .../templates/skills/error-recovery/SKILL.md | 99 + .../templates/skills/external-comms/SKILL.md | 329 + .../skills/gh-auth-isolation/SKILL.md | 183 + .squad/templates/skills/git-workflow/SKILL.md | 204 + .../skills/github-multi-account/SKILL.md | 95 + .../templates/skills/history-hygiene/SKILL.md | 36 + .squad/templates/skills/humanizer/SKILL.md | 105 + .squad/templates/skills/init-mode/SKILL.md | 102 + .../skills/iterative-retrieval/SKILL.md | 165 + .../templates/skills/model-selection/SKILL.md | 117 + .squad/templates/skills/nap/SKILL.md | 24 + .../skills/notification-routing/SKILL.md | 105 + .../templates/skills/personal-squad/SKILL.md | 57 + .../skills/pr-review-response/SKILL.md | 268 + .../templates/skills/pr-screenshots/SKILL.md | 149 + .../skills/project-conventions/SKILL.md | 56 + .../skills/ralph-two-pass-scan/SKILL.md | 35 + .squad/templates/skills/reflect/SKILL.md | 229 + .../templates/skills/release-process/SKILL.md | 131 + .squad/templates/skills/reskill/SKILL.md | 92 + .../skills/retro-enforcement/SKILL.md | 148 + .../skills/reviewer-protocol/SKILL.md | 79 + .../templates/skills/secret-handling/SKILL.md | 200 + .../skills/session-recovery/SKILL.md | 155 + .../skills/squad-conventions/SKILL.md | 69 + .../templates/skills/test-discipline/SKILL.md | 37 + .../templates/skills/tiered-memory/SKILL.md | 234 + .../skills/versioning-policy/SKILL.md | 119 + .../skills/windows-compatibility/SKILL.md | 98 + .squad/templates/squad.agent.md.template | 1325 +++ .squad/templates/workflows/squad-ci.yml | 24 + .squad/templates/workflows/squad-docs.yml | 54 + .../templates/workflows/squad-heartbeat.yml | 167 + .../workflows/squad-insider-release.yml | 61 + .../workflows/squad-issue-assign.yml | 161 + .../workflows/squad-label-enforce.yml | 181 + .squad/templates/workflows/squad-preview.yml | 55 + .squad/templates/workflows/squad-promote.yml | 120 + .squad/templates/workflows/squad-release.yml | 77 + .squad/templates/workflows/squad-triage.yml | 262 + .../templates/workflows/sync-squad-labels.yml | 171 + scripts/validate-msix-storage-paths.ps1 | 1085 +++ 147 files changed, 28063 insertions(+) create mode 100644 .squad/.first-run create mode 100644 .squad/agents/aaron-4/history.md create mode 100644 .squad/agents/aaron/charter.md create mode 100644 .squad/agents/aaron/history-archive.md create mode 100644 .squad/agents/aaron/history.md create mode 100644 .squad/agents/bostick/charter.md create mode 100644 .squad/agents/bostick/history-archive.md create mode 100644 .squad/agents/bostick/history.md create mode 100644 .squad/agents/kranz/charter.md create mode 100644 .squad/agents/kranz/history.md create mode 100644 .squad/agents/mattingly/charter.md create mode 100644 .squad/agents/mattingly/history-archive.md create mode 100644 .squad/agents/mattingly/history.md create mode 100644 .squad/agents/ralph/charter.md create mode 100644 .squad/agents/ralph/history.md create mode 100644 .squad/agents/scribe/charter.md create mode 100644 .squad/agents/scribe/history.md create mode 100644 .squad/casting/history.json create mode 100644 .squad/casting/policy.json create mode 100644 .squad/casting/registry.json create mode 100644 .squad/ceremonies.md create mode 100644 .squad/config.json create mode 100644 .squad/decisions-archive.md create mode 100644 .squad/decisions.md create mode 100644 .squad/decisions/archive/round-17-archive.md create mode 100644 .squad/decisions/decisions.md create mode 100644 .squad/decisions/inbox-processed/round-15/aaron-bug1-bootstrap-token-fix.md create mode 100644 .squad/decisions/inbox-processed/round-15/copilot-directive-prototype-as-bugfix-reference.md create mode 100644 .squad/decisions/inbox-processed/round-15/kranz-bug-fixes-verdict.md create mode 100644 .squad/decisions/inbox-processed/round-15/mattingly-bug2-stage-propagation-fix.md create mode 100644 .squad/decisions/inbox-processed/round-17/aaron-bug1-final-gate-fix.md create mode 100644 .squad/decisions/inbox-processed/round-17/aaron-bug1-quoting-or-ws-fix.md create mode 100644 .squad/decisions/inbox-processed/round-17/aaron-bug1-residual-fix.md create mode 100644 .squad/decisions/inbox-processed/round-17/aaron-bug1-retry-and-diagnosability.md create mode 100644 .squad/decisions/inbox-processed/round-17/aaron-bug1-two-stage-approve.md create mode 100644 .squad/decisions/inbox-processed/round-17/aaron-bug3-role-upgrade-approve.md create mode 100644 .squad/decisions/inbox-processed/round-17/bostick-bug-fix-e2e-verification.md create mode 100644 .squad/decisions/inbox-processed/round-17/bostick-bug1-reverify.md create mode 100644 .squad/decisions/inbox-processed/round-17/mattingly-bug2-screenshot-verification.md create mode 100644 .squad/decisions/inbox/bostick-msix-validation-script.md create mode 100644 .squad/history.md create mode 100644 .squad/identity/now.md create mode 100644 .squad/identity/wisdom.md create mode 100644 .squad/log/2026-05-04T17-00-00Z-wsl-gateway-clean-rebuild-kickoff.md create mode 100644 .squad/log/2026-05-04T20-10-27Z-phase3-approved-and-model-swap.md create mode 100644 .squad/log/2026-05-04T21-15-00Z-phase5-approved-and-phase6-landed.md create mode 100644 .squad/log/2026-05-05T01-35-00Z-pr-prep-cleanup-localization-mcp.md create mode 100644 .squad/log/20260507-135500Z-pr274-tray-init-p0-fix.md create mode 100644 .squad/orchestration-log.md create mode 100644 .squad/orchestration-log/2026-05-04T17-00-00Z-aaron.md create mode 100644 .squad/orchestration-log/2026-05-04T17-00-00Z-bostick.md create mode 100644 .squad/orchestration-log/2026-05-04T17-00-00Z-kranz.md create mode 100644 .squad/orchestration-log/2026-05-04T17-00-00Z-mattingly.md create mode 100644 .squad/orchestration-log/2026-05-04T21-15-00Z-round8-spawn-outcomes.md create mode 100644 .squad/orchestration-log/20260507-135500Z-aaron-pr274-tray-init-fix.md create mode 100644 .squad/orchestration-log/20260507-135500Z-bostick-tray-flyout-regression.md create mode 100644 .squad/orchestration-log/20260507-135500Z-bostick-tray-init-state-gate.md create mode 100644 .squad/prototype-reference.md create mode 100644 .squad/registry.md create mode 100644 .squad/routing.md create mode 100644 .squad/team.md create mode 100644 .squad/templates/casting-history.json create mode 100644 .squad/templates/casting-policy.json create mode 100644 .squad/templates/casting-reference.md create mode 100644 .squad/templates/casting-registry.json create mode 100644 .squad/templates/casting/Futurama.json create mode 100644 .squad/templates/ceremonies.md create mode 100644 .squad/templates/charter.md create mode 100644 .squad/templates/constraint-tracking.md create mode 100644 .squad/templates/cooperative-rate-limiting.md create mode 100644 .squad/templates/copilot-instructions.md create mode 100644 .squad/templates/history.md create mode 100644 .squad/templates/identity/now.md create mode 100644 .squad/templates/identity/wisdom.md create mode 100644 .squad/templates/issue-lifecycle.md create mode 100644 .squad/templates/keda-scaler.md create mode 100644 .squad/templates/machine-capabilities.md create mode 100644 .squad/templates/mcp-config.md create mode 100644 .squad/templates/multi-agent-format.md create mode 100644 .squad/templates/orchestration-log.md create mode 100644 .squad/templates/package.json create mode 100644 .squad/templates/plugin-marketplace.md create mode 100644 .squad/templates/ralph-circuit-breaker.md create mode 100644 .squad/templates/ralph-triage.js create mode 100644 .squad/templates/raw-agent-output.md create mode 100644 .squad/templates/roster.md create mode 100644 .squad/templates/routing.md create mode 100644 .squad/templates/run-output.md create mode 100644 .squad/templates/schedule.json create mode 100644 .squad/templates/scribe-charter.md create mode 100644 .squad/templates/skill.md create mode 100644 .squad/templates/skills/agent-collaboration/SKILL.md create mode 100644 .squad/templates/skills/agent-conduct/SKILL.md create mode 100644 .squad/templates/skills/architectural-proposals/SKILL.md create mode 100644 .squad/templates/skills/ci-validation-gates/SKILL.md create mode 100644 .squad/templates/skills/cli-wiring/SKILL.md create mode 100644 .squad/templates/skills/client-compatibility/SKILL.md create mode 100644 .squad/templates/skills/cross-machine-coordination/SKILL.md create mode 100644 .squad/templates/skills/cross-squad/SKILL.md create mode 100644 .squad/templates/skills/distributed-mesh/SKILL.md create mode 100644 .squad/templates/skills/distributed-mesh/mesh.json.example create mode 100644 .squad/templates/skills/distributed-mesh/sync-mesh.ps1 create mode 100644 .squad/templates/skills/distributed-mesh/sync-mesh.sh create mode 100644 .squad/templates/skills/docs-standards/SKILL.md create mode 100644 .squad/templates/skills/economy-mode/SKILL.md create mode 100644 .squad/templates/skills/error-recovery/SKILL.md create mode 100644 .squad/templates/skills/external-comms/SKILL.md create mode 100644 .squad/templates/skills/gh-auth-isolation/SKILL.md create mode 100644 .squad/templates/skills/git-workflow/SKILL.md create mode 100644 .squad/templates/skills/github-multi-account/SKILL.md create mode 100644 .squad/templates/skills/history-hygiene/SKILL.md create mode 100644 .squad/templates/skills/humanizer/SKILL.md create mode 100644 .squad/templates/skills/init-mode/SKILL.md create mode 100644 .squad/templates/skills/iterative-retrieval/SKILL.md create mode 100644 .squad/templates/skills/model-selection/SKILL.md create mode 100644 .squad/templates/skills/nap/SKILL.md create mode 100644 .squad/templates/skills/notification-routing/SKILL.md create mode 100644 .squad/templates/skills/personal-squad/SKILL.md create mode 100644 .squad/templates/skills/pr-review-response/SKILL.md create mode 100644 .squad/templates/skills/pr-screenshots/SKILL.md create mode 100644 .squad/templates/skills/project-conventions/SKILL.md create mode 100644 .squad/templates/skills/ralph-two-pass-scan/SKILL.md create mode 100644 .squad/templates/skills/reflect/SKILL.md create mode 100644 .squad/templates/skills/release-process/SKILL.md create mode 100644 .squad/templates/skills/reskill/SKILL.md create mode 100644 .squad/templates/skills/retro-enforcement/SKILL.md create mode 100644 .squad/templates/skills/reviewer-protocol/SKILL.md create mode 100644 .squad/templates/skills/secret-handling/SKILL.md create mode 100644 .squad/templates/skills/session-recovery/SKILL.md create mode 100644 .squad/templates/skills/squad-conventions/SKILL.md create mode 100644 .squad/templates/skills/test-discipline/SKILL.md create mode 100644 .squad/templates/skills/tiered-memory/SKILL.md create mode 100644 .squad/templates/skills/versioning-policy/SKILL.md create mode 100644 .squad/templates/skills/windows-compatibility/SKILL.md create mode 100644 .squad/templates/squad.agent.md.template create mode 100644 .squad/templates/workflows/squad-ci.yml create mode 100644 .squad/templates/workflows/squad-docs.yml create mode 100644 .squad/templates/workflows/squad-heartbeat.yml create mode 100644 .squad/templates/workflows/squad-insider-release.yml create mode 100644 .squad/templates/workflows/squad-issue-assign.yml create mode 100644 .squad/templates/workflows/squad-label-enforce.yml create mode 100644 .squad/templates/workflows/squad-preview.yml create mode 100644 .squad/templates/workflows/squad-promote.yml create mode 100644 .squad/templates/workflows/squad-release.yml create mode 100644 .squad/templates/workflows/squad-triage.yml create mode 100644 .squad/templates/workflows/sync-squad-labels.yml create mode 100644 scripts/validate-msix-storage-paths.ps1 diff --git a/.squad/.first-run b/.squad/.first-run new file mode 100644 index 000000000..fb918968f --- /dev/null +++ b/.squad/.first-run @@ -0,0 +1 @@ +2026-05-04T15:59:50.798Z diff --git a/.squad/agents/aaron-4/history.md b/.squad/agents/aaron-4/history.md new file mode 100644 index 000000000..c223b6e48 --- /dev/null +++ b/.squad/agents/aaron-4/history.md @@ -0,0 +1,51 @@ +# Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh + +## Core Context + +Clean WSL gateway rebuild. Prototype lives in worktree `openclaw-windows-node` (branch `pr-241-feedback-fixes`) and is intentionally dirty / reference-only. Final implementation goes in sibling worktree `..\openclaw-wsl-gateway-clean` (branch `feat/wsl-gateway-clean` from upstream/master). + +Read these on first spawn: +- `.squad/identity/now.md` — current focus and immediate next todo. +- `.squad/prototype-reference.md` — file-by-file porting inventory. + +## Recent Updates + +📌 Team hired 2026-05-04. Universe: Apollo 13. + +## Learnings + +### 2026-05-04T20:03:45Z — Phase 3 LocalGatewaySetup Port Complete + +**Agent:** Aaron (Phase 3 owner) +**Commit:** 98bdf77 on feat/wsl-gateway-clean +**Status:** ✅ **LANDED** + +**Duration:** ~683 seconds +**Scope:** Port LocalGatewaySetup engine from prototype to clean worktree with Craig-approved deltas + +Phase 3 completed with all architectural deltas applied: +- Loopback-only networking (removed WSL-IP fallback, lan/auto modes, port promotion) +- Simplified endpoint resolver to trivial `http://localhost:{port}` +- Trust `wsl --install` exit code (dropped postcondition-on-hang guard) +- 5 dead phases pruned: VerifyRootfsArtifact, ImportDistro, VerifyDistro, StartWorker, PairWorker +- Config files: `/etc/wsl.conf` and `/etc/wsl-distribution.conf` +- Repair primitive: `wsl --terminate OpenClawGateway` (never global `wsl --shutdown`) +- Error paths surface `aka.ms/wsllogs` link +- Lifecycle: user-systemd + tray keepalive both acceptable + +**Code changes:** +- Pruned ~130 lines of dead code +- Kept 19 phases in `LocalGatewaySetupPhase` enum per approval +- Simplified endpoint resolver to return `http://localhost:{port}` trivially +- Diagnostics aligned to `aka.ms/wsllogs` surface link pattern + +**Integration testing:** +- Shared Tests: 1180/1180 ✅ +- Tray Tests (filtered): 426/426 ✅ +- LocalGatewaySetupTests.cs: 33/33 ✅ + +**[2026-05-04T20:05:00Z Round 5 Update]** Phase 3 landed at 98bdf77. Kranz Phase 3 verdict in flight (parallel). Bostick Phase 3 verification in flight (parallel). Next: Phase 4 spawn pending reviewer gates. diff --git a/.squad/agents/aaron/charter.md b/.squad/agents/aaron/charter.md new file mode 100644 index 000000000..21f0212e4 --- /dev/null +++ b/.squad/agents/aaron/charter.md @@ -0,0 +1,60 @@ +# Aaron — Backend / Infra + +> Steely-eyed. Owns the WSL gateway plumbing end to end. + +## Identity + +- **Name:** Aaron +- **Role:** Backend / Infrastructure Engineer +- **Expertise:** WSL gateway setup, identity/token plumbing, gateway client, NodeService, OpenClaw shared layer, PowerShell validation scripts +- **Style:** Surgical. Touches the smallest area that solves the problem. Heavy on tests and postcondition checks. + +## Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh +- **Current focus:** Clean WSL gateway rebuild — port validated prototype behavior to `..\openclaw-wsl-gateway-clean`. +- Prototype reference: `.squad/prototype-reference.md`. + +## What I Own + +- `src/OpenClaw.Shared/DeviceIdentity.cs` — role-specific operator/node token storage, `NodeDeviceToken`, `NodeDeviceTokenScopes`. +- `src/OpenClaw.Shared/OpenClawGatewayClient.cs` — `auth.bootstrapToken` initial connect, stored operator reconnect via `auth.deviceToken`, role-specific token handoff from `hello-ok.auth`. +- `src/OpenClaw.Shared/WindowsNodeClient.cs` — node reconnect using `auth.deviceToken`. +- `src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs` — Ubuntu Store/package install, postcondition verification, first-boot config, upstream `install-cli.sh` invocation, gateway config/service mgmt, endpoint resolver, keepalive, operator pairing. +- `src/OpenClaw.Tray.WinUI/Services/NodeService.cs` — shared identity data path support. +- `src/OpenClaw.Tray.WinUI/App.xaml.cs` — setup engine construction, shared identity path, node service for local gateway pairing. +- `scripts/validate-wsl-gateway.ps1` — focused on `PreflightOnly` / `UpstreamInstall` / `FreshMachine` / `Recreate` modes. +- `scripts/reset-openclaw-wsl-validation-state.ps1` — exact-target destructive cleanup gated by `-ConfirmDestructiveClean`. + +## How I Work + +- All WSL file I/O via `wsl bash -c '...'`. NEVER `\\wsl$` or `\\wsl.localhost`. +- App-owned Ubuntu LTS WSL instance named `OpenClawGateway`. Do NOT create a custom OpenClaw distro/rootfs. +- Use the upstream public OpenClaw Linux installer inside WSL — no dev shims, no rootfs forks. +- `systemctl active` is insufficient — require Windows-reachable health, gateway RPC/status, and successful setup-code mint before declaring "up". +- Token/setup-code/private-key redaction is mandatory in artifacts and logs. +- Destructive cleanup is exact-target only and requires `-ConfirmDestructiveClean`. + +## Boundaries + +**I handle:** Shared layer, WSL setup, identity/token plumbing, gateway client, validation scripts. + +**I don't handle:** Onboarding XAML / WinUI3 pages (Mattingly), running the test suites and capturing screenshots (Bostick), scope decisions (Kranz). + +**When I'm unsure:** Read the prototype file first, then ask Kranz before deviating from validated behavior. + +## Model + +- **Preferred:** auto (`claude-sonnet-4.6` for code; bump for multi-file refactors) + +## Collaboration + +- Resolve repo via `TEAM ROOT` — we work in `..\openclaw-wsl-gateway-clean`, not the prototype worktree. +- Read `.squad/decisions.md` and the prototype file under review before editing. +- Drop decisions to `.squad/decisions/inbox/aaron-{slug}.md`. + +## Voice + +Concise. "Postcondition: `wsl --list --quiet` shows `OpenClawGateway`. Verified." Doesn't speculate when there's a check available. diff --git a/.squad/agents/aaron/history-archive.md b/.squad/agents/aaron/history-archive.md new file mode 100644 index 000000000..4d51e0e28 --- /dev/null +++ b/.squad/agents/aaron/history-archive.md @@ -0,0 +1,206 @@ +# Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh + +## Core Context + +Clean WSL gateway rebuild on sibling worktree `..\openclaw-wsl-gateway-clean` (branch `feat/wsl-gateway-clean` from upstream/master `871b959`). Prototype worktree `openclaw-windows-node` is reference-only. + +Read on first spawn: `.squad/identity/now.md`, `.squad/prototype-reference.md`. + +## Recent Updates + +📌 Team hired 2026-05-04. Universe: Apollo 13. + +## Learnings + +### Summary — Phases 1–8 PLAN COMPLETE [Scribe-compacted 2026-05-04T19:35-07:00 / round 13] + +**Phases 1–8 all landed and APPROVED on `feat/wsl-gateway-clean` (16 commits since baseline `871b959`):** + +- **P1 DeviceIdentity** `95911b8`+`3ae03d3`: operator/node-token accessors with strict `DeviceTokenRole` whitelist. +- **P2 Gateway/Node clients** `b20b5ce`+`b69202d`: bootstrap setup-code (`auth.bootstrapToken`), stored-token reconnect (`auth.deviceToken`), role-specific hello-ok handoff. No WebBridge. +- **P3 LocalGatewaySetup** `98bdf77`: ported full WSL setup state machine (NotStarted→Preflight→ElevationCheck→EnsureWslEnabled→CreateWslInstance→ConfigureWslInstance→InstallOpenClawCli→PrepareGatewayConfig→InstallGatewayService→StartGateway→WaitForGateway→MintBootstrapToken→PairOperator→CheckWindowsNodeReadiness→PairWindowsTrayNode→VerifyEndToEnd→Complete/Failed/Cancelled). Removed: rootfs/import/worker/LocalOnlyComplete. Loopback-only networking. No `\\wsl$`, no `--shutdown`, no `gateway.bind`. +- **P4 App wiring** `4ab1ec6`+`8cc32c6`: removed PreserveWorkerData; gated distro override behind DEBUG/TRAY_TESTS; added `App.IdentityDataPath` (`%APPDATA%\OpenClawTray`). +- **P6 Validation script** `8060ae9`: `scripts/validate-wsl-gateway.ps1` (~620 lines). Scenarios: PreflightOnly/UpstreamInstall/FreshMachine/Recreate. `Recreate` uses `--unregister` only. +- **P7 Reset script** `dbd7708`: `scripts/reset-openclaw-wsl-validation-state.ps1` (388 lines). Distro hardcoded `OpenClawGateway`. Backup-before-remove. APPROVED Kranz, Bostick SHA256-verified. +- **P8 docs** `1300981`: `docs/wsl-owner-validation.md` + `docs/wsl-owner-open-issues.md` (Craig's Q&A inlined). Omitted rootfs doc per Mike. APPROVED. + +**Empirical research (round 6/7):** `wsl --install Ubuntu-24.04 --no-launch --name OpenClawGateway --location --version 2` 10/10 vs `winget install Canonical.Ubuntu.2404 --silent` 0/10 (APPX is launcher-only; never registers distro on silent). Deeper H1-H6 sweep confirmed: only viable winget fallback is winget+`ubuntu2404.exe install --root` (3/3) but cannot pass `--name`/`--location`. `winget install Microsoft.WSL` returns `0x8A15006B` UPDATE_NOT_APPLICABLE on already-current host — must treat as success-equivalent. **Recommendation locked:** `wsl --install` is the production path. + +**Round 11 PR-prep:** +- aaron-13: discarded 6 stale unstaged files (`LocalSetupProgressPage.cs` + 5 resw locales) after pre-snapshot to `artifacts/stale-files-discarded-2026-05-04/`. HEAD unchanged at `1300981`; tests match Phase-8 anchor (1180/1180, 434/434). Files confirmed superseded by `32cbeae`. +- mattingly-3 closed i18n blocker at `ce89251` (85 entries × 5 locales). +- coordinator (autopilot) recorded Next-button defaults on LocalSetupProgressPage. + +**Round 12 PR-prep:** +- aaron-15 wrote 22 KB uninstall robustness plan (`.squad/decisions/inbox/aaron-uninstall-plan.md`, now merged to decisions.md). 8 open Qs for Mike. Recommends shipping as **follow-up PR** after WSL gateway clean PR merges (uninstall depends on packaging decisions Q1/Q2). +- mattingly-5 implemented Next-button policy at `73767c5` (+13 tests → Tray 447/447). +## 2026-05-04T19:30-07:00 — Aaron-14: E2E install drive (FAILED at PairOperator) + +**Worktree:** openclaw-wsl-gateway-clean | **HEAD:** 73767c5 | **Task:** drive auto-WSL install end-to-end up to gateway wizard step 1. + +**Pre-flight:** baseline 18 distros snapshotted to rtifacts/e2e-drive-2026-05-04/before-distros.txt. OpenClawGateway present from prior prototype — cleaned via scripts\reset-openclaw-wsl-validation-state.ps1 -ConfirmDestructiveClean. Backup at rtifacts\reset-backups\20260504190728\ (438 files / 19.3 GB pre-unregister). Build PASS. + +**Launch:** PID 8240 at 19:11:35. SetupWarningPage rendered ✓. + +**Click:** computer-use MCP failed with Bun is not defined. Fell back to PowerShell UIA — OnboardingSetupLocal button found by AutomationId, InvokePattern.Invoke() at 19:12:35. + +**Engine progress (inferred from filesystem + gateway logs, NOT page UI which froze):** +- ✅ EnsureWslEnabled → CreateWslInstance → ConfigureWslInstance → InstallOpenClawCli (/opt/openclaw/{bin,tools} populated, node-v22.22.0 staged) +- ✅ PrepareGatewayConfig → InstallGatewayService (user systemd openclaw-gateway.service Active running since 02:14:21 UTC) +- ✅ StartGateway / WaitForGateway (HTTP 494ms succeeded; 18789 listening loopback v4+v6) +- ✅ MintBootstrapToken (Windows-side BootstrapToken populated [REDACTED]; gateway-side pending.json written) +- ❌ **PairOperator FAILED** — gateway log: 2× cause:device-auth-invalid handshake:failed (1062ms, 2018ms) then cause:pairing-required handshake:failed durationMs:31. Last gateway log activity 02:14:35 UTC; engine did not retry after. +- ⛔ CheckWindowsNodeReadiness, PairWindowsTrayNode, VerifyEndToEnd: not reached. + +**Final UI state:** LocalSetupProgressPage stuck rendering only first stage (• Checking system) with ProgressRing "Busy" spinning — even though engine reached PairOperator and failed. Next disabled, Back enabled. No FailedRetryable/Terminal transition. **Separate UI state-sync defect from the engine pairing defect.** + +**App still running PID 8240; Mike has control.** App NOT killed per task. Wizard step 1 NOT reached so nothing to "stop at". Two defects to triage: (1) PairOperator handshake — bootstrap token from Windows tray rejected as device-auth-invalid by gateway holding the same token in pending.json (likely client framing or scope mismatch); (2) LocalSetupProgressPage doesn't propagate phase updates past stage 0. + +**Decision:** .squad/decisions/inbox/aaron-e2e-drive.md (full timeline + redaction confirmation). + +**Redaction:** BootstrapToken observed in settings.json during diagnostic dump — redacted from report + history. No tokens/setup-codes/private-keys/ed25519 material in artifacts. + + +## 2026-05-04T19:00-07:00 — Aaron-15: Uninstall robustness plan (planning only) + +22 KB design doc covering 8 sections + 8 open questions for Mike (per-user vs per-machine, MSIX vs MSI, keep-WSL-data option, tray menu, wsl --export pre-backup, telemetry, script location, backup retention). Recommends shipping as **follow-up PR** after WSL gateway clean PR merges. Read-only investigation. Decision: aaron-uninstall-plan.md. SUCCESS. + +## 2026-05-04T19:35-07:00 — Aaron-16 (in flight) + +Investigating + fixing **Bug 1** from aaron-14 E2E drive: PairOperator handshake — Windows tray's uth.bootstrapToken rejected by gateway as device-auth-invalid despite pending.json containing the same token. Likely framing/scope mismatch in OpenClawGatewayClient bootstrap-token round-trip. Mattingly-6 in parallel on Bug 2 (UI phase propagation). +## 2026-05-04T19:35Z — Aaron-15: Bug 1 fix landed (commit e2de09) — operator-pending auto-approve + +Root cause: MintBootstrapToken/PairOperator round-trip is correct, but on a fresh local-loopback gateway the upstream registers the bootstrap-token connect as a *pending* operator pairing request (logged in `~/.openclaw/devices/pending.json`) and rejects the same connect with `cause:device-auth-invalid reason:device-signature` then `cause:pairing-required reason:not-paired`. The upstream auto-approve path (`gateway.nodes.pairing.autoApproveCidrs`, `node-pairing-auto-approve.ts`) gates on `role === 'node'` so it does not fire for `operator` pairings; the canonical mechanism is explicit `openclaw devices approve`. On loopback the tray user IS the operator, so the engine drives that approval automatically. + +Fix in `src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs`: new `IPendingDeviceApprover` seam + `WslGatewayCliPendingDeviceApprover` invokes `openclaw devices approve --latest --json --url --token "$(cat /var/lib/openclaw/gateway-token)"` inside the distro (token read in shell — never on argv). `SettingsOperatorPairingService.PairAsync` retries the bootstrap connect once after approval succeeds. Approval is gated on `credential.IsBootstrapToken && LocalGatewayApprover.IsLocalGateway(state.GatewayUrl) && _pendingApprover != null` so remote gateways and previously-paired devices keep their existing PairingRequired surface unchanged. Wired in `Build()`. + +Tests: `tests/OpenClaw.Tray.Tests/OperatorPairingApprovalTests.cs` — 10 new (round-trip approve+retry, double-PairingRequired bounded, approval-failure error path, remote-gateway opt-out, non-bootstrap opt-out, first-connect happy path, 4 `ParseApproveJson` cases). Tray 493/493, Shared 1180/1180 with `OPENCLAW_RUN_INTEGRATION=1` + `OPENCLAW_REPO_ROOT`. Build.ps1 WinUI step blocked by PID 8240 .exe lock (expected: task forbids killing it; source compilation is clean per `dotnet build` of WinUI which only fails at the post-link copy). All redaction enforced — token VALUES never appear in code/tests/decision file. No e2e re-run by Aaron-15 (running app must remain at broken state for Mike's inspection). + +## Learnings + +### 2026-05-06T09:37:38-07:00 — Aaron wizard 3-bug deep debug (investigation only) + +**Build-verification-vs-running-binary lesson:** +Always check both the commit timestamp AND the DLL LastWriteTime before concluding "fix not in binary". Commit `2487aef` was at 08:07; DLL was built at 08:30 — fix WAS present. The bugs were genuine behavioral issues, not a stale-build artifact. The stale-build trap from decisions.md (Aaron-21) applies: after source edits, always explicitly rebuild WinUI with `dotnet build src\OpenClaw.Tray.WinUI\OpenClaw.Tray.WinUI.csproj -p:Platform=x64 --no-restore -v q` and verify DLL timestamp. + +**Upstream wizard contract (openclaw/openclaw, ref bc97182d):** +`src/wizard/session.ts`: `WizardSession` is pure in-memory; NOT persisted across gateway process restart. `wizard.start` always creates a NEW session from step 0. `wizard.status` returns the current pending step of an EXISTING session. When a transient disconnect occurs mid-wizard (gateway process stayed up), the `answerDeferred` for the in-flight step is still live on the gateway — `wizard.status` will return that same step. `wizard.start` in this case creates a parallel new session, which is wrong. The correct recovery protocol after transient disconnect is `wizard.status` first, then `wizard.start` fallback only if session is gone. + +**FunctionalUI RadioButtons binding behavior:** +`ConfigureRadioButtons` (FunctionalUI.cs:678–697) sets `control.ItemsSource = element.Items`. WinUI3 RadioButtons resets internal selection whenever `ItemsSource` is assigned to a new object reference, even if the content is identical. Since `WizardPage.Render()` calls `labels.ToArray()` on every render cycle, EVERY render replaces `ItemsSource` with a new array → visual flash (brief deselect during layout pass) and apparent "two-click to select" behavior. Fix: cache the options array in `UseState` and only replace it when the step changes (inside `ApplyStep`), so re-renders from heartbeat/channel-health state changes reuse the same object reference. + +**Log pattern for wizard issues:** +`[Wizard]` prefix in tray log captures WizardPage lifecycle. Key events: "WizardPage constructed" = new instance (either mount or recovery restart); "Sending wizard.start frame" vs "Sending wizard.next" distinguishes fresh vs. advance. A second "WizardPage constructed" immediately after an ERROR line is the smoking gun for unwanted recovery restart (Symptom 3). Absence of "wizard.status" in the log means the recovery path never tried to resume — it went straight to wizard.start. +## 2026-05-06T22:00:00Z — Aaron PR #274: Merge with master (graft pattern documentation) + +**Context:** PR #274 merged to origin/master via merge commit 37745b2. Aaron orchestrated final graft + merge sequence (aaron-pr274-graft agent). + +**Pattern: Feature-branch graft with conditional re-dispatch** +- **Goal:** Preserve feature branch's design (tray-menu redesign) while adopting master's new entry pattern (Setup Guide / Reconfigure). +- **Method:** Master's `OnboardingExistingConfigGuard` + dispatch case `"setup"` are existing, stable patterns. Graft inserts the Setup/Reconfigure action between QuickSend and Exit in the master tray menu structure using the same guard + dispatch. +- **Implementation:** No new case added to dispatcher; reused case `"setup"` (which already existed on master for onboarding-gate flows). Conditional `OnboardingExistingConfigGuard` ensures Setup Guide shows only for unconfigured tray, Reconfigure for configured tray — both dispatch via existing `"setup"` case. +- **Side-fixes applied during merge:** + - **DeviceIdentity.cs:** Kept feature branch's multi-method operator/node-token dispatch; merged in master's empty-token guard (new condition to `StoreDeviceTokenCore` + `StoreNodeDeviceTokenCore`). + - **SetupCodeDecoder.cs:** Adopted master's strict version pattern; dropped feature branch's bootstrap_token/token field-name fallbacks. + - **Architectural decision:** Multi-method dispatch + single empty-token guard is more maintainable than feature branch's single-method with fallback logic — each token type has its own path; guard applies uniformly. +- **Lost in merge** (file separately if needed): Activity Stream flyout, Support/Debug flyouts, AutoStart entry, RestartSshTunnel entry — feature branch had these; master does not. Redesign trade-off. +- **ARM64 messaging:** Softened from "not supported" → "unvalidated" (bostick-pr274-arm64-wording agent). Install scripts already auto-detect arch; wording now matches capability. +- **Build/test result:** PASS (build.ps1 + tray tests 447/447 + shared tests 1180/1180). + +**Future merge pattern:** When grafting conditional UI/dispatch changes, anchor to existing guard + case structure on target branch to minimize merge conflicts and preserve dispatch stability. + +## 2026-05-06 +- Security plan + implementation + + +## 2026-05-07 — Aaron: WSL Gateway Uninstall Plan v2 (feat/wsl-gateway-uninstall) + +**Task:** Refined planning following Mike's D1–D4 decisions. Investigation-only; no code changes. + +### New Findings + +**Installer Flavors (confirmed from GH release v0.5.0 + ci.yml + installer.iss):** +- **Inno Setup** (non-MSIX installer): `OpenClawTray-Setup-{x64,arm64}.exe`. Script: `installer.iss` in repo root. `DefaultDirName={localappdata}\OpenClawTray`. Current `[UninstallRun]` only removes CommandPalette Appx — no WSL cleanup. WSL cleanup hook via new `[UninstallRun]` entry calling a dropped helper script. Inno does NOT auto-clean runtime app state. +- **Portable ZIP**: `OpenClawTray-{ver}-win-{rid}.zip`. No OS uninstall hook. Only path: in-tray "Remove Local Gateway" button. +- **MSIX (sideloaded)**: `OpenClawTray-{ver}-win-{rid}.msix`. `Package.appxmanifest` declares `runFullTrust` capability → VFS redirection does NOT apply → app writes to REAL `%APPDATA%\OpenClawTray\` and `%LOCALAPPDATA%\OpenClawTray\`, not MSIX package container. MSIX removal only cleans `%LOCALAPPDATA%\Packages\OpenClaw.Tray_\` — all runtime app state (WSL distro, VHD, credentials) remains after MSIX removal. **No standard uninstall hook available for runFullTrust MSIX.** Critical risk: orphaned WSL distro after MSIX removal. + +**mcp-token.txt (D3 investigation):** +- File: `%APPDATA%\OpenClawTray\mcp-token.txt` (via `NodeService.McpTokenPath` = `SettingsManager.SettingsDirectoryPath + "mcp-token.txt"`). +- Created lazily when user enables Local MCP Server (`McpAuthToken.LoadOrCreate(McpTokenPath)` in `NodeService.StartMcpServerAsync`). +- Bearer token for local MCP HTTP server (loopback-only). Read by external MCP clients (Claude Desktop, VS Code, `openclaw-windows-node` CLI). +- **Completely independent of WSL gateway** — not created or used by the WSL gateway install path. +- **Decision: PRESERVE unconditionally.** Deleting it silently invalidates all user MCP client registrations. `KeepMcpToken` option removed from uninstall API. + +**device-key-ed25519.json schema (D2 investigation):** +- Today: single-entry flat JSON `{ PrivateKeyBase64, PublicKeyBase64, DeviceId, DeviceToken, Algorithm, CreatedAt }`. +- NOT a list/multi-entry structure. Mike's D2 multi-gateway assumption does NOT match current schema. +- Ed25519 keypair is global device identity (used for all gateways). `DeviceToken` is the most-recently-stored pairing credential. +- **v1 uninstall approach:** Null out `DeviceToken` field in place. Preserve keypair. `HasStoredDeviceToken` returns false → `RequiresSetup` triggers correctly. +- **Schema v2 proposal:** `{ SchemaVersion:2, DeviceId, Algorithm, ..., GatewayEntries: [{GatewayUrl, DeviceToken, PairedAt}] }` for full per-gateway edit-vs-delete. Filed as separate work item / prerequisite for full D2 compliance. + + +**Task:** Planning-only uninstall design following PR #274 merge. +**Worktree:** `openclaw-uninstall` | **Branch:** `feat/wsl-gateway-uninstall` + +### Artifact Catalog (key facts) + +- **Two separate Windows data roots:** `%APPDATA%\OpenClawTray` (roaming — settings.json, device-key-ed25519.json, mcp-token.txt) vs `%LOCALAPPDATA%\OpenClawTray` (local — setup-state.json, Logs/, wsl/OpenClawGateway/, crash.log, run.marker, exec-policy.json). +- **WSL VHD location:** `%LOCALAPPDATA%\OpenClawTray\wsl\OpenClawGateway\ext4.vhdx` (from `WslStoreInstanceInstaller.ResolveInstallLocation`). +- **`wsl --unregister` deletes the VHD** — no separate file delete needed for the VHD, but the parent directory may linger. +- **DistroName is stored in `setup-state.json`** (`LocalGatewaySetupState.DistroName`) — uninstall should read it from state file rather than hardcoding `OpenClawGateway`, to handle env-var overrides. +- **Keepalive process** `WslDistroKeepAlive` launches `sleep 2147483647` inside the distro; it dies when `wsl --terminate` runs. +- **`StartupSetupState.RequiresSetup` gate:** returns `true` (requires setup) when `Token` is empty AND NOT (`EnableNodeMode` AND (bootstrap token or device key file)). Uninstall must clear `Token`, `BootstrapToken`, `EnableNodeMode=false`, and delete `device-key-ed25519.json`. If `EnableMcpServer=true`, `RequiresSetup` returns `false` regardless — open Q7. +- **AutoStartManager:** registry at `HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\OpenClawTray`. No settings flag sync needed unless Q8 decided. +- **MCP token:** `%APPDATA%\OpenClawTray\mcp-token.txt` — credential for local MCP HTTP server. Deleting breaks external MCP registrations. Open Q4. + +### Decisions Made + +- **API surface:** New `LocalGatewayUninstall.cs` alongside `LocalGatewaySetup.cs`. +- **UI entry point:** Settings page "Remove Local Gateway" button; existing tray "Reconfigure" dispatch unchanged. +- **Confirmation gate:** `ConfirmDestructive=true` required; dry-run mode when false. +- **Order:** service stop → terminate → unregister → VHD dir cleanup → settings clear → device key delete → setup-state delete → autostart remove → optional mcp/logs/exec-policy cleanup. +- **Idempotency:** every step skip-on-absent; distro unregister is a no-op if not registered. + +### Open Questions for Mike (8 total) + +Q1 Packaging scope (MSIX/MSI hook vs. in-tray settings button) +Q2 Per-user install only? (no elevation needed — confirm) +Q3 wsl --export backup before unregister? +Q4 Delete mcp-token.txt on uninstall? +Q5 Delete logs on uninstall? +Q6 Delete exec-policy.json on uninstall? +Q7 Set EnableMcpServer=false on uninstall? (affects RequiresSetup gate) +Q8 Set settings.AutoStart=false in addition to removing registry entry? + +**Decision file:** `.squad/decisions/inbox/aaron-uninstall-plan.md` +**Status:** PLAN COMPLETE — awaiting Mike's answers to Q1-Q8 before coding begins. + +## 2026-05-07 — PR #274 P0 Tray Init Regression: async-void OnLaunched Ordering (aaron-pr274-tray-init-fix) + +**Critical pattern for future merges:** + +**Root Cause:** `App.OnLaunched` is `async void` (fire-and-forget). During PR #274 merge, `InitializeTrayIcon()` was deferred until AFTER the `RequiresSetup` branch. On fresh-box test, the sequence becomes: +1. OnLaunched async-void starts (no await) +2. RequiresSetup branch shows onboarding wizard +3. async InitializeTrayIcon eventually runs, tray icon ctor throws +4. Exception swallowed by async-void; tray icon never created +5. User has setup wizard but no tray icon + +**Fix:** Reorder `InitializeTrayIcon()` BEFORE the `RequiresSetup` branch (Commit 3e4c217). +Wrap `ShowOnboardingAsync()` in try/catch with `Logger.Error()` so ANY wizard failure surfaces in openclaw-tray.log rather than crashing silently. + +**Core principle: Tray is application chrome, must outlive any wizard failure.** +UI wizards (setup, reconfigure) are disposable flows; tray icon is foundational. Never defer tray init past conditional branches. Always wrap wizard invocations in try/catch. + +**Tests:** Shared 1252/1274, Tray 617/617. Build PASS. Underlying constructor exception still unidentified (env-specific to fresh contributor box — defensive log will surface it on next repro). + +**Pattern for future codebases:** +- async-void lifecycle methods (OnLaunched, OnSuspending) execute as fire-and-forget +- Initialization order matters: critical foundational objects before conditional branches +- Wrap branch-flow initiators (wizard.Show, setup.Start) in try/catch with Logger.Error + + diff --git a/.squad/agents/aaron/history.md b/.squad/agents/aaron/history.md new file mode 100644 index 000000000..63a557fd3 --- /dev/null +++ b/.squad/agents/aaron/history.md @@ -0,0 +1,56 @@ +# Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh + +## Core Context + +Clean WSL gateway rebuild on sibling worktree ..\openclaw-wsl-gateway-clean (branch eat/wsl-gateway-clean from upstream/master 871b959). Prototype worktree openclaw-windows-node is reference-only. + +Read on first spawn: .squad/identity/now.md, .squad/prototype-reference.md. + +## Recent Updates + +📌 Team hired 2026-05-04. Universe: Apollo 13. + +## Executive Summary — Key Patterns & Decisions + +### Phases 1–8 COMPLETE [Landed 16 commits since 871b959] + +**Architectural Phases:** +- **P1 DeviceIdentity:** operator/node-token accessors; strict role-based whitelist +- **P2 Gateway/Node clients:** bootstrap setup-code auth + stored-token reconnect; role-specific hello-ok +- **P3 LocalGatewaySetup:** Full WSL state machine (15 stages); loopback-only networking +- **P4 App wiring:** IdentityDataPath setup; removed PreserveWorkerData +- **P6–P8:** Validation script, reset script, documentation + +**Key empirical finding:** wsl --install Ubuntu-24.04 10/10 vs winget install 0/10. Production path locked. + +### Bug Fixes & Learnings (Phases 1–8 to present) + +**Bug #1 — PairOperator handshake (2026-05-04):** +Root: Fresh loopback gateway auto-registers bootstrap-token connect as *pending* operator pairing, rejects same connect with device-auth-invalid. Fix in LocalGatewaySetup.cs: new IPendingDeviceApprover seam → wsl invokes openclaw devices approve --latest. Gated on loopback + bootstrap + no existing pairing. Tests: 10 new (OperatorPairingApprovalTests.cs). Tray 493/493. + +**Bug #2 — PairOperator handshake + FunctionalUI RadioButtons (2026-05-06):** +Stale-build lesson: check DLL LastWriteTime, not commit date. Three genuine wizard behavioral defects: (1) wizard.start on transient disconnect creates parallel session (should wizard.status first); (2) RadioButtons re-bind on every render → visual flash + apparent double-click required (fix: cache options in UseState); (3) LocalSetupProgressPage phase updates stuck at stage 0 (symptom: UI ProgressRing spinning but not advancing). + +**Bug #3 — PR #274 P0 Tray Init Regression (2026-05-07):** +Root: App.OnLaunched is sync void (fire-and-forget). InitializeTrayIcon deferred past RequiresSetup branch → tray icon ctor throws while wizard displayed → no tray chrome. Core principle: **Tray is application chrome, must outlive any wizard failure.** Fix: Reorder InitializeTrayIcon BEFORE RequiresSetup. Wrap ShowOnboardingAsync in try/catch + Logger.Error. Commit 3e4c217. Defensive pattern: async-void lifecycle methods need critical object initialization FIRST, before conditional branches. Always wrap wizard/setup flows in try/catch. + +### Active Workstreams + +**WSL Gateway Uninstall (feat/wsl-gateway-uninstall) — Commits 1+2 COMPLETE (2026-05-08):** +Executed Kranz's uninstall plan v3 commits 1 and 2. Baseline merge of pr-241-feedback-fixes into worktree required manual copy of 7 untracked files (LocalGatewaySetup.cs, LocalGatewayLifecycle.cs, scripts, tests, RootfsArtifactManifest.cs, WslGatewayContracts.cs) and resolution of 4 API incompatibilities. Commit 1 removes OPENCLAW_WSL_INSTALL_LOCATION env-var from LocalGatewaySetupRuntimeConfiguration while retaining InstanceInstallLocation on options as test seam. Commit 2 creates scripts/_uninstall-helpers.ps1 with Test-IsOpenClawOwnedDistroName (moved from reset script), plus new Invoke-WslCommand, Stop-OpenClawProcessByPid, Assert-DryRunGate, Add-Step helpers. Fixed 12 pre-existing test failures from baseline merge (localization duplicates, test-code mismatches, env-isolation). All 447 tray tests pass. Next: commits 3+ (uninstall implementation). +Previous: Planning-complete (2026-05-07). Two Windows data roots identified: roaming (%APPDATA%\OpenClawTray) + local (%LOCALAPPDATA%\OpenClawTray). Uninstall order: service stop → terminate → unregister → cleanup. Awaiting Mike's answers to 8 design questions (packaging scope, per-user install, wsl --export backup, mcp-token.txt delete, logs/exec-policy cleanup, EnableMcpServer flag, AutoStart removal). + +## Test Results (Latest) + +- **Shared Tests:** passing (all) +- **Tray Tests:** 447/447 +- **Build:** PASS (2026-05-08, feat/wsl-gateway-uninstall after commits 1+2) + +## Deferred & Open + +- Underlying tray ctor exception (env-specific to fresh box) — defensive try/catch will surface in openclaw-tray.log +- Uninstall feature: 8 open design Qs for Mike (see Active Workstreams) diff --git a/.squad/agents/bostick/charter.md b/.squad/agents/bostick/charter.md new file mode 100644 index 000000000..51023973d --- /dev/null +++ b/.squad/agents/bostick/charter.md @@ -0,0 +1,57 @@ +# Bostick — Tester / FIDO + +> "Tough and competent." Verifies trajectory. The clean branch doesn't ship until the numbers prove it. + +## Identity + +- **Name:** Bostick +- **Role:** Tester / Quality / Validation +- **Expertise:** `dotnet test`, `build.ps1`, `validate-wsl-gateway.ps1`, screenshot verification, baseline tracking +- **Style:** Empirical. Reports actual pass counts, not "tests passed". Owns the green-build gate. + +## Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh +- **Current focus:** Validate every port into `..\openclaw-wsl-gateway-clean` against the established baseline and validate WSL gateway end-to-end in the clean worktree. + +## What I Own + +- Required validation per `AGENTS.md`: `./build.ps1`, `dotnet test ./tests/OpenClaw.Shared.Tests/... --no-restore`, `dotnet test ./tests/OpenClaw.Tray.Tests/... --no-restore`. +- Test files being ported: `DeviceIdentityTests.cs`, `OpenClawGatewayClientTests.cs`, `WindowsNodeClientTests.cs`, `LocalGatewaySetupTests.cs`, `SetupCodeDecoderTests.cs`, `OnboardingStateTests.cs`. +- Running `scripts\validate-wsl-gateway.ps1` in the supported modes (`PreflightOnly`, `UpstreamInstall`, `FreshMachine`, `Recreate`) and reading the produced summary.json. +- Screenshot verification for Mattingly's UI work when she requests a second pair of eyes. +- Reporting baselines: actual passed/skipped counts, deltas vs. prior baseline. + +## How I Work + +- Always use `--no-restore` on test runs once the build has restored. +- Use `OPENCLAW_TRAY_DATA_DIR` or a temp settings dir when constructing SettingsManager in tests — never real %APPDATA%. +- If a build/test is blocked by a running EXE locking outputs, stop the process by PID (`Stop-Process -Id `), rerun. +- Don't claim completion without reporting the actual numbers. +- Keep validation focused on the four supported `validate-wsl-gateway.ps1` scenarios; don't resurrect dev shims. + +## Boundaries + +**I handle:** Build, unit tests, integration validation script, baselines, regression checks. + +**I don't handle:** Writing production code (Aaron / Mattingly), porting strategy (Kranz). + +**When I'm unsure:** Run the test, read the actual output, report what I saw — never infer a result. + +**If I review others' work:** I reject on red builds, broken tests, or unverified UI claims. Lockout applies — original author can't self-revise. + +## Model + +- **Preferred:** auto (`claude-sonnet-4.6` when writing test code; `claude-haiku-4.5` for mechanical run-and-report) + +## Collaboration + +- Resolve repo via `TEAM ROOT` — clean worktree. +- Read `.squad/decisions.md` for any test-policy decisions. +- Drop decisions to `.squad/decisions/inbox/bostick-{slug}.md`. + +## Voice + +"Shared.Tests: 1152 passed / 20 skipped. Tray.Tests: 407 passed. Matches baseline." Numbers. Always numbers. diff --git a/.squad/agents/bostick/history-archive.md b/.squad/agents/bostick/history-archive.md new file mode 100644 index 000000000..da3f388dc --- /dev/null +++ b/.squad/agents/bostick/history-archive.md @@ -0,0 +1,218 @@ +# bostick History Archive - 2026-05-06 +Entries consolidated from full history. + +## Summary +- Long-running project +- Multiple work streams +- See current history.md for recent activity + +# Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh + +## Core Context + +Clean WSL gateway rebuild. Prototype lives in worktree `openclaw-windows-node` (branch `pr-241-feedback-fixes`) and is intentionally dirty / reference-only. Final implementation goes in sibling worktree `..\openclaw-wsl-gateway-clean` (branch `feat/wsl-gateway-clean` from upstream/master). + +Read these on first spawn: +- `.squad/identity/now.md` — current focus and immediate next todo. +- `.squad/prototype-reference.md` — file-by-file porting inventory. + +## Recent Updates + +📌 Team hired 2026-05-04. Universe: Apollo 13. + +## Learnings + +### Summary — Phase 0/1/2 verifications [Scribe-compacted 2026-05-04T21:15Z] + +- **Baseline capture (round 1, 09:52)**: pr-241-feedback-fixes branch wouldn't compile (CS8604 in OpenClawGatewayClientTests.cs:461 elevated by `TreatWarningsAsErrors=true`). No counts. Pivoted to clean worktree. +- **Clean-worktree baseline (10:00, `871b959`)**: build SUCCESS (57.14s). Shared 1172/1151/1f/20s (1f = pre-existing `ReadmeValidationTests.ReadmeAllowCommandsJsonExample_IsValid` env-discovery flap). Tray 407/407/0/0. +- **Phase 1 verification (10:25, `95911b8`)**: build PASS (32.9s). DeviceIdentity filter 17 total / 4 passed / 13 [IntegrationFact]-skipped (gated on `OPENCLAW_RUN_INTEGRATION`). Aaron's "17/17 pass" claim re-classified as "4 pass + 13 intentionally skipped without integration env". Without env vars: Shared 1174/1151/1f/22s; Tray 407/401/6f/0 (6f = `LocalizationValidationTests` env-discovery flap). With env vars all green. +- **Phase 2 verification (11:00, `b69202d`)**: build PASS (16.69s). Shared without env: 1180/1157/1f/22s. Shared with `OPENCLAW_RUN_INTEGRATION=1`: 1180/1179/1f/0s (1f still ReadmeValidationTests pre-existing). Tray without env: 407/401/6f. Tray with `OPENCLAW_REPO_ROOT` set: 407/407/0/0. +- **Locale flap root cause** (verified): `ReadmeValidationTests` and `LocalizationValidationTests` both call `GetRepositoryRoot()` which checks `OPENCLAW_REPO_ROOT` then walks up from `AppContext.BaseDirectory` looking for `.git/README.md`. From a test bin/ dir, the walk fails. Confirmed reproducible: T1 (no env) = 6 fails; set env, rerun = 0 fails. Stable when env set. **Not a Phase-N code defect**; environmental — needs `build.ps1`/CI to set the env var. +### Summary — Phase 3 (Aaron commit + Bostick verify) [Scribe-compacted 2026-05-04T21:35Z] + +Aaron landed `98bdf77` (LocalGatewaySetup port): loopback-only networking, `http://localhost:{port}` resolver, dropped postcondition-on-hang, 5 dead phases pruned (VerifyRootfsArtifact/ImportDistro/VerifyDistro/StartWorker/PairWorker), `/etc/wsl.conf` + `/etc/wsl-distribution.conf`, repair via `wsl --terminate OpenClawGateway` (never `--shutdown`), `aka.ms/wsllogs` in error paths. Bostick independent verification @ `98bdf77` with `OPENCLAW_RUN_INTEGRATION=1` + `OPENCLAW_REPO_ROOT` set: build PASS, filter 33/33, Tray 426/426, Shared 1180/1180 — all numbers CONFIRMED. Bonus diagnostic without env vars: 6 LocalizationValidationTests fail (env-var dependency on `OPENCLAW_REPO_ROOT` confirmed, not Phase 3 defect — root cause: `GetRepositoryRoot()` search from `AppContext.BaseDirectory` fails when nested in test output dir). Phase 3 verdict: AARON'S CLAIM CONFIRMED. + + +## [Round 5 — 2026-05-04T20:10:27Z] Orchestration log + team update + +**Spawn outcomes (this round):** +- bostick-4 (claude-haiku-4.5, background, ~190s): **SUCCESS** — Phase 3 verification confirmed Aaron's numbers under proper env (OPENCLAW_RUN_INTEGRATION=1, OPENCLAW_REPO_ROOT set). Tray 426/426, Shared 1180/1180. LocalizationValidationTests flap = env-dependent, not Phase 3 defect. Decision merged: bostick-phase3-verification.md. + +**Team update:** Kranz issued CONDITIONAL APPROVE on 98bdf77; Phase 4 unlocked. aaron-5/aaron-6 sonnet-4.6 spawns stopped early; replaced by aaron-7/aaron-8 on opus-4.7 (in flight). Mike's defaultModel now claude-opus-4.7. Watch for Phase 4 verification ask next round. + +### Summary — Phase 4–7 verifications + interim team updates [Scribe-compacted 2026-05-04T22:00Z] + +All four verifications confirmed Aaron / Mattingly numerics with `OPENCLAW_RUN_INTEGRATION=1` + `OPENCLAW_REPO_ROOT=`: + +- **Phase 4 @ `8cc32c6` (2026-05-04T13:25):** Build PASS 31.29s, LocalGatewaySetup filter 17/17/0/0, Tray 426/426, Shared 1180/1180. All Aaron Phase 4 claims CONFIRMED. +- **Phase 5 @ `99f5107` (2026-05-04T13:55):** Build PASS 28.0s, Tray 434/434, Shared 1180/1180, onboarding-filter (`OnboardingState|SetupWarning|LocalSetupProgress`) 32/32/0/0 — +8 vs Phase 4 confirmed onboarding-related (CurrentRoute_Defaults*, SetupPath_*, RequestAdvance_*, GetPageOrder_*). Without env vars: 6 LocalizationValidationTests pre-existing flap + 1 ReadmeValidationTests flap (not Phase 5 defects). **Both screenshots viewed inline:** `phase5-warning/page-02.png` (lobster, "Set up OpenClaw", folded ⚠️ notice, accent CTA, hyperlink, 6-dot indicator first-active, Back+Next disabled — SetupPath null) and `phase5-progress-active/page-02.png` (lobster, "Setting up locally", 7-stage list, Checking system ✓ / Installing Ubuntu • spinner / 5 pending ○, no time estimate). Mattingly Phase 5 CONFIRMED. +- **Phase 6 @ `8060ae9` (2026-05-04T14:15):** Build PASS 51.53s, Tray 434/434, Shared 1180/1180. PreflightOnly status=Passed, validationStatus=Passed, scenario=Passed, relay-prototype-probe=NotAvailable (expected). Stripped-item grep on `scripts/validate-wsl-gateway.ps1` for `BuildRootfs|RootfsManifest|StartWorker|PairWorker|--shutdown` → 1 doc-comment hit only at line 781, 0 code references. UpstreamInstall/FreshMachine/Recreate NOT run (Phase 6 guardrail). Aaron Phase 6 CONFIRMED. +- **Phase 7 @ `dbd7708` (2026-05-04T14:35):** Build PASS, Tray 434/434, Shared 1180/1180. **Dry-run safety hard-confirmed:** exit 0; `destructiveConfirmed=false`, `dryRun=true`; steps `mode/unregister-OpenClawGateway/backup-appdata/backup-localappdata=DryRun`; `backup-install-location/postconditions=Skipped`. `wsl --list -q` SHA256 `8F1E9581144DFB791FFF0A9137DCE9793E04688E492832E5228014F5FE9568C8` identical before/after; Compare-Object diff=0; `OpenClawGateway` distro present in both. **Negative test confirmed escape hatch absent:** `-Force`, `-AllowNonStandardDistroNameForDestructiveClean`, `-DistroName Foo` all rejected as parameter-not-found before script body ran. Stripped-item grep: 1 doc-comment hit (line 13), 0 code hits. Did NOT invoke with `-ConfirmDestructiveClean` (guardrail). Worktree restored to `32cbeae` after detached verify. Aaron Phase 7 CONFIRMED. + +**Interim team updates (rounds 6/7/8):** Phase 4 landed (`4ab1ec6` punch-list closed + `8cc32c6` App wiring). Phase 5 onboarding UX landed (`43035ca`..`99f5107`). Aaron-8 empirical 20-iter winget result (`wsl --install` 10/10 vs `winget Canonical.Ubuntu.2404` 0/10 — APPX only stages launcher). Phase 5 CONDITIONAL APPROVE from Kranz; punch-list pending. Phase 6 validation script (`8060ae9`) landed. Phase 7 reset script (`dbd7708`) landed. Decisions hygiene: `decisions.md` rewritten under 20 KB hard-gate (Phase 1+2+3 archived round-6, Phase 4+5+0 + literature winget archived round-9). +### 2026-05-04T15:00:00-07:00 — PHASE 8 + FINAL INTEGRATION SWEEP + +**Worktree:** `openclaw-wsl-gateway-clean` @ `1300981` (Phase 8 — final). +**Branch:** `feat/wsl-gateway-clean` +**Verifier:** Bostick + +**Env:** `OPENCLAW_RUN_INTEGRATION=1`, `OPENCLAW_REPO_ROOT=`. + +**Build:** ✅ SUCCESS (build.ps1 — Shared/Cli/WinNodeCli/WinUI all PASS). +**Shared.Tests:** Total 1180 / Passed 1180 / Failed 0 / Skipped 0 ✅ (8s) +**Tray.Tests:** Total 434 / Passed 434 / Failed 0 / Skipped 0 ✅ (620 ms) + +**Doc spot-check:** +- `docs/wsl-owner-validation.md` — 300 lines, parses OK ✅ +- `docs/wsl-owner-open-issues.md` — 266 lines, parses OK ✅ +- `docs/wsl-gateway-rootfs.md` — does NOT exist ✅ (per Mike's autopilot decision) + +**Branch commit count since baseline `871b959`:** 15 commits. +``` +1300981 docs(wsl): port wsl-owner-validation + wsl-owner-open-issues (Phase 8) +32cbeae fix(onboarding): drop time estimate + clean orphan Welcome resw (Phase 5 fast-follow) +dbd7708 feat(scripts): port reset-openclaw-wsl-validation-state.ps1 (Phase 7) +8060ae9 feat(scripts): port validate-wsl-gateway.ps1 (Phase 6) +99f5107 chore(onboarding): remove WelcomePage (Phase 5.4) +c2ad1e5 feat(onboarding): LocalSetupProgressPage (Phase 5.3) +6a5783a feat(onboarding): SetupWarningPage (Phase 5.2) +43035ca feat(onboarding): SetupWarning + LocalSetupProgress routes + SetupPath (Phase 5.1) +8cc32c6 feat(tray): wire setup engine + shared identity path (Phase 4) +4ab1ec6 fix(tray): close Phase 3 punch list +98bdf77 feat(tray): port LocalGatewaySetup (Phase 3) +b69202d feat(shared): port WindowsNodeClient (Phase 2.2) +b20b5ce feat(shared): port OpenClawGatewayClient (Phase 2.1) +3ae03d3 fix(shared): close Phase 1 punch list +95911b8 feat(shared): port DeviceIdentity (Phase 1) +``` + +**Net test delta vs pre-Phase-1 anchor:** +- Anchor: Shared 1172 (1151 pass + 1 pre-existing fail + 20 skip), Tray 407/407. +- Post-Phase-8 (env set): Shared 1180/1180/0/0, Tray 434/434/0/0. +- Δ Shared = +8 tests added. Δ Tray = +27 tests added. **Total +35 new tests.** +- Regressions: **0**. The 1 anchor-fail (ReadmeValidationTests env-discovery flap) now passes with `OPENCLAW_REPO_ROOT` set — confirmed environmental, not code defect. + +**`git status` (worktree):** +- 6 pre-existing unstaged mods (`LocalSetupProgressPage.cs` + 5 `Resources.resw` locales). NOT included in any Phase 8 commit per Aaron's note. These are leftover from Mattingly's Phase 5 fast-follow drafts that were superseded by `32cbeae`. **They should be reverted before PR push or left out via selective add.** + +**PR-readiness sanity:** +- `.gitignore` covers `artifacts/` ✅ (line 64). +- `.squad/` directory does **not exist** in this worktree ✅ (lives only in TEAM_ROOT). No `.squad/log/` or `.squad/orchestration-log/` to ignore. Zero `.squad` files tracked. +- `scripts/experiments/` does **not exist** in this worktree ✅. Aaron's empirical harness stayed in the prototype. +- Zero tracked files under `artifacts/`. +- Only worktree noise: the 6 unstaged files above. Recommend `git checkout -- src/OpenClaw.Tray.WinUI/Onboarding/Pages/LocalSetupProgressPage.cs src/OpenClaw.Tray.WinUI/Strings/*/Resources.resw` before pushing. + +**Verdict:** ✅ PHASE 8 CONFIRMED. Aaron's claim (Build PASS, Shared 1180/1180, Tray 434/434) matches exactly. Branch is PR-ready pending revert of 6 unstaged stragglers. Final pass: **GREEN.** + + +## Team update — Round 9 (2026-05-04T22:00Z) [Scribe] + +- **Phase 6 (validation script):** APPROVED at `8060ae9` (Kranz verdict + Bostick independent verification: Tray 434/434, Shared 1180/1180, loopback-only confirmed, no forbidden primitives). +- **Phase 7 (reset script):** APPROVED at `dbd7708` (Aaron port, Kranz verdict, Bostick verification — dry-run safe, `wsl --list -q` SHA256 identical before/after, no escape-hatch parameters). +- **Phase 8 (docs):** Aaron landed at `1300981` — `docs/wsl-owner-validation.md` + `docs/wsl-owner-open-issues.md`, rootfs doc omitted per Mike. **Pending Kranz round-10 verdict.** +- **Aaron-9 deeper winget research:** 6 hypotheses tested. H2 (winget+ubuntu2404 install --root) and H4 (winget+wsl --install --no-launch) both 3/3 in distro registration, but neither satisfies `--name`/`--location` requirements. Recommendation unchanged: stay with `wsl --install`. +- **Mattingly Phase 5 fast-follow:** landed at `32cbeae` — time-estimate string dropped, 45 orphan `Onboarding_Welcome_*` resw entries removed (9 keys × 5 locales). Punch-list items 1+2 closed; 3 (i18n) + 4 (Next button mid-install) deferred for Mike. +- **Plan is functionally complete pending Phase 8 verdict.** + + +--- + +## 📌 PLAN COMPLETE — 2026-05-04T22:15Z (Round 10, Phase 8 final) + +Phase 8 (FINAL phase) — wsl-owner documentation port — **APPROVED** by +Kranz at commit `1300981`. Bostick independent sweep confirms. + +- **Total commits on `feat/wsl-gateway-clean`:** 15 (since baseline `871b959`). +- **Build:** PASS · **Shared:** 1180/1180/0/0 · **Tray:** 434/434/0/0. +- **Net delta from anchor:** +35 new tests across 8 phases, zero regressions. +- **PR-readiness:** clean. `.squad/` not in worktree, `artifacts/` + gitignored, `scripts/experiments/` absent. No `.gitignore` update needed. + +**Mike's three PR-prep blockers (must resolve before `git push`):** + +1. Revert 6 stale unstaged files (`LocalSetupProgressPage.cs` + 5 resw + locales) — Mattingly drafts superseded by `32cbeae`. +2. Decide Mattingly Phase-5 Item 4 (Next-button mid-install policy). +3. Decide Mattingly Phase-5 Item 3 (i18n of new page literals) — likely + post-merge patch with PR-description callout. + +No lockouts. All four agents available for any post-PR review feedback. +See `.squad/decisions/decisions.md` Round-10 section and +`.squad/log/2026-05-04T22-15-00Z-plan-complete-final-verdict.md`. + +--- + +## Team update — Round 11 (2026-05-04T18:35-07:00) [Scribe] + +- **Aaron-13** discarded the 6 stale unstaged worktree files after pre-snapshotting diffs to `artifacts/stale-files-discarded-2026-05-04/`. Build PASS, Shared 1180/1180, Tray 434/434 — files confirmed stale, no restore needed. **PR-prep blocker #1 CLOSED.** HEAD unchanged at `1300981`. +- **Mattingly-3** landed Phase-5 i18n at commit `ce89251` (parent `1300981`): 17 new keys × 5 locales = 85 entries, `OPENCLAW_TEST_LOCALE` env hook in `OnboardingWindow`, fr-fr screenshot verified, 5 low-confidence translations flagged `?` for Mike. Build PASS, Tray 434/434, Shared 1180/1180. **PR-prep blocker #3 CLOSED.** +- **Coordinator** (autopilot) recorded Next-button defaults on `LocalSetupProgressPage` (Mike was offline): industry-standard onboarding-progress behavior — Idle hidden, Running visible+disabled, Success visible+enabled briefly before auto-advance, Failed states visible+disabled with Back enabled. **PR-prep blocker #2 CLOSED with autopilot defaults**, Mike-override-on-PR-review. See `decisions.md` round-11 entry. +- **configure-copilot** enabled `windows-computer-use-mcp` v0.1.1 (18 desktop automation tools) in user MCP config — replaces brittle visual-test env-var pipeline. +- **mattingly-4** in flight running full visual pass via computer-use MCP for final PR evidence. +- Branch `feat/wsl-gateway-clean` now at 16 commits since baseline `871b959`. Working tree clean modulo mattingly-4. Next: mattingly-4 returns → Mike pushes → PR opens. + + +## 2026-05-04T19:35-07:00 — Team update (round 13) + +Aaron-14 E2E drive on 73767c5 reached PairOperator and surfaced **2 real bugs**: (1) bootstrap-token handshake rejected as device-auth-invalid; (2) LocalSetupProgressPage doesn't propagate phase updates past stage 0. **Aaron-16** + **Mattingly-6** in flight fixing in parallel. Tray 447/447, Shared 1180/1180 (mattingly-5 added Next-button policy at 73767c5). PR push deferred until both bugs resolved. + +--- + +## Learnings — 2026-05-06T15:52:34-07:00 — Cross-platform wizard pattern (Symptom 3 research) + +### OpenClawKit / Mac wizard module structure + +- `OnboardingWizardModel` lives in `apps/macos/Sources/OpenClaw/OnboardingWizard.swift` (not in + a separate `OpenClawKit` framework at the Swift source level — it imports `OpenClawKit` for + other things but the wizard model is mac-local). +- `OnboardingWizardModel` is an `@MainActor @Observable final class` — long-lived, persists + through UI re-renders. Not recreated on navigation. +- The wizard state (`sessionId`, `currentStep`, `status`) lives on the model, not the view. + This is the key structural difference from the Windows functional component approach. + +### Mac recovery pattern — exact behavior + +- `submit()` in `OnboardingWizardModel`: on network error (not `GatewayResponseError`), sets + `status = "error"` and `errorMessage`. Does NOT auto-restart. Shows error UI with "Retry". +- `startIfNeeded()` guard: `guard self.sessionId == nil, !self.isStarting` — idempotent; won't + restart if session is still tracked. +- On user "Retry": `reset()` clears sessionId → `startIfNeeded()` → wizard.start → step 0. + The mac also returns to step 0 on retry, but the user explicitly triggered it. +- Auto-restart only fires in `restartIfSessionLost()` for the specific case of + `GatewayResponseError` with "wizard not found"/"wizard not running", max 1 attempt. + +### The "WizardPage constructed" log is misleading + +- `WizardPage.cs:180`: `"[Wizard] WizardPage constructed; gatewayClient=..."` is logged inside + `StartWizardAsync()`, not in an actual constructor. Fires every time `StartWizardAsync` is + called — including from recovery fallbacks. + +### Mattingly's WaitForConnectionAsync fix DID work (partial) + +- From live log: `WaitForConnectionAsync` returned `connected=True` at 15:51:29. +- wizard.next was subsequently tried (~15:51:29-32, filtered out of log by `[Wizard]` filter). +- wizard.next failed ("wizard not found" — wsl --terminate killed the Node.js process). +- The fallback in the recovery lambda called `StartWizardAsync(allowRestore: false)` → wizard.start → step 0. +- The remaining bug: the fallback silently restarts from step 0 instead of surfacing an error. + +### The one-line fix (conceptually) + +Change the `fallbackStartWizardAsync` lambda in `WizardPage.cs:303-312` to throw instead of +calling `StartWizardAsync`. `TryRecoverAsync` catches the throw → `Failed` → +`SetRecoveryFailureError()` → "Setup couldn't continue. Restart wizard to try again." → +user clicks "Restart Wizard" → explicit, transparent wizard.start. + +### Log filtering lesson + +Searching `[WizardDiag]|\[Wizard\]` misses `[WizardFlow]` category logs from +`WizardFlowController.TryResumeWithSessionAsync`. Always include `[WizardFlow]` when +debugging recovery paths. Full filter: `[WizardDiag]|\[Wizard\]|\[WizardFlow\]`. +## 2026-05-06 +- Mac pattern + WSL terminate trace + upstream history + clean relaunch + devloop script skill + + diff --git a/.squad/agents/bostick/history.md b/.squad/agents/bostick/history.md new file mode 100644 index 000000000..70421e20e --- /dev/null +++ b/.squad/agents/bostick/history.md @@ -0,0 +1,98 @@ +# bostick History + +## Summarized +Older entries archived. See history-archive.md. + +--- + +## 2026-05-07 — MSIX Storage Path Validation Script (anticipatory, pre-commit-7) + +**Task:** Draft `scripts/validate-msix-storage-paths.ps1` before Aaron's commits 5-7 land, so +the script is ready for commit-7 verification. + +**Script created:** `scripts/validate-msix-storage-paths.ps1` (1085 lines) + +### What the script does + +Empirically determines whether the OpenClawTray MSIX (with `runFullTrust`) writes user-data +files to real `%APPDATA%\OpenClawTray\` / `%LOCALAPPDATA%\OpenClawTray\` paths (Path A — +OrphanRisk) or to MSIX package-virtualized storage under +`%LOCALAPPDATA%\Packages\\` (Path B — CleanRemove). The answer controls +which uninstall surfaces and warning banners are required in commit 5. + +**Execution phases:** +1. **Preflight** — interactive session check, no OpenClaw* processes running, MSIX file exists, no + conflicting package installed. +2. **Pre-install snapshot** — capture dir listings + `Get-AppxPackage` JSON to `pre-*.txt/json`. +3. **Install** — `Add-AppxPackage` (with optional `Import-Certificate`); resolve and record + `PackageFamilyName`, `InstallLocation`, `PackageFullName` → `package-info.json`. +4. **Probe** (AutoSetup mode, default) — write session-ID probe markers to real APPDATA paths, + launch tray via `explorer.exe shell:AppsFolder\!App`, wait up to 30 s for process, kill + by PID, clean markers. If `-SkipAutoSetup`: emit `MANUAL-STEP-REQUIRED.txt` and exit 3. +5. **Post-install snapshot** — re-capture same paths → `post-*.txt/json`. +6. **Diff & verdict** — compute new paths in real vs. virtualized storage; write `verdict.json` + with `msix_writes_to_real_appdata`, `msix_writes_to_real_localappdata`, + `msix_writes_to_virtualized_storage`, `verdict`, `reasoning`, `package_family_name`. + Color-coded console output (red=PathA, green=PathB, yellow=Inconclusive). +7. **Teardown** — `Remove-AppxPackage`; post-uninstall snapshot; compute `removal_orphans`; + append to `verdict.json`. + +### Pass/fail criteria + +| Condition | Result | +|---|---| +| Non-Inconclusive verdict AND all evidence files present AND no terminating errors | Exit 0 (PASS) | +| Inconclusive verdict | Exit 1 (FAIL) | +| Missing evidence files | Exit 1 (FAIL) | +| Preflight blocked (process running, etc.) | Exit 2 (PREFLIGHT_BLOCK) | +| `-SkipAutoSetup` mode | Exit 3 (MANUAL_REQUIRED) | + +### Required evidence files (all must be present for PASS) + +`pre-appdata.txt`, `pre-localappdata.txt`, `pre-packages.txt`, `pre-appx.json`, +`post-appdata.txt`, `post-localappdata.txt`, `post-packages.txt`, `post-appx.json`, +`post-uninstall-appdata.txt`, `post-uninstall-localappdata.txt`, `post-uninstall-packages.txt`, +`verdict.json`, `package-info.json`, `summary.json` + +### Manual steps that may be required + +If `-SkipAutoSetup` is used (or if the default auto-probe path fails because `explorer.exe +shell:AppsFolder` does not launch in the test environment), the operator must: +1. Manually walk through the Setup-Locally flow in the tray UI. +2. Kill the tray by PID. +3. Re-run the script with `-SkipInstall -EvidenceDir ` to capture post-setup state + and proceed to verdict + teardown. + +The `-AutoSetup` default path avoids this for most dev machines. CI runners (non-interactive) +cannot use MSIX install at all — this script is intended for manual validation on a physical +machine or interactive VM. + +### Verdict-to-action mapping + +See `scripts/validate-msix-storage-paths.ps1` header comment (`## Notes for Aaron`) for full +details. Summary: + +- **PathA-OrphanRisk** → Keep in-tray "Remove Local Gateway" button as canonical cleanup. + MUST add pre-uninstall warning banner gated on `PackageHelper.IsPackaged() && setup-state.json + exists`. Recovery script still relevant. +- **PathB-CleanRemove** → `Remove-AppxPackage` handles file cleanup. MSIX section limited to + WSL distro cleanup only. Warning banner optional. +- **Inconclusive** → Block MSIX uninstall claims in commit 5. Re-run on clean VM or defer to + tracked TODO. + +### CI artifact consumption + +MSIX is produced by the `build-msix` CI job. Download with: +``` +gh run download --name openclaw-msix-win-x64 --dir ./msix-drop/ +``` +Pass the `.msix` path to `-MsixPath`. + +### Parse / syntax status + +Verified clean (0 syntax errors via `[System.Management.Automation.Language.Parser]::ParseFile`). + +### What this gates + +Commit 7 verification. The script must produce a non-Inconclusive verdict before MSIX coverage +claims in the PR are considered validated. diff --git a/.squad/agents/kranz/charter.md b/.squad/agents/kranz/charter.md new file mode 100644 index 000000000..3251ba0ec --- /dev/null +++ b/.squad/agents/kranz/charter.md @@ -0,0 +1,57 @@ +# Kranz — Lead / Architect + +> "Failure is not an option." Methodical, calls the shots, owns the porting strategy. + +## Identity + +- **Name:** Kranz +- **Role:** Lead / Architect +- **Expertise:** Porting strategy from prototype → clean PR; architectural decisions; reviewer gate; .NET/WinUI3 codebase navigation +- **Style:** Direct, decisive, scopes ruthlessly. Pushes back on anything that smells like prototype clutter sneaking into the clean branch. + +## Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh +- **Current focus:** Clean WSL gateway rebuild in `..\openclaw-wsl-gateway-clean` +- See `.squad/identity/now.md` and `.squad/prototype-reference.md` for full context. + +## What I Own + +- Porting decisions: what to copy from the prototype, what to leave behind, what to rewrite cleanly. +- Architectural shape of the clean branch (forked onboarding UX, app-owned `OpenClawGateway` Ubuntu instance, role-specific tokens, localhost-first endpoint resolution). +- Reviewer gate on Aaron / Mattingly / Bostick output before it lands in the clean branch. +- Final PR scope and commit hygiene. + +## How I Work + +- Read `.squad/prototype-reference.md` and `.squad/identity/now.md` before any porting decision. +- Use `.squad/decisions.md` as the source of truth for scope/architecture rules already agreed. +- Port behavior and tests, NOT prototype clutter. No dev rootfs, no fake gateway shims, no historical scaffolding. +- All `.squad/` paths resolve from `TEAM ROOT` in the spawn prompt. + +## Boundaries + +**I handle:** Porting strategy, code review, architectural decisions, scope calls, reviewer rejections. + +**I don't handle:** Writing the actual WSL plumbing (Aaron), onboarding UX implementation (Mattingly), running the validation script / tests (Bostick). + +**When I'm unsure:** I ask the user. The clean branch is the production PR — I do not guess. + +**If I review others' work:** On rejection, the lockout is strict — original author cannot self-revise. I will name a different agent or escalate. + +## Model + +- **Preferred:** auto +- **Rationale:** Reviewer gates and architecture proposals warrant a bump to premium; routine triage stays cheap. + +## Collaboration + +- Resolve repo via `git rev-parse --show-toplevel` or use `TEAM ROOT` from spawn prompt — we work across two worktrees. +- Read `.squad/decisions.md` first. +- Write team-relevant decisions to `.squad/decisions/inbox/kranz-{slug}.md`. + +## Voice + +Plain. No theatrics. "Port the test, leave the script. Move on." If something is half-baked it gets sent back. The clean branch is the deliverable — everything else is process. diff --git a/.squad/agents/kranz/history.md b/.squad/agents/kranz/history.md new file mode 100644 index 000000000..8218c79d9 --- /dev/null +++ b/.squad/agents/kranz/history.md @@ -0,0 +1,68 @@ +# Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh + +## Core Context + +Clean WSL gateway rebuild. Prototype lives in worktree `openclaw-windows-node` (branch `pr-241-feedback-fixes`) and is intentionally dirty / reference-only. Final implementation goes in sibling worktree `..\openclaw-wsl-gateway-clean` (branch `feat/wsl-gateway-clean` from upstream/master). + +Read these on first spawn: +- `.squad/identity/now.md` — current focus and immediate next todo. +- `.squad/prototype-reference.md` — file-by-file porting inventory. + +## Recent Updates + +📌 Team hired 2026-05-04. Universe: Apollo 13. + +## Learnings + +### Summary — Rounds 1–5 (planning + Phase 1/2/3 reviewer gates) [Scribe-compacted 2026-05-04T21:15Z] + +- **Sequenced porting plan** (round 1): 8 ordered phases. Strip rootfs/custom-distro path; Windows tray node only (no WSL worker); Phase 5 UX is Mattingly-owned and gated on Phase 4 app wiring; Phases 5/6 can parallelize after Phase 4. Craig confirmation hard-gated Phase 3. +- **Phase 3 revised against Craig's answers**: loopback only (drop `lan`/`auto`/WSL-IP fallback); trust `wsl --install` exit code (drop postcondition-on-hang); install spec locked `wsl --install Ubuntu-24.04 --name OpenClawGateway --location --no-launch --version 2`; no worker in WSL (`StartWorker`/`PairWorker` dropped); repair = `wsl --terminate OpenClawGateway` only — global `wsl --shutdown` banned in product paths; aka.ms/wsllogs surfaced on failure; WelcomePage removed (security notice folds into SetupWarning); port-with-pruning over rewrite (~130 lines contamination in 2600-line file). +- **Phase 1 verdict — CONDITIONAL APPROVE** on `95911b8`: role-specific operator/node token storage present; no rootfs/trusted-signing leak. Punch list before Phase-2 final: non-empty node-scope persistence coverage + unknown-role handling lockdown. +- **Phase 2 verdict — APPROVE** through `b69202d`: Phase 1 punch list closed; GatewayClient preserves `auth.bootstrapToken` / stored `auth.deviceToken` / role-specific `hello-ok.auth`; WindowsNodeClient reconnect uses `auth.deviceToken` with role-aware `DeviceIdentity` APIs; no WebBridge / WSL UNC / token leak. Validation needed `OPENCLAW_REPO_ROOT`. +- **Phase 3 verdict — CONDITIONAL APPROVE** on `98bdf77` (Aaron's LocalGatewaySetup port): all Craig deltas present; loopback resolver, WSL config writes, `wsl --terminate` repair, aka.ms/wsllogs, `loginctl enable-linger`, tray keepalive. No product `wsl --shutdown` / `--web-download` / `--from-file` / rootfs / WSL-IP fallback / UNC I/O / StartWorker/PairWorker. Validation: build PASS, Tray 426/426, Shared 1180/1180, LocalGatewaySetupTests 33/33. Punch list before merge: strip `PreserveWorkerData`/`worker_data_preserved`; gate distro-name override as test/dev-only. + +Five open questions filed for Mike before Phase 1 starts (clean worktree remote, Craig status, WSL worker requirement, offline fallback scope, rootfs doc disposition). + +**2026-05-04 17:00:00Z — Team Update** +Clean worktree exists and porting plan is canonical. Aaron ready for Phase 1 upon Mike approval; Mattingly ready for Phase 5 layout work. + +### Summary — Rounds 5–6 team updates (Phase 4 verdict + lead-up to Phase 5) [Scribe-compacted 2026-05-04T21:35Z] + +- **Round 5:** kranz-4 issued **CONDITIONAL APPROVE** on Phase 3 (`98bdf77`); Phase 4 unlocked. Aaron switched to opus-4.7 (aaron-7/8). Punch list owners: Aaron (worker-vocab strip, distro-override gating). +- **Phase 4 reviewer gate (`4ab1ec6` + `8cc32c6`) — APPROVE.** Worker vocabulary fully purged; distro override hard-locked behind `#if DEBUG || OPENCLAW_TRAY_TESTS` (Release returns constant `OpenClawGateway`). `App.CreateLocalGatewaySetupEngine()` factory wires Phase 1+2+3 with lazy `NodeService`; `App.IdentityDataPath` (`%APPDATA%\OpenClawTray`, `OPENCLAW_TRAY_APPDATA_DIR` override) is shared operator+node DeviceIdentity store. No rootfs/UNC/worker leakage. Validation: build PASS, Shared 1180/1180, Tray 426/426 (env: `OPENCLAW_REPO_ROOT`, `OPENCLAW_RUN_INTEGRATION=1`). Decision: `kranz-phase4-verdict.md`. Phase 5 unlocked unconditionally. +- **Round 6 team update:** Phase 5 in flight (Mattingly: SetupWarning + LocalSetupProgress XAML + screenshots); aaron-8 empirical 20-iter winget harness running. `decisions.md` compacted 33.6 KB → 10.8 KB; Phase 1/2/3 archived to `decisions-archive.md`. + +### Summary — Phase 5/6/7 reviewer gates + interim team updates [Scribe-compacted 2026-05-04T22:00Z] + +Three reviewer gates at `HEAD` on `feat/wsl-gateway-clean` with `OPENCLAW_REPO_ROOT` + `OPENCLAW_RUN_INTEGRATION=1`: + +- **Phase 5 @ `99f5107` (2026-05-04T13:55) — CONDITIONAL APPROVE** (Mattingly `43035ca`..`99f5107`). `SetupWarningPage` matches contract (Grid Auto/1*/Auto/Auto, MaxWidth 460, accent CTA verb-phrase, `TextBlockButtonStyle` hyperlink, folded ⚠️ notice, no HStack/no TextBox). `LocalSetupProgressPage` matches (Grid Auto/Auto/1*/Auto, MaxWidth 520, per-stage Auto/1*/Auto, error-row collapsed unless Failed*). Welcome route removed; `SetupPath` enum + `AdvanceRequested` event wired; `GetPageOrder()` forks Local vs Advanced. Nav Next disabled until path picked; 1s auto-advance on Complete (gated by `s_advanceFiredForCompletion`); FailedTerminal → aka.ms/wsllogs hint. Tests: `OnboardingStateTests` rewritten with full forked matrix; `ConnectionPageTopologyTests` updated for Advanced-fork-only WSL/SSH. `./build.ps1` PASS, Tray **434/434** (+8 vs 426), Shared **1180/1180**. No `\\wsl$`/`\\wsl.localhost`. Both screenshots viewed and matched contract. Punch list (fast-follow, NOT Phase 6 blocker): (1) trim subtitle time-estimate; (2) Mike question on Next-button mid-install; (3) clean orphan `Onboarding_Welcome_*` resw across 5 locales; (4) i18n post-merge. **Mattingly fast-follow @ `32cbeae` closed items 1+2 round-9.** +- **Phase 6 @ `8060ae9` (2026-05-04T14:15) — APPROVE** (Aaron `validate-wsl-gateway.ps1`, +940/-0). Scenarios reduced to `PreflightOnly | UpstreamInstall | FreshMachine | Recreate` (line 35). Stripped-parameter grep (rootfs/manifest/signing-key/public-key/gateway-package/allow-unsigned-dev-artifact/allow-non-standard-distro-name) all empty. Loopback-only networking confirmed: `wslIp|wsl-ip|GetWslIp|FallbackBind|AutoBind|gateway\.bind` empty; endpoint check on `127.0.0.1:18789` only. `Recreate` uses `wsl.exe --unregister` (line 782); sole `--shutdown` is prohibition comment (line 781). UI clicks `OnboardingSetupLocal` only (single click; relies on `LocalSetupProgressPage` self-start). `aka.ms/wsllogs` surfaced in setup-failure / setup-timeout / gateway-health-failure throws + `Save-DiagnosticsSnapshot` + `summary.md` failure footer + final host print. Redaction covers stdout/settings/device-key/setup-state/relay-probe/journal/openclaw-cli probe; `Token|GatewayToken|BootstrapToken|NodeToken`; `setupCode|PrivateKeyBase64|PublicKeyBase64`. `StartWorker|PairWorker|WorkerPairing` empty. PreflightOnly run PASS, parser zero errors, `./build.ps1` PASS, Shared 1180/1180, Tray 434/434. Non-blocking fast-follows: ordinal-based `Convert-SetupPhase` (recommend property-name once engine emits names); script relies on default `SetupWarning` route. None gate Phase 7. +- **Phase 7 @ `dbd7708` (2026-05-04T14:35) — APPROVE** (Aaron `reset-openclaw-wsl-validation-state.ps1`, +388/-0). No fast-follow punch list. Dry-run default (`.dryRun = -not `); every destructive branch emits `DryRun` step. Distro hard-locked (` = "OpenClawGateway"`); `param()` has no `-DistroName`/`-AllowNonStandardDistroNameForDestructiveClean`/`-CleanOpenClawState`. Backup-before-destruction order recovery-preserving (Copy then Remove); default `artifacts\reset-backups\\`. Stripped surface (rootfs/manifest, worker-data, `wsl --shutdown`, `\\wsl$`/`\\wsl.localhost`) absent in code; sole hits are prohibition comments. Lifecycle: `wsl --terminate OpenClawGateway` then `wsl --unregister OpenClawGateway` only. Token redaction not applicable (script writes no token payloads). `./build.ps1` PASS, Shared 1180/1180, Tray 434/434, parser clean, dry-run smoke exit 0. + +**Interim team updates (rounds 7/8):** Phase 4 APPROVED (`8cc32c6`); Phase 5 onboarding UX landed (`43035ca`..`99f5107`). Aaron-8 empirical 20-iter winget result (`wsl --install` 10/10 vs `winget Canonical.Ubuntu.2404` 0/10 — APPX only stages launcher). Phase 6 `8060ae9` landed (4 scenarios, loopback-only, `wsl --unregister` for Recreate). Phase 7 `dbd7708` landed (hard-locked `OpenClawGateway`, dry-run default). +### Summary — Phase 8 verdict + Plan Complete [Scribe-compacted 2026-05-04T18:35-07:00 / round 11] + +- **Phase 8 reviewer gate @ `1300981` (2026-05-04T15:00-07:00) — APPROVE** (Aaron's docs port +744/-0, FINAL phase). Two new docs present (validation ~17.5 KB, open-issues ~16.5 KB); rootfs doc correctly absent. Install command canonical across diagram/empirical/UpstreamInstall. `wsl --terminate` documented as repair primitive (6 hits); all 10 `wsl --shutdown` mentions are prohibitions; aka.ms/wsllogs 11×. 4 validation scenarios match Phase 6 exactly. Forbidden-as-design grep (rootfs/`--web-download`/`--from-file`/wsl-ip/lan-bind/StartWorker/BuildRootfs) all in negation or removed-context framing; UNC grep all prohibitions. 19 questions all ✅ Answered. `.squad/` not in worktree, `artifacts/` gitignored, `scripts/experiments/` absent — no `.gitignore` update. AGENTS.md gate satisfied by Aaron's Phase-8 run. +- **PLAN COMPLETE — 2026-05-04T22:15Z (round 10).** 15 commits on `feat/wsl-gateway-clean` since baseline `871b959`. Build PASS, Shared 1180/1180/0/0, Tray 434/434/0/0. Net delta from anchor: **+35 new tests across 8 phases, zero regressions.** +- **Mike's 3 PR-prep blockers documented round-10:** (1) 6 stale unstaged files revert, (2) Next-button mid-install policy, (3) i18n strategy. **All three closed in round 11** (see team update below). + +--- +## Team update — Round 11 (2026-05-04T18:35-07:00) [Scribe] + +- **Aaron-13** discarded the 6 stale unstaged worktree files after pre-snapshotting diffs to `artifacts/stale-files-discarded-2026-05-04/`. Build PASS, Shared 1180/1180, Tray 434/434 — files confirmed stale, no restore needed. **PR-prep blocker #1 CLOSED.** HEAD unchanged at `1300981`. +- **Mattingly-3** landed Phase-5 i18n at commit `ce89251` (parent `1300981`): 17 new keys × 5 locales = 85 entries, `OPENCLAW_TEST_LOCALE` env hook in `OnboardingWindow`, fr-fr screenshot verified, 5 low-confidence translations flagged `?` for Mike. Build PASS, Tray 434/434, Shared 1180/1180. **PR-prep blocker #3 CLOSED.** +- **Coordinator** (autopilot) recorded Next-button defaults on `LocalSetupProgressPage` (Mike was offline): industry-standard onboarding-progress behavior — Idle hidden, Running visible+disabled, Success visible+enabled briefly before auto-advance, Failed states visible+disabled with Back enabled. **PR-prep blocker #2 CLOSED with autopilot defaults**, Mike-override-on-PR-review. See `decisions.md` round-11 entry. +- **configure-copilot** enabled `windows-computer-use-mcp` v0.1.1 (18 desktop automation tools) in user MCP config — replaces brittle visual-test env-var pipeline. +- **mattingly-4** in flight running full visual pass via computer-use MCP for final PR evidence. +- Branch `feat/wsl-gateway-clean` now at 16 commits since baseline `871b959`. Working tree clean modulo mattingly-4. Next: mattingly-4 returns → Mike pushes → PR opens. + + +## 2026-05-04T19:35-07:00 — Team update (round 13) + +Aaron-14 E2E drive on 73767c5 reached PairOperator and surfaced **2 real bugs**: (1) bootstrap-token handshake rejected as device-auth-invalid; (2) LocalSetupProgressPage doesn't propagate phase updates past stage 0. **Aaron-16** + **Mattingly-6** in flight fixing in parallel. Tray 447/447, Shared 1180/1180 (mattingly-5 added Next-button policy at 73767c5). PR push deferred until both bugs resolved. diff --git a/.squad/agents/mattingly/charter.md b/.squad/agents/mattingly/charter.md new file mode 100644 index 000000000..9548dfbc0 --- /dev/null +++ b/.squad/agents/mattingly/charter.md @@ -0,0 +1,56 @@ +# Mattingly — Frontend / Onboarding UX + +> Builds the procedure in the simulator before the crew flies it. Owns the onboarding flow. + +## Identity + +- **Name:** Mattingly +- **Role:** Frontend / WinUI3 Onboarding UX +- **Expertise:** WinUI3 XAML/C#, onboarding wizard pages, Grid layout (not HStack), screenshot-verified UI work +- **Style:** Methodical. Writes the layout contract before the XAML. Never claims a UI works without seeing a screenshot. + +## Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh +- **Current focus:** Forked onboarding UX in `..\openclaw-wsl-gateway-clean`: + - First warning page: centered **Setup locally** button + **Advanced setup** link. + - **Setup locally** → dedicated local setup progress page → gateway wizard. + - **Advanced setup** → current master connection page → gateway wizard. + +## What I Own + +- The forked onboarding pages (warning page, local setup progress page, hand-off into the gateway wizard). +- WinUI3 layout integrity — Grid for "left + right on same row", read-only display via TextBlock not TextBox. +- Wiring onboarding pages to Aaron's `LocalGatewaySetup` engine. +- Screenshot verification for every visible UI change (MANDATORY — see global Copilot instructions). + +## How I Work + +- Restate the spatial layout BEFORE writing XAML. Get Kranz/user approval on the layout contract. +- Build → kill running OpenClaw → launch with `OPENCLAW_VISUAL_TEST=1` and `OPENCLAW_VISUAL_TEST_DIR` → wait ≥10s → navigate to changed page → view captured PNG with the `view` tool. +- Verify alignment, truncation, spacing, control visibility in the screenshot before declaring done. +- Reference only: `src/OpenClaw.Tray.WinUI/Onboarding/Pages/ConnectionPage.cs` from the prototype — final clean UX is a forked warning-page flow, not a port. + +## Boundaries + +**I handle:** Onboarding XAML/C#, page navigation, layout, screenshot verification. + +**I don't handle:** WSL setup engine internals (Aaron), test infrastructure (Bostick), scope/architecture (Kranz). + +**When I'm unsure:** Stop. Ask the user to clarify the layout. Do NOT guess at spatial intent. + +## Model + +- **Preferred:** auto (`claude-sonnet-4.6` for XAML/code; vision bump only when I need to analyze a screenshot) + +## Collaboration + +- Resolve repo via `TEAM ROOT` — clean worktree, not prototype. +- Read `.squad/decisions.md` for UX decisions already made. +- Drop decisions to `.squad/decisions/inbox/mattingly-{slug}.md`. + +## Voice + +"Warning page: Grid with two rows. Row 1 = centered Setup locally button. Row 2 = centered Advanced setup link. Confirming before I touch the XAML." Layout-first, every time. diff --git a/.squad/agents/mattingly/history-archive.md b/.squad/agents/mattingly/history-archive.md new file mode 100644 index 000000000..33aaa0646 --- /dev/null +++ b/.squad/agents/mattingly/history-archive.md @@ -0,0 +1,138 @@ +# mattingly History Archive - 2026-05-06 +Entries consolidated from full history. + +## Summary +- Long-running project +- Multiple work streams +- See current history.md for recent activity + +# Project Context + +- **Project:** openclaw-windows-node (Windows tray app + WSL gateway) +- **Created:** 2026-05-04 +- **User:** Mike Harsh + +## Core Context + +Clean WSL gateway rebuild on sibling worktree `..\openclaw-wsl-gateway-clean` (branch `feat/wsl-gateway-clean` from upstream/master `871b959`). Onboarding UX is Mattingly's primary scope. Read `.squad/identity/now.md` and `.squad/prototype-reference.md` on first spawn. + +## Recent Updates + +📌 Team hired 2026-05-04. Universe: Apollo 13. + +## Learnings + +### UX constraints (locked) + +- **Grid for left+right rows** — never HStack for alignment. +- **TextBlock for read-only display** — never editable TextBox (clear-button leak). +- **Screenshot verification mandatory** before declaring any UI page done. Use `OPENCLAW_VISUAL_TEST=1` harness; `windows-computer-use` MCP currently fails with `Bun is not defined` on this machine. + +### Summary — Phase 5 onboarding UX [Scribe-compacted 2026-05-04T19:35-07:00 / round 13] + +**Phase 5 landed and APPROVED (commits `43035ca` → `99f5107` → `32cbeae` → `ce89251` → `73767c5`):** + +- Added `SetupWarning` + `LocalSetupProgress` routes + `SetupPath` enum + `AdvanceRequested` event on `OnboardingState`. +- `SetupWarningPage.cs`: Grid Auto/1*/Auto/Auto, MaxWidth 460, accent "Set up locally" + hyperlink "Advanced setup", folded ⚠️ security notice. AutomationIds: `OnboardingSetupLocal` / `OnboardingSetupAdvanced`. +- `LocalSetupProgressPage.cs`: drives engine via `App.CreateLocalGatewaySetupEngine()`. **7 visible stages:** Checking system / Installing Ubuntu / Configuring instance / Installing OpenClaw / Preparing gateway / Starting gateway / Generating setup code. (Skipped phases not in `s_visibleStages[]`: `EnsureWsl`, `InstallService`, `Complete`.) Error/retry row; 1s auto-advance on Complete; static engine fields survive page nav. +- `WelcomePage.cs` deleted; `GetPageOrder()` branches on `SetupPath` (null defaults to Local for indicator stability). +- **Fast-follow `32cbeae`:** subtitle time-estimate dropped; 45 orphan `Onboarding_Welcome_*` resw entries removed (9 keys × 5 locales) via `XmlDocument` (`PreserveWhitespace=true`) + XPath. +- **i18n `ce89251` (mattingly-3, round 11):** 17 new keys × 5 locales = 85 entries; `OPENCLAW_TEST_LOCALE` env hook in `OnboardingWindow`. fr-fr screenshot verified. 5 low-confidence translations flagged `?` for Mike (nl-nl Title; zh `正在` prefix; fr-fr nbsp-before-colon; zh quote style; nl-nl Advanced). +- **Visual pass `ce89251` (mattingly-4, round 12):** all 5 required states + WelcomePage removal verified shippable. Captures: `visual-test-output/full-pass-2026-05-04/`. +- **Next-button policy `73767c5` (mattingly-5, round 12):** new `OnboardingNextButtonState` enum + `SetNextButtonState()` + `NavBarStateChanged` event on `OnboardingState`. New pure helper `LocalSetupProgressPolicy.MapStatusToNextButtonState()` (no WinUI deps). `OnboardingApp` consults state **only** when `currentRoute == LocalSetupProgress`. Bonus fix: 1s auto-advance on Complete now checks `CurrentRoute == LocalSetupProgress` to prevent over-advance. **Tests +13 → Tray 447/447**, Shared 1180/1180. All 4 active states screenshot-verified at `visual-test-output/next-button-impl-2026-05-04/`. + +**Net delta from baseline `871b959` across 17 commits:** Tray 407 → 447 (+40), Shared 1172 → 1180 (+8), zero regressions. +## 2026-05-04T18:35-07:00 — Mattingly-4: Full visual pass (round 12) + +Visually verified 5 onboarding states + WelcomePage removal on eat/wsl-gateway-clean@ce89251: SetupWarning en-us, LocalSetupProgress idle (Preflight), LocalSetupProgress active (InstallOpenClawCli), ConnectionPage Advanced, SetupWarning fr-fr. All layout contracts hold (MaxWidth 460/520, NavigationHost 680). No truncation, no English fallback in fr-fr, no prototype residue. Verdict: **visually ship-ready**. windows-computer-use MCP returned Bun is not defined — fell back to OPENCLAW_VISUAL_TEST=1 harness. Captures under isual-test-output/full-pass-2026-05-04/. Tray 434/434, Shared 1180/1180 (no code change). Decision: mattingly-full-visual-pass.md. + +## 2026-05-04T18:55-07:00 — Mattingly-5: Phase 5 final — Next/Back-button policy (commit 73767c5) + +Implemented coordinator's autopilot Next-button defaults. New OnboardingNextButtonState enum + SetNextButtonState() + NavBarStateChanged event on OnboardingState; new pure helper LocalSetupProgressPolicy.MapStatusToNextButtonState(); OnboardingApp consults state **only** when currentRoute == LocalSetupProgress. Bonus fix: 1s auto-advance on Complete now checks current route to prevent over-advance. Tests +13 → **Tray 447/447**; Shared 1180/1180. All 4 active states screenshot-verified at isual-test-output/next-button-impl-2026-05-04/. Net delta from baseline 871b959: Tray +40, Shared +8 across 17 commits. Decision: mattingly-next-button-policy.md. + +## 2026-05-04T19:35-07:00 — Mattingly-6 (in flight) + +Investigating + fixing **Bug 2** from aaron-14 E2E drive: LocalSetupProgressPage never propagates engine phase updates past stage 0 (• Checking system stayed spinning while engine progressed through all phases to PairOperator), and never transitions to FailedRetryable/FailedTerminal on engine failure. Aaron-16 in parallel on Bug 1 (bootstrap-token handshake). +## Round 13 — 2026-05-04T19:35:00-07:00 — Bug 2 fix: LocalSetupProgressPage stage propagation + FailedRetryable rendering (mattingly-6) + +Fixes the page-binding bug Aaron's e2e drive surfaced (.squad/decisions/inbox/aaron-e2e-drive.md § 4): UI stayed on stage 1 spinner the entire 12-minute run even though the engine advanced through 9+ phases and ultimately failed at PairOperator. Commit 4af2581 on eat/wsl-gateway-clean (parent 73767c5). + +**Root cause (concrete):** Reference-equality in Component.UseState. EqualityComparer.Default.Equals for a class without an Equals override falls through to ReferenceEquals. The page held `UseState` and the engine raises StateChanged?.Invoke(state) with the same mutating instance every call (LocalGatewaySetup.cs:1964). First null→state transition rendered once; every subsequent state→state event was deemed "no change" and the framework swallowed the re-render request. Stage list never advanced. FailedRetryable never rendered. + +**Files modified:** +- `src/OpenClaw.Tray.WinUI/Onboarding/Pages/LocalSetupProgressPage.cs` — introduced `private sealed record RenderSnapshot(Phase, Status, LastRunningPhase, UserMessage, FailureCode)` + `Capture(LocalGatewaySetupState)` static helper; switched to `UseState`; `Capture()` runs OFF the dispatcher (before `TryEnqueue`) so the snapshot reflects the state at event-fire time, not whatever the engine has mutated to by the time the dispatcher dequeues; deleted inline `s_visibleStages` / `ComputeStageState` / `StageState` (moved to helper); `TryReadVisualTestState` now does `StartPhase(MintBootstrapToken)` before `Block(...)` so `LastRunningPhase` pins the failure marker on the correct stage in retryable/terminal visual-test scenarios. +- `src/OpenClaw.Tray.WinUI/Onboarding/Services/LocalSetupProgressStageMap.cs` *(new, +119 lines)* — pure helper hosting `StageState` enum, `VisibleStages` array, `ComputeStageState`, `IndexOfStageForPhase`, `ShouldShowErrorRow`, `ShouldShowRetryButton`. `VisibleStages` now folds `PairOperator`/`CheckWindowsNodeReadiness`/`PairWindowsTrayNode`/`VerifyEndToEnd` (previously hidden) into the MintToken stage so a PairOperator failure (the actual e2e-drive bug) pins on a visible stage instead of being unrepresentable. +- `src/OpenClaw.Tray.WinUI/Onboarding/Services/LocalSetupProgressPolicy.cs` — added `MapStatusToNextButtonState(bool hasSnapshot, status)` overload used by the page; existing `(LocalGatewaySetupState?, status)` overload preserved for back-compat with `LocalSetupProgressPageNextButtonTests`. +- `tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj` — `` for the new helper. + +**Tests added** (`LocalSetupProgressStageMapTests`, +36 net new; some are Theory rows expanding from 15 InlineData): +- Stage advancement: every running engine phase resolves to the expected visible-stage index — 15 InlineData covering `Preflight`/`EnsureWslEnabled`/`ElevationCheck` → 0; `CreateWslInstance` → 1; `ConfigureWslInstance` → 2; `InstallOpenClawCli` → 3; `PrepareGatewayConfig`/`InstallGatewayService` → 4; `StartGateway`/`WaitForGateway` → 5; `MintBootstrapToken`/`PairOperator`/`CheckWindowsNodeReadiness`/`PairWindowsTrayNode`/`VerifyEndToEnd` → 6. +- `NotStarted_RendersAllStagesPending`, `Complete_RendersAllStagesComplete`. +- `EveryDeclaredEnginePhase_IsCoveredBySomeVisibleStageOrIsTerminal` — coverage guard against future enum additions silently dropping off the page. +- `FailedRetryable_AtPairOperator_PinsFailureOnLastVisibleStage` — concretely the Aaron-14 scenario; stages 0–5 Complete, stage 6 Failed. +- `FailedRetryable_AtCreateWslInstance_PinsFailureOnSecondStage`. +- `FailedTerminal_AtPreflight_PinsFailureOnFirstStage`. +- `ShouldShowErrorRow`/`ShouldShowRetryButton` truth tables (9 + 5 InlineData). +- `IndexOfStageForPhase_ReturnsMinusOne_ForUncoveredPhases` (NotStarted/Complete/Failed/Cancelled). + +**Validation (per AGENTS.md reporting standard):** +- Env: `OPENCLAW_REPO_ROOT=`, `OPENCLAW_RUN_INTEGRATION=1`. +- `dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj` — **Passed: 1180, Failed: 0, Skipped: 0** (anchor 1180/1180; no change). +- `dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj` — **Passed: 493, Failed: 0, Skipped: 0** (was 447/447 at `73767c5`; **+46 net new tests**). +- `./build.ps1` — Shared/Cli/WinNodeCli ✅; **WinUI build BLOCKED** by running tray app PID 8240 holding write-locks on `src\OpenClaw.Tray.WinUI\bin\x64\Debug\...` (lock contention error: `MSB3026 Could not copy ... OpenClaw.Shared.dll`). Per the e2e-drive guardrail (`DO NOT touch the running tray app at PID 8240 — Mike is looking at the broken state`) PID 8240 was NOT terminated. Side-output build (`-p:BaseOutputPath=bin-verify\`) failed with duplicate-AssemblyInfo errors because the obj/ + obj-verify/ dirs both fed into compilation. +- **Screenshot verification BLOCKED** for the same reason (cannot launch a fresh WinUI build to drive the visual harness while PID 8240 holds the lock). Mike (or a follow-up agent after Mike releases PID 8240) should: + 1. `Stop-Process -Id 8240` + 2. `dotnet build src\OpenClaw.Tray.WinUI\OpenClaw.Tray.WinUI.csproj -p:Platform=x64 --no-restore` + 3. Launch with `OPENCLAW_VISUAL_TEST=1` + `OPENCLAW_FORCE_ONBOARDING=1` + `OPENCLAW_ONBOARDING_START_ROUTE=LocalSetupProgress` and these scenarios: + - `OPENCLAW_VISUAL_TEST_LOCAL_SETUP=active:CreateWslInstance` — confirm stage 1 shows spinner, stage 0 shows ✅. + - `OPENCLAW_VISUAL_TEST_LOCAL_SETUP=active:MintBootstrapToken` — confirm stages 0–5 ✅, stage 6 spinner. + - `OPENCLAW_VISUAL_TEST_LOCAL_SETUP=retryable:device-auth-invalid` — confirm stage 6 ❌ red, error row + Try Again button. + - `OPENCLAW_VISUAL_TEST_LOCAL_SETUP=terminal:Setup cannot continue` — confirm error row + diagnostics hint, no retry button. + +**Confidence:** High that the unit-tested mapping is correct (every phase covered + theory-driven). High that the reference-equality fix is correct (record value-equality is well-defined; first-render still works because `null → RenderSnapshot` is a value-difference; subsequent transitions differ in at least `Phase` or `Status`). Visual verification deferred — surfaced explicitly above. + +**Commit:** `4af2581239f7544df3fc5da92788b3a458ca9042` on `feat/wsl-gateway-clean` (parent `73767c5`). Branch is now 17 commits since baseline `871b959`. + +## 2026-05-06T09:28:55-07:00 — Mattingly-7: PR #274 existing-config gate — plan (plan-only turn) + +Produced `mattingly-pr274-existing-config-gate-plan.md` for RubberDucky review. No code edited. + +### Learnings + +- **`IdentityDataPath`** lives at `%APPDATA%\OpenClawTray` (env override `OPENCLAW_TRAY_APPDATA_DIR`), distinct from **`DataPath`** (`%LOCALAPPDATA%\OpenClawTray\...`). The split matters: `DeviceIdentity` uses `IdentityDataPath`; `LocalGatewaySetupStateStore` and `SettingsManager` use `DataPath`. When constructing `OnboardingExistingConfigGuard`, both paths are needed — get `IdentityDataPath` from `App.IdentityDataPath` (static field, already used by `StartupSetupState`). + +- **FunctionalUI pages cannot use `async void` click handlers safely.** ContentDialog.ShowAsync() is the natural WinUI3 confirm pattern but requires awaiting from an async context. The FunctionalUI click callback is synchronous `void`. The correct pattern for modal confirmation in FunctionalUI is **inline `UseState` flag** — flip a boolean on click, re-render a warning section in-place. `SetupWarningPage` already follows this shape (single-frame render with no async plumbing). + +- **`OnboardingWindow` currently takes only `SettingsManager`** — when wiring in the guard, the cleanest pass-through is `identityDataPath` as a second constructor param, supplied by `App.ShowOnboardingAsync()`. Do not add the guard to `App.xaml.cs` statics; keep guard construction co-located with `OnboardingState` construction in `OnboardingWindow`. + +- **Engine fail-closed via `CreateLocalOnly`** is the right seam — not `RunLocalOnlyAsync`. The factory is the only external-API surface; `RunLocalOnlyAsync` is engine-internal. Throwing `InvalidOperationException` with a structured error-code prefix (`existing_config_replacement_not_confirmed: ...`) lets the `LocalSetupProgressPage` catch block surface the message as a terminal failure. + +- **`settings.Token`** is the sufficient proxy for "has existing config" at the engine level. It is non-empty iff a prior setup completed (operator pair sets it at `LocalGatewaySetup.cs:1562`) or the user manually configured a remote gateway — both data-loss scenarios. `BootstrapToken` and DeviceIdentity checks are enrichments for the summary display; not needed in the engine guard. + +- **Mobile returning-user UX (iOS/Android):** both clients default returning users to reconnect/re-pair, never to reinstall. The Windows equivalent is defaulting `SetupPath=Advanced` so the nav-bar Next button lands on ConnectionPage. This aligns with platform precedent and uses existing plumbing with ~12 LOC. + +### Addendum — prototype cross-check (mattingly-6) + +Per Mike's mid-flight reminder, verified the fix against prototype `openclaw-windows-node` branch `pr-241-feedback-fixes` `ConnectionPage.cs:415-432`. The prototype's apparent "working" engine binding was **accidental masking**, not a robust pattern: it updated three sibling `UseState`s per event (`setWslSetupState(state)` + `setWslSetupStatus(setupMessage)` + `setStatusMsg(setupMessage)`). The `LocalGatewaySetupState`-typed setter had the same reference-equality bug latent — but `BuildWslSetupStatusMessage(state)` produced a per-phase unique string, so the companion `UseState.Set` calls forced re-renders the state-typed setter silently swallowed. When mattingly-1 forked into `LocalSetupProgressPage` and dropped the free-form status-text companion (the forked design uses a stage list instead of running text), the masking went away and the bug surfaced. `RenderSnapshot` (record value-equality) is the correct durable fix; it doesn't regress if a future page drops companion text-state. Cross-check **strengthens** — does not change — the fix shipped at `4af2581`. + +## 2026-05-06T15:31:47-07:00 — Mattingly-8: Wizard loopback Symptom 3 fix (commit b3275a8) + +Owned the 4th-round recovery artifact for Symptom 3 (loopback to step 0 after channels page disconnect). Aaron's plan was rejected (wrong protocol: wizard.status). Hockney's plan shipped (commit 04c46df, wizard.next resume) but loopback still occurred. + +**Root cause found from live log:** +`TryResumeWithSessionAsync` (WizardFlowController.cs:167) guards the wizard.next branch with `client?.IsConnectedToGateway == true`. Recovery fires at disconnect time — `connected=False` at that exact moment. The guard fails, control falls immediately to fallback `wizard.start`, which has its own 30-second reconnect polling loop. After reconnect (~27s in Mike's repro), wizard.start creates a NEW session at step 0. The gateway's live in-memory `WizardSession` was never queried. + +**Fix:** Added `WaitForConnectionAsync(IWizardGateway?, int maxPollCount, Func? delayAsync)` to `WizardFlowController` — polls `IsConnectedToGateway` up to 30 times (injectable for test speed). Called from the recovery lambda in `WizardPage.cs` BEFORE `TryResumeWithSessionAsync`, so the IsConnectedToGateway guard is true when the resume path is evaluated. + +**Key learnings:** +- `TryResumeWithSessionAsync` was correct in its design but the caller assumption (connected on entry) was violated — recovery fires synchronously at disconnect, not after reconnect. +- `StartWizardAsync` had its own 30s polling loop that silently "fixed" the delay for wizard.start — the asymmetry is what caused the bug (start waited, resume did not). +- `WizardSession.answerDeferred` survives client WebSocket disconnect as long as the Node.js process is alive (confirmed by RubberDucky / Hockney plan). wizard.next on the live session should return the channels step, not step 0. +- Delay must be injectable (`Func? delayAsync`) for unit tests to run instantly. + +**Validation:** build=pass, shared-tests=1184/1206 skipped=22, tray-tests=611/611 (3 new WaitForConnectionAsync tests). Commit b3275a8 on feat/wsl-gateway-clean. Tray PID 48836. + +## 2026-05-06 +- Wizard plans + impls + + diff --git a/.squad/agents/mattingly/history.md b/.squad/agents/mattingly/history.md new file mode 100644 index 000000000..18a90857b --- /dev/null +++ b/.squad/agents/mattingly/history.md @@ -0,0 +1,6 @@ +# mattingly History + +## Summarized +Older entries archived. See history-archive.md. + + diff --git a/.squad/agents/ralph/charter.md b/.squad/agents/ralph/charter.md new file mode 100644 index 000000000..858417dd7 --- /dev/null +++ b/.squad/agents/ralph/charter.md @@ -0,0 +1,20 @@ +# Ralph — Ralph + +Persistent memory agent that maintains context across sessions. + +## Project Context + +**Project:** openclaw-windows-node + + +## Responsibilities + +- Collaborate with team members on assigned work +- Maintain code quality and project standards +- Document decisions and progress in history + +## Work Style + +- Read project context and team decisions before starting work +- Communicate clearly with team members +- Follow established patterns and conventions diff --git a/.squad/agents/ralph/history.md b/.squad/agents/ralph/history.md new file mode 100644 index 000000000..ea6a0fc64 --- /dev/null +++ b/.squad/agents/ralph/history.md @@ -0,0 +1,21 @@ +# Project Context + +- **Project:** openclaw-windows-node +- **Created:** 2026-05-04 + +## Core Context + +Agent Ralph initialized and ready for work. + +## Recent Updates + +📌 Team initialized on 2026-05-04 + +## Learnings + +Initial setup complete. + + +## 2026-05-04T19:35-07:00 — Team update (round 13) + +Aaron-14 E2E drive on 73767c5 reached PairOperator and surfaced **2 real bugs**: (1) bootstrap-token handshake rejected as device-auth-invalid; (2) LocalSetupProgressPage doesn't propagate phase updates past stage 0. **Aaron-16** + **Mattingly-6** in flight fixing in parallel. Tray 447/447, Shared 1180/1180. PR push deferred until both bugs resolved. diff --git a/.squad/agents/scribe/charter.md b/.squad/agents/scribe/charter.md new file mode 100644 index 000000000..a7f652010 --- /dev/null +++ b/.squad/agents/scribe/charter.md @@ -0,0 +1,20 @@ +# Scribe — Scribe + +Documentation specialist maintaining history, decisions, and technical records. + +## Project Context + +**Project:** openclaw-windows-node + + +## Responsibilities + +- Collaborate with team members on assigned work +- Maintain code quality and project standards +- Document decisions and progress in history + +## Work Style + +- Read project context and team decisions before starting work +- Communicate clearly with team members +- Follow established patterns and conventions diff --git a/.squad/agents/scribe/history.md b/.squad/agents/scribe/history.md new file mode 100644 index 000000000..cb8eed6fd --- /dev/null +++ b/.squad/agents/scribe/history.md @@ -0,0 +1,21 @@ +# Project Context + +- **Project:** openclaw-windows-node +- **Created:** 2026-05-04 + +## Core Context + +Agent Scribe initialized and ready for work. + +## Recent Updates + +📌 Team initialized on 2026-05-04 + +## Learnings + +Initial setup complete. + + +## 2026-05-04T19:35-07:00 — Round 13 + +Merged 3 inbox decisions (aaron-e2e-drive, mattingly-full-visual-pass, mattingly-next-button-policy) → decisions.md. Logged orchestration entries for aaron-15/16 + mattingly-4/5/6. Cross-agent team updates to bostick/kranz/ralph noting 2 real bugs surfaced by E2E drive + parallel fixes in flight (aaron-16, mattingly-6). Wrote session log. Summarized aaron + mattingly histories (both >= 15360 byte gate). Decisions.md grew past 20480 during merge — pre-check was under so gate did not fire; will dedupe next round if it stays high. diff --git a/.squad/casting/history.json b/.squad/casting/history.json new file mode 100644 index 000000000..7b3046614 --- /dev/null +++ b/.squad/casting/history.json @@ -0,0 +1,13 @@ +{ + "universe_usage_history": [ + { "universe": "Apollo 13", "assigned_at": "2026-05-04" } + ], + "assignment_cast_snapshots": { + "wsl-gateway-clean-2026-05-04": { + "assignment_id": "wsl-gateway-clean-2026-05-04", + "universe": "Apollo 13", + "assigned_at": "2026-05-04", + "members": ["kranz", "aaron", "mattingly", "bostick", "scribe", "ralph"] + } + } +} diff --git a/.squad/casting/policy.json b/.squad/casting/policy.json new file mode 100644 index 000000000..547c4cdfa --- /dev/null +++ b/.squad/casting/policy.json @@ -0,0 +1,39 @@ +{ + "casting_policy_version": "1.1", + "allowlist_universes": [ + "The Usual Suspects", + "Reservoir Dogs", + "Alien", + "Ocean's Eleven", + "Arrested Development", + "Star Wars", + "The Matrix", + "Firefly", + "The Goonies", + "The Simpsons", + "Breaking Bad", + "Lost", + "Marvel Cinematic Universe", + "DC Universe", + "Futurama", + "Apollo 13" + ], + "universe_capacity": { + "The Usual Suspects": 6, + "Reservoir Dogs": 8, + "Alien": 8, + "Ocean's Eleven": 14, + "Arrested Development": 15, + "Star Wars": 12, + "The Matrix": 10, + "Firefly": 10, + "The Goonies": 8, + "The Simpsons": 20, + "Breaking Bad": 12, + "Lost": 18, + "Marvel Cinematic Universe": 25, + "DC Universe": 18, + "Futurama": 12, + "Apollo 13": 10 + } +} diff --git a/.squad/casting/registry.json b/.squad/casting/registry.json new file mode 100644 index 000000000..dfb86093f --- /dev/null +++ b/.squad/casting/registry.json @@ -0,0 +1,52 @@ +{ + "agents": { + "kranz": { + "persistent_name": "Kranz", + "role": "Lead / Architect", + "universe": "Apollo 13", + "created_at": "2026-05-04", + "legacy_named": false, + "status": "active" + }, + "aaron": { + "persistent_name": "Aaron", + "role": "Backend / Infra", + "universe": "Apollo 13", + "created_at": "2026-05-04", + "legacy_named": false, + "status": "active" + }, + "mattingly": { + "persistent_name": "Mattingly", + "role": "Frontend / Onboarding UX", + "universe": "Apollo 13", + "created_at": "2026-05-04", + "legacy_named": false, + "status": "active" + }, + "bostick": { + "persistent_name": "Bostick", + "role": "Tester / Validation", + "universe": "Apollo 13", + "created_at": "2026-05-04", + "legacy_named": false, + "status": "active" + }, + "scribe": { + "persistent_name": "Scribe", + "role": "Session Logger", + "universe": "(exempt)", + "created_at": "2026-05-04", + "legacy_named": false, + "status": "active" + }, + "ralph": { + "persistent_name": "Ralph", + "role": "Work Monitor", + "universe": "(exempt)", + "created_at": "2026-05-04", + "legacy_named": false, + "status": "active" + } + } +} diff --git a/.squad/ceremonies.md b/.squad/ceremonies.md new file mode 100644 index 000000000..ec16d6b98 --- /dev/null +++ b/.squad/ceremonies.md @@ -0,0 +1,69 @@ +# Ceremonies + +> Team meetings that happen before or after work. Each squad configures their own. + +## Design Review + +| Field | Value | +|-------|-------| +| **Trigger** | auto | +| **When** | before | +| **Condition** | multi-agent task involving 2+ agents modifying shared systems | +| **Facilitator** | lead | +| **Participants** | all-relevant | +| **Time budget** | focused | +| **Enabled** | ✅ yes | + +**Agenda:** +1. Review the task and requirements +2. Agree on interfaces and contracts between components +3. Identify risks and edge cases +4. Assign action items + +--- + +## Retrospective + +| Field | Value | +|-------|-------| +| **Trigger** | auto | +| **When** | after | +| **Condition** | build failure, test failure, or reviewer rejection | +| **Facilitator** | lead | +| **Participants** | all-involved | +| **Time budget** | focused | +| **Enabled** | ✅ yes | + +**Agenda:** +1. What happened? (facts only) +2. Root cause analysis +3. What should change? +4. Action items for next iteration + + +--- + +## Retrospective with Enforcement + +| Field | Value | +|-------|-------| +| **Trigger** | auto | +| **When** | weekly | +| **Condition** | No *retrospective* log in .squad/log/ within the last 7 days | +| **Facilitator** | lead | +| **Participants** | all | +| **Time budget** | focused | +| **Enabled** | yes | +| **Enforcement skill** | retro-enforcement | + +**Agenda:** +1. What shipped this week? (closed issues, merged PRs) +2. What did not ship? (open issues, blockers) +3. Root cause on any failures +4. Action items -- each MUST become a GitHub Issue labeled retro-action + +**Coordinator integration:** +At round start, call Test-RetroOverdue (see skill retro-enforcement). If overdue, run this ceremony before the work queue. + +**Why GitHub Issues, not markdown:** +Production data: 0% completion across 6 retros using markdown checklists, 100% after switching to GitHub Issues. diff --git a/.squad/config.json b/.squad/config.json new file mode 100644 index 000000000..940f09f0b --- /dev/null +++ b/.squad/config.json @@ -0,0 +1,7 @@ +{ + "version": 1, + "defaultModel": "claude-opus-4.7", + "agentModelOverrides": { + "rubberducky": "gpt-5.5" + } +} diff --git a/.squad/decisions-archive.md b/.squad/decisions-archive.md new file mode 100644 index 000000000..beb40aaa8 --- /dev/null +++ b/.squad/decisions-archive.md @@ -0,0 +1,196 @@ +# Squad Decisions Archive + +Archived 2026-05-04 | Entries from Phase 0 planning and early team decisions that were resolved, superseded, or preserved for historical reference. + +## Phase 0 Planning (2026-05-04) — Now Resolved + +### Early Architectural Assumptions + +Kranz filed initial porting plan with 5 open questions for Mike. All answered by 2026-05-04T10:15-07:00: + +1. **Clean worktree remote** → Resolved: `origin` (no `upstream` exists) +2. **Craig confirmation status** → Resolved: ✅ Craig answered all questions (see coordinator-craig-wsl-answers decision) +3. **WSL worker requirement** → Resolved: Windows tray node only (Mike decision) +4. **Offline/from-file fallback** → Resolved: Not needed per Craig (modern WSL distributions not via Store) +5. **wsl-gateway-rootfs.md disposition** → Resolved: Omit from clean PR (historical reference only) + +### Initial Conditional Architecture Statements + +Decisions.md lines 5–39 contained conditional language ("Assume Craig confirms...") for WSL direction, networking, and lifecycle. All conditions were satisfied by Craig's verbatim answers and Mike's Phase-0 decisions. Conditional language removed; see `coordinator-craig-wsl-answers` and `kranz-phase3-revised-craig-answers` for authoritative final specs. + +### Mattingly's Onboarding Layout Contract (2026-05-04) + +Mattingly filed full pre-XAML layout contract for SetupWarning and LocalSetupProgress pages with 6 open questions (OQ-1 through OQ-6). OQ-1 answered by Mike (fold security notice, delete WelcomePage). OQ-2–OQ-6 remain open for Phase 5 scope. Layout structural contract (Grid rows/cols, localization keys, phase mapping) is now baked into kranz-phase3-revised-craig-answers final phase surfacing spec. + +### Bostick Phase-0 Baseline (2026-05-04 10:00 UTC-7) + +Clean worktree baseline captured: +- Build: ✅ 57.14s, no errors +- Shared.Tests: 1172 total (1151p, 1f [pre-existing ReadmeValidationTests], 20s) +- Tray.Tests: 407p, 0f + +Baseline locked for Phase 1+ regression detection. Pre-existing failure in Shared.Tests (ReadmeValidationTests) is not a blocker. + +--- + +**Archive decision:** All Phase 0 planning entries have been resolved by final verdicts and Michael's decisions. Preserved here for historical context; canonical reference should use kranz-phase3-revised-craig-answers, coordinator-craig-wsl-answers, and Phase 2 closures from decisions.md. + +--- + +## Phase 1 + Phase 2 Closure (2026-05-04, archived 2026-05-04 round 6) + +Archived because superseded by Phase 3 completion and Phase 4 landing. + +### Phase 1 Reviewer Verdict (Kranz @ 95911b8) — CONDITIONAL APPROVE +- Role-specific operator/node token storage and persistence present. +- DeviceIdentity integration tests 17/17 with `OPENCLAW_RUN_INTEGRATION=1`. +- Punch-list deferred to Phase 2 closure (non-empty node-scope persistence + unknown-role handling) — **closed in commit 3ae03d3**. + +### Phase 1 Independent Verification (Bostick @ 95911b8) +- Phase 1 approval stood. Surfaced env-var dependency that became the Reporting Standard (still canonical). +- LocalizationValidationTests + ReadmeValidationTests failures identified as environmental (`OPENCLAW_REPO_ROOT` discovery), not code defects. + +### Phase 1 Punch-List Closure (Aaron, 3ae03d3) +- Implemented Option B: role-string APIs convert via private `DeviceTokenRole` enum (case-sensitive `"operator"` / `"node"` whitelist). +- Added non-empty node-scope persistence + invalid-role exception coverage. + +### Phase 2.1 GatewayClient Port (Aaron, b20b5ce) +- Bootstrap setup-code consumption via `auth.bootstrapToken`; stored operator reconnect via `auth.deviceToken`. +- Role-specific token handoff from `hello-ok.auth` (incl. node-token). +- `_operatorReadScopeUnavailable` fallback ported as-is (compatibility uncertain — flagged for revisit if needed). +- Not ported: WebBridge relay, prototype UI-automation hooks. + +### Phase 2.2 WindowsNodeClient Port (Aaron, b69202d) +- Node reconnect via stored `NodeDeviceToken` → `auth.deviceToken`. +- Node-token storage via `StoreDeviceTokenForRole("node", ...)`; startup credential resolution prefers stored node token, then gateway token, then bootstrap token. +- Public API: kept `HasStoredNodeDeviceToken(...)`. + +### Phase 2 Reviewer Verdict (Kranz @ b69202d) — APPROVE +- Bootstrap, stored-token reconnect, role-specific handoff, redaction all verified. +- No `\\wsl$` / `\\wsl.localhost` paths. +- Phase 3 unlocked. + +### Phase 2 Verification (Bostick @ b69202d) +- Build PASS; Shared.Tests 1179/1180 (1 pre-existing failure: `ReadmeAllowCommandsJsonExample_IsValid`); Tray.Tests 407/407 with `OPENCLAW_REPO_ROOT` set. +- Locale flap diagnosed as env-var dependency (test `GetRepositoryRoot()` walks from `AppContext.BaseDirectory`); fix is to set `OPENCLAW_REPO_ROOT` in build/CI. + +--- + +## Phase 3 (2026-05-04, archived 2026-05-04 round 6) + +Archived because Phase 3 commit landed, was reviewed (CONDITIONAL APPROVE), independently verified, and the conditions (`PreserveWorkerData` removal + distro-name override gating) were closed in Phase 4 commit `4ab1ec6`. + +### Phase 3 Plan — Revised Against Craig's Authoritative Answers (Kranz) +Authoritative deltas now embedded in code: +- Install: `wsl --install Ubuntu-24.04 --name OpenClawGateway --location \OpenClawTray\wsl --no-launch --version 2`. No `--web-download` / `--from-file` / offline fallback. +- Networking: loopback ONLY; resolver returns `http://localhost:{port}`. +- Trust `wsl --install` exit code (no postcondition-on-hang fallback). +- Config: `/etc/wsl.conf` (automount/interop/appendWindowsPath = false) + `/etc/wsl-distribution.conf` (systemd, default user openclaw). +- Repair: `wsl --terminate OpenClawGateway` only; never global `wsl --shutdown`. +- Diagnostics: `aka.ms/wsllogs` link; no internal log scraping. +- Lifecycle: `loginctl enable-linger openclaw` + tray-owned keepalive. +- Worker phases removed (Mike: Windows tray node only). + +Phase enum kept (19): NotStarted, Preflight, ElevationCheck, EnsureWslEnabled, CreateWslInstance, ConfigureWslInstance, InstallOpenClawCli, PrepareGatewayConfig, InstallGatewayService, StartGateway, WaitForGateway, MintBootstrapToken, PairOperator, CheckWindowsNodeReadiness, PairWindowsTrayNode, VerifyEndToEnd, Complete, Failed, Cancelled. Dropped: VerifyRootfsArtifact, ImportDistro, VerifyDistro, StartWorker, PairWorker, LocalOnlyComplete. + +Progress UI mapping (for Mattingly Phase 5): +| UI Stage | Internal Phase(s) | +|---|---| +| Checking system | Preflight, ElevationCheck, EnsureWslEnabled | +| Installing Ubuntu | CreateWslInstance | +| Configuring instance | ConfigureWslInstance | +| Installing OpenClaw | InstallOpenClawCli | +| Preparing gateway | PrepareGatewayConfig, InstallGatewayService | +| Starting gateway | StartGateway, WaitForGateway | +| Generating setup code | MintBootstrapToken | +| Connecting operator | PairOperator | +| Connecting node | CheckWindowsNodeReadiness, PairWindowsTrayNode | +| Verifying | VerifyEndToEnd | + +### Phase 3 LocalGatewaySetup Port (Aaron, 98bdf77) +- Created `src/OpenClaw.Tray.WinUI/Services/LocalGatewaySetup/LocalGatewaySetup.cs`; moved `SetupCodeDecoder.cs` (kept `OpenClawTray.Onboarding.Services` namespace); created `tests/OpenClaw.Tray.Tests/LocalGatewaySetupTests.cs`. +- Loopback-only resolver; removed WSL-IP fallback, `gateway.bind` writes, LAN/auto bind, worker phases, post-clone repairs. +- Repair primitive: `wsl --terminate OpenClawGateway` (no global shutdown). +- Runtime env bindings retained: `OPENCLAW_WSL_DISTRO_NAME`, `OPENCLAW_WSL_INSTALL_LOCATION`, `OPENCLAW_WSL_ALLOW_EXISTING_DISTRO`. +- Validation (env: `OPENCLAW_RUN_INTEGRATION=1`, `OPENCLAW_REPO_ROOT=...openclaw-wsl-gateway-clean`): build PASS; filter 33/33; Tray 426/426; Shared 1180/1180. + +### Phase 3 Reviewer Verdict (Kranz @ 98bdf77) — CONDITIONAL APPROVE +All architectural guardrails verified (install command, loopback-only, wsl.conf/wsl-distribution.conf, instance-scoped terminate, no UNC WSL paths, redaction, `aka.ms/wsllogs`, lifecycle preserves linger + keepalive). Two punch-list items left (BOTH closed in Phase 4 commit `4ab1ec6`): +1. Remove `PreserveWorkerData` / `worker_data_preserved` worker vocabulary from lifecycle removal API. +2. Gate distro-name override (`OPENCLAW_WSL_DISTRO_NAME`) to test/dev only; lock shipping path to `OpenClawGateway`. + +### Phase 3 Independent Verification (Bostick @ 98bdf77) — CONFIRMED +Aaron's claim fully confirmed. Filter 33/33, Tray 426/426, Shared 1180/1180, build PASS — all with required env vars set. LocalizationValidationTests hypothesis re-confirmed (env-var dependency, not Phase 3 regression). + + +## Round-9 Archive (2026-05-04) — Superseded Phase Author + Verdict Entries + +The following entries were consolidated to `decisions.md` round-9 condensed forms or fully superseded by later phases. Preserved here for audit. + +### Mike's Three Phase-0 Decisions (now baked into Active Canonical) + +**Date:** 2026-05-04 — **By:** Mike Harsh + +- Craig confirmation: ✅ Craig answered full `wsl-owner-open-issues.md` set. Phase 3 unblocked. +- WSL worker requirement: Windows tray node ONLY. Do NOT port `StartWorker`/`PairWorker`. +- Welcome page disposition: REMOVE existing `WelcomePage`. Fold security notice into `SetupWarningPage` body. Fork page is page 0 of onboarding. + +### Literature winget vs `wsl --install` (Aaron, 2026-05-04T12:41:45) + +Literature-only research. Recommendation: stay with `wsl --install`. **Superseded by:** Aaron-8 empirical (Phase 6 entry, decisions.md) and Aaron-9 deeper hypothesis test (decisions.md). Original key finding preserved: `Canonical.Ubuntu.2404` APPX has no `--name`/`--location` semantics; `wsl --install` is the only single primitive for app-owned named instances. + +### Phase 4 — App Wiring + Phase 3 Punch-List Closure (Aaron, 2026-05-04T13:10:27) + +Commits `4ab1ec6` (punch list) + `8cc32c6` (Phase 4 wiring) on `feat/wsl-gateway-clean`. + +**Task A — Phase 3 punch list:** `PreserveWorkerData` / `worker_data_preserved` / `workerData` vocabulary fully deleted (`LocalGatewayRemoveRequest` parameter removed; `LocalGatewayLifecycleManager.RemoveAsync` step write removed). Distro-name override (`OPENCLAW_WSL_DISTRO_NAME`) gated behind `#if DEBUG || OPENCLAW_TRAY_TESTS`; Release returns constant `"OpenClawGateway"` regardless of caller input or env. + +**Task B — Phase 4 wiring:** `App.CreateLocalGatewaySetupEngine()` factory in `App.xaml.cs:55-62`. `IdentityDataPath` (`%APPDATA%\OpenClawTray`, override via `OPENCLAW_TRAY_APPDATA_DIR`) at `App.xaml.cs:152-161`. `NodeService` constructor accepts optional `identityDataPath` (`NodeService.cs:151,157`); falls back to `dataPath`. `WindowsNodeClient` (`NodeService.cs:179`) and `StartupSetupState` callsites (`App.xaml.cs:1082, 1167`) switched to `IdentityDataPath` — closes prototype operator/node identity divergence. `DataPath` (`%LOCALAPPDATA%\OpenClawTray`) preserved for crash logs / run markers / exec-approval policy / diagnostics. + +Stripped: prototype env-var rootfs/manifest overrides, dev-shim auto-accept, worker-in-WSL wiring. + +Validation (`OPENCLAW_REPO_ROOT` + `OPENCLAW_RUN_INTEGRATION=1`): `./build.ps1` PASS, Tray.Tests 426/426/0/0, Shared.Tests 1180/1180/0/0. + +Diff vs `98bdf77..HEAD`: `LocalGatewaySetup.cs` +16/-5; `App.xaml.cs` +62/-4; `NodeService.cs` +12/-1. + +### Phase 4 Reviewer Gate — APPROVE (Kranz) + Independent Verification (Bostick) — 2026-05-04T13:25:00 + +Kranz APPROVE on `4ab1ec6` + `8cc32c6`. No punch list. Phase 5 unblocked unconditionally. Worker vocabulary strip clean (0 hits). Distro override gated at three independent gates (`LocalGatewaySetupRuntimeConfiguration.FromEnvironment`, `LocalGatewaySetupEngineFactory.ResolveDistroName`, `OPENCLAW_TRAY_TESTS` defined only in tests csproj). Prohibited additions all empty: `OPENCLAW_WSL_ROOTFS_*`, `TrustedSigningKeyId`, `RootfsArtifactManifest`, `WslRootfsOverlay`, `\\wsl$`, `\\wsl.localhost`, dev-shim auto-accept, `StartWorker`, `PairWorker`. Diff minimal/surgical. Bostick verification (env vars set): build PASS 31.29s, filter 17/17/0/0, Tray 426/426/0/0, Shared 1180/1180/0/0 — matches Aaron exactly. + +### Phase 5 — Onboarding UX (SetupWarning + LocalSetupProgress) — Mattingly — 2026-05-04 + +Commits `43035ca`..`99f5107` over Phase 4 tip `8cc32c6`. Created `Onboarding/Pages/SetupWarningPage.cs` and `Onboarding/Pages/LocalSetupProgressPage.cs`. Modified `OnboardingState.cs`, `OnboardingApp.cs`, `OnboardingWindow.cs`, `OnboardingStateTests.cs`, `ConnectionPageTopologyTests.cs`. Deleted `WelcomePage.cs`. + +State: `OnboardingRoute` removed `Welcome`, added `SetupWarning` and `LocalSetupProgress`. New `SetupPath { Local, Advanced }`. `OnboardingState.SetupPath` (`SetupPath?`), `event AdvanceRequested`, `RequestAdvance()`. Default `CurrentRoute = SetupWarning`. `GetPageOrder()` branches on `SetupPath`; null defaults to Local for indicator stability; Next disabled until SetupPath set. + +Layout: SetupWarning MaxWidth=460 (lobster, centered title, body with folded ⚠️ security notice + Advanced-setup pointer, accent "Set up locally" button MinWidth=200 Height=44, hyperlink "Advanced setup"). LocalSetupProgress MaxWidth=520 (lobster, title, subtitle, 7-stage list ✓/spinner/○, error/retry row). + +Visible 7 phases: Checking system, Installing Ubuntu, Configuring instance, Installing OpenClaw, Preparing gateway, Starting gateway, Generating setup code. Hidden subtitle-only: ElevationCheck, PairOperator, CheckWindowsNodeReadiness, PairWindowsTrayNode, VerifyEndToEnd. Auto-advance on `Complete` after 1s. Retry on FailedRetryable; `aka.ms/wsllogs` hint on FailedTerminal. + +Visual-test hooks: `OPENCLAW_ONBOARDING_START_SETUP_PATH=Local|Advanced`; `OPENCLAW_ONBOARDING_START_ROUTE=LocalSetupProgress` auto-sets `SetupPath=Local`; `OPENCLAW_VISUAL_TEST_LOCAL_SETUP` (only with `OPENCLAW_VISUAL_TEST=1`) renders synthetic engine state. + +Validation: build PASS, Tray 434/434 (+8 vs Phase 4's 426), Shared 1180/1180. Screenshots `phase5-warning/page-02.png` and `phase5-progress-active/page-02.png` verified. + +### Phase 5 Reviewer Gate — CONDITIONAL APPROVE (Kranz) + Verification (Bostick) — 2026-05-04T13:55:00 + +HEAD `99f5107`. Punch list (fast-follow, NOT Phase 6 blocker): (1) trim subtitle "This usually takes a few minutes."; (2) Mike question — Next button mid-install policy; (3) step-indicator default-7 acceptable; (4) static `s_engine`/`s_runTask`/`s_advanceFiredForCompletion` need reset comment. Orphan `Onboarding_Welcome_*` resw entries in 5 locales (~45 lines): fast-follow. Hard-coded English copy: post-PR i18n landing. + +**Punch list items 1 + 2 closed by Mattingly Phase 5 fast-follow @ `32cbeae` (decisions.md round-9). Items 3 + 4 stand as-is.** + +Bostick verification (env vars set): build PASS 28.0s; Tray 434/434/0/0, Shared 1180/1180/0/0; onboarding-filter `OnboardingState|SetupWarning|LocalSetupProgress` 32/32/0/0. Both screenshots viewed and confirmed match contract. + +## Round-9–10 Phase Cycles (archived 2026-05-04T22:15Z) — Phases 5 fast-follow / 6 / 7 + +Round-by-round phase landings on `feat/wsl-gateway-clean`. All approved by Kranz (round-9 & round-10) and independently verified by Bostick. Final round-10 PLAN COMPLETE entry remains in active `decisions.md`. + +### Phase 6 — `validate-wsl-gateway.ps1` port (Aaron, HEAD `8060ae9`) + +`scripts/validate-wsl-gateway.ps1` (~620 lines, vs prototype 1537). Scenarios kept (4): `PreflightOnly` / `UpstreamInstall` / `FreshMachine` / `Recreate`. Stripped: `BuildRootfs`, `InstallOnly`, `Smoke`, `Full`, `Loop` scenarios; `-BuildDevRootfs`, `-BaseRootfsPath`, `-GatewayPackagePath`, `-UseExistingManifest`, `-RootfsPath`, `-AllowUnsignedDevArtifact`, `-SigningKeyId`, `-PublicKeyPath`, `-AllowNonStandardDistroNameForDestructiveClean`, `-NetworkingMode`, `-LoopMode`, `-RequireWorkerPairing`, `-CleanOpenClawState`, `-GoSkillProofCommand`, `-RequireGoSkillProof`. Networking: loopback only `:18789`. UI hook: drives `OnboardingSetupLocal`; polls `setup-state.json`. Diagnostics surface `aka.ms/wsllogs`. Redaction at all token-emitting sinks. Build PASS · Tray 434/434 · Shared 1180/1180. **Kranz APPROVE; Bostick verified.** + +### Phase 7 — `reset-openclaw-wsl-validation-state.ps1` port (Aaron, HEAD `dbd7708`) + +388 lines new file. `-AllowNonStandardDistroNameForDestructiveClean`, `-CleanOpenClawState`, `-DistroName` all stripped. Distro hard-coded `$script:OpenClawDistroName = "OpenClawGateway"`. Dry-run default; `Backup-Directory` runs Copy-then-Remove. Lifecycle uses `wsl --terminate` then `wsl --unregister` only. Build PASS · Tray 434/434 · Shared 1180/1180. **Kranz APPROVE, no fast-follow; Bostick dry-run hard-confirmed: WSL state SHA256 identical before/after, escape hatch refused for `-Force` / `-AllowNonStandardDistroNameForDestructiveClean` / `-DistroName Foo`.** + +### Phase 5 fast-follow — time-estimate drop + orphan Welcome resw cleanup (Mattingly, HEAD `32cbeae`) + +Closes Phase-5 verdict punch-list items 1 & 2 (items 3 i18n + 4 Next-button policy deferred). `LocalSetupProgressPage.cs:127` fallback subtitle trimmed to `"Setting up your local OpenClaw gateway."` (no time estimate). 9 `Onboarding_Welcome_*` resw entries removed × 5 locales = 45 total. Diffstat: 6 files, +50/-185. Build PASS · Tray 434/434 · Shared 1180/1180; `LocalizationValidationTests` parity preserved. Screenshot: `visual-test-output/phase5-followup/page-02.png`. diff --git a/.squad/decisions.md b/.squad/decisions.md new file mode 100644 index 000000000..73703503f --- /dev/null +++ b/.squad/decisions.md @@ -0,0 +1,8407 @@ +# Squad Decisions (Deduplicated - Round 17) + +## Governance + +- All meaningful changes require team consensus +- Document architectural decisions here +- Keep history focused on work, decisions focused on direction +- Older / superseded entries live in `decisions-archive.md` + +## Active Canonical Decisions + +### Dedicated Ubuntu WSL instance, not custom OpenClaw distro + +OpenClaw creates a dedicated app-owned Ubuntu-24.04 WSL instance named `OpenClawGateway` from the Store Ubuntu package, then applies OpenClaw-owned configuration. No custom rootfs or offline fallback path in this clean PR. (Craig confirmed.) + +### Public Linux installer remains source of truth + +Windows tray invokes the public OpenClaw Linux installer unchanged inside WSL at `https://openclaw.ai/install-cli.sh` with prefix `/opt/openclaw`. No forking or patching. + +### Use upstream setup-code/bootstrap pairing + +Local setup calls upstream `openclaw qr --json`, decodes/consumes upstream `setupCode` bootstrap payload, and pairs through the normal WebSocket handshake using `auth.bootstrapToken`. Windows does not directly edit gateway pairing stores. + +### Store role-specific credentials + +Windows tray identity may receive both node and operator credentials. Persist separately: operator token in existing field, node token in separate field. Paired reconnects use `auth.deviceToken`; node credentials never sent as `auth.token`. + +### Windows tray node is acceptable, WSL worker optional + +Mac app parity supports same-app node model. For Windows: gateway in WSL + Windows tray operator + Windows tray node is the scope for this clean PR. (Mike: Windows tray node ONLY; no WSL worker port.) + +### Fork onboarding setup UX + +Fork before current master connection page: first warning page (SetupWarning) offers centered **Setup locally** and **Advanced setup** link. **Setup locally** opens dedicated WSL local setup progress page then gateway wizard. **Advanced setup** opens current connection page then gateway wizard. (WelcomePage deleted, security notice folds into SetupWarning body — Mike decision.) + +### Reporting Standard (test counts) + +All test-count claims must include: + +1. Failures broken out, even when pre-existing. +2. `OPENCLAW_RUN_INTEGRATION` env-var state at time of run. +3. Any other env-vars materially affecting counts (notably `OPENCLAW_REPO_ROOT`, which test repo-root discovery requires; without it, `LocalizationValidationTests` and `ReadmeValidationTests` fail environmentally). + +Pre-existing baseline for this branch: Shared.Tests 1172 total (1151p, 1f [ReadmeValidationTests], 20s), Tray.Tests 407p. + +Phase-anchor baseline (Phases 6→7→8 stable): Shared **1180/1180**, Tray **434/434**. + +### Mike Harsh directive: prototype is valid reference for bug fixes + +When fixing bugs in the clean worktree, agents should consult the prototype worktree at `C:\Users\mharsh\OneDrive - Microsoft\Desktop\OpenClawWindowsInstaller\openclaw-windows-node` (branch `pr-241-feedback-fixes`) as a reference. The prototype code went through real end-to-end validation, so when the clean port has a regression that the prototype didn't have, the prototype is the authoritative answer for what the working behavior looked like. **Applies to all future spawns** that involve diagnosing or fixing behavior the prototype demonstrably worked. + +--- + +## Round 17 Canonical Decisions — Bug 1 + Bug 3 GREEN End-to-End + +### Bug 1: 6-commit fix journey for operator-pairing auto-approve (Aaron-17 through Aaron-21) + +**Final status:** ✅ GREEN end-to-end per Bostick Round 5 (all phases through "Grant Permissions" + manual node verification). + +**Commits (in order):** +- **Aaron-17 `3927451`:** Drop `--url` from `devices approve` (Bug 1 residual). The bundled CLI v2026.5.3-1 rejects `--url` + `--token` with `ensureExplicitGatewayAuth` guard. Solution: omit `--url` entirely; CLI falls back to local file-based approve when the WS hop fails or is omitted. +- **Aaron-18 `6942a81`:** Two-stage approve (preview + explicit requestId). CLI `devices approve --latest --json` is a **preview operation** (returns valid JSON but exit 1). Second stage commits with explicit requestId. +- **Aaron-19 `05f7be0`:** Retry stage-1 on first-call race + surface stderr. Gateway's internal auto-bootstrap races with the first CLI invocation. Fix: retry stage 1 once with 750 ms backoff; surface both attempts' stderr for diagnosability. +- **Aaron-20 `f2dec42`:** Read gateway token in C# + interpolate as shell literal + surface stdout. Hypothesis test for quoting-mediated argv mangling. Change eliminates embedded `$(...)` and `"` from approve script; surfaces STDOUT alongside STDERR for visibility. +- **Aaron-21 (Bug 1 final) `4d36dcd`:** Gate inversion — treat valid preview JSON as stage-1 success regardless of exit code. **Smoking gun discovery by Bostick:** the CLI returns exit code 1 deterministically in preview mode even with valid JSON stdout. Exit code is NOT the success signal; parseable JSON IS. + +**Canonical gotcha — Exit code is NOT the success signal:** +> OpenClaw CLI v2026.5.3-1 `devices approve --latest --json` returns exit code 1 in preview mode with valid JSON on stdout. Exit code is NOT the success signal; valid parseable JSON IS. + +**Canonical gotcha — Surface all three streams immediately:** +> When debugging shell-out from .NET via `wsl.exe -- bash -lc