+## Choosing what runs
+
+Arguments to `setup-windows.bat` set the starting point of the plan; you can
+still adjust it before pressing Enter unless you also pass `-Yes`.
+
+| | |
+| --- | --- |
+| `setup-windows.bat -WhatIf` | Show the plan for this machine and stop. Nothing is changed. |
+| `setup-windows.bat -Skip VirtualBox,Brave` | Start with those switched off. |
+| `setup-windows.bat -Only E` | Start with only the elevated half. |
+| `setup-windows.bat -Yes` | Do not ask: run the plan as it stands. For unattended runs. |
+| `setup-windows.bat /?` | Usage. |
+
+- Steps are named as the plan shows them, comma-separated. A group letter works
+ anywhere a name does: `U` per-user installs, `M` machine-wide installs and the
+ WiX pin, `E` the elevated half, `C` per-user configuration and Pillow. A name
+ it does not recognise stops the run before anything happens — a mistyped
+ `-Skip` that was quietly ignored would install exactly what you meant to leave
+ out.
+- **With no console to ask on** — piped, scheduled, a non-interactive `ssh`
+ command — it prints the plan and stops with exit code 2 unless given `-Yes`.
+ It never assumes yes.
+- The two halves take `-Only`, `-Skip` and `-Yes` too, and when run on their own
+ print their part of the plan and ask before doing anything, e.g.
+ `.\setup-windows-with-uac.ps1 -Only VisualStudio,Wdk`. From the batch file
+ they are handed exactly what the plan left selected, with `-Yes`, since you
+ were asked already. With nothing selected for a half it is not started — so
+ no UAC prompt is raised for an elevated half with no steps.
+- Every step is declared once, in `setup-windows-steps.ps1`: its name, what it
+ does, and — with the reason — whether it is x64-only (`-X64Only`) or needs an
+ administrator (`-Admin`). The planner, the batch file and both halves read
+ that one list and check each other: a step the list does not know is refused
+ rather than run, and a selected step that nothing implements fails the run
+ rather than quietly not happening. Adding a step means a row there plus the
+ code that does it, gated on the same name.
+- Some steps build on others — the WiX pin needs the .NET SDK, the Clang and XP
+ toolsets need Visual Studio. The plan notes it when you switch the
+ prerequisite off, but does not stop you: it may well be installed already.
+
+## Re-running
+
+Every step checks before it acts, so running `setup-windows.bat` again on a
+provisioned box installs only what is missing or has a newer version out.
+Nothing is reinstalled at the version it already has. Where a check cannot
+decide — no network, a version string it does not recognise — it installs as
+before rather than skipping: a failed check must never be why something is left
+missing or out of date.
+
+| step | how it decides |
+| --- | --- |
+| winget packages | `winget install` on a package winget can see is installed upgrades it when a newer version exists and otherwise does nothing — winget's own default. `--force`, which would install regardless, is never used. |
+| `ClaudeCode` | Anthropic's installer always downloads and reinstalls, so `setup-windows-current.ps1` asks first: is `%USERPROFILE%\.local\bin\claude.exe` the latest release — the version the installer's own endpoint names — and the build for this host? Only both skip it. |
+| `NASM` | Its per-user fallback install registers nothing, so winget cannot see it and would rerun the installer every time. `setup-windows-current.ps1` compares that `nasm.exe` with the version winget offers. A machine-wide NASM is left to winget. |
+| `Rustup` | Needs no help: rustup registers itself under the manifest's product code and rewrites its version when it updates itself, so winget sees what is really there. |
+| `WiX` | Skipped when 5.0.2 is already in the .NET global tool store. |
+| `OpenSshClient`, `OpenSshServer` | Installed only when the capability is not. |
+| `Rsync` | The release's `.sha256` is fetched first and compared with the hash recorded when the files were installed (`rsync-windows.sha256`). The zip is downloaded only when they differ or a file is missing. |
+| `VisualStudio`, `VsClang`, `VsWinXP` | `vswhere -requires` says whether the install already has every component of a pass. A pass with nothing to add does not run the installer, and with nothing to add anywhere the bootstrapper is not even downloaded. The script never updates Visual Studio itself; the Visual Studio Installer does that. |
+| `Wdk`, `Wpt` | Skipped when the kit, or the toolkit, is already there. |
+| `BinSkim` | Asks NuGet for the newest stable version before downloading a package well over 100 MB; `nupkg-version.txt` beside the tool records what is installed. |
+| `RustToolchain` | `rustup toolchain install` updates stable when there is a newer one and otherwise reports it unchanged. |
+| `Pillow` | `pip install` leaves an installed Pillow alone. It does not upgrade it either. |
+| the rest | Configuration: `PATH` entries are added only when missing, and settings are written with the values they already have. |
+