Skip to content

latest does not move on approval — the dist-tag promote is manual, unrecorded, and easy to forget #366

Closed as not planned

Description

@tps-flint

After approval, latest does not move — the promote is by hand and undocumented

Raised in review of #365. That PR migrates publishing to OIDC + npm stage publish --tag staged, which is correct. This issue is the gap it leaves.

The flow as it now stands

  1. Tag push → six packages staged via OIDC under the staged dist-tag
  2. A maintainer approves in npm (2FA) → the version becomes public
  3. latest still points at the previous version
  4. Someone must run, per package:
    npm dist-tag add @tpsdev-ai/<pkg>@<version> latest
    

Step 4 is manual, unrecorded, and easy to forget — and until it happens npm install -g @tpsdev-ai/cli serves the old version while the GitHub release advertises the new one.

Why it is this way

--tag is an immutable property of a staged package, and npm stage approve has no tag flag — verified on npm 11.19.0, where it accepts only --otp and --registry. So the dist-tag is decided at stage time and approval cannot change it.

flair documents the same behaviour from production (flair#1686): "After a maintainer approves, the version is public but NOT latest". flair's latest moves through a sha-bound npm dist-tag add run by its canary after the staged build passes a dogfood run.

What to build

Port flair's pattern:

  • a promote step that moves latest only after a canary exercises the staged artifact
  • sha-bound: promote the exact version that was tested, never "whatever is newest", so a promote cannot skip past an untested publish
  • all six packages promoted together — packages/cli pins the platform binaries at exact versions, so a partial promote serves a latest CLI that resolves older binaries

Until then

The manual step is documented in release.yml's publish comment and in the run summary, so an approving maintainer is told that latest will not move and what to run. That is a mitigation, not a fix: it depends on someone reading it at the right moment.

Acceptance

  • latest moves only via an explicit, sha-bound promote of a version that has passed a canary against the staged artifact.
  • A partial promote is not possible — either all six move or none do.
  • The release summary states which version latest points at after the promote, so the end state is observable rather than assumed.

Refs #365, #362

Activity

  1. tps-flint commented on Oct 1, 2026

    @tps-flint
    ContributorAuthor

    Duplicate of #422. Closing in favour of #422. The all-six-or-none promote shipped in #371 (eacd365, scripts/promote-latest.sh); the remaining sha-bound, gated promote that reports the end state of latest is the scope of #422 (CI release-promote job with a tarball sha256 preflight and a skew check after).

    (Daily triage, verified on main.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions