From 71e3c2e82376c216b0731a9875f7c55aac840e22 Mon Sep 17 00:00:00 2001 From: Charles Ewert Date: Fri, 12 Jun 2026 13:40:26 -0400 Subject: [PATCH 1/2] renovate: enable lockFileMaintenance to kill the npm --before notice minimumReleaseAge makes Renovate pass 'npm install --before=' to age-protect transitive deps. When the existing lockfile holds packages newer than that cutoff (e.g. a freshly-pinned direct dep, or a recent npm install), npm errors, Renovate retries without --before, and logs a noisy 'npm --before could not be enforced' artifact notice on every affected dependency PR. There is no flag to suppress just the notice (it's automatic in the npm post-update manager). The documented fix: lockFileMaintenance regenerates the lockfile from scratch WITH --before on a schedule, keeping the base lockfile clean so the fallback (and its notice) stops firing on regular dep PRs. Enabled with automerge + monthly schedule = one quiet self-merging PR per repo per month. --- renovate/README.md | 10 ++++++++++ renovate/default.json | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/renovate/README.md b/renovate/README.md index deff8f8..8f6e6ed 100644 --- a/renovate/README.md +++ b/renovate/README.md @@ -58,6 +58,16 @@ The org default carries: **minor**. **Majors never automerge** — always human-reviewed (see the **Major-bump SOP** below). Minor automerge raises the CI bar; see the **Automerge contract** below. +- **`lockFileMaintenance` enabled** (automerge, monthly). This exists + *because* of `minimumReleaseAge`: for npm, Renovate passes + `--before=` so transitive deps are age-protected too. When + the existing lockfile already holds packages newer than that cutoff, + npm errors, Renovate falls back to no `--before`, and logs a noisy + "npm `--before` could not be enforced …" artifact notice on the PR. + Monthly lock-file maintenance regenerates the lockfile from scratch + *with* `--before`, keeping the base lockfile clean so that notice + doesn't recur on regular dependency PRs. **Don't disable it** without + also removing `minimumReleaseAge`, or the notices come back. Things that belong **per-repo**, not in the default: diff --git a/renovate/default.json b/renovate/default.json index 1505b65..73175ee 100644 --- a/renovate/default.json +++ b/renovate/default.json @@ -12,6 +12,11 @@ "timezone": "America/New_York", "separateMinorPatch": true, "internalChecksFilter": "none", + "lockFileMaintenance": { + "enabled": true, + "automerge": true, + "schedule": ["before 4am on the first day of the month"] + }, "packageRules": [ { "description": "Group GitHub Actions updates together; pin to SHA digests so version tags can't be silently re-pointed by upstream.", From 025c365aa22b0a836be5f20e8531f0df03fef58f Mon Sep 17 00:00:00 2001 From: Charles Ewert Date: Fri, 12 Jun 2026 13:56:31 -0400 Subject: [PATCH 2/2] renovate: disable platformAutomerge so the soak actually gates automerge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL: minimumReleaseAge's soak is a NON-required 'renovate/stability-days' status check. With platformAutomerge:true (the Renovate default), GitHub's native auto-merge fires as soon as the REQUIRED checks pass and ignores the non-required stability check — so the soak is bypassed entirely. That's how the sharp 0.35.1 minor PR (jellyrock/jellyrock#657) merged ~11 min after CI instead of after its 5-day soak. platformAutomerge:false makes Renovate perform the merge itself, which honours minimumReleaseAge. Keeping stability-days NON-required is deliberate: a human can still merge a hotfix early, while Renovate's own automerge waits out the soak. (Same PR also enables lockFileMaintenance to stop the npm --before artifact notice — see the other commit.) --- renovate/README.md | 18 ++++++++++++++---- renovate/default.json | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/renovate/README.md b/renovate/README.md index 8f6e6ed..3295e55 100644 --- a/renovate/README.md +++ b/renovate/README.md @@ -50,10 +50,20 @@ The org default carries: hotfixed release before it lands unattended. - **PRs are created immediately** (`internalChecksFilter: "none"`), even while soaking — so every update is visible and a human can manually - merge early (e.g. a hotfix). The soak only gates **automerge**: a - pending `renovate/stability-days` check holds the auto-merge until the - window passes, but it isn't a required branch-protection check, so - manual merge still works. + merge early (e.g. a hotfix). The soak only gates **automerge**. +- **`platformAutomerge: false`** — load-bearing for the soak. Renovate's + soak is a non-required `renovate/stability-days` status check. With + GitHub's *platform* automerge (`platformAutomerge: true`, the Renovate + default), GitHub merges as soon as the *required* checks pass and + ignores that non-required check — so the soak gets **bypassed** (this + is how a `minimumReleaseAge` PR can merge minutes after CI, not after + the window). Setting `platformAutomerge: false` makes Renovate do its + own merge, which *does* honour `minimumReleaseAge`. Keeping + `stability-days` non-required is deliberate: it lets a human still + merge a hotfix early, while Renovate's own automerge waits out the + soak. **Do not set this back to `true`** unless you also make + `renovate/stability-days` a required status check (which would also + block manual early-merge). - **Automerge** on green CI after soak for **patch + digest** and **minor**. **Majors never automerge** — always human-reviewed (see the **Major-bump SOP** below). Minor automerge raises the CI bar; see the diff --git a/renovate/default.json b/renovate/default.json index 73175ee..f171a82 100644 --- a/renovate/default.json +++ b/renovate/default.json @@ -12,6 +12,7 @@ "timezone": "America/New_York", "separateMinorPatch": true, "internalChecksFilter": "none", + "platformAutomerge": false, "lockFileMaintenance": { "enabled": true, "automerge": true,