Flagged in #1438: the codebase carried three parallel implementations of update-type classification — utils/helpers.getUpdateType (the one live paths import), a private Buddy.getUpdateType, and VersionResolver.getUpdateType. A three-reader workflow mapped their exact semantics, a synthesis produced a difference table, and two adversarial verifiers reproduced every claimed disagreement by executing all three against the real source (24-case matrix, zero refutations).
Where they disagreed, and what won
| Input | helpers | Buddy (private) | VersionResolver | Decided |
|---|---|---|---|---|
v4 → v4.2.2 | patch ❌ | minor | minor | minor — Bun.semver.order('4.2.2','4') is -1, so helpers' upgrade guard misread a real bump as a downgrade |
v1.0.0 → v2.0.0 | major | major | patch ❌ | major — the resolver never stripped v, so a breaking change vanished |
1.0.0-beta.1 → 1.0.0 | major ❌ | patch | patch | patch — helpers' major was an accidental fall-through that let excludeMajor block a beta graduation |
latest → 1.0.0 | patch | patch | major ❌ | patch — the resolver fabricated major from NaN parts |
3.19-alpine → 3.20-alpine | minor | patch ❌ | patch ❌ | minor — only helpers read the numeric core; the others returned patch as a failure artifact |
The consolidation
helpers.getUpdateTypeis canonical — amended with numeric-only pad-to-3 before the semver guard (fixes short tags; suffixed tags deliberately pass through untouched), apatchfall-through instead ofmajor(fixes prerelease movement), and its deadsemver.satisfiesfallback catch removed (nothing in that try block could throw).Buddy's private copy is deleted; its three call sites (deps.yaml, GitHub Actions, Dockerfile scans) rebind to the already-imported helper. The verifier confirmed no behavioral change on the numeric/prerelease shapes those paths pass — except the deliberate suffixed-tag fix.VersionResolver.getUpdateTypedelegates, keeping the package-root export source- and type-compatible.
Deliberate behavior deltas on live paths
- GH Actions short-tag bumps (
v4→v4.2.2) stop reading aspatch— an auto-merge conditioned onpatch-onlyno longer waves them through. - Prerelease graduations stop reading as
major—excludeMajorstops blocking them. - Suffixed Docker tag bumps classify by their numeric core (
minor/major), so apatchstrategy now correctly excludes them.
Tests
New matrix in test/version-classification.test.ts pins every decided case, plus a parity check that VersionResolver answers identically. bun test: 2232 pass / 0 fail; typecheck and pickier green. All pre-existing assertions in both version suites pass unchanged.
🤖 Generated with Claude Code