Skip to content

ci(workflows): run CI and PR policy on every base branch - #1257

Closed
Harry19081 wants to merge 1 commit into
developfrom
ci/run-workflows-on-all-base-branches
Closed

ci(workflows): run CI and PR policy on every base branch#1257
Harry19081 wants to merge 1 commit into
developfrom
ci/run-workflows-on-all-base-branches

Conversation

@Harry19081

Copy link
Copy Markdown
Member

Problem

ci.yml and pr-policy.yml both filtered their triggers to
branches: [develop, release, master]. A pull request whose base is any other
branch therefore matched no trigger at all — the workflows never queued, so
nothing was skipped, cancelled, or reported; they simply did not exist for that
pull request.

Stacked pull requests are exactly that case. #1220
targets junyu/mobile-remote-control and #1222
targets junyu/ios-remote-shared, so both ran zero CI. gh pr checks on each
returns a single entry:

check   pass   12s   .../runs/33595326872   # workflow: "Check AI attribution"

That is check-ai-attribution.yml, which is base-branch-agnostic by accident —
it declares a bare pull_request: because it was written as a history guard,
not as a CI entry point. Neither CI nor the PR contract ran. Typecheck,
lint, vitest, clippy, and PR-policy compliance on those two pull requests are
author-reported only.

15 of the 51 currently open pull requests target a non-develop base and are in
the same position.

Solution

Delete the branches: filter from both workflows, so pull_request /
pull_request_target fire for every base branch. Each file carries a comment
recording why the filter must not come back.

Cost is already bounded per-diff rather than per-branch, and stacking makes that
bound tighter rather than looser: ci.yml's changes job scopes on
base.sha...head.sha, which for a stacked pull request is the increment over
its parent branch, not the whole feature. Measured against the two real diffs
with the repo's own detectors:

PR rust_required audit_required lint mode
#1220 false false files (32)
#1222 false false all (touches package.json)
this PR true false skip

So #1220 costs one Linux frontend job and allocates no macOS runner. The
existing per-PR concurrency group with cancel-in-progress: true keys on
github.event.pull_request.number, so it already de-duplicates pushes on these
pull requests too.

Potential risks

  • Hosted-runner spend rises, and this change sets no ceiling on it. Every
    push to any of the ~15 non-develop-based pull requests now buys a frontend
    job (~11m41s on Linux, per the 2026-08-28 measurements) and, whenever the
    increment touches src-tauri/, the macos-latest clippy + workspace-test job
    that is billed at 10× Linux. The per-diff scoping above limits the common
    case; it does not cap the aggregate.
  • pull_request_target's trust anchor is now weaker. pr-policy.yml
    checks out github.event.pull_request.base.sha as "trusted policy" and
    executes scripts/ci/pr-policy.cjs from it. With the filter gone, that base
    can be any branch, including one whose author edited that script — it is no
    longer guaranteed to be a protected branch. Blast radius stays small: pushing
    a branch to this repository requires write access, the job's token is
    contents: read + pull-requests: read, and the checkout sets
    persist-credentials: false. If that is judged too loose, the follow-up is to
    pin the checkout to the repository's default branch instead of base.sha.
  • Existing stacked pull requests may go red on their next push, on problems
    the filter was hiding rather than on anything this change introduces. Branch
    protection covers only develop/release/master, so a failing check on a
    pull request into a feature branch is informational and blocks no merge.
  • The PR contract now applies to stacked pull requests whose titles and
    descriptions were never written against it, so some will fail Enforce PR contract until updated.
  • Not fixed here, and worth its own change: scripts/ci/detect-rust-changes.cjs
    scopes Rust on the src-tauri/ prefix, so feat(mobile-remote): add Tauri iOS shell #1222's new apps/remote-ios/src-tauri/
    crate and its Cargo.lock report rust_required=false even after this change
    — and the rust job's working-directory: src-tauri with cargo clippy --workspace would not cover a second Cargo workspace anyway. Making CI build
    the iOS crate is real work that belongs to that stack, not to a trigger fix.

Verification

Ran, on this branch's exact diff:

  • node --test scripts/ci/*.test.cjs28 pass, 0 fail (the CI policy
    helpers this workflow invokes).
  • Both workflows re-parsed after the edit, confirming the triggers are what was
    intended and nothing else moved:
    ci.yml -> {"pull_request": null} (all activity types, all base branches);
    pr-policy.yml -> {"pull_request_target": {"types": [opened, edited, reopened, synchronize, ready_for_review, converted_to_draft]}};
    job lists unchanged (changes, frontend, rust, cargo-audit and enforce).
  • The scope table above, produced by piping refactor(mobile-remote): add platform adapter boundary #1220's and feat(mobile-remote): add Tauri iOS shell #1222's real changed-file
    lists (gh pr view --json files) through detect-rust-changes.cjs,
    detect-audit-changes.cjs, and select-lint-targets.cjs.
  • gh pr checks 1220 / gh pr checks 1222 before the change, which is the
    evidence for the Problem section above.

Did not run, and why:

  • actionlint — not installed on this machine. The YAML was parsed instead, as
    described above.
  • typecheck / eslint / vitest / clippy — the diff is two YAML files with no
    source change. This pull request's own diff scores rust_required=true
    (.github/workflows/ is a Rust-relevant prefix by design), so CI on this pull
    request will run the full frontend job and the macOS clippy + workspace-test
    job, and that run is the real evidence.
  • The pre-commit hook did not run: the commit was built with git plumbing
    (temporary index) because the shared checkout holds another session's
    uncommitted work. No Pre-commit hook ran. trailer, and lint-staged did not
    format anything — neither matters for a YAML-only diff, which
    select-lint-targets.cjs reports as lint_mode=skip.

The claim this change actually makes cannot be proved before merge, since a
workflow trigger is read from the base branch. Post-merge check: push to (or
reopen) #1220 and confirm Frontend (typecheck · lint · test) and Enforce PR contract attach to it.

🤖 Generated with Claude Code

The `branches: [develop, release, master]` filter on ci.yml and
pr-policy.yml meant a pull request targeting any other branch matched
no trigger at all. Stacked pull requests -- #1220 into
junyu/mobile-remote-control, #1222 into junyu/ios-remote-shared -- ran
neither, so typecheck, lint, vitest, clippy and the PR contract were
author-reported only; the sole check on them was Check AI attribution,
which is base-branch-agnostic by accident rather than by design.

Drop the filter from both. ci.yml's `changes` job already scopes cost
to the diff, and a stacked pull request's base..head diff is the
increment alone.
@sudomaggie

Copy link
Copy Markdown
Collaborator

Closing as superseded by #1258, which implements the same all-base CI and PR-policy trigger change and has been merged.

@sudomaggie sudomaggie closed this Sep 4, 2026
@Harry19081 Harry19081 added duplicate This issue or pull request already exists maintenance Maintenance, CI, build, release, cleanup, or tooling work dev-tooling Developer tooling, build, CI, tests, diagnostics, or release labels Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-tooling Developer tooling, build, CI, tests, diagnostics, or release duplicate This issue or pull request already exists maintenance Maintenance, CI, build, release, cleanup, or tooling work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants