Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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

Sync manifest versions during the bump, not after publish, and guard it - #186

Merged
brentrager merged 1 commit into
mainfrom
fix/version-sync
Aug 20, 2026
Merged

Sync manifest versions during the bump, not after publish, and guard it#186
brentrager merged 1 commit into
mainfrom
fix/version-sync

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

"ci:publish": "node scripts/ci-publish.mjs"// → build → changeset publish → pnpm version:sync

The sync ran after the publish. It mutated manifests in a CI workspace that was then discarded, so nothing it wrote was ever committed. Two consequences, both live in this repo today:

  1. Every git tag ships stale version constants. With 4.4.0 on npm, git show origin/main:go/version.go says 3.2.3.
  2. cargo publish --allow-dirty exists only to paper over the dirt — the comment above it says so outright.

The actual state of main before this PR:

manifestversion
package.json4.4.0
python/pyproject.toml3.2.3
python/uv.lock3.2.3
rust/logger/Cargo.toml + Cargo.lock3.1.2
go/version.go3.2.3
dotnet/…/SmooAI.Logger.csproj4.1.0

Five languages, four different versions, none of them the published one. This is also how the /v3 Go module bug survived: sync-versions.mjs never looked at go.mod at all.

Fix

  • Sync moves into the changesets version lifecycle."version": "changeset version && node scripts/sync-versions.mjs", with version: pnpm run version on changesets/action. The action commits the working tree after version, so the synced manifests land in the release commit.
  • ci:publish no longer syncs.
  • cargo publish drops --allow-dirty, gains --locked.
  • python/uv.lock joins the synced set. Missed before, and not cosmetic: poe install-dev runs uv sync --locked, which errors when the lock disagrees with pyproject.toml — syncing pyproject.toml alone would have broken dev installs outright.
  • sync-versions.mjs rewrites go.mod's /vN suffix on a major bump, the other half of the tag-resolution fix.

The guard

New check:versionsfails — never warns — when any manifest disagrees with package.json, including go.mod's major. It runs in two places:

wherewhy
pr-checks.yml + release pre-flightfast feedback
inside release.yml's "Tag and publish Go module" stepchangesets has bumped by then; the only point where the version that becomes the tag exists

scripts/check-go-module.mjs is folded into it, not kept alongside. Both now read one scripts/versioned-files.mjs, so the guard cannot drift from the syncer — a hand-copied second list is exactly the failure mode this change is about. All six of the go-module spec's cases carried over into check-versions.spec.ts.

Verification

The guard, run on main before syncing — this is the bug, printed:

check-versions: FAILED — manifests disagree with package.json (4.4.0)
- python/pyproject.toml is at 3.2.3, expected 4.4.0 (package.json)
- python/uv.lock is at 3.2.3, expected 4.4.0 (package.json)
- rust/logger/Cargo.toml is at 3.1.2, expected 4.4.0 (package.json)
- rust/logger/Cargo.lock is at 3.1.2, expected 4.4.0 (package.json)
- go/version.go is at 3.2.3, expected 4.4.0 (package.json)
- dotnet/src/SmooAI.Logger/SmooAI.Logger.csproj is at 4.1.0, expected 4.4.0 (package.json)

After node scripts/sync-versions.mjs: check-versions: OK (all manifests at 4.4.0).

  • Hand-broke go/version.go to 9.9.9 → exit 1 with exactly that one line. Restored → green.
  • cargo check --locked --all-targets and cargo package clean after the sync, so --locked on publish is safe.
  • uv sync --locked --group dev resolves smooai-logger==4.4.0.
  • scripts/check-versions.spec.ts: 8 cases, including the real 4.3.0-vs-3.2.3 skew and all four Go-module cases.

Note on this PR's own diff

It contains a one-time version bump of five manifests from 3.x/4.1.0 to 4.4.0 — that is the accumulated skew being closed, not a release. The next changeset release will bump them together from here on.

🤖 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: 456ad51

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

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

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

`ci:publish` ran `pnpm build && changeset publish && pnpm version:sync`. The
sync happened AFTER the publish, mutating manifests in a CI workspace that was
then discarded — so every git tag shipped stale version constants, and
`cargo publish --allow-dirty` existed only to paper over the dirt. On a repo
publishing 4.4.0 to npm, this is what the manifests actually said:
package.json 4.4.0
python/pyproject.toml 3.2.3
python/uv.lock 3.2.3
rust/logger/Cargo.toml/.lock 3.1.2
go/version.go 3.2.3
dotnet/…/SmooAI.Logger.csproj 4.1.0
The sync moves into the changesets `version` lifecycle, whose working tree the
action commits, so the bumped manifests land in the release commit. cargo
publish drops --allow-dirty and gains --locked (verified: cargo check --locked
and cargo package both clean after the sync).
python/uv.lock joins the synced set. It was missed before and is not cosmetic:
`poe install-dev` runs `uv sync --locked`, which errors outright when the lock
disagrees with pyproject.toml — so syncing pyproject alone would have broken
dev installs. sync-versions also rewrites go.mod's /vN suffix on a major bump,
which is the other half of the tag-resolution fix.
The new check:versions guard fails — never warns — when any manifest disagrees.
It runs in PR checks and again inside the release tagging step, which is the
only point where the post-bump version that becomes the tag exists. Verified red
by hand-setting go/version.go to 9.9.9.
check-go-module is folded into it rather than kept alongside: both now read the
same scripts/versioned-files.mjs, so the guard cannot drift from the syncer. A
hand-copied second list is precisely the failure mode this change is about.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@brentrager
brentrager merged commit ad58fce into mainAug 20, 2026
1 check passed
@brentrager
brentrager deleted the fix/version-sync branch August 20, 2026 18:30
brentrager added a commit that referenced this pull request Aug 20, 2026
…189)
The release that bumped package.json to 4.5.1 ran from the commit BEFORE the
version-sync fix (#186) landed, so it used the old plain `changeset version`
with no sync. The next release run then hit the new guard and stopped, exactly
as designed:
check-versions: FAILED — manifests disagree with package.json (4.5.1)
- python/pyproject.toml is at 4.5.0, expected 4.5.1 (package.json)
... (all six)
That is the guard working, not a regression — main genuinely carries a
package.json bump that never reached the other five manifests. This is the last
bump that can happen: from here `changeset version` runs
`changeset version && node scripts/sync-versions.mjs`, and the changesets action
commits the whole working tree, so the manifests ride along in the bump commit.
No changeset on purpose. 4.5.1 was never published — the failing guard skipped
every publish step — so merging this lets the release finish 4.5.1 consistently
across npm, PyPI, crates.io, the Go tag and NuGet. Adding a changeset would bump
to 4.5.2 and strand 4.5.1 in the changelog with nothing published under it.
Verified: `uv sync --locked` and `cargo check --locked` both clean at 4.5.1.
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Aug 20, 2026
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
brentrager added a commit that referenced this pull request Aug 20, 2026
#192)
* Commit the formatting, and stop the release from dirtying its own tree
Dropping `cargo publish --allow-dirty` (#186) surfaced what the flag had been
hiding for who knows how long:
error: 1 files in the working directory contain changes that were not yet
committed into git:
rust/logger/README.md
The dirt comes from release.yml's own `Format` step. It runs `pnpm format`,
which REWRITES files and then never commits them — so `cargo publish` a few
steps later stares at a dirty tree. `--allow-dirty` existed to shrug that off,
which meant every published crate silently carried uncommitted reformatting.
main is format-drifted across seven files: .claude/settings.json (4-space vs
oxfmt's 2), README.md (94 lines), CHANGELOG.md, package.json (devDependencies
unsorted, peerDependencies out of position), a Python test, a TS spec, and
rust/logger/README.md. Nothing checked: PR checks run oxlint but never a
formatter check, and `pnpm format:check` did not exist.
Three changes:
1. Commit the formatting. `pnpm format` is now a no-op on main.
2. Add `format:check` (oxfmt + ruff + cargo fmt + gofmt) and run it in PR
checks, so this cannot drift again. Verified red by hand-breaking both a
markdown file and a TS file.
3. release.yml's `Format` step becomes `Format check` — check, never rewrite. A
release pipeline that mutates the tree and discards the result is exactly the
thing that made `--allow-dirty` look necessary.
Also: `changeset version` writes CHANGELOG.md and package.json, and oxfmt wants
both formatted differently, so the version lifecycle now ends with
`oxfmt --write CHANGELOG.md package.json`. Without it the very next release PR
would land unformatted and break `cargo publish --locked` all over again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
* Add the changeset
Needed for its own sake (this changes package.json scripts) and to unstick the
release: crates.io, NuGet and the Go tag stalled at 4.5.0 while npm and PyPI
reached 4.5.2, and the downstream publish steps only fire when changesets
reports it published something — which needs a version bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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