diff --git a/.renovate/packageRules.json5 b/.renovate/packageRules.json5 index cf0351c..755ec94 100644 --- a/.renovate/packageRules.json5 +++ b/.renovate/packageRules.json5 @@ -53,7 +53,7 @@ minimumReleaseAge: "14 days", }, { - description: "ghcr.io / lscr.io / quay.io do not expose a trusted release timestamp, so the default timestamp-required behaviour marks every release 'pending' forever and no PR is ever created. Treat missing timestamps as stable so Renovate opens the PR (and enables automerge); the 14-day soak is instead enforced by the pr-cooldown required status check. Placed after the generic docker rule so it wins. See docs/design-decisions/0005-pr-age-cooldown-for-untrusted-timestamps.md.", + description: "ghcr.io / lscr.io / quay.io do not expose a trusted release timestamp, so the default timestamp-required behaviour marks every release 'pending' forever and no PR is ever created. Treat missing timestamps as stable so Renovate opens the PR (and enables automerge); the 14-day soak is instead enforced by the pr-cooldown required status check, which measures the PR branch head commit age. rebaseWhen:conflicted stops behind-base-branch rebases from rewriting that commit on every base change and perpetually resetting the cooldown clock (branch protection is non-strict, so a behind-base branch still auto-merges once soaked). Placed after the generic docker rule so it wins. See docs/design-decisions/0005-pr-age-cooldown-for-untrusted-timestamps.md.", matchDatasources: ["docker"], matchPackageNames: [ "/^ghcr\\.io\\//", @@ -61,6 +61,7 @@ "/^quay\\.io\\//", ], minimumReleaseAgeBehaviour: "timestamp-optional", + rebaseWhen: "conflicted", }, { description: "Auto-merge dotfiles devcontainer image digest, patch, and minor updates via branch without tests, ignoring the global schedule and release-age soak so they can always merge. Placed after the generic docker minimumReleaseAge rule so its minimumReleaseAge:0 wins. Major bumps are intentionally excluded and left for manual review.", diff --git a/docs/design-decisions/0005-pr-age-cooldown-for-untrusted-timestamps.md b/docs/design-decisions/0005-pr-age-cooldown-for-untrusted-timestamps.md index fe27210..32f0785 100644 --- a/docs/design-decisions/0005-pr-age-cooldown-for-untrusted-timestamps.md +++ b/docs/design-decisions/0005-pr-age-cooldown-for-untrusted-timestamps.md @@ -56,6 +56,15 @@ Age is measured from the **branch head commit**, not PR creation: when Renovate rebases the PR to a newer version the clock correctly restarts, so the exact content being merged has always soaked for the full period. +Because the gate reads the branch head commit date, the gated rule also sets +**`rebaseWhen: "conflicted"`**. Renovate's default (`auto`, which becomes +`behind-base-branch` once automerge is enabled) would rebase the PR every time +`main` advances, rewriting the head commit and resetting the cooldown clock +forever on an active repo. `conflicted` limits rebases to genuine merge +conflicts; branch protection is non-strict +(`strict_required_status_checks_policy: false`), so a behind-base gated PR still +auto-merges once the soak completes — no rebase required. + Datasources that DO provide a trusted timestamp (docker.io, github tags/releases) are left on the default `timestamp-required` + `internalChecksFilter: strict` path — their soak is enforced natively and they