Uh oh!
There was an error while loading. Please reload this page.
fix(release): three traps that report success while doing nothing - #82
Merged
Conversation
🦋 Changeset detectedLatest commit: 18b8e9a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
All three confirmed live in this repo, not theoretical. 1. `go test ./...` served a CACHED pass against a corrupted fixture. Go's build cache does not invalidate on a file read from outside the package directory — exactly the shape of the shared contract fixtures in spec/. Verified by zeroing every sha256 and setting headBytes to 999: still `ok (cached)`. So the Go quarter of the five-port lazy contract was proving nothing. `go:test` now passes `-count=1`; the same corruption fails immediately. 2. release.yml ran `pnpm format` in WRITE mode. Whatever it rewrote was either swept into the release commit unreviewed, or — in publish mode, where the changesets action commits nothing — left the tree dirty for `cargo publish --locked`, which would fail every release now that `--allow-dirty` is gone (dropped in #66). The step is now `format:check`, and the formatting the release genuinely needs moved into `pnpm run version`, before the action commits. Confirmed that changesets' generated CHANGELOG.md is NOT oxfmt-clean, so without that ordering `format:check` would redden every future release PR. 3. PyPI, crates.io, NuGet and the Go tag were gated on `steps.changesets.outputs.published == 'true'` — on npm having published in THAT run. npm succeeds, a later step fails, the retry finds nothing new for npm, all four skip: a GREEN run that published nothing, leaving four ports on the old version indefinitely. Each is now gated on whether its own registry carries package.json's version, so a retry ships exactly what is missing, and a final step fails the run if npm published a version the others did not. `scripts/check-registries.mjs` does the detection, waits out index propagation (reading "missing" during the lag would skip the publish this run just earned, then report success), and doubles as a manual "are we stranded?" command. Verified both directions: all five present on 2.2.14 exits 0; npm present with the Go tag missing exits 1 naming it. Checked and NOT stranded today: npm, PyPI, crates.io, both NuGet packages and the Go tag are all on 2.2.14, so the truncation fix reached every port. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
…ying wolf on NuGet Two corrections found while verifying the previous commit rather than assuming it. A botched edit had left the npm-probe result being overwritten by a later branch, so `--expect-npm` returned exit 0 on a version npm did not have. Every downstream gate is `!has && present.npm`, so a false npm reading would have switched all four publishes off and let the run go green having shipped nothing — the exact fail-open this script exists to remove, reintroduced one level up. Now exits 1 with a message naming the disagreement. Verified: exit 1 on an unpublished version, exit 0 once npm has it. NuGet is no longer asserted on. Its index takes minutes to tens of minutes to show a package it has already accepted — 2.2.19 logged "Your package was pushed" for both packages and the flat-container index still read 2.2.14 twenty minutes later — so the guard would have reddened every successful release, and a guard that cries wolf gets deleted. npm, PyPI, crates.io and the Go tag index in seconds and stay strict. NuGet keeps its own protection: `dotnet nuget push` exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely already there. Its state is still reported, just not enforced, and the reason is in the code so it does not read as an oversight. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
The stranding guard's comment still said "any of the other four" after NuGet was dropped from the strict set, and the PyPI step still called the wheels it cleans "pre-sync version" — which stopped being true when sync-versions moved into the `version` lifecycle. A comment that describes behaviour the code no longer has is worse than none, because the next reader trusts it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentragerforce-pushed
the
fix/release-traps
branch
from
August 20, 2026 19:41
e9e1e11 to
18b8e9aCompareUh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
All three confirmed live in this repo, not theoretical. Flagged by the audit agent from a sibling repo; each reproduced here before fixing.
1.
go test ./...served a cached pass against a corrupted fixtureGo's build cache doesn't invalidate on a file read from outside the package directory — exactly the shape of the shared contract fixtures in
spec/. Reproduced:So the Go quarter of the five-port lazy contract was proving nothing.
go:testnow passes-count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end throughpnpm go:test: exit 1 corrupted, exit 0 restored.The other four ports were never affected — vitest, pytest, cargo and dotnet all re-read the fixture.
-count=1went in the package.json script rather than the workflow, sopnpm test,pnpm check-alland the husky pre-commit all get it.2.
release.ymlranpnpm formatin write modeWhatever it rewrote was either swept into the release commit unreviewed, or — in publish mode, where the changesets action commits nothing — left the tree dirty for
cargo publish --locked, which would fail every release now that--allow-dirtyis gone (dropped in #66). #68 widened the blast radius by addingdotnet formattopnpm format.Now
format:check, with the write moved intopnpm run version, before the action commits.Sequencing confirmed necessary rather than assumed: ran
changeset versionlocally and checked its output — the generatedCHANGELOG.mdis not oxfmt-clean. Without formatting insideversion,format:checkwould redden every future release PR. With it,pnpm run versionleaves a format-clean tree.3. Four registries gated on npm succeeding in the same run
if: steps.changesets.outputs.published == 'true'on PyPI, crates.io, the Go tag and NuGet. npm succeeds, a later step fails, the retry finds nothing new for npm →publishedis false → all four skip, the run goes green, and nothing was published.Each step is now gated on whether its own registry carries
package.json's version, so a retry ships exactly what's missing, plus a final step that fails the run on a real strand.Two corrections found while verifying this, not after merging it
--expect-npmexited 0 on a version npm didn't have. Since every gate is!has && present.npm, a false npm reading would have switched all four publishes off and gone green having shipped nothing — the exact defect being removed, reintroduced one level up. Now exits 1 naming the disagreement.Your package was pushedfor both packages at 19:26 and the flat-container index still read 2.2.14 twenty minutes later. Asserting on it would have reddened every successful release, and a guard that cries wolf gets deleted. NuGet keeps its own protection —dotnet nuget pushexits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.Controls, all three run
--expect-npmon an unpublished versionStatus check the lead asked for — not stranded
At the time of checking, npm / PyPI / crates.io / both NuGet packages / the Go tag were all on 2.2.14, so the truncation fix reached every port. 2.2.19 has since published to npm, PyPI, crates.io and the Go tag, with NuGet accepted and indexing. Two earlier release runs did fail, both at "a pull request already exists for changeset-release/main" — a concurrency race before any publish step, so nothing was half-published.
🤖 Generated with Claude Code
https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC