Skip to content

fix(release): the baseline must not trail the branch being released - #589

Merged
rubenvdlinde merged 1 commit into
mainfrom
fix/release-baseline-must-not-trail-development
Aug 27, 2026
Merged

fix(release): the baseline must not trail the branch being released#589
rubenvdlinde merged 1 commit into
mainfrom
fix/release-baseline-must-not-trail-development

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

#584 was not enough, and I merged it saying it closed defect 2. It did not. This is the correction.

What #584 got wrong

#584 made the unstable version one patch ahead of the stable baseline. But that baseline is derived from the latest stable tag (or main's info.xml), and on several apps it trails development badly:

app baseline (tag) development
thematiq v1.0.0 1.1.0
versioniq v1.2.0 1.4.1
planninq v0.1.3 0.2.13
shillinq v0.1.9 0.2.1-unstable.*
integriq no tag 0.3.4
humaniq no tag 0.2.0

Bumping the patch of a baseline that already trails still lands below what is shipping — 1.2.1-unstable.<ts> is less than 1.4.1.

The fix

Take the max of the baseline and the branch's own version before bumping.

Verification

Simulated against all 21 apps' real tags and development versions, not invented ones:

downgrades
#584 as merged 6 / 21
with the baseline max 0 / 21

The condition was wrong, not just the arithmetic

shillinq is a sixth app the earlier analysis missed entirely. Its development carries a prerelease, so it passed the "does development carry a stable version?" test I used to enumerate affected apps — yet its tag trails anyway, so it was always affected.

The real condition was never "development is stable". It is "development has outrun the latest tag", which is a strictly larger set. My original enumeration found five apps by testing the wrong property and got a plausible answer, which is why it survived review — including my own.

Follows #584.

#584 was not enough, and I merged it saying it closed defect 2. It did
not. This is the correction.

#584 made the unstable version one patch ahead of the STABLE BASELINE.
But that baseline comes from the latest stable tag (or main's info.xml),
and on several apps it trails `development` badly:

    thematiq   tag v1.0.0   development 1.1.0
    versioniq  tag v1.2.0   development 1.4.1
    planninq   tag v0.1.3   development 0.2.13
    shillinq   tag v0.1.9   development 0.2.1-unstable.*
    integriq   no tag       development 0.3.4
    humaniq    no tag       development 0.2.0

Bumping the patch of a baseline that already trails still lands below
what is shipping: 1.2.1-unstable.<ts> is less than 1.4.1.

Taking the max of the baseline and the branch's own version is what
actually closes it.

Simulated against all 21 apps' real tags and development versions:

    downgrades with #584 as merged     6 / 21
    downgrades with the baseline max   0 / 21

The six are integriq, thematiq, shillinq, humaniq, versioniq, planninq.
shillinq is a sixth app the earlier analysis missed entirely: its
development carries a PRERELEASE, so it passed the "does development
carry a stable version" test, yet its tag trails anyway. The real
condition was never "development is stable" -- it is "development has
outrun the latest tag", which is a strictly larger set.
@rubenvdlinde
rubenvdlinde merged commit a106122 into main Aug 27, 2026
36 checks passed
rubenvdlinde added a commit that referenced this pull request Aug 27, 2026
…t land (#593)

Two defects, both of which made a broken release look like a good one.

1. The version could be lower than what the store already serves.

The baseline came from the newest stable git tag and, since #589, the
branch's own info.xml. Neither can see a prerelease line that ran ahead
somewhere else, and the fleet spent June and July releasing from
Codeberg where the beta line had walked up a minor: pipelinq
0.4.0-beta.2, decidesk 1.1.0-beta.1, larpingapp 0.2.0-beta.1. Those are
prerelease tags, so the ^v[0-9]+\.[0-9]+\.[0-9]+$ filter is blind to
them by construction. Back on GitHub the baseline fell back to the old
stable patch line, and pipelinq has been computing 0.3.2-beta against a
store holding 0.4.0-beta.2. Measured 2026-08-27: 14 of 21 fleet apps
were computing a downgrade.

Nothing rejected it. _check_permission in the appstore validates that
the app exists and that you own it; there is no version ordering rule at
all. A lower version uploads with a 200 and is then never offered to
anyone already on a higher one, so the only place this is visible is
here, before the number is chosen.

Read /api/v1/apps.json and fold its max into the baseline, then assert
under real semver that what we are about to publish outranks it. The
assertion is separate arithmetic on the full version string rather than
the stripped cores the baseline works in, so it can disagree with the
step it checks. Verified that apps.json agrees with the union of three
per-platform files across 18 fleet ids -- the per-platform endpoint
drops releases that do not match that platform and would reintroduce the
downgrade. A failed fetch fails the job; falling back to "the store has
nothing" is indistinguishable from an unregistered app.

A major bump is now refused unless it is a stable release carrying the
`major` label, so the arithmetic can adopt a higher minor but never
invent a major on its own.

Renamed apps are a new store entry starting from nothing, so their line
would restart below what the app already shipped: filinq was about to
publish 0.0.40 against docudesk's 0.1.0-beta.3. previous-app-id folds
the old entry in.

Simulated over all 21 apps: every one now outranks both its own entry
and its pre-rename entry, and none crosses a major.

2. A failed App Store upload was a ::warning:: and an exit 0.

On 2026-08-27 eighteen of the twenty-one fleet apps failed this call --
400 for an id that is not registered, 403 for a token that does not own
the app -- and every one of those runs is recorded as a green release.
The step advised a manual retry that nobody was ever told to perform.
Publishing to the store is the job; if it did not happen, the job did
not succeed. The two failures the fleet actually hits now name what to
do rather than what went wrong.

Registration also stops running on every release. POST /api/v1/apps is
the certificate-update endpoint and is rate limited hard; it was
returning 429 with a 17-hour lockout, bought for nothing since the app
was already registered. The catalogue fetched above says whether the id
exists, so registration runs only when it actually needs to.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
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