Skip to content

Stabilize the real-Windows (MSYS2) CI job: green build + gating - #19

Merged
connollydavid merged 6 commits into
mainfrom
claude/native-windows-ci
Jun 12, 2026
Merged

Stabilize the real-Windows (MSYS2) CI job: green build + gating#19
connollydavid merged 6 commits into
mainfrom
claude/native-windows-ci

Conversation

@connollydavid

Copy link
Copy Markdown
Owner

Stabilize the real-Windows CI job (#38)

The windows-native parity job (MSYS2 MINGW32 → builds the i386 PEs natively and runs them on a real Windows runner, so exec/Winsock/ConPTY exercise real cmd.exe/Winsock/ConPTY rather than Wine) had been permanently red and informational. It died at the RC/manifest step. This makes it build and pass the full suite green, then flips it to gating.

Each fix was diagnosed from the actual CI error, not a guess:

  1. Manifest from a prebuilt .res (no windres preprocessor). MSYS2's windres (binutils 2.46) cannot spawn a preprocessor to compile the .rc — even a full-path .exe gives CreateProcess failed: The system cannot find the file specified. Ship the manifest as a prebuilt, byte-deterministic src/mcp-w32s.res; compiling .res → coff needs no preprocessor, so the same manifest bakes into every binary on every runner. A new Ubuntu CI step regenerates the .res from .rc + .manifest and byte-diffs it, so the committed artifact can't drift. (MSVC keeps rc.exe on the .rc.)
  2. Full-path windres via find_program. The .res→coff custom command runs via cmd.exe, where the bare i686-w64-mingw32-windres is "not recognized"; find_program (at configure, in the MSYS2 PATH) resolves the full path cmd.exe can spawn.
  3. Unprefixed objdump. MSYS2 MINGW32 ships binutils unprefixed; the native job's import check used the cross-prefixed name (command not found).
  4. Host-robust shell-builtin tests. shell_builtin_is_shell / shell_dir_routing assumed bare dir has no .exe and spawn-fails — false where coreutils ships dir.exe (MSYS2 /usr/bin), so the device correctly classified it as a real PE. Switched the subject to ver (a cmd built-in with no .exe on any host), so the "unresolvable bare name → shell built-in" path is exercised deterministically across the dev host, Wine, and real Windows.

Result: the native job builds, the binary is import-clean ({kernel32, user32} only — the native toolchain also hits the Win32s floor), and the full exec/Winsock/ConPTY suite passes on real Windows. continue-on-error dropped so its result counts (add it to branch-protection required checks to make it a hard merge gate). No device-behaviour or spec change — pure CI/build/test infra; the Ubuntu suite stays green.

🤖 Generated with Claude Code

connollydavid and others added 6 commits June 12, 2026 17:00
…-path preprocessor

The native-Windows parity job (MSYS2 MINGW32, real cmd.exe/Winsock/ConPTY) died
at the RC step: its windres (binutils 2.46) fails to spawn a bare-named
preprocessor ('CreateProcess failed: The system cannot find the file
specified'). Rather than skip the manifest there (which would build a different
binary than ships and weaken the parity), drive windres with the FULL resolved
path to the C compiler CMake already verified - which spawns reliably on every
host. The RT_MANIFEST now bakes into the SAME binary on the Ubuntu cross build
and the native-Windows build alike. The .rc is self-contained (expands only its
own two #defines, no system include), so any cpp suffices; this only makes the
spawn reliable. Verified locally: windres uses the full path and wrestool shows
one type-24 manifest. Supersedes the toolchain's bare-name Windows-only override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s no windres preprocessor

The MSYS2 native-Windows parity job's windres (binutils 2.46) cannot spawn a
preprocessor to compile the .rc - even a full-path .exe gives 'CreateProcess
failed: The system cannot find the file specified'. Ship the manifest as a
prebuilt, byte-deterministic src/mcp-w32s.res instead: compiling .res -> coff
needs NO preprocessor, so it builds identically on the Ubuntu cross host and the
native-Windows runner - the SAME manifest in every binary (no runner-specific
divergence). MSVC keeps rc.exe on the .rc. A new Ubuntu CI step regenerates the
.res from the .rc + .manifest (where the cross preprocessor works) and byte-
diffs it, so the committed artifact can never drift from source. Verified
locally: res->coff runs without --preprocessor, the exe carries one RT_MANIFEST,
imports stay {kernel32,user32}.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The res->coff custom command runs via cmd.exe on the MSYS2 native runner, where
a bare 'i686-w64-mingw32-windres' is 'not recognized' - CMake resolves the RC
compiler internally for its own RC rule, but ${CMAKE_RC_COMPILER} stays the bare
toolchain name. find_program (run at configure time in the MSYS2 PATH) yields the
full path cmd.exe can spawn. Verified locally: MCP_WINDRES resolves to the full
path, the custom command uses it, the manifest is present.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ips unprefixed binutils)

The native runner got past the build (prebuilt .res) but the import check died
with 'i686-w64-mingw32-objdump: command not found' (exit 127): MSYS2 MINGW32
provides binutils UNPREFIXED (objdump/windres/nm), not under the cross prefix
that exists on the Ubuntu host. Use plain objdump on the native job (it is the
i686 one in /mingw32/bin). The Ubuntu job keeps the cross-prefixed name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…subject)

shell_builtin_is_shell + shell_dir_routing assumed a bare 'dir' has no .exe on
PATH and spawn-fails. That is false on runners that ship a coreutils dir.exe
(MSYS2 /usr/bin on the native-Windows CI), where the device CORRECTLY resolves
and classifies dir as a real PE - so the assertions failed there even though the
device behaved right. Switch the subject to 'ver', a cmd built-in with no .exe
equivalent on any host, so the 'unresolvable bare name -> shell built-in' path
is exercised deterministically across the dev host, Wine, and real Windows.
test_binfmt verified green; test_exec_ops is spawn-based (CI-verified, not the
interop-down local wine).
…is green

The native-Windows parity job builds and runs the full exec/Winsock/ConPTY suite
green on real Windows (manifest from a prebuilt .res, unprefixed objdump,
host-robust shell-builtin subject). Drop continue-on-error so its result counts
toward the run conclusion. (A hard merge gate also needs it added to the
branch-protection required checks.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@connollydavid connollydavid changed the title Stabilize the real-Windows CI job: green + gating (#38) Stabilize the real-Windows (MSYS2) CI job: green build + gating Jun 12, 2026
@connollydavid
connollydavid merged commit 07fa852 into main Jun 12, 2026
8 checks passed
@connollydavid
connollydavid deleted the claude/native-windows-ci branch June 12, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant