fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(release): three traps that report success while doing nothing - #82

Merged
brentrager merged 3 commits into
mainfrom
fix/release-traps
Aug 20, 2026
Merged

fix(release): three traps that report success while doing nothing#82
brentrager merged 3 commits into
mainfrom
fix/release-traps

Conversation

@brentrager

@brentragerbrentrager commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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 fixture

Go'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:

$ python3 -c "...zero every sha256, set headBytes to 999..."
$ go test ./...
ok github.com/SmooAI/file/go/file/v2 (cached)

So the Go quarter of the five-port lazy contract was proving nothing.go:test now passes -count=1, and the same corruption fails immediately (streamHeadBytes = 65536, contract says 999). Verified end to end through pnpm 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=1 went in the package.json script rather than the workflow, so pnpm test, pnpm check-all and the husky pre-commit all get it.

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). #68 widened the blast radius by adding dotnet format to pnpm format.

Now format:check, with the write moved into pnpm run version, before the action commits.

Sequencing confirmed necessary rather than assumed: ran changeset version locally and checked its output — the generated CHANGELOG.md is not oxfmt-clean. Without formatting inside version, format:check would redden every future release PR. With it, pnpm run version leaves 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 → published is 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

  • A fail-open in the fix itself. A botched edit left the npm-probe result being overwritten by a later branch, so --expect-npm exited 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.
  • NuGet is reported but not asserted. 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 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 push exits non-zero on a real failure, and the per-registry gate skips it only when the version is genuinely there.

Controls, all three run

controlexpectedresult
all five present (2.2.14)exit 0
npm present, Go tag missing, NuGet laggingexit 1 naming go only
--expect-npm on an unpublished versionexit 1

Status 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

@changeset-bot

changeset-botBot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b8e9a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
NameType
@smooai/filePatch

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

brentragerand others added 3 commits August 20, 2026 15:40
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
@brentrager
brentrager merged commit d4cb3a3 into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/release-traps branch August 20, 2026 20:07
Sign up for freeto 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

@brentrager