Skip to content

npm-publish: an unmoved package is not a burned version name - #272

Merged
lannbot merged 2 commits into
mainfrom
fix-npm-githead
Sep 4, 2026
Merged

lannbot merged 2 commits into
mainfrom
fix-npm-githead

Conversation

@lannbot

@lannbot lannbot commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator

The v0.6.2 cut published to JSR and published nothing to npm. Fixing the guard, then re-running the publish for that release.

What happened

#268 added an already-published skip that compares a live tarball's gitHead to the sha being published, failing on any mismatch. That has a real job — telling "already published, same content" from "name occupied by a foreign tree" — but it cannot express the normal steady state:

@polyengine/protocol is not part of the lockstep; it versions independently (AGENTS.md §Consuming). So at every cut where protocol does not move, its live tarball is necessarily stamped with an earlier cut's sha. v0.6.2's protocol was the untouched 0.3.1 from v0.6.1, and the check called that a burned version name.

protocol is first in the publish loop, so it failed before runtime, translator, wasi and ct-runner were even attempted. Nothing reached npm.

#268 verified its check against a genuinely-foreign tarball and against a same-sha re-run — both correct. The unexercised third shape is the common one.

The fix

The guard keeps its job: an already-published version may only be skipped when the tarball provably carries this content. It gains one more way to be satisfied —

  • gitHead is the sha being published (a straight re-run), or
  • gitHead is an ancestor of ours and the package's source is unchanged since.

Everything else still fails hard, before any dependent publishes: a gitHead outside our history, a missing one, or our own history with the package changed since.

Verified locally against all four shapes:

case result
protocol@0.3.1 stamped 858d9dd (the v0.6.1 cut), protocol/ unchanged skip — the incident
protocol@0.3.0 stamped 7df6ec2, source since rewritten fatal — #268's original hole, still closed
a lockstep package whose source moved fatal
missing gitHead fatal

Why the checkout changed too

Deciding "ancestor, and unchanged since" needs both the old commit and its tree. The checkout was shallow (actions/checkout defaults to depth 1), which has neither — it would have failed every such check as if the name were burned. Hence fetch-depth: 0.

After this merges

Re-dispatch npm-publish.yml with tag: v0.6.2 to complete that cut, then confirm npm view @polyengine/runtime dist-tags names 0.6.2 as latest.

No version bump: this is CI only, no published surface.

The v0.6.2 cut published to JSR and published NOTHING to npm. The
already-published skip added in #268 compares a live tarball's `gitHead`
to the sha being published and fails on any mismatch. protocol is not part
of the lockstep — it versions independently — so at every cut where it
does not move, its tarball is necessarily stamped with an EARLIER cut's
sha. That is the normal steady state, and the check called it a burned
name. It failed on the first loop iteration, so the four lockstep packages
never got as far as being published.

#268's check has a real job and keeps it: an already-published version may
only be skipped when the tarball provably carries this content. It just
needs one more way to be satisfied. Now a version is skipped when its
`gitHead` is the sha being published (a straight re-run) OR when that
`gitHead` is an ancestor of ours and the package's source is unchanged
since. Everything else still fails hard before any dependent publishes: a
`gitHead` outside our history, a missing one, or our own history with the
package changed since.

The case that motivated #268 — `protocol@0.3.0` stamped `7df6ec2`, whose
protocol source has since been rewritten — still fails, on the
source-changed arm. Verified against all four shapes locally: the v0.6.1
protocol stamp skips, that foreign stamp fails, a lockstep package whose
source moved fails, and a missing `gitHead` fails.

The checkout needs `fetch-depth: 0` for this: deciding "ancestor, and
unchanged since" requires both the old commit and its tree, and the
default shallow clone has neither — it would fail every check as if the
name were burned.
@lannbot
lannbot enabled auto-merge September 4, 2026 02:26
@lannbot
lannbot merged commit 22b5d3d into main Sep 4, 2026
4 checks passed
@lannbot
lannbot deleted the fix-npm-githead branch September 4, 2026 02:41
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.

2 participants