Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2745,6 +2745,30 @@ jobs:
- name: Release-body limit guard
run: pnpm check:release-body

# Post-publish npm verification (#15321). The last thing the `publish` job
# does is prove every published package is readable on npm. That check ran
# as one `npm view` of @objectstack/cli and failed the 17.3.0 release,
# which had succeeded completely: npm committed cli@17.3.0 at 10:53:25.108
# and the read at 10:53:32 got an absence, because the write path and the
# CDN-fronted read path are eventually consistent. Worse, it looked at 1
# package of 69, so the one failure it exists to catch — a package that
# genuinely did not publish — is the one it could not see, and the false
# red on `cli` would have masked it.
#
# scripts/release-verify-npm.mjs replaces it with bounded backoff over the
# whole derived publishable set. Its --self-test is the ONLY instrument on
# that logic: the production path runs once per release, on a runner, with
# npm's real timing, so nothing else can tell a working retry loop from a
# broken one. It drives the real code with a stub registry — the #15321
# cold read reproduced through the OLD parameters (one target, no retry,
# which is a red on a healthy package) and then absorbed by the new ones,
# plus the partial publish the old shape reported green.
#
# Invoked as `node` rather than through a `pnpm check:*` alias: see the
# GATE INVOCATION IDIOM note at the top of this file.
- name: Post-publish npm verification self-test
run: node scripts/release-verify-npm.mjs --self-test

# #3825 Node-version drift guard: a runtime pin is 18 separate string
# literals across .github/workflows, so a split is invisible until someone
# greps for it. One did open — every PR gate sat on Node 20 (EOL
Expand Down
43 changes: 40 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1224,10 +1224,47 @@ jobs:

# `changeset publish` skips versions already on the registry, so a
# re-dispatch over a partially-published release is a repair, not a
# duplicate. What is NOT optional is that the version is on npm when
# duplicate. What is NOT optional is that EVERY package is on npm when
# this step ends.
if ! npm view "@objectstack/cli@$VERSION" version >/dev/null 2>&1; then
echo "::error::publish ran but @objectstack/cli@$VERSION is still not on npm"
#
# ⚠️ This checks what happens AFTER a publish, never WHETHER one runs.
# The gating above it — `environment: release`, the `publish-pending`
# predicate and its parenthesisation, `force`'s dispatch-only
# semantics — is the "ONLY A HUMAN PUBLISHES" invariant and is not
# this check's business.
#
# It used to be one `npm view` of @objectstack/cli, and #15321 is the
# two ways that failed on the 17.3.0 release, which had succeeded
# completely:
#
# ① It raced the registry. npm committed cli@17.3.0 at 10:53:25.108
# and this read at 10:53:32 — seven seconds later — and got an
# absence. The write path and the CDN-fronted read path are
# eventually consistent; a single shot immediately after a
# 69-package burst bets the release on how fast reads settle.
# scripts/release-verify-npm.mjs retries with bounded backoff for
# 15 minutes, derived from that release's own npm `time` field:
# the last package (@objectstack/runtime) committed 7m07s after
# the first read.
#
# ② It looked at 1 package of 69. Had a package genuinely failed to
# publish, this step could not have seen it — and the false red
# on `cli` would have MASKED it. The verifier now derives the
# whole publishable set from the workspace (never a transcribed
# list) and names, on failure, exactly which packages are absent,
# so the `force` repair dispatch has something to act on.
#
# ⛔ It still fails CLOSED. The retry absorbs LATENCY, never absence:
# a package still missing when the budget is spent exits non-zero, and
# so does a registry that could not be read at all. No `|| true`, no
# downgrade to a warning — the value of this step is that it reds.
# `published=true` below is written only on its success.
#
# `$VERSION` is handed over as RELEASE_VERSION — the spelling the two
# steps below already use for the same value — so the verifier refuses
# outright if the workspace it derives targets from disagrees with the
# version this run was approved for.
if ! RELEASE_VERSION="$VERSION" node scripts/release-verify-npm.mjs; then
exit 1
fi
echo "published=true" >> "$GITHUB_OUTPUT"
Expand Down
Loading
Loading