Skip to content

ci: run the suite on windows-latest - #272

Merged
slowdini merged 4 commits into
devfrom
ci/windows-job
Aug 15, 2026
Merged

ci: run the suite on windows-latest#272
slowdini merged 4 commits into
devfrom
ci/windows-job

Conversation

@slowdini

Copy link
Copy Markdown
Owner

Closes #249.

Both CI jobs ran on ubuntu-latest while releases attach a Windows binary, so every Windows fix in
#250, #251, #267, #268, #269 and #271 was found by hand rather than by the pipeline. This adds the
job that would have caught them.

The job caught one before it ever reached a runner

Installing jq locally to exercise the three judge_recipe_* tests — which had never executed on
any host, here or on the #267 branch — turned them red rather than green, and not for a test-shaped
reason. jq's native Windows build opens stdout in text mode, so every \n it writes arrives as
\r\n. Both shipped recipes read that output as paths, and neither reader drops the carriage
return: read -r keeps it by definition, and tr '\n' '\0' converts only the newline.

So the CR rides on the end of every path. The judge recipe reports 0/2 verdicts present where it
should say 1/2, and the parallel-dispatch recipe hands every task a corrupted eval_root,
dispatch_prompt_path and outputs_dir. This is on the setup POSIX_TOOLING_REQUIREMENT
documents — Git Bash with jq — and it is in 0.9.0.

The fix is | tr -d '\r' after each of the four jq calls: a no-op wherever jq already writes LF, and
tr is already declared alongside jq. Its regression test defines a CRLF-emitting jq as a shell
function in front of the recipe rather than shimming PATH, so the Ubuntu runner covers the Windows
failure mode too, and no executable bit has to be set for it to work.

The job itself

The matrix runs fail-fast: false, since a Linux failure cancelling the Windows leg would lose the
result exactly when it is worth having. Clippy earns its place on both hosts — the #[cfg(windows)]
arms in core::fs and command_check are lint-invisible on Ubuntu.

EVAL_MAGIC_REQUIRE_POSIX_TOOLS applies to both runners, so Windows is provisioned for the gated
capabilities rather than exempted from them: choco install jq, which Git for Windows does not
bundle, and Developer Mode for symlink creation. Two deliberate non-actions: LongPathsEnabled
stays unset, because those tests are only meaningful while they pass on a default box, and
EVAL_MAGIC_SH stays unset so the run exercises the Git install-root discovery a Windows user
actually hits.

Verification

cargo fmt --check, cargo test --all-targets and cargo clippy --all-targets -- -D warnings all
pass on Windows 11 (1138 tests, 0 failures). Separately, under EVAL_MAGIC_REQUIRE_POSIX_TOOLS=1 so
a skip becomes a failure: the three judge_recipe_* tests pass with real jq, and the three
task_repository_* long-path tests pass with no provisioning, confirming #271's verbatim-path
reasoning on a real Windows host rather than inferring it.

Two things only the first run can settle: whether the runner's token permits symlink creation, and
whether sh resolves through the Git install root.

Needs a repo-settings change to merge

The ruleset requires a status check named Test suite. The matrix renames it to
Test suite (ubuntu-latest) / Test suite (windows-latest), so the contexts have to be updated or
this PR — and every one after it — blocks on a check that no longer reports.

🤖 Generated with Claude Code

slowdini and others added 3 commits August 15, 2026 02:36
jq's native Windows build opens stdout in text mode, so every `\n` it
writes arrives as `\r\n`. Both shipped recipes read that output as paths,
and neither reader drops the CR: `read -r` keeps it by definition, and
`tr '\n' '\0'` converts only the newline.

The carriage return then rides on the end of every path. The judge recipe
reports `0/N verdicts present` because `[ -s "$response_path" ]` matches
nothing, and the parallel-dispatch recipe hands every task a corrupted
`eval_root`, `dispatch_prompt_path`, and `outputs_dir`. Git Bash with `jq`
is the setup the tooling requirement documents, so this is the supported
Windows path rather than an exotic one.

Pipe each jq call through `tr -d '\r'`: a no-op wherever jq already writes
LF, and `tr` is a declared requirement alongside `jq` itself.

The regression test defines a CRLF-emitting `jq` as a shell function in
front of the recipe rather than shimming `PATH`, so the failure mode is
covered on every host instead of only where a Windows jq is installed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Releases attach a Windows binary and the README documents a PowerShell
installer, but both jobs ran on ubuntu-latest, so every Windows fix so far
was found by hand rather than by the pipeline.

Matrix the test job across ubuntu-latest and windows-latest with
`fail-fast: false`, since a Linux failure cancelling the Windows leg would
lose the result exactly when it is worth having. Clippy earns its place on
both: the `#[cfg(windows)]` arms in `core::fs` and `command_check` are
lint-invisible on Ubuntu.

`EVAL_MAGIC_REQUIRE_POSIX_TOOLS` applies to both runners, so the Windows
host is provisioned for the gated capabilities rather than exempted from
them: `jq`, which Git for Windows does not bundle, and Developer Mode for
symlink creation. Long paths need nothing — task repositories carry their
own `core.longpaths`, and `LongPathsEnabled` stays unset deliberately so
those tests keep proving what a default box does. `EVAL_MAGIC_SH` stays
unset for the same reason: discovering the shell from the Git install root
is what a Windows user hits.

The guard test pins all of it together, because a matrix entry whose
enforcement variable went missing would report green while covering six
fewer tests than it appears to.

Also corrects both contributor docs, which still described two gated
capabilities before long-path staging became the third.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The long-path tests padded from `std::env::temp_dir()`, which can hand back
an 8.3 short name: a GitHub runner's `%TEMP%` lives under `RUNNER~1`, while
git expands that to `runneradmin` before it measures. Three characters no
length computed here could see.

That was enough to move the deepest test from one side of a ceiling to the
other. It passed locally with `.git/config` at 257 and failed on the runner
with the same target at 260, which reads as a Windows-only product failure
and is nothing of the sort.

Canonicalise the base first, so the padding measures the spelling git will
report. Then step the root back to 244 and assert the window it has to sit
in, because git's long-path awareness turns out to be per-operation:
creating `.git/objects/pack` survives well past the budget, `git init`
writing `.git/config` stops exactly at it, and the `git config --local`
that follows gives up two characters earlier still. The old literal sat one
character inside the tightest of those, with nothing recording that it did.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@slowdini
slowdini merged commit ed3afbd into dev Aug 15, 2026
8 checks passed
@slowdini
slowdini deleted the ci/windows-job branch August 15, 2026 20:10
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.

CI: add a Windows job

1 participant