A monorepo pipeline that runs every job on every push spends most of its minutes proving that unchanged code still works.
on:
push:
paths:
- 'src/**'
- 'composer.lock'
- '.github/workflows/test.yml'
# and the trap: a REQUIRED check that is skipped counts as
# neither passed nor failed, and blocks the merge forever.
The required-check interaction is the part that costs an afternoon. A skipped job reports no status, and a branch protection rule requiring it waits indefinitely — so path filtering and required checks do not compose. The workaround in 2020 is a second job with the same name that runs unconditionally and succeeds immediately when the paths did not match, which is ugly and is the only thing that works.