Merge branch 'main' into the desktop updater, and give way on two numbers

Main landed a realtime push feature while this branch was building the updater,
and the two collided in three places. Every one of them resolves the same way:
main got there first, so this branch moves.

**Two ADRs were both numbered 0012.** Main's is realtime push; this one is now
[ADR 0013](docs/adr/0013-desktop-distribution-and-updates.md). Git did not call
this a conflict — the filenames differ — so it would have merged quietly and left
the directory with two 0012s and every cross-reference ambiguous. Renumbered here
along with the nine places that point at it.

**Two manual-check phases were both numbered 15**, and that one git did catch.
Main's "Changes that arrive without a timer" keeps 15; installing and updating
the desktop client becomes Phase 16, with its checks and every reference to them
renumbered. The file's own rule is that a number is for life, which is exactly
why the one that had not been pushed is the one that gives way.

**The merge rewrote several files with CRLF**, and `.editorconfig` asks for LF on
everything except `*.ps1`. That is not cosmetic here: IDE0055 is an error and
`EnforceCodeStyleInBuild` is on, so it failed the build on three lines of
App.axaml.cs whose only change in this branch was an ADR number in a comment.
Forty-six files normalised back to LF; the release script keeps CRLF, which is
what `.gitattributes` and `.editorconfig` both already say for a PowerShell file.

Nothing else conflicted. The updater does not touch the sync loop or the event
stream, and the one file both sides edited heavily — MainWindowViewModel — merged
without a hunk in common.

Verified after merging: the solution restores locked and builds clean, and 304
shell, 100 layout, 54 session, 28 client-api and 25 contracts tests pass. The
first two counts are higher than before the merge because main's own tests came
with it and pass alongside these.
This commit is contained in:
2026-08-04 17:52:57 +02:00
52 changed files with 6205 additions and 341 deletions
+4 -4
View File
@@ -225,7 +225,7 @@ suspect.
40-character corporate username adds 35 of them back. The shipped installer is not at risk. Two things
would reopen it and neither is in the plan: a self-extracting single-file publish, whose native libraries
land under a hashed temp path, and `%LOCALAPPDATA%` folder-redirected to a deep UNC path in a domain.
Manual check 15.2 measures it on the real machine rather than trusting this paragraph.
Manual check 16.2 measures it on the real machine rather than trusting this paragraph.
**WebView2's user data folder must be kept out of the install directory.** It defaults to a directory
beside the host executable, which under Velopack is inside `current\` — and `current\` is *replaced* by
@@ -233,7 +233,7 @@ every update. Left alone, the browser profile would be destroyed on each one, so
every update would pay a cold WebView2 start: a fresh user-data directory and a new process tree, which is
the slow path `RendererTimeout`'s fifteen seconds was sized for, arriving at the exact moment somebody is
most ready to believe the update broke the terminal. `Program.Main` sets `WEBVIEW2_USER_DATA_FOLDER` to
`%LOCALAPPDATA%\DodoSSH\WebView2` — under the profile directory, which Velopack never touches. Check 15.8
`%LOCALAPPDATA%\DodoSSH\WebView2` — under the profile directory, which Velopack never touches. Check 16.8
is what would notice it regressing, and it is worth having because the symptom is "slow but working", which
gets dismissed as a fluke.
@@ -243,7 +243,7 @@ gets dismissed as a fluke.
choice — would have made the uninstaller delete the vault cache and the outbox of changes not yet pushed,
silently, which is the thing the application will not do without a counted confirmation. The pack id is
`DodoSSH.Desktop` for that reason and no other; `--packTitle` supplies the name people see, so nothing is
lost. Do not "tidy" it. See [ADR 0012](adr/0012-desktop-distribution-and-updates.md) and check 15.9.
lost. Do not "tidy" it. See [ADR 0013](adr/0013-desktop-distribution-and-updates.md) and check 16.9.
**The Windows app manifest must declare a `supportedOS` list.** Without it the process reports a
downlevel Windows version and Avalonia's native control host fails outright — *"Unable to create child
@@ -358,7 +358,7 @@ for Windows/macOS/AppImage; Flatpak and deb/rpm defer updates to the package man
reintroduce the thing MSIX was ruled out for. `Setup.exe` is an ordinary Win32 executable that unpacks a
directory under `%LOCALAPPDATA%` and creates shortcuts — there is no `AppxManifest`, no package identity,
no `runFullTrust`, no elevation and no execution alias, so the process stays an ordinary desktop process
and WebView2 stays out of an AppContainer. That is reasoning, not measurement; manual check 15.4 is the
and WebView2 stays out of an AppContainer. That is reasoning, not measurement; manual check 16.4 is the
measurement, because if a package identity ever did appear the symptom would be the terminal hanging and
then reporting the WebView2 message after fifteen seconds, which reads like a broken runtime rather than
like packaging.