ci: a rebase ran every path-filtered workflow, because paths: matches the push delta #191

Merged
dcharlot merged 1 commit from ci/pr-diff-path-gate into main 2026-10-09 02:48:49 -04:00

2026-10-08

Transaction Science
ci: a rebase ran every path-filtered workflow, because paths: matches the push delta
All checks were successful
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 1h4m33s
standards workspaces build + test / aac-rs (pull_request) Successful in 15m41s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 5m23s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 4m7s
standards workspaces build + test / map-rs (pull_request) Successful in 5m41s
standards workspaces build + test / mesh-rs (pull_request) Successful in 2m16s
standards workspaces build + test / openpay (pull_request) Successful in 13m43s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m13s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m30s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m13s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m17s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m18s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m16s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m5s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m37s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 4s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m59s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 2m47s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m54s
wai-pack / wai-pack · linux (pull_request) Successful in 1m48s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 3m0s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 24s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 2m0s
wai-pack / wai-pack · macos (pull_request) Successful in 2m11s
Forgejo matches a workflow's `paths:` filter against the **push delta**, not the
pull request's diff. A rebase moves a branch across every commit main has
gained, so its delta touches nearly every path and every path-filtered workflow
fires.

Measured on this repo, as a clean natural experiment — five PRs, all changing
only `jcp/` or `mesh/`:

| PRs | how pushed | workflows triggered |
|---|---|---|
| #189, #190 | fresh branch, one push | **2** |
| #165, #177, #183 | force-push after rebase | **15** |

Fifteen includes JPEG-AI whole decode, `wai-pack` on three platforms, and
cross-architecture byte-equality on three — none of which a change to
`jcp/jcp-rs/crates/jcp-grant/src/checkpoint.rs` can affect. Rebasing three PRs
put the queue 65 runs deep behind one macOS runner, which delays everyone's real
jobs, and there is no way to rebase without it: a merge of main into the branch
has the same delta.

So the `paths:` filters still gate the *trigger*, and a new `relevant` job gates
the *work*, from the pull request's own diff. It reads the path list out of the
workflow file it guards, so there is one list rather than a third copy to drift
from the two `on:` blocks. On a push to main there is no pull-request context,
the shas are empty, and the gate answers `true` — main runs everything, as
before.

**It fails open, by construction.** A gate that decides whether tests run is
load-bearing in the dangerous direction: a wrong `false` silently skips a whole
workflow, which is the "passes but tested nothing" failure. Every way the script
can fail to decide — a missing workflow file, a filter it cannot parse, an empty
or unresolvable sha, too few arguments, an empty diff — prints `true`. The
self-test pins all six of those, both directions of the real decision, and that
`**` spans a path separator while `*` does not.

Writing that self-test caught one of its own cases: the single-star case first
created a top-level `.md` alongside the nested one, so the glob matched
legitimately and the case proved nothing. It now changes only the nested file,
and asserts separately that the glob does match at its own level — so it cannot
pass by never matching anything.

Applied to `wai-pack.yml` alone, not all eighteen. What a *skipped* job reports
as a commit status on this forge is the open question, and a required context
that never reports would make PRs unmergeable. That failure is at least loud
rather than silent, but it is worth learning on the most expensive workflow —
six job instances across three platforms — before changing the rest. Validated
against real branches first: every WAI workflow answers `false` for #165's
jcp-only diff and `true` for a WAI branch, and `standards-build.yml` correctly
answers `true` for #165 because it builds every workspace.

The hygiene workflow runs the self-test, so the gate cannot regress silently,
and its own `paths:` filter now lists the scripts it checks.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-08 11:40:23 -04:00