The intake workflow re-closes a reopened PR whose author is still over the
open-PR limit, so a maintainer cannot rescue PRs it auto-closed. When the
reopening actor has write, maintain or admin permission, skip the limit and
remove the "open PR limit" label instead. Contributor reopens behave as
before, and if the permission lookup fails the limit still applies.
The relinker job ran its 182 tests one at a time: 233 s on windows-latest, most of it Python tool tests. The full windows job already runs the same tests with --parallel 4.
Co-Authored-By: Claude <noreply@anthropic.com>
A change to build.yml ran the relinker, register-context and write-watch jobs whatever it touched. The patch's lines are now mapped to the job sections of the workflow at the head, and a test job runs only if its own section, the eligibility job or the shared part outside jobs changed; without a patch every job runs as before.
Co-Authored-By: Claude <noreply@anthropic.com>
Queue builds are workflow_dispatch runs on main and never saved their ccache,
so each one restored the last push build's entry and recompiled everything the
queued PRs and the merges since then touched (32 min vs 6 min warm). They now
save under their own prefix, restore it first and fall back to the push
entries; push builds still restore only push entries, so main never starts
from a tree that held unmerged PRs.
Co-Authored-By: Claude <noreply@anthropic.com>
Both jobs checked out without a ref, so a dispatched build compiled and
tested main instead of the selected pull requests, although the gate
starts them because a pull request touched their files. They now check
out the gate's main commit and merge the pull requests with the same
step as the relinker, Linux and Windows jobs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The segment-prefix-at-eof case from #6401 only catches the 1-byte read
past the input when the relinker is built with AddressSanitizer, and no
CI job did that. The new job builds the relinker alone in Debug with
ANYPS5_ENABLE_ASAN and runs the tls_function_coverage tests. It has to
be Debug: at -O3 GCC no longer emits the stray load, so a Release ASan
build passes with the fix reverted.
The cached tar held the 3rdparty work trees too, and its extraction fails on
the dangling symlink 3rdparty/zstd/tests/cli-tests/bin/unzstd, which Git Bash
tar can't create. Cache .git/modules alone and let git submodule update check
the work trees out from it, as a clean checkout does.
Co-Authored-By: Claude <noreply@anthropic.com>
Push builds of main ran one after another, so a merge waited for the
builds of every earlier merge before main got a result for its tree; a
fix of a red main sat behind a build of the tree it fixes. The newest
push now cancels the build in progress, like pull request and dispatched
builds already do. The merge queue's baselines already skip cancelled
main builds and use the nearest completed ones.
Co-Authored-By: Claude <noreply@anthropic.com>
A new select input of the Build workflow limits the Linux and Windows jobs
to the test executables and tests whose build inputs the merged pull
requests change. Push builds of main always build and run everything and
save the test graph of their tree; dispatched runs with select restore the
latest graph and fall back to a full run without one.
tools/select_tests.py dump walks the ninja graph of every test executable
(order-only dependencies included, so prx libraries loaded at run time are
in it) plus the header dependencies of its objects, the CMake files that
register each test, the source files its command line names, and its
fixtures. select picks the tests whose closure, registration or arguments
contain a changed file, and every test that is not a native executable of
the tree; files no build reads select the tests under their directory;
changes to the root build, cmake/, 3rdparty/, the workflow or the tool run
everything. Tests added since the graph was written always run. ctest gets
the selection as -I indices through the tool, which keeps the cmd shell on
Windows and stays under its command line limit.
Co-Authored-By: Claude <noreply@anthropic.com>
The runner cannot create directories under /var/cache/anyps5 (mkdir: Permission denied), so the install step failed
and the linux job built nothing.
Co-Authored-By: Claude <noreply@anthropic.com>
The self-hosted runners share one 32-thread host and were fixed at one job each, so
a build with many ccache misses compiled them one after another (686 misses took 37 min).
Pick jobs from the free CPUs and available memory (1 to 8, ctest at most 4) and pass a
load limit to ninja so a busy host backs off.
Co-Authored-By: Claude <noreply@anthropic.com>
Git for Windows 2.56 (runner image 20261002) moved from mingw64 to ucrt64,
so the fixed SSL_CERT_FILE path no longer exists and the WinLibs CMake
fails the FFmpeg download with status 60 on every Windows build. Take the
bundle from whichever of ucrt64 and mingw64 exists.
Co-Authored-By: Claude <noreply@anthropic.com>
The eligibility job enabled the relinker matrix for a pull request only
when repos.listCommits on main with the author's login returned a
commit. That filter misses authors whose commits in main are not
matched to their login. On 2026-10-13 it found no commit for 26 authors
of open pull requests who have 1 to 44 pull requests merged into main,
so their pull requests skip the relinker, against CONTRIBUTING.md ("if
its author already has a commit in main").
When listCommits finds nothing, the job now also searches for the
author's merged pull requests into main, with the query pr-intake.yml
uses. Incomplete search results count as none. A failed search, such as
the search API's own rate limit, skips the relinker with a warning
instead of failing the job. Both requests now run only when the pull
request changes a relinker file, so other pull requests make neither.
test_build_eligibility.py runs the step's script in node with a mocked
github object and skips when node is missing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pr_overlap.py links each conflicting range to main at the commit it ran
on, so every push to main changes every non-empty report. The workflow
keeps a hash of each report to read the comments of changed reports
only, but with the commit in the hash every report counts as changed:
each run reads the comments of every pull request with an overlap and
rewrites its comment although only the commit differs. In one hour on
2026-10-13 it rewrote 107 existing overlap comments, against the 1000
requests per hour GITHUB_TOKEN has for the repository.
The hash and the comparison with the posted comment now replace the
commit in blob links with a fixed ref, so a report whose ranges, exports
and files are unchanged makes no request. Posted comments keep their
links pinned to the commit they were written at.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A push to main ran every job: relinker on three hosts, register context
on four and write watch on two, next to the full Linux and Windows
builds. The eligibility gate now reads the files of the push (compare
before...after) and applies the same path rules as pull requests; when
it cannot (a first push, 300 or more files, an API error) every job runs
as before.
Whenever the full builds run (push and manual builds), the Linux and
Windows relinker jobs repeat tests the full builds already run: the
relinker-only ctest lists (150 and 145 tests) are subsets of the full
Linux and Windows ones (1052 and 1069) in run 38397922579. The relinker
matrix now keeps only macOS then; automatic pull request builds, which
have no full build, still run all three.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3rdparty/mbedtls (#3897) has its own framework submodule. The PR build
fetched it in its merge step, but push builds on main skipped that step
and failed at configure.
Co-Authored-By: Claude <noreply@anthropic.com>
build.yml runs git submodule update --init --recursive, but release.yml checked out only the top-level submodules. A submodule with its own submodules, such as Mbed TLS's framework in #3897, would leave the release configure step without them.
The area-labels workflow listed open PRs with -L 200, so with more than 200
open PRs the older ones never entered the todo list and never got their area
labels (#3295 changes libkernel and has no libkernel label). List up to 1000;
the head -n 40 cap still bounds labeler work per run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zyXkUzTZGh3nBwNMtrLaW
Stale conflicts runs actions/stale with only-pr-labels: needs rebase.
actions/stale skips any PR without all only-labels before it looks at
remove-pr-stale-when-updated, so after a rebase removes needs rebase the
PR is never processed again and keeps its stale label for good. A step
before actions/stale now removes stale from open PRs that no longer
carry needs rebase.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zyXkUzTZGh3nBwNMtrLaW
pr-intake runs once per opened PR, and each run lists every open PR by
the author. When an author opens several PRs within seconds, every run
sees all of them and closes its own, so a newcomer opening two PRs at
once loses both, and an author with one merge opening 21 loses all 21.
On opened events the limit now counts only lower-numbered PRs, so the
earliest ones stay open and only the PRs over the limit are closed.
Reopened events still count every open PR, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zyXkUzTZGh3nBwNMtrLaW
Build SDL's Wayland backend next to X11 and ask SDL for "wayland,x11"
on Linux, so the window runs natively under a Wayland compositor instead
of through XWayland. SDL loads libwayland, xkbcommon and libdecor at run
time, so systems without them, or sessions without WAYLAND_DISPLAY, keep
using X11. SDL_VIDEODRIVER still overrides the choice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #5263 the Linux job restores a lavapipe shader cache keyed by the
runner's /proc/cpuinfo flags. llvmpipe compiles shaders with LLVM's host
CPU *name* (from vendor, family and model) plus the detected feature bits,
and keys its cache only by the feature bits, so two runners with the same
flags but different models share cached code. A hull shader JIT-compiled
on a znver4/znver5 or Ice Lake class host uses GFNI (vgf2p8affineqb);
loaded on a Zen 3 host with the same flags it raises SIGILL, which is what
agc_driver_tessellation has been hitting on main and on dispatched builds
since the first main build after #5234 saved that hull variant.
Hash vendor_id, cpu family, model and flags into the key, so a runner only
restores code compiled for its own CPU model, and print the model name so a
future mismatch can be read off the log.
The cache from #5107 was keyed by Mesa version only, so a runner restored
llvmpipe code compiled on another runner's CPU and about 85 agc tests died
with SIGILL (Illegal instruction) on main.
Co-Authored-By: Claude <noreply@anthropic.com>