Skip to content

ci: scope Feature Unification Check to PR-affected crates#1695

Open
gilescope wants to merge 4 commits into
mainfrom
giles-fast-feature-unification
Open

ci: scope Feature Unification Check to PR-affected crates#1695
gilescope wants to merge 4 commits into
mainfrom
giles-fast-feature-unification

Conversation

@gilescope

@gilescope gilescope commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Overview

Your PRs just got 42 minutes faster.

The Feature Unification Check was CI's most expensive subscription: ~42 min of serial cargo hack check across 74 crates, on every PR push and every merge-group entry — fully cold each time (ephemeral runner, no warm cache anywhere in that job) — while gating nothing, since it isn't a required status check.

This PR replaces brute force with a dependency graph:

  • 🎯 Runs only when it can matter — its own workflow, triggered solely by PRs touching a manifest (**/Cargo.toml, Cargo.lock, Earthfile, the workflow itself). The .rs-only PR that dominates daily traffic: 42 min → 0.
  • 🕸️ Checks only what changedscripts/feature-unification-scope.sh attributes the diff to crates and computes the reverse-dependency closure over normal+build edges, feeding cargo hack -p exactly the crates whose isolated resolution could have changed. Touch one pallet → ~5 crates, not 74. Dev-dep edges are deliberately ignored: the check strips dev-deps, so nothing can break through one.
  • 🛡️ Fails safe, never silentCargo.lock, root Cargo.toml, .cargo/, Earthfile, or any file no crate claims → full --workspace run. Files inside crate dirs always attribute (yes, docs/ and res/ are crates — include_str! is watching).
  • ✂️ Sheds dead weight — upstream partner-chains-demo-{node,runtime} excluded (~5 min of zero signal), cargo-hack pinned to 0.6.45 (no more version drift between runs), GHCR login dropped (the build chain only pulls the public midnight-node-ci image from docker.io — one less secret in a PR-triggered job).

Worst case (lock-bump PR) pays roughly the old price minus the demo crates. The common case pays nothing. Coverage for what lands on a PR is unchanged: a change can only break the per-package check of itself or its dependents — exactly the closure we check.

🗹 TODO before merging

  • Watch the first scoped run on this very PR (it triggers itself — the workflow file changed)
  • Ready

📌 Submission Checklist

  • All commits are signed off (git commit -s) for the DCO
  • Changes are backward-compatible (or flagged if breaking)
  • Pull request description explains why the change is needed
  • Self-reviewed the diff
  • I have included a change file, or skipped for this reason: CI-only change
  • If the changes introduce a new feature, I have bumped the node minor version (N/A — CI only)
  • Update documentation (if relevant) (workflow + script are self-documenting; no docs/ impact)
  • Updated AGENTS.md if build commands, architecture, or workflows changed (no commands changed)
  • No new todos introduced

🧪 Testing Evidence

  • scripts/feature-unification-scope.sh --self-test — 11 cases green (closure propagation, dev-dep edge inertness, global-input fallback, ignore list, demo-crate exclusion, whole-closure collapse to --workspace).
  • Real-repo spot checks: pallets/midnight/src/lib.rs → 5 crates; node/src/main.rs → 1; primitives/midnight → ~10; Cargo.lock → full workspace.
  • cargo hack check -p docs --no-dev-deps validated locally against this workspace (flag combination works with the pinned 0.6.45).
  • shellcheck clean; workflow YAML parses; earthly ls parses the Earthfile.
  • Timing baseline from 3 CI runs on 2026-06-12 (runs 27422192789 / 27414909470 / 27413182280): ~42 min wall, 99% in cargo hack, hot spots midnight-node 6.7 min and the demo crates 5.2 min.
  • Additional tests are provided (if possible)

🔱 Fork Strategy

  • Node Runtime Update
  • Node Client Update
  • Other:
  • N/A — CI-only; no node, runtime, or network impact.

Links

None — CI housekeeping (labels applied accordingly).

Signed-off-by: Giles Cope <gilescope@gmail.com>
Signed-off-by: Giles Cope <gilescope@gmail.com>
@gilescope gilescope marked this pull request as ready for review June 13, 2026 06:16
@gilescope gilescope requested a review from a team as a code owner June 13, 2026 06:16

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c551779b53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/feature-unification-scope.sh Outdated
Comment thread scripts/feature-unification-scope.sh Outdated
@gilescope gilescope enabled auto-merge June 15, 2026 07:43
@LGLO

LGLO commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Your PRs just got 42 minutes faster.

This is a lie.

Comment thread scripts/feature-unification-scope.sh Outdated
| map(select($o[.] != $n[.]))
'

# Workspace members ($members) reverse-reachable from $seeds in the lock

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are "reverse-reachable" (transitive) dependent crates?

LGLO
LGLO previously approved these changes Jun 15, 2026
@ozgb

ozgb commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

The .rs-only PR that dominates daily traffic: 42 min → 0.

I think this is also not true - the script checks for file changes, and runs checks for the crate that changed, and any crate that depends on the changed crate

Comment thread Earthfile Outdated
ARG PACKAGES="--workspace --exclude partner-chains-demo-node --exclude partner-chains-demo-runtime"
# Pinned: an unpinned binstall here can drift from the version baked into
# the CI base image and change check behaviour between runs.
RUN cargo binstall --no-confirm --locked cargo-hack@0.6.45

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Will this version pin get picked up by dependabot?

Comment thread scripts/feature-unification-scope.sh Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This script is pretty hard to parse - could we replace this with a typescript implementation?

Then we could read the lockfile directly as toml rather than converting it to JSON - I imagine knowledge of jq script is limited in our team, particularly at this level of complexity

Signed-off-by: Giles Cope <gilescope@gmail.com>
Signed-off-by: Giles Cope <gilescope@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b554fba74f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +247 to +249
const touched = files
.map((f) => owningCrate(f, crates))
.filter((x): x is string => x !== null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Check all shared users for dependency feature edits

When a non-root Cargo.toml changes only the feature set of a shared third-party dependency, Cargo.lock does not change and the root-manifest path is not used, so these lines seed only the crate that owns that manifest. The reverse closure then checks that crate and its workspace dependents, but skips unrelated crates that use the same dependency and may now compile only because the new feature is unified in the workspace, which is exactly the class of regression this job is meant to catch.

Useful? React with 👍 / 👎.

Comment on lines +13 to +18
paths:
- "**/Cargo.toml"
- "Cargo.lock"
- "rust-toolchain.toml"
- "scripts/feature-unification-scope.ts"
- ".github/workflows/feature-unification.yml"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Trigger this workflow for its build inputs

This path allowlist omits inputs that now directly affect +check-feature-unification, notably Earthfile and scripts/package*.json; a PR that changes only the Earthly target or the npm lockfile that npm ci consumes will not start this workflow at all. Since this commit also enables Dependabot for /scripts, those dependency-update PRs can merge without ever exercising the scoper install/runtime path they modify.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants