Skip to content

fix(ci): the docs-only skip has never worked — negations need predicate-quantifier: every - #418

Merged
doublegate merged 1 commit into
mainfrom
fix/v2.3.9-paths-filter-quantifier
Aug 19, 2026
Merged

fix(ci): the docs-only skip has never worked — negations need predicate-quantifier: every#418
doublegate merged 1 commit into
mainfrom
fix/v2.3.9-paths-filter-quantifier

Conversation

@doublegate

Copy link
Copy Markdown
Owner

Found while diagnosing why two documentation-only PRs were failing an ARM cross-compile.

The docs-only skip has never worked

dorny/paths-filter's predicate-quantifier defaults to some, which includes a file if it matches any pattern in the filter. The code filter is '**' followed by seven exclusions — so '**' matches everything and every ! line under it has been dead since the filter was written. The action's README says it outright: under some, negation syntax is ineffective.

Proven from a run, not from the docs. #416 changed exactly one file, and the filter job's own log reads:

[modified] AGENTS.md
Filter code = true
Matching files: AGENTS.md [modified]

A markdown file matched a filter whose entire purpose is to exclude markdown.

So every documentation PR in this repository's history has run the full code matrix — fmt/clippy/rustdoc, wasm32, no_std, and all four ARM cross-compiles. Today that stopped being merely wasteful: #414 and #416 were both blocked by a flaky apt provision, for jobs that should never have been scheduled.

Why two steps and not one flag

predicate-quantifier is a step-level input, and the two filters need opposite settings:

filter shape needs
code one positive pattern + seven exclusions every — otherwise '**' alone satisfies it
accuracy eight alternative trees the default some — a file lives in one of them, never in all eight

Setting every on a shared step would make accuracy unsatisfiable and silently disable the accuracy battery at review time — the gate A5 exists to add, turned off by the fix for a different gate. Sharing one step is how this bug arrived; one quantifier cannot serve both.

Verification, and what is not yet verified

Asymmetric, and worth stating plainly rather than implying both halves are done:

actionlint clean; the step wiring (filter-codecode, filter-accuracyaccuracy, no stale steps.filter. references) checked by parsing the workflow rather than by reading it.

Relationship to #417

Independent defects, same symptom. #417 fixes the provisioning that failed; this fixes the reason docs PRs were exposed to it at all. Either alone leaves the other standing.

Copilot AI lite review requested due to automatic review settings August 19, 2026 20:18
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f874e2bf-2f7b-49ac-95ac-38cef1fce553


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the CI “changes” detection logic so documentation-only pull requests can correctly skip the heavier code/ARM matrix, by separating dorny/paths-filter invocations and using the appropriate quantifier for negated patterns. It also updates ARM cross-compile provisioning to install only the needed glibc header packages and adjusts the bounded apt retry wrapper.

Changes:

  • Split dorny/paths-filter into two steps and set predicate-quantifier: every for the code filter while keeping the default quantifier for the accuracy filter.
  • Update ARM cross-compile provisioning to install libc6-dev-*-cross header packages instead of full cross toolchains.
  • Rework .github/scripts/apt-install-retry.sh to skip apt-get update on the first attempt and to use --no-install-recommends with updated timeouts.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
.github/workflows/ci.yml Splits change-detection filters and updates ARM provisioning package selection.
.github/scripts/apt-install-retry.sh Adjusts retry/update strategy and install flags/timeouts for bounded apt provisioning.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/workflows/ci.yml
@doublegate

Copy link
Copy Markdown
Owner Author

The half I said was unproven is now proven

The PR body stated plainly that the bug was demonstrated but the fix was not, since this PR touches ci.yml and so cannot itself produce a skip. Here is the missing half, run against picomatch 4.0.5 — the matcher dorny/paths-filter uses — with the code filter's pattern list taken verbatim from ci.yml:

file some (today) every (this PR)
AGENTS.md true false
CHANGELOG.md true false
to-dos/plans/v2.3.9-crucible-plan.md true false
docs/ram-atlas.md true false
notes.txt true false
screenshots/a.png true false
LICENSE-MIT true false
NOTICE true false
.gitignore true false
.codegraph/db.sqlite true false
crates/rustynes-ppu/src/ppu.rs true true
.github/workflows/ci.yml true true
Cargo.toml true true
tests/roms/foo.nes true true

Under some, the code filter is a constant true — all fourteen files match, every exclusion is dead, and the entire seven-line negation list has never had any effect. Under every, all ten excluded paths drop out and all four genuine code paths survive.

Why this is credible rather than just a model

It reproduces the real defect exactly. AGENTS.mdtrue under some is precisely what #416's filter job logged (Filter code = true / Matching files: AGENTS.md). A model that reproduces the observed failure and then predicts the fix is the strongest evidence available short of a merged run.

What it is not: it models how the action combines per-pattern matchers under each quantifier, not the action's source. The remaining verification is unchanged and still worth doing — rebase a docs-only PR (#414 or #416) onto this after it merges and confirm code = false in the filter log.

@doublegate
doublegate force-pushed the fix/v2.3.9-paths-filter-quantifier branch 2 times, most recently from 12eb200 to 14442f5 Compare August 19, 2026 21:33
`dorny/paths-filter`'s `predicate-quantifier` defaults to `some`, which
includes a file if it matches ANY pattern in the filter. The `code`
filter is `'**'` followed by seven exclusions, so `'**'` matches
everything and every `!` line under it has been dead since the filter was
written. The action's README states it outright: under `some`, negation
syntax is ineffective.

Proven from a run, not from the docs. PR #416 changed exactly one file,
`AGENTS.md`, and the filter job's log reads:

  [modified] AGENTS.md
  Filter code = true
  Matching files: AGENTS.md [modified]

A markdown file matched a filter whose whole purpose is to exclude
markdown. Every documentation PR in this repository's history has
therefore run the full code matrix -- fmt/clippy/rustdoc, wasm32, no_std
and all four ARM cross-compiles -- and today two docs-only PRs (#414,
#416) were blocked by a flaky apt provision for jobs that should never
have been scheduled at all.

Fixed with TWO filter steps rather than one, because
`predicate-quantifier` is a step-level input and the two filters need
opposite settings. `code` is one positive pattern plus exclusions, so it
needs `every`. `accuracy` must keep the default: its eight patterns are
ALTERNATIVES -- a file lives in one of those trees, never in all eight --
so `every` would make it unsatisfiable and silently disable the accuracy
battery at review time, which is the gate A5 exists to add. Putting both
filters in one step is exactly how the bug got here, and one quantifier
cannot serve both.

Verification is asymmetric and worth stating plainly. That the bug exists
is proven by the log above. That the fix works is NOT yet proven: this PR
touches `.github/workflows/ci.yml`, so it is correctly a code change and
cannot demonstrate a skip. The demonstration is rebasing a docs-only PR
onto this and observing `code = false` -- #414 and #416 are both
available and both currently show the opposite.
@doublegate
doublegate force-pushed the fix/v2.3.9-paths-filter-quantifier branch from 14442f5 to 612ad8f Compare August 19, 2026 21:55
@github-actions

Copy link
Copy Markdown

Antigravity review (Gemini via Ultra)

This PR splits the CI path filtering into two distinct steps with different predicate quantifiers to correctly implement the docs-only skip.

Blocking issues

None found.

Suggestions

Nitpicks

  • .github/workflows/ci.yml (lines 126-135): Avoid using all-caps for emphasis (TWO, ANY, NEVER); standard casing is preferred for a professional tone.

Automated first-pass review by agy on a self-hosted runner -- not a human review.

@doublegate

Copy link
Copy Markdown
Owner Author

Antigravity review — no blocking issues. Both points declined, one on the project rule and one on the file's own convention.

Comment history. Answered on #412/#415: AGENTS.md carries an explicit, opposite rule ("Comprehensive rustdoc + comments (project rule)... explain the why"), and a repo-level instruction outranks a generic default. The specific reason it applies here: the historical context is the why. "Use every" reads as a preference until you know that under some this filter was a constant true and that a markdown-only PR logged Filter code = true / Matching files: AGENTS.md. Without the evidence, the next person to add a filter puts it back in the shared step and the docs-only skip breaks again silently — which is precisely how it broke the first time.

All-caps emphasis. Declined as a matter of matching the file. ci.yml on main already uses that form in 18 comment lines (NOT, ALWAYS, NEVER, ONLY, FULL, SAME) — it is the established way this workflow flags a load-bearing word, and markdown emphasis is not available in YAML comments. Changing it here would make this block the odd one out.

Both are style calls rather than correctness ones, and I would rather be consistent with the surrounding file than with a general guideline it does not follow.

@doublegate
doublegate merged commit 46e9e00 into main Aug 19, 2026
25 checks passed
@doublegate
doublegate deleted the fix/v2.3.9-paths-filter-quantifier branch August 19, 2026 22:13
@doublegate

Copy link
Copy Markdown
Owner Author

The remaining verification is done — proven on a real PR

The PR body said the bug was demonstrated but the fix was not, and that the confirmation would be "rebase a docs-only PR onto this and observe code = false". #416 changes exactly one file, AGENTS.md. Rebased onto this after merge, its detect code changes job now logs:

[modified] AGENTS.md
Detected 1 changed files
Filter code = false
Matching files: none
Changes output set to []

Compare the same PR before the fix:

[modified] AGENTS.md
Filter code = true
Matching files: AGENTS.md [modified]

Same file, same filter list, opposite verdict.

What that changes for a docs PR

#416's check rollup, before → after:

job before after
fmt + clippy + rustdoc ran SKIPPED
wasm32 build + clippy ran SKIPPED
no_std build (thumbv7em-none-eabihf) ran SKIPPED
libretro cross-compile ×4 ran (and failed twice on the apt mirror) SKIPPED
test (matrix) / test (test-roms) ran SKIPPED
CI success SUCCESS SUCCESS

The required check still reports, which is the property the workflow header has always claimed and never actually had. The accuracy filter correctly reports false on the same run — confirming the second half of the two-step split, that giving code its every quantifier did not break the filter that must keep some.

Two docs PRs were blocked earlier today by a cross-compile failure on jobs that should never have been scheduled. They no longer are.

@doublegate

Copy link
Copy Markdown
Owner Author

The control, which the skip proof needed

The previous comment showed Filter code = false on a markdown-only PR. A filter stuck at false would look identical on that test — so on its own it proves the skip fires, not that the filter still discriminates.

#414 supplies the control without being set up for it. It was docs-only when it went green earlier; a config.rs fix was then added to it, and the same job now logs:

[modified] CHANGELOG.md
[modified] crates/rustynes-frontend/src/config.rs
[modified] to-dos/plans/v2.3.9-crucible-plan.md
Detected 3 changed files

Filter code = true
Matching files:
crates/rustynes-frontend/src/config.rs      <- ONLY the .rs file

Filter accuracy = false
Matching files: none

Three things at once, and the middle one is the part every makes possible:

  1. code flips back to true the moment a non-doc file joins — the filter discriminates, it is not pinned.
  2. Only the .rs file is listed as matching. The two .md files were in the same diff and were excluded individually, which is exactly what the negations were supposed to do and never did.
  3. accuracy stays false on a diff that contains a real source change — correct, since rustynes-frontend is not an accuracy path, and confirmation that the second step's default quantifier survived the split.

Taken with the earlier code = false run, both directions are now observed on real PRs rather than modelled.

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.

2 participants