chore(deps): keep major bumps out of dependabot's grouped PRs (#871) - #872
Open
isadeks wants to merge 1 commit into
Open
chore(deps): keep major bumps out of dependabot's grouped PRs (#871)#872isadeks wants to merge 1 commit into
isadeks wants to merge 1 commit into
Conversation
This was referenced Sep 9, 2026
isadeks
force-pushed
the
chore/871-dependabot-group-split
branch
from
September 10, 2026 13:29
fef993a to
51ed4a0
Compare
isadeks
force-pushed
the
chore/871-dependabot-group-split
branch
from
September 10, 2026 13:30
51ed4a0 to
1ba93cc
Compare
Each ecosystem groups every update into one PR with a PR limit of 1, so a breaking major freezes that ecosystem outright: the group PR cannot merge and the limit stops a second PR being opened for the safe remainder. #860 has held 47 npm updates since 2026-09-05 behind typescript 6->7 and cdk-nag 2->3, and #859 has held 10 python updates behind mcp 1->2. The cost was concrete: #860 carries astro 7.1.3 -> 7.2.9, which fixes GHSA-26w7-cxv4-gfx2 (CVSS 9.8), and it sat unmergeable for five days. #870 had to hand-write that same bump plus six other advisory fixes, duplicating work dependabot had already done. Exclude majors from the grouped PR instead of routing them to a second group. A group restricted to minor/patch would leave majors *ungrouped*, and an ungrouped update gets its own PR — that would mean one PR per major dependency, strictly worse than today. Ignoring them keeps the steady state at one grouped PR per ecosystem, the same count as now but without the wedge. - Ignore `version-update:semver-major` for `*` in all four ecosystems. Groups are left exactly as they are on main. - Raise `open-pull-requests-limit` 1 -> 2: one grouped PR plus a slot of headroom, so a lone ungrouped or security PR cannot starve the group. - Ignore `python` minor on docker (#105). 3.13 -> 3.14 must land with agent/mise.toml, agent/.python_version, the ruff and ty targets in agent/pyproject.toml, the lockfile, and three prose sites naming the base tag. #827 moved only the Dockerfile. Digest and patch refreshes still flow. - Ignore `claude-agent-sdk`, mirroring cedarpy. It bundles the `claude` CLI, pinned separately by an `npm install -g` line in agent/Dockerfile that is in no package.json — so no ecosystem tracks it and only a human can move it. An automated SDK bump diverges bundled from installed CLI and stales the version in pyproject's own comment (#215). - State `semver-major` explicitly on each per-dependency ignore even though the blanket rule covers it. The blanket rule is a policy that may be revisited; each per-dependency block is an invariant. Relaxing the policy must not silently degrade one. Trade-off: a major that fixes an advisory no longer arrives as a PR. Detection is unaffected — `//:security:deps` fails the build on any advisory regardless of dependabot — but the upgrade is driven by hand. Majors become issues.
isadeks
force-pushed
the
chore/871-dependabot-group-split
branch
from
September 10, 2026 13:41
1ba93cc to
8ebb6e5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #871.
Rewritten. The first version of this PR routed majors into a second group per ecosystem, which raised the open-PR ceiling from 4 to 8. That drew the reasonable objection that it trades one problem for PR sprawl. This version excludes majors instead, so the steady state is one grouped PR per ecosystem — the same count as today, but without the wedge. Groups are now left exactly as they are on
main; the diff is four limit bumps plusignorerules.Problem
Every ecosystem groups all updates into one PR and allows one open PR:
With
update-typesunset the group takes majors, minors and patches together. A breaking major then freezes the whole ecosystem — the group PR cannot merge, and the limit of 1 stops Dependabot opening a second PR for the safe remainder.This is not a theoretical cost. #860 carries
astro7.1.3→7.2.9, which fixes GHSA-26w7-cxv4-gfx2 (CVSS 9.8), and it has been unmergeable since 2026-09-05 — blocked bytypescript^6.0.3→^7.0.2andcdk-nag^2.38.2→^3.0.2in the same PR. #870 exists to hand-write that astro bump plus six other advisory fixes: work Dependabot had already computed and delivered, in a PR nobody can merge. #859 is the same shape, holding 10 python updates behindmcp1.28.1→2.1.1.Why exclude majors rather than group them separately
This is the part worth checking, because the obvious fix is wrong. A group restricted to
update-types: ["minor", "patch"]leaves majors ungrouped — and an ungrouped update gets its own PR. So restricting the group without also ignoring majors would produce one PR per major dependency, which is strictly worse than today. Ignoring them is what holds the queue at one PR per ecosystem.Change
version-update:semver-majorfor*in all four ecosystems. Groups are untouched frommain.open-pull-requests-limit1 → 2. One grouped PR plus one slot of headroom, so a lone ungrouped or security PR cannot starve the group. With a single group per ecosystem, Dependabot still opens at most one grouped PR — the limit is a ceiling, not a target.pythonminor on the docker ecosystem (chore(agent): upgrade Python 3.13 → 3.14 #105).3.13→3.14has to land withagent/mise.toml,agent/.python_version, the rufftarget-versionand typython-versiontargets inagent/pyproject.toml, the lockfile, and three prose sites that name the base tag. chore(deps): docker: bump the all-docker group across 1 directory with 3 updates #827 moved only the Dockerfile. Digest and patch refreshes still flow.claude-agent-sdk, mirroring the existingcedarpytreatment. It bundles theclaudeCLI, which is pinned separately by annpm install -g @anthropic-ai/claude-code@<version>line inagent/Dockerfile. That line is in nopackage.json— verified withgrep -rn "anthropic-ai/claude-code" --include=package.json, which returns nothing — so no ecosystem tracks it and only a human can move it. An automated SDK bump therefore diverges the bundled CLI from the installed one and stales the version named inagent/pyproject.toml:19's own comment, with no CI check able to notice. chore(deps): uv: bump the all-python group across 1 directory with 10 updates #859 does exactly this: SDK to0.2.148, Dockerfile untouched.semver-majorexplicitly on each per-dependency ignore even though the blanket rule covers it. Deliberate overlap: the blanket rule is a policy and may be revisited, whereas each per-dependency block is an invariant — a lockstep partner that must not move alone. Stating them fully means relaxing the policy cannot silently degrade an invariant.Trade-off, stated plainly
A major that fixes an advisory will no longer arrive as a PR. Detection is unaffected:
//:security:depsruns osv-scanner overyarn.lock,agent/uv.lockand the jira-forge-app lockfile and fails the build on any advisory regardless of Dependabot. But the upgrade has to be driven by hand.That is the trade for not having a breaking major freeze the ecosystem it lands in. Today's config does not avoid the work — it just hides it behind a PR that cannot merge, while still costing a weekly rebase and a 13-minute CI run. Majors become issues instead; #105 already exists for the Python interpreter, and TypeScript 7, cdk-nag 3 and mcp 2 need filing.
Testing
update-types(which would leave majors ungrouped and produce per-dependency PRs — the failure mode above), that every ecosystem carries the blanket major ignore, and that each per-dependency ignore statesmajorexplicitly.mise run security:gh-actions(zizmor over.github) gives identical output on this branch and on cleanmain— 53 findings, 6 ignored, 46 suppressed, 1 medium. The medium issecrets-outside-envat.github/workflows/auto-approve.yml:48, untouched here; it is pre-existing and a local-only artefact of a newer zizmor than CI's pin. Zero findings added..github/dependabot.yml(grep -rn dependabot mise.toml .github/workflows/ scripts/is empty), so GitHub's own validator on the Dependabot page is the authoritative check after merge.1c296c0b(currentmain, which includes fix(deps): clear 7 osv advisories blocking the merge queue #870 and chore(deps): docker: bump mise digest and golang 1.26.4 to 1.27.1 #873). Diff againstmainis one file,.github/dependabot.yml— confirmed withgit diff upstream/main --stat.A note on the earlier red CI here, since the history is public: an intermediate push of this branch reverted #870. I had used
git reset --softto re-parent onto the newermain, which keeps the old worktree, so the commit captured a tree predating #870 and rolledastroback from 7.2.8 to 7.1.3.//:security:depscorrectly failed on the seven advisories that reappeared, and I initially misread that as advisories inherited frommain. It was self-inflicted. The commit now contains only.github/dependabot.yml, andastrois 7.2.8 at this head withe96dc21e(#870) verified as an ancestor.Follow-up
Once this merges, closing #859 and #860 lets Dependabot regenerate a single grouped PR per ecosystem carrying only the routine updates — recovering the 45 npm and 6 python bumps currently held behind majors. Deliberately sequenced that way: with the limit still 1 and no major ignore in place, closing them today just returns the same frozen groups on the next Saturday run.