Psmux(fix[gates]): Prove the release gates on a real runner - #16
Merged
Conversation
why: The gates section named the runner and its labels but not how to get one, so the only path to a working release machine was reading release.yml and inferring it. The psmux job has no hosted fallback, so a missing or offline runner queues the job rather than failing it, which reads as a hung release. what: - Give the config.cmd invocation, including the label that makes runs-on match and the registration token's lifetime - State the machine's prerequisites, including the WSL side the smoke drives - Show the command that reports what GitHub actually sees
why: The psmux job never ran before, and its first run failed in setup-dotnet: global.json pins 10.0.302 with rollForward disabled, so the action installs that exact SDK rather than using what Windows has, and it defaults to C:\Program Files\dotnet. A self-hosted runner is an ordinary user account, so the install was denied and the gate failed before reaching any psmux code. what: - Point DOTNET_INSTALL_DIR at the runner tool cache for that step, which the runner account owns and which persists between runs
why: The re-pin changed the version, full commit, banner and hash but left the short-hash and date markers on aa26cd3 and 2026-08-17. Those markers are scanned in the binary itself, so LibTmux and the smoke harness would reject the very client the pin now names. Nothing local caught it: the marker scan only runs against a real psmux executable, which is Windows-only, so the first psmux gate run was the first time it executed. what: - Point the markers in PsmuxBinaryTrust and Invoke-PsmuxSmoke.ps1 at 66cf613 and 2026-08-18, which the published v3.3.8 client contains and the old one does not - Move the unit-test fixtures onto the same markers
why: The gate restores into a throwaway NuGet cache so the build proves it needs nothing already on the machine, which verify_workflows enforces by requiring the isolation before the solution restore. On a self-hosted Windows runner that cold restore is far slower than the hosted equivalent and ran past the 45 minute limit while still making progress. what: - Raise the psmux job timeout to 90 minutes and say why the restore is cold
why: The harness passes three shell scripts to /bin/sh inside WSL. git checks this file out with CRLF wherever core.autocrlf is on, which is the default on Windows, so the first line arrived as 'case ... in' followed by a carriage return and dash rejected it with 'word unexpected (expecting in)'. The gate failed on the checkout's line endings rather than on anything the harness or psmux did. what: - Normalise the three WSL scripts to LF where they are defined, so they are correct by construction rather than by how the checkout landed
why: The smoke exercises both target frameworks, but global.json pins only the 10.x SDK, so an isolated install directory holds no .NET 8 runtime and the native Windows lane died with framework 'Microsoft.NETCore.App' version '8.0.0' not found. A hosted image hides this by shipping .NET 8 already. what: - Install the 8.0 runtime into the same directory, so the job carries both frameworks it runs rather than inheriting one from the machine
why: The smoke asserted the literal 3.3.7 while the pin had moved to 3.3.8, so the gate failed against the client it is supposed to accept. This is the third copy of the pin the re-pin missed, and each one was invisible until a real psmux ran: this class only executes against a live client, so no Linux lane ever reached the assertion. what: - Assert PsmuxCompatibility.SupportedVersion, so the check moves with the pin instead of being another value to remember
why: A failed leg said only 'Native Windows .NET smoke exited 1.' A test runner writes the failing assertion to stdout and leaves stderr empty, and the harness kept stdout in a buffer it never showed, so the one place this gate runs is the one place its output was discarded. Diagnosing it needed a patched copy of the harness. what: - Fall back to a bounded tail of stdout when stderr carries no detail - Pass the captured output at every leg that already passed its error
why: Standing the runner up failed three times on machine setup rather than on psmux, and each was something a hosted runner supplies: PowerShell 7, a writable place for the pinned SDK, and the .NET 8 runtime the smoke also runs on. A reader provisioning a machine should not have to rediscover any of them from a red gate. what: - Require pwsh explicitly and give the install command - Say a Windows dotnet is not needed, because the job installs the pinned SDK into its own tool cache - Say the listener reads its environment once, so it needs a restart after a PATH change
tony
force-pushed
the
psmux-release-gates
branch
from
August 22, 2026 19:46
3b2d0a0 to
13bd82c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proves the two release gates that had never executed, and fixes seven defects that only a real Windows runner could surface.
Banner
psmux.exe -Vfrom the publishedv3.3.8asset prints exactly whatPsmuxCompatibilitypins:Previously derived from the binary's embedded strings and psmux's
print_version()rather than executed.Runner
A
[self-hosted, Windows, X64, psmux]runner is registered and online, withPSMUX_WSL_DISTRIBUTIONandPSMUX_WSL_DOTNET_PATHset.CONTRIBUTING.mdnow says how to provision one, including the prerequisites these runs uncovered.What the gate found
The
psmuxjob had never run. Each failure below was invisible to the Linux lanes:aa26cd3/2026-08-173.3.7dashwith CRLFcore.autocrlfis a Windows-only defaultC:\Program Files\dotnetVerification
release.ymlwas dispatched against this branch with a temporary commit that letvalidatedry-run and skippedpublish. The final run was green acrossvalidate,published psmux artifact,full dotnet gate / gate,supported tmux matrix / compatibilityandpsmux native Windows and WSL, withpublishskipped. That commit has been rebased out; this branch contains no dry-run guards.