Context
The v13.0.0 npm publish failed (masked E404 on PUT registry.npmjs.org/neo.mjs, run 2026-06-12T06:07Z) although the operator had ALREADY configured npm Trusted Publishing for neo.mjs (npmjs.com: trusted publisher neomjs/neo / npm-publish.yml / permissions: npm publish). The registry still serves 12.1.0; the morning cloud-trial anchor and the pages update are blocked on it.
Release classification: release-completion-blocking (the cut's distribution leg).
The Problem
.github/workflows/npm-publish.yml predates the trusted-publisher setup and defeats it twice:
- No
permissions: id-token: write on the job — GitHub never mints the OIDC token, so the npm CLI cannot perform the trusted-publishing exchange at all.
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} is still passed — token auth takes precedence over OIDC when present, and that token expired 2026-03-27 (operator-confirmed). The publish therefore attempted token auth with a dead token → npm's masked 404-on-PUT.
The Architectural Reality
.github/workflows/npm-publish.yml — release: published trigger, ubuntu-latest (hosted runner ✓ OIDC-compatible), node 24 (npm ≥11.5.1 ✓ trusted-publishing-capable), npm ci + npm publish with the token env.
- npmjs.com side: trusted publisher pinned to this exact workflow filename — already correct, nothing to change there.
- Re-trigger constraint: re-running the failed run executes the workflow as committed at the original ref — the fix can't reach it. A
workflow_dispatch trigger lets the operator re-publish 13.0.0 from dev tip (whose package.json already carries the bump).
The Fix
One workflow edit: add permissions: {id-token: write, contents: read}; remove the NODE_AUTH_TOKEN env (the NPM_TOKEN secret can be deleted afterward — trusted-publisher-only posture); add workflow_dispatch for the re-trigger (and future manual re-publishes).
Acceptance Criteria
Post-Merge Verification (operator-executed)
Tracked on PR #12971's Post-Merge Validation checklist + the #12696 publish runbook — reclassified from ACs in cycle 2 per the Resolves-mandate shape (operator rule #12367: a ticket's close-gating ACs are what the PR delivers; operator-credentialed runtime outcomes are post-merge verification):
- Operator dispatch on dev →
npm view neo.mjs version returns 13.0.0.
- Provenance attestation visible on the npm package page (free under OIDC publishing).
Out of Scope
- The KB-zip 404-at-publish ordering quirk (noted on #12969's trail).
- Deleting the dead
NPM_TOKEN secret (operator housekeeping, post-success).
Related
#12696 (the cut), #12965/PR #12966 (the cut's first unblock — same release).
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "npm publish OIDC trusted publisher id-token write expired NPM_TOKEN E404"
Context
The v13.0.0 npm publish failed (masked
E404onPUT registry.npmjs.org/neo.mjs, run 2026-06-12T06:07Z) although the operator had ALREADY configured npm Trusted Publishing forneo.mjs(npmjs.com: trusted publisherneomjs/neo/npm-publish.yml/ permissions: npm publish). The registry still serves 12.1.0; the morning cloud-trial anchor and the pages update are blocked on it.Release classification:release-completion-blocking (the cut's distribution leg).The Problem
.github/workflows/npm-publish.ymlpredates the trusted-publisher setup and defeats it twice:permissions: id-token: writeon the job — GitHub never mints the OIDC token, so the npm CLI cannot perform the trusted-publishing exchange at all.NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}is still passed — token auth takes precedence over OIDC when present, and that token expired 2026-03-27 (operator-confirmed). The publish therefore attempted token auth with a dead token → npm's masked 404-on-PUT.The Architectural Reality
.github/workflows/npm-publish.yml—release: publishedtrigger, ubuntu-latest (hosted runner ✓ OIDC-compatible), node 24 (npm ≥11.5.1 ✓ trusted-publishing-capable),npm ci+npm publishwith the token env.workflow_dispatchtrigger lets the operator re-publish 13.0.0 from dev tip (whosepackage.jsonalready carries the bump).The Fix
One workflow edit: add
permissions: {id-token: write, contents: read}; remove theNODE_AUTH_TOKENenv (theNPM_TOKENsecret can be deleted afterward — trusted-publisher-only posture); addworkflow_dispatchfor the re-trigger (and future manual re-publishes).Acceptance Criteria
id-token: writeand carries no token env.workflow_dispatchtrigger present (the re-publish path from dev tip).Post-Merge Verification (operator-executed)
Tracked on PR #12971's Post-Merge Validation checklist + the #12696 publish runbook — reclassified from ACs in cycle 2 per the
Resolves-mandate shape (operator rule #12367: a ticket's close-gating ACs are what the PR delivers; operator-credentialed runtime outcomes are post-merge verification):npm view neo.mjs versionreturns13.0.0.Out of Scope
NPM_TOKENsecret (operator housekeeping, post-success).Related
#12696 (the cut), #12965/PR #12966 (the cut's first unblock — same release).
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "npm publish OIDC trusted publisher id-token write expired NPM_TOKEN E404"