Skip to content

chore: sort the unified pre.* prerelease timeline (drop followTag) - #144

Merged
insipx merged 3 commits into
mainfrom
insipx/unified-prerelease-versioning
Aug 26, 2026
Merged

chore: sort the unified pre.* prerelease timeline (drop followTag)#144
insipx merged 3 commits into
mainfrom
insipx/unified-prerelease-versioning

Conversation

@insipx

@insipx insipx commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Why

On 2026-08-25 renovate automerged a backwards version move in convos-assistants (#3646): it walked the @xmtp/node-sdk / @xmtp/node-bindings pins off a fresh dev.999b077 build and onto a three-day-old nightly.20260822 one.

Nothing malfunctioned — that is just what followTag does. followTag: "nightly" tells renovate "whatever the nightly dist-tag points at is the target", so it follows the tag regardless of whether the tagged version is newer or older than what is already pinned. Because dev builds and nightly builds used two unrelated, mutually unorderable suffix shapes (dev.<sha> vs nightly.<date>.<sha>), there was no way for semver to arbitrate between them, and tag-following was the only mechanism available.

What changes

xmtp/libxmtp#4048 gives main-cut dev and nightly releases one shared, sortable format:

X.Y.Z-pre.<YYYYMMDDHHMMSS>.<channel>.<shortSha>

Both channels now live on a single monotonic timeline, so plain semver ordering is enough and the tag-following crutch can go away.

1. .github/renovate.json — drop followTag

"followTag": "nightly" is deleted from the @xmtp/node-sdk / @xmtp/node-bindings packageRule. ignoreUnstable: false and respectLatest: false stay exactly as they were, so prereleases remain eligible; default npm semver sorting now picks the highest version rather than chasing a tag. Sorting cannot move backwards, so the #3646 class of regression is structurally impossible.

Candidate scope

Dropping followTag on its own would leave the rule sorting every published version, and rc/final releases are numerically higher than any prerelease of the same X.Y.Z — a stable release, not the newest prerelease, would become the top candidate. The rule therefore also gains an allowedVersions regex that pins it to the prerelease timeline — pre.* on both channels, plus legacy nightlies for the transition:

/-(?:pre\.\d{14}\.(?:dev|nightly)\.[0-9a-f]+|nightly\.\d{8}\.[0-9a-f]+)$/

Legacy dev.<sha> is deliberately excluded, so branch-cut devs stay renovate-invisible, and adopting a stable release stays a deliberate human change. A suffix-less pair could never have automerged past the lockstep guard in any case — test/xmtpLockstep.test.ts asserts both pins carry a prerelease suffix, so an rc/final pin fails CI — but not being proposed at all beats failing loudly.

2. test/xmtpLockstep.test.ts — widen the suffix guard

PRERELEASE_SUFFIX grows a third alternative for the unified shape:

const PRERELEASE_SUFFIX =
  /-(pre\.\d{14}\.(?:dev|nightly)\.[0-9a-f]+|nightly\.\d{8}\.[0-9a-f]+|dev\.[0-9a-f]+)$/;

The two legacy alternatives are deliberately kept: branch-cut dev releases still publish X.Y.Z-dev.<shortSha>, and the current pins on main (6.2.0-dev.999b077 / 1.12.0-dev.999b077) must keep matching so the guard stays live through the transition. rc<N> and final releases are still rejected.

The same-suffix lockstep assertion is unaffected. One libxmtp release run stamps one timestamp for the whole run, so node-sdk and node-bindings from that run carry an identical pre.<ts>.<channel>.<sha> suffix even though their X.Y.Z differ — which is precisely what the "must come from the same libxmtp commit" check compares.

Transition bridge

This lands safely before, during, or after libxmtp#4048 ships:

  • Before the first pre.* publish — legacy nightlies are still internally semver-ordered among themselves (nightly.20260822 < nightly.20260825), so dropping followTag keeps updates flowing normally; renovate just sorts within the legacy series instead of following the tag.
  • After the first pre.* publishpre sorts above both dev and nightly as a dot-separated prerelease identifier, so every pre.* build outranks the entire legacy series and renovate migrates onto the new timeline on its own.
  • Branch-cut devs stay dev.<sha>, which sorts below everything and is never offered as an update — they remain renovate-invisible by construction, exactly as today.

No pin changes are needed in this PR; the next normal release re-pins onto the new format.

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_01QF99maZfAqQ5onTGatgDvy


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Note

Replace followTag with allowedVersions regex for unified prerelease timeline

  • Replaces followTag: nightly in renovate.json with an allowedVersions regex that permits only pre.<14-digit ts>.(dev|nightly).<hex>, nightly.<8-digit date>.<hex>, and dev.<hex> suffixes
  • Expands PRERELEASE_SUFFIX in xmtpLockstep.test.ts to accept the new pre.<ts>.<channel>.<hash> form alongside the legacy nightly/dev forms, and updates the lockstep test failure message accordingly
  • Behavioral Change: Renovate now selects versions by suffix pattern rather than following the nightly tag, so versions published under a different tag but matching the pattern are eligible while nightly-tagged versions that do not match are excluded

Macroscope summarized 5f5e082.

Drop "followTag": "nightly" so default npm semver sorting picks the newest
@xmtp/node-sdk / @xmtp/node-bindings prerelease, and widen the lockstep guard
to accept libxmtp'''s unified pre.<YYYYMMDDHHMM>.<channel>.<shortSha> suffix
alongside the legacy nightly.<date>.<hash> / dev.<hash> shapes.

ignoreUnstable: false and respectLatest: false are unchanged, so prereleases
stay eligible.
@macroscopeapp

macroscopeapp Bot commented Aug 25, 2026

Copy link
Copy Markdown

Approvability

Verdict: Approved at 5f5e082

Macroscope's review found this PR approvable — This is a small, self-contained Renovate maintenance change with a matching development-only lockstep-test update. It changes future prerelease dependency selection but does not modify shipped CLI behavior, schemas, deployment targets, or sensitive areas.

You can add or adjust custom eligibility rules. Learn more.

Dropping followTag left this rule sorting the whole @xmtp/node-sdk /
@xmtp/node-bindings version list for the highest candidate, and rc/final
releases are numerically higher than any prerelease of the same X.Y.Z --
so a stable release would have become the update candidate. allowedVersions
pins the rule back to the prerelease timeline:

- unified pre.<YYYYMMDDHHMM>.<channel>.<sha>, both channels: main-cut dev
  and nightly are one ordered timeline now;
- legacy nightly.<date>.<sha>, kept for the transition so a cross-X.Y.Z
  move off the current legacy pins is still offered;
- legacy dev.<sha> deliberately excluded -- branch-cut devs stay
  renovate-invisible and are delivered by bot PRs.

Stable adoption therefore stays a deliberate human change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QF99maZfAqQ5onTGatgDvy
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 25, 2026
Tracks xmtp/libxmtp#4048's same-minute-collision fix: the prerelease timestamp widened from YYYYMMDDHHMM to YYYYMMDDHHMMSS, so releases minted in the same minute no longer tie and fall back to channel-word ordering.
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 26, 2026 02:16

Dismissing prior approval to re-evaluate 5f5e082

@insipx
insipx merged commit 1ee6e9c into main Aug 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant