fix(apps): winget launch failure no longer crashes Apply #19

Merged
SilverLABS merged 1 commits from fix/winget-launch-resilience into main 2026-06-10 00:24:03 +00:00
Owner

Symptom (found on VM 102)

The wizard reached Apply (Apps step worked) then hard-failed:

Configuration failed — An error occurred trying to start process 'winget' with working directory 'C:\Windows\System32'. The system cannot find the file specified.

Root cause

On IoT Enterprise LTSC, winget (App Installer) is absent, so Process.Start("winget", "--version") throws Win32Exception instead of returning a non-zero exit code. The winget probe in EnsureWingetAsync threw, the exception propagated out of InstallAsync → out of ApplyService.RunAsync, and aborted the entire Apply. Continue-on-failure only handled non-zero exits, not launch exceptions — exactly the risk flagged in the original B1 review.

Fix

AppInstaller is now fully exception-safe (it never throws):

  • TryRunAsync wraps every runner.RunAsync and converts a launch throw into a failed run (exit -1).
  • ResolveWingetAsync finds a usable winget defensively: on PATH → else bootstrap App Installer + re-probe → else the WindowsApps execution-alias path (%LOCALAPPDATA%\Microsoft\WindowsApps\winget.exe, which bare-name Process.Start can't always launch). Returns the target or null.
  • When winget is unavailable, installs are skipped (apps marked not-installed) and onboarding continues — instead of crashing.
  • Per-app install throws are isolated, so one bad app can't abort the batch.

This makes onboarding robust on offline/LTSC machines (like the test VM) and improves winget resolution on real hardware.

Test Plan

  • dotnet test windows/welcome/SilverOS.Welcome.sln -c Release38/38 pass (2 new: probe-throws-skips-and-doesn't-crash; per-app-throw-isolated)
  • VM re-test: Apply completes through to Done (apps skipped gracefully — VM has no network/winget)
  • Hardware/network re-test: winget resolves + installs actually run

🤖 Generated with Claude Code

## Symptom (found on VM 102) The wizard reached **Apply** (Apps step worked) then hard-failed: > Configuration failed — An error occurred trying to start process 'winget' with working directory 'C:\Windows\System32'. The system cannot find the file specified. ## Root cause On IoT Enterprise LTSC, winget (App Installer) is **absent**, so `Process.Start("winget", "--version")` throws `Win32Exception` instead of returning a non-zero exit code. The winget **probe** in `EnsureWingetAsync` threw, the exception propagated out of `InstallAsync` → out of `ApplyService.RunAsync`, and aborted the entire Apply. Continue-on-failure only handled non-zero exits, not launch exceptions — exactly the risk flagged in the original B1 review. ## Fix `AppInstaller` is now fully exception-safe (it never throws): - **`TryRunAsync`** wraps every `runner.RunAsync` and converts a launch throw into a failed run (exit -1). - **`ResolveWingetAsync`** finds a usable winget defensively: on PATH → else bootstrap App Installer + re-probe → else the WindowsApps execution-alias path (`%LOCALAPPDATA%\Microsoft\WindowsApps\winget.exe`, which bare-name `Process.Start` can't always launch). Returns the target or `null`. - When winget is **unavailable**, installs are **skipped** (apps marked not-installed) and onboarding continues — instead of crashing. - Per-app install throws are isolated, so one bad app can't abort the batch. This makes onboarding robust on offline/LTSC machines (like the test VM) and improves winget resolution on real hardware. ## Test Plan - [x] `dotnet test windows/welcome/SilverOS.Welcome.sln -c Release` → **38/38 pass** (2 new: probe-throws-skips-and-doesn't-crash; per-app-throw-isolated) - [ ] VM re-test: Apply completes through to **Done** (apps skipped gracefully — VM has no network/winget) - [ ] Hardware/network re-test: winget resolves + installs actually run 🤖 Generated with [Claude Code](https://claude.com/claude-code)
SilverLABS added 1 commit 2026-06-10 00:23:51 +00:00
fix(apps): winget launch failure no longer crashes Apply
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 4m44s
3daa770584
On IoT LTSC winget is absent, so Process.Start('winget') throws Win32Exception
('cannot find the file specified') rather than returning non-zero. That throw
propagated out of InstallAsync and failed the entire Apply ('Configuration failed').

AppInstaller is now fully exception-safe: a TryRunAsync wrapper converts launch
throws into a failed run, winget is resolved defensively (PATH -> bootstrap+re-probe
-> WindowsApps alias path) and when unavailable the installer skips apps and marks
them not-installed instead of throwing. Per-app launch throws are isolated too.
Two new tests cover probe-throws-skips and per-app-throw-isolated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SilverLABS merged commit 72fa329ddd into main 2026-06-10 00:24:03 +00:00
SilverLABS deleted branch fix/winget-launch-resilience 2026-06-10 00:24:03 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SilverLABS/SilverMetal#19