Repository navigation
Stop the release job formatting its own tree, and gate formatting instead - #11
Merged
Merged
Conversation
|
…tead
The 0.2.1 release published to npm and PyPI and then FAILED on crates.io:
error: 1 files in the working directory contain changes that were not
yet committed into git: rust/audit/Cargo.toml
Cause: release.yml ran `pnpm format` — WRITE mode — as a step, and nothing
committed the result. main was not format-clean, so the formatter dirtied the
tree, and `cargo publish` refused. That is the only thing `--allow-dirty` was
ever masking, and it was masking it blindly: the flag would have shipped
whatever the formatter happened to change.
Because that job aborted, the Go tag and the NuGet push never ran either, so
0.2.1 exists on npm + PyPI only. The next release restores lockstep across all
five; nothing is published by hand here.
- release.yml formats nothing. It runs `pnpm format:check`.
- pr-checks.yml gains the same gate — the repo had NO format check at all,
which is how main drifted out of format in the first place.
- New `format:check` (oxfmt --check + ruff format --check + the existing
rust/go check scripts) and `python:format-check`.
- The repo is formatted once, so the gate is green from the start.
- `pnpm run version` now ends with `pnpm format`. Verified necessary, not
decorative: a changesets-generated CHANGELOG.md is NOT oxfmt-clean, so
format:check would have redded every release PR — the same self-inflicted
break in a new place. Simulated the full lifecycle (`changeset version` ->
sync -> format) and confirmed both format:check and version:check pass on
the resulting tree at 0.3.0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
The new format:check gate immediately caught its own motivating case: release #10 appended a changesets-generated 0.3.0 entry to CHANGELOG.md, and that output is not oxfmt-clean. Exactly what the `pnpm run version` change in this PR prevents from recurring — this commit clears the one already on main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager
force-pushed
the
fix/format-check
branch
from
August 20, 2026 18:18
93b98b0 to
5564e9d
Compare
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 free
to 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.
What broke
The 0.2.1 release published to npm and PyPI, then died on crates.io (run 32401070715):
release.ymlhad a step that ranpnpm format— write mode — and nothing committed the result.mainwas not format-clean (this repo has never had a format check anywhere), so the formatter reliably dirtied the tree beforecargo publishran.That is the entire reason
--allow-dirtyexisted. Removing it in #7 didn't cause this; it revealed it. And the flag was masking it blindly:--allow-dirtywould publish whatever the formatter happened to rewrite, unreviewed.Collateral: the crates.io step aborting killed the rest of the job, so the Go tag and the NuGet push for 0.2.1 never ran. 0.2.1 is on npm + PyPI only. I have not hand-published anything — the next release restores all five to lockstep (see below).
The fix
release.ymlformats nothing. It runspnpm format:check. A write-mode formatter in a release pipeline can only dirty the tree; formatting is a gate, not a release side effect.pr-checks.ymlgains the same gate. There was no format check in either workflow, which is howmaindrifted out of format at all.format:check(oxfmt --check+ruff format --check+ the existingrust:fmt:check/go:fmt:check) andpython:format-check. Added tocheck-alltoo.README.md, reindentsspec/parity-corpus.jsonfrom 4-space to 2-space, and reflows some TOML/package.jsonkey order. No content or semantic change — every suite still passes, corpus loaders included (they parse JSON, not bytes).The part that would have bitten again
pnpm run versionnow ends withpnpm format.That is not decoration. I simulated it: a changesets-generated
CHANGELOG.mdis not oxfmt-clean, so addingformat:checkalone would have redded every future release PR — the same self-inflicted break, one step further down the pipeline. Folding the format into theversionlifecycle works because that lifecycle's output is already committed by the changesets action (the Spec A fix from #7).Verified end to end with a scratch changeset:
Both gates pass on exactly the tree a release PR will contain, in both the version run and the subsequent publish run.
Verification
format:check,version:check,tsc --noEmit,oxlint(0 errors),pnpm test(51 TS · 63 Python · 21 Rust · 9 Go),dotnet test(31) all green on the reformatted tree.No changeset: no published code changes, only formatting and CI configuration.
🤖 Generated with Claude Code
https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC