fix(ci): drop per-rule rangeStrategy from npm-majors packageRule (#94) #112

Merged
james merged 1 commit from 94-renovate-config-fix into main 2026-06-18 13:14:23 +00:00
Owner

Closes #94.

What happened

Renovate's config validator started rejecting the combination of matchUpdateTypes + rangeStrategy in the same packageRule. The bot filed #94 and stopped opening PRs until the config is fixed:

packageRules[2]: packageRules cannot combine both matchUpdateTypes and rangeStrategy.

The offending rule:

{
  "matchUpdateTypes": ["major"],
  "rangeStrategy": "bump",
  ...
}

The intent was: for npm major updates, override the default update-lockfile strategy to bump so the package.json range actually gets changed (since update-lockfile alone can't satisfy an out-of-range update).

Fix

Remove the per-rule "rangeStrategy": "bump" and rely on the root-level "rangeStrategy": "update-lockfile"'s documented fallback behavior: when the lockfile can't satisfy an in-range update (which is exactly what a major is), Renovate automatically falls back to replace, which produces the same package.json range change bump would have for caret/tilde ranges. The packageRule keeps matchUpdateTypes: ["major"] + group + label + automerge: false without the forbidden override.

The architectural intent — lockfile-only by default, separate PR + human review for majors — is preserved. Only the mechanism shifted from per-rule override to implicit root-level fallback.

Files

File Change
renovate.json Drop "rangeStrategy": "bump" from the npm-major-bumps packageRule; expand the rule's description to explain the new mechanism + cite this issue
docs/ci.md Update the "Lockfile-only updates by default" paragraph to describe the fallback-to-replace behavior instead of the now-impossible per-rule override

Test plan

  • python3 -c 'import json; json.load(open("renovate.json"))' — clean.
  • npx --yes --package=renovate@latest -- renovate-config-validatorConfig validated successfully against 1 file(s).
  • After merge, Renovate's next scheduled run does NOT re-file the "Action Required" issue, and routine dep-update PRs resume.

Why ADR-0009 was not edited

ADR-0009 mentions rangeStrategy: "bump" in its prose. Per ADR-0001's immutability rule, ADRs aren't edited after acceptance — they record the architectural decision at a point in time, and the decision (lockfile-only default + separate PR for majors + never-auto-merge) is unchanged here. Only the syntactic mechanism shifted, driven by an external validator tightening. docs/ci.md is the current-truth source for config syntax; ADR-0009 stays as the historical reasoning record.

Heads up: stray validator warning

Locally, an older Renovate (37.x) also flags github-actions.managerFilePatterns as an "invalid option" — that's a field-renaming churn between Renovate versions, not a real problem (your live instance, which filed #94, clearly accepts the option since #94's error was about something else). No action needed unless Renovate upstream actually removes the field.

Closes #94. ## What happened Renovate's config validator started rejecting the combination of `matchUpdateTypes` + `rangeStrategy` in the same packageRule. The bot filed #94 and stopped opening PRs until the config is fixed: ``` packageRules[2]: packageRules cannot combine both matchUpdateTypes and rangeStrategy. ``` The offending rule: ```json { "matchUpdateTypes": ["major"], "rangeStrategy": "bump", ... } ``` The intent was: for npm major updates, override the default `update-lockfile` strategy to `bump` so the package.json range actually gets changed (since `update-lockfile` alone can't satisfy an out-of-range update). ## Fix Remove the per-rule `"rangeStrategy": "bump"` and rely on the root-level `"rangeStrategy": "update-lockfile"`'s documented fallback behavior: when the lockfile can't satisfy an in-range update (which is exactly what a major is), Renovate automatically falls back to `replace`, which produces the same package.json range change `bump` would have for caret/tilde ranges. The packageRule keeps `matchUpdateTypes: ["major"]` + group + label + `automerge: false` without the forbidden override. The architectural intent — lockfile-only by default, separate PR + human review for majors — is preserved. Only the mechanism shifted from per-rule override to implicit root-level fallback. ## Files | File | Change | |---|---| | `renovate.json` | Drop `"rangeStrategy": "bump"` from the npm-major-bumps packageRule; expand the rule's `description` to explain the new mechanism + cite this issue | | `docs/ci.md` | Update the "Lockfile-only updates by default" paragraph to describe the fallback-to-`replace` behavior instead of the now-impossible per-rule override | ## Test plan - [x] `python3 -c 'import json; json.load(open("renovate.json"))'` — clean. - [x] `npx --yes --package=renovate@latest -- renovate-config-validator` — `Config validated successfully against 1 file(s)`. - [ ] After merge, Renovate's next scheduled run does NOT re-file the "Action Required" issue, and routine dep-update PRs resume. ## Why ADR-0009 was not edited ADR-0009 mentions `rangeStrategy: "bump"` in its prose. Per ADR-0001's immutability rule, ADRs aren't edited after acceptance — they record the *architectural decision* at a point in time, and the decision (lockfile-only default + separate PR for majors + never-auto-merge) is unchanged here. Only the *syntactic mechanism* shifted, driven by an external validator tightening. `docs/ci.md` is the current-truth source for config syntax; ADR-0009 stays as the historical reasoning record. ## Heads up: stray validator warning Locally, an older Renovate (37.x) also flags `github-actions.managerFilePatterns` as an "invalid option" — that's a field-renaming churn between Renovate versions, not a real problem (your live instance, which filed #94, clearly accepts the option since #94's error was about something else). No action needed unless Renovate upstream actually removes the field.
fix(ci): drop per-rule rangeStrategy from npm-majors packageRule (#94)
All checks were successful
Commits / Conventional Commits (pull_request) Successful in 6s
PR / Typecheck (pull_request) Successful in 30s
PR / Lint (pull_request) Successful in 34s
PR / Static analysis (pull_request) Successful in 36s
PR / OSV-Scanner (pull_request) Successful in 24s
Secrets / gitleaks (pull_request) Successful in 18s
PR / Trivy (image) (pull_request) Successful in 1m4s
PR / npm audit (pull_request) Successful in 1m48s
PR / Test (sqlite) (pull_request) Successful in 2m11s
PR / Test (postgres) (pull_request) Successful in 2m29s
PR / Build (pull_request) Successful in 2m56s
0afa90631d
Renovate's config validator started rejecting the combination of
`matchUpdateTypes` and `rangeStrategy` in the same packageRule, which
blocked the bot from opening PRs until the config is fixed.

The intent of the original rule — `rangeStrategy: "bump"` for majors
so the package.json range actually gets changed — is preserved
implicitly. The root-level `rangeStrategy: "update-lockfile"` falls
back to `replace` for out-of-range updates (per Renovate's
documented semantics for that strategy), which produces the same
range-change PR for majors that `bump` would have. The packageRule
keeps `matchUpdateTypes: ["major"]` + group + label + automerge:false
without the forbidden override.

Verified with `renovate-config-validator` from renovate@latest:
"Config validated successfully against 1 file(s)".

docs/ci.md updated to explain the new mechanism. ADR-0009 left as-is
per the immutability rule — the architectural decision (lockfile-only
by default, separate PR for majors, never auto-merged) is unchanged;
only the syntactic mechanism shifted.

Closes #94.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
james force-pushed 94-renovate-config-fix from 0afa90631d
All checks were successful
Commits / Conventional Commits (pull_request) Successful in 6s
PR / Typecheck (pull_request) Successful in 30s
PR / Lint (pull_request) Successful in 34s
PR / Static analysis (pull_request) Successful in 36s
PR / OSV-Scanner (pull_request) Successful in 24s
Secrets / gitleaks (pull_request) Successful in 18s
PR / Trivy (image) (pull_request) Successful in 1m4s
PR / npm audit (pull_request) Successful in 1m48s
PR / Test (sqlite) (pull_request) Successful in 2m11s
PR / Test (postgres) (pull_request) Successful in 2m29s
PR / Build (pull_request) Successful in 2m56s
to 7c601e6d5c
All checks were successful
Commits / Conventional Commits (pull_request) Successful in 12s
PR / OSV-Scanner (pull_request) Successful in 22s
Secrets / gitleaks (pull_request) Successful in 14s
PR / Static analysis (pull_request) Successful in 35s
PR / Trivy (image) (pull_request) Successful in 1m3s
PR / npm audit (pull_request) Successful in 1m30s
PR / Lint (pull_request) Successful in 1m55s
PR / Typecheck (pull_request) Successful in 2m4s
PR / Test (sqlite) (pull_request) Successful in 2m13s
PR / Test (postgres) (pull_request) Successful in 2m14s
PR / Build (pull_request) Successful in 2m28s
2026-06-18 13:13:58 +00:00
Compare
james merged commit ceb8282824 into main 2026-06-18 13:14:23 +00:00
james deleted branch 94-renovate-config-fix 2026-06-18 13:14:24 +00:00
Sign in to join this conversation.
No description provided.