Skip to content

docs(releasing): distinguish npm replication lag from a failed publish - #101

Merged
ChessMess merged 1 commit into
mainfrom
docs/releasing-replication-lag
Sep 10, 2026
Merged

ChessMess merged 1 commit into
mainfrom
docs/releasing-replication-lag

Conversation

@ChessMess

Copy link
Copy Markdown
Owner

Documentation only. Both lessons come from the 2026-09-10 release of all 9 packages (run 34495769507) — the first end-to-end publish this workflow has actually performed.

New section — confirm a publish actually failed before debugging it

Placed before the existing failure playbook, so the "did it even fail?" question gets asked first.

npm replication lags a publish by up to ~5 minutes, and a lagging package is indistinguishable from a failed one:

Package Visible on npm
7 of 9 within seconds
ultimatedarktowerdisplay@2.0.0 ~3 min (15:32:19, run finished 15:29:12)
ultimatedarktowerrelay-shared@1.0.2 ~5 min (15:34:15)

For that window the repo looked exactly like a partial failure — green workflow, git tags pushed for all nine, two packages 404ing. And it was the same two package families as the real July 2026 partial failure, which makes the false positive genuinely convincing.

The fix: read Changesets’ own success manifest from the run log rather than trusting one registry query. A package listed under packages published successfully with a matching New tag: line was accepted by npm. The section adds the exact gh run view --log incantation, a poll-don’t-single-shot curl, and a warning to never re-run a publish or bump a version off a single 404 — the version is already taken on npm’s side, so retrying burns a number for nothing.

Softened the NPM_TOKEN allow-list claim

The old wording said the granular-token failure "fires every time a new published package joins the monorepo." That is too strong, and I acted on it this session — I flagged relay-cli as a near-certain blocker before merging.

It didn’t fire. ultimatedarktowerrelay-cli@0.2.0 — a brand-new name never before on npm (the log even shows Received 404 for npm info "ultimatedarktowerrelay-cli") — published cleanly on the first attempt, alongside eight existing packages. So the current token is either not package-scoped or was already broadened.

Now framed as the first hypothesis when a new package’s publish fails, rather than a blocker to fix pre-emptively. The old wording would send a future session to npmjs.com to solve a problem it doesn’t have.

https://claude.ai/code/session_01Br4DeujSD86Rj6uxYuTC2r

Both lessons come from the 2026-09-10 release of all 9 packages (run
34495769507), the first end-to-end publish this workflow has actually done.

New section, placed BEFORE the failure playbook so the "did it even fail?"
question gets asked first: npm replication lags a publish by up to ~5 minutes,
and a lagging package is indistinguishable from a failed one. Seven packages
were queryable within seconds; ultimatedarktowerdisplay@2.0.0 took ~3 minutes
and ultimatedarktowerrelay-shared@1.0.2 took ~5. For that window the repo looked
exactly like a partial failure -- green workflow, git tags pushed for all nine,
two packages 404ing on npm -- and it was the SAME two package families as the
real July 2026 partial failure, which makes the false positive very convincing.

The fix is to read Changesets' own success manifest from the run log rather than
trusting a single registry query: a package listed under "packages published
successfully" with a matching "New tag:" line was accepted by npm. Section adds
the exact `gh run view --log` incantation and a poll-don't-single-shot curl, plus
a warning never to re-run a publish or bump a version off one 404, since the
version is already taken on npm's side and retrying burns a number for nothing.

Also softens the NPM_TOKEN allow-list claim, which was too strong. It said the
granular-token failure "fires every time a new published package joins the
monorepo". It did not fire here: ultimatedarktowerrelay-cli@0.2.0, a brand-new
name never before on npm (the log even shows `Received 404 for npm info`),
published cleanly on the first attempt alongside eight existing packages. So the
current token is either not package-scoped or was already broadened. Now framed
as the first hypothesis when a new package's publish fails, rather than a
blocker to fix pre-emptively -- the old wording would send a future session to
npmjs.com to solve a problem it does not have.

Claude-Session: https://claude.ai/code/session_01Br4DeujSD86Rj6uxYuTC2r
@ChessMess
ChessMess merged commit b63d6f9 into main Sep 10, 2026
5 checks passed
@ChessMess
ChessMess deleted the docs/releasing-replication-lag branch September 10, 2026 16:17
ChessMess added a commit that referenced this pull request Sep 11, 2026
Audited 2026-09-10 after noticing only 1 of 9 published packages had ever
produced a provenance attestation -- 71 versions, 7 attested, all of them
ultimatedarktowerboard.

Nothing in the repo explains it. repository fields, publishConfig, prepack
hooks and NPM_CONFIG_PROVENANCE are identical across all nine, and the release
log shows no provenance error, warning or skip. The cause is npm-side: Trusted
Publisher is a PER-PACKAGE setting naming an exact repo + workflow file. When
the OIDC claim (workflow_ref: .github/workflows/release.yml) does not match the
package's entry, or no entry exists, npm cannot mint the attestation and
silently falls back to the NPM_TOKEN auth the workflow also supplies.

Checking all nine found two distinct faults, and the second was the common one:

  - No entry at all -- six packages (game-data, relay-{client,core,shared},
    mcp-server, relay-cli). Never configured.
  - Stale entry -- two packages. ultimatedarktower named publish.yml, deleted
    2026-07-11; ultimatedarktowerdisplay named ChessMess/UltimateDarkTowerDisplay,
    the archived pre-consolidation repo.

board was the only correct one, configured 2026-07-12 -- the day after the
workflow rename -- which is why it alone produced provenance.

The new section records the diagnosis path (registry, not repo: count attested
versions, then decode a working attestation to see which workflow produced it),
the exact field values that work, and two traps found while fixing it: entries
are immutable so a wrong one must be deleted and re-created, and Environment
must be left blank because release.yml declares no environment key -- filling it
in breaks the claim match silently. Also notes npm permits multiple entries per
package, so a correct one can be added alongside a stale one without deleting
anything, which matters because every write costs a 2FA security-key tap.

Closes the loop on the replication-lag section added in #101: that one was about
misreading a good publish as failed, this one is about a publish that really is
missing something and never says so.

Claude-Session: https://claude.ai/code/session_01Br4DeujSD86Rj6uxYuTC2r
ChessMess added a commit that referenced this pull request Sep 11, 2026
Audited 2026-09-10 after noticing only 1 of 9 published packages had ever
produced a provenance attestation -- 71 versions, 7 attested, all of them
ultimatedarktowerboard.

Nothing in the repo explains it. repository fields, publishConfig, prepack
hooks and NPM_CONFIG_PROVENANCE are identical across all nine, and the release
log shows no provenance error, warning or skip. The cause is npm-side: Trusted
Publisher is a PER-PACKAGE setting naming an exact repo + workflow file. When
the OIDC claim (workflow_ref: .github/workflows/release.yml) does not match the
package's entry, or no entry exists, npm cannot mint the attestation and
silently falls back to the NPM_TOKEN auth the workflow also supplies.

Checking all nine found two distinct faults, and the second was the common one:

  - No entry at all -- six packages (game-data, relay-{client,core,shared},
    mcp-server, relay-cli). Never configured.
  - Stale entry -- two packages. ultimatedarktower named publish.yml, deleted
    2026-07-11; ultimatedarktowerdisplay named ChessMess/UltimateDarkTowerDisplay,
    the archived pre-consolidation repo.

board was the only correct one, configured 2026-07-12 -- the day after the
workflow rename -- which is why it alone produced provenance.

The new section records the diagnosis path (registry, not repo: count attested
versions, then decode a working attestation to see which workflow produced it),
the exact field values that work, and two traps found while fixing it: entries
are immutable so a wrong one must be deleted and re-created, and Environment
must be left blank because release.yml declares no environment key -- filling it
in breaks the claim match silently. Also notes npm permits multiple entries per
package, so a correct one can be added alongside a stale one without deleting
anything, which matters because every write costs a 2FA security-key tap.

Closes the loop on the replication-lag section added in #101: that one was about
misreading a good publish as failed, this one is about a publish that really is
missing something and never says so.

Claude-Session: https://claude.ai/code/session_01Br4DeujSD86Rj6uxYuTC2r
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