feat(settings): new builds follow the launcher's channel until the player picks one #14

Merged
HumanBean merged 1 commit from HumanBean/LongshotLauncher:feat/build-channel-follows-launcher into main 2026-11-13 06:49:49 +00:00
Owner

Why

A nightly launcher starts new builds on stable, which has no Longshot release yet, so its home says the version to build is not known and Build stays off. settings.json saved the old default, "stable", for every player, so there was no way to tell a pick from the default.

What changed

  • settings: LauncherSettings.DefaultChannel (Core/LauncherSettings.cs) is now null until the player picks a channel in Settings. BuildChannel(ownTag) gives the channel new builds start on: the pick, else the launcher's own channel (SelfUpdate.ChannelOf: LauncherChannel when set, else Versions.TrackOf(<launcher version>, LauncherFirstMajor)). A nightly launcher builds nightlies, an rc launcher release candidates, a stable one (and a build from a checkout) stable.
  • migration: settings.json format 2. Load reads a format-1 file's "defaultChannel": "stable" as no pick, once (format 1 wrote that for everyone); "rc" or "nightly" there was a pick and stays. A format bump rather than a defaultChannelChosen flag: no second field to keep in step with the first forever, and null already means "not picked". The one case it gets wrong, a player who really picked stable under format 1, is the same as the old default and still builds stable on a stable launcher.
  • app: LauncherService.DefaultChannel is that channel; the home's Build and "Change", the channel picker and Settings use it (HomeViewModel, ChannelPickerViewModel, SettingsViewModel). The picker's row and Settings' hint for it add "It follows the launcher until you pick one in Settings." while nothing is picked. Changing Launcher updates moves it along. The picker still picks for one build only and saves nothing, as before.
  • README: Channel for new builds says it follows the launcher's channel until you pick one.
  • tests: SettingsChecks in tests/launcher_core/Program.cs: each launcher track (stable, rc, nightly, dev), LauncherChannel, a pick that sticks after a save and load, no pick saved as null, and the migration of a format-1 file (stable read as no pick, rc kept).

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
settings.json defaultChannel the channel new builds start on; null follows the launcher null (follows the launcher) keep nightly and rc launchers - Windows

Measurements

main: 968b7963 (2026-11-13)
this PR: feat/build-channel-follows-launcher @ 497d5399
Hardware: Linux (CachyOS), sway on Wayland
Scene: the launcher's empty home, a copy of a real settings.json (format: 1, defaultChannel: "stable", launcherChannel: null)
Method: each side built Release with -p:LongshotTag=nightly-8-3b243d73 and started with its own HOME holding the copy; the home's channel read off the window. Tests: python -I tests/test_launcher_core.py and python -I tests/test_release.py
How to reproduce: dotnet build App -c Release -p:LongshotTag=nightly-8-3b243d73 -o out, then start out/LongshotLauncher with HOME pointing at a folder whose .local/share/longshot/launcher/settings.json is a format-1 file with "defaultChannel": "stable"

main @ 968b7963 this PR @ 497d5399
channel new builds start on (nightly launcher, old settings.json) stable (none released: Build off) nightly (Nightly 34 · 545618fc)
launcher core checks 526 passed 536 passed
release tests 19 OK 19 OK

Testing

Tested: Release build with warnings as errors; the launcher core checks and release tests (above). The real launcher on sway (Wayland, 1.5 scale, headless output): main and this PR, both stamped nightly-8-3b243d73, on a copy of a format-1 settings.json; the home and the channel picker (screenshots).

Not tested: Windows (the change is in shared code and view models, nothing platform-specific); the Settings page itself on screen (its hint uses the same text as the picker).

Needs other testers:

  • Windows: an rc or nightly launcher with an old settings.json starts new builds on its own channel, expecting the home's tag to show rc or nightly (request to open)

Screenshots

main @ 968b7963, a nightly launcher with an old settings.json: stable, nothing to build

main @ 968b7963

this PR @ 497d5399: nightly

this PR @ 497d5399

this PR @ 497d5399: the picker

this PR @ 497d5399, the picker

Risk and rollback

A player who had picked stable under format 1 gets the launcher's channel once (only on an rc or nightly launcher); picking stable again in Settings sticks. Reverting the commit is enough: format 1 reads a null channel as stable.

Reviewer notes

HomeViewModel changes in four lines only (Service.Settings.DefaultChannel to Service.DefaultChannel), to stay clear of the busy-states work.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • Screenshots for a change that shows on screen.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.
## Why A nightly launcher starts new builds on stable, which has no Longshot release yet, so its home says the version to build is not known and Build stays off. settings.json saved the old default, `"stable"`, for every player, so there was no way to tell a pick from the default. ## What changed - settings: `LauncherSettings.DefaultChannel` (`Core/LauncherSettings.cs`) is now null until the player picks a channel in Settings. `BuildChannel(ownTag)` gives the channel new builds start on: the pick, else the launcher's own channel (`SelfUpdate.ChannelOf`: `LauncherChannel` when set, else `Versions.TrackOf(<launcher version>, LauncherFirstMajor)`). A nightly launcher builds nightlies, an rc launcher release candidates, a stable one (and a build from a checkout) stable. - migration: settings.json format 2. `Load` reads a format-1 file's `"defaultChannel": "stable"` as no pick, once (format 1 wrote that for everyone); `"rc"` or `"nightly"` there was a pick and stays. A format bump rather than a `defaultChannelChosen` flag: no second field to keep in step with the first forever, and null already means "not picked". The one case it gets wrong, a player who really picked stable under format 1, is the same as the old default and still builds stable on a stable launcher. - app: `LauncherService.DefaultChannel` is that channel; the home's Build and "Change", the channel picker and Settings use it (`HomeViewModel`, `ChannelPickerViewModel`, `SettingsViewModel`). The picker's row and Settings' hint for it add "It follows the launcher until you pick one in Settings." while nothing is picked. Changing *Launcher updates* moves it along. The picker still picks for one build only and saves nothing, as before. - README: *Channel for new builds* says it follows the launcher's channel until you pick one. - tests: `SettingsChecks` in `tests/launcher_core/Program.cs`: each launcher track (stable, rc, nightly, dev), `LauncherChannel`, a pick that sticks after a save and load, no pick saved as null, and the migration of a format-1 file (stable read as no pick, rc kept). ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | settings.json `defaultChannel` | the channel new builds start on; null follows the launcher | null (follows the launcher) | keep | nightly and rc launchers | - | Windows | ## Measurements main: 968b7963 (2026-11-13) this PR: feat/build-channel-follows-launcher @ 497d5399 Hardware: Linux (CachyOS), sway on Wayland Scene: the launcher's empty home, a copy of a real settings.json (`format: 1`, `defaultChannel: "stable"`, `launcherChannel: null`) Method: each side built Release with `-p:LongshotTag=nightly-8-3b243d73` and started with its own HOME holding the copy; the home's channel read off the window. Tests: `python -I tests/test_launcher_core.py` and `python -I tests/test_release.py` How to reproduce: `dotnet build App -c Release -p:LongshotTag=nightly-8-3b243d73 -o out`, then start `out/LongshotLauncher` with `HOME` pointing at a folder whose `.local/share/longshot/launcher/settings.json` is a format-1 file with `"defaultChannel": "stable"` | | main @ 968b7963 | this PR @ 497d5399 | |---|---|---| | channel new builds start on (nightly launcher, old settings.json) | stable (none released: Build off) | nightly (Nightly 34 · 545618fc) | | launcher core checks | 526 passed | 536 passed | | release tests | 19 OK | 19 OK | ## Testing **Tested:** Release build with warnings as errors; the launcher core checks and release tests (above). The real launcher on sway (Wayland, 1.5 scale, headless output): main and this PR, both stamped nightly-8-3b243d73, on a copy of a format-1 settings.json; the home and the channel picker (screenshots). **Not tested:** Windows (the change is in shared code and view models, nothing platform-specific); the Settings page itself on screen (its hint uses the same text as the picker). **Needs other testers:** - Windows: an rc or nightly launcher with an old settings.json starts new builds on its own channel, expecting the home's tag to show rc or nightly (request to open) ## Screenshots main @ 968b7963, a nightly launcher with an old settings.json: stable, nothing to build ![main @ 968b7963](https://git.magicbean.dev/HumanBean/LongshotLauncher/raw/branch/pr-assets-channel-follow/home-before.png) this PR @ 497d5399: nightly ![this PR @ 497d5399](https://git.magicbean.dev/HumanBean/LongshotLauncher/raw/branch/pr-assets-channel-follow/home-after.png) this PR @ 497d5399: the picker ![this PR @ 497d5399, the picker](https://git.magicbean.dev/HumanBean/LongshotLauncher/raw/branch/pr-assets-channel-follow/picker-after.png) ## Risk and rollback A player who had picked stable under format 1 gets the launcher's channel once (only on an rc or nightly launcher); picking stable again in Settings sticks. Reverting the commit is enough: format 1 reads a null channel as stable. ## Reviewer notes `HomeViewModel` changes in four lines only (`Service.Settings.DefaultChannel` to `Service.DefaultChannel`), to stay clear of the busy-states work. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] Screenshots for a change that shows on screen. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated.
feat(settings): new builds follow the launcher's channel until the player picks one
All checks were successful
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 7s
497d539943
A nightly launcher started new builds on stable, which has no Longshot release yet, because settings.json saved
"stable" for everyone. The channel for new builds is now null until the player picks one in Settings, and then it
follows the launcher's own channel (LauncherChannel, else its version's track). settings.json format 2: a format-1
file's "stable" was the old default, so it is read as no pick; another channel there was a pick and stays.
HumanBean deleted branch feat/build-channel-follows-launcher 2026-11-13 06:49:49 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/LongshotLauncher!14
No description provided.