Skip to content

Make the Go adapter modules actually resolvable, and gate the four publishes - #103

Merged
brentrager merged 1 commit into
mainfrom
fix/go-modules-releasable
Aug 20, 2026
Merged

Make the Go adapter modules actually resolvable, and gate the four publishes#103
brentrager merged 1 commit into
mainfrom
fix/go-modules-releasable

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

The Go adapters could never have been published

go/fiber and go/gin are separate Go modules. Both carried:

require github.com/SmooAI/observability/go v0.0.0
replace github.com/SmooAI/observability/go => ../

Go honours replace only in the main module's go.mod. In a published module it is invisible: a consumer running go get github.com/SmooAI/observability/go/fiber@vX resolves the core at v0.0.0 — a version that has never existed — and fails.

Nothing in the repo could tell, because inside the repo the replace makes everything build.

Demonstrated, not assumed. Dropping the replace on a scratch copy reproduces the consumer's exact error:

go: downloading github.com/SmooAI/observability/go v0.0.0
reading github.com/SmooAI/observability/go/go.mod at revision go/v0.0.0: unknown revision go/v0.0.0

Fix

The adapters now require the core at its real released version and carry no replace. go/go.work supplies the sibling source for local builds and CI — and a workspace is not published.

The workspace replace has to be version-specific (Go rejects an all-versions replace of a workspace module), so that line is version-bearing too and joins sync-versions.mjs's TARGETS along with both require lines. 14 files now, up from 11.

The guard

scripts/check-go-modules.sh, run by both pr-checks.yml and the publish gate so the two cannot drift:

  1. no replace in any published go.mod
  2. each module path matches its directory
  3. Spec B's /vN rule, checked in both directions — a major ≥ 2 must carry the suffix, a 0.x/1.x must not. It reads the major from package.json, so it flips over automatically at the 2.0 bump instead of waiting to be remembered. Today it asserts the suffix is absent, correct at 0.19.x, and it is the check that would have caught the fetch/file/logger defect.

Negative-controlled by hand: adding a replace back to go/fiber exits 1; setting package.json to 2.0.0 exits 1 naming all three modules.

publish.yml

  • go/fiber/v* and go/gin/v* tag triggers, and the go job condition widened to refs/tags/go/. The adapters previously had no way to be published at all — go/v* does not glob-match go/fiber/v0.19.2.
  • A verify gate every publish job depends on: all 14 version-bearing files agree with package.json, and the tag names that same version. A mistyped tag now fails on a bare runner before any toolchain boots — which matters, because crates.io/PyPI/NuGet publishes are irreversible.
  • cargo package/publish --locked instead of bare. --locked, never --allow-dirty: a publish that has to mutate the lockfile is publishing something the tag never built.
  • Proxy warming derives the module path from the tag and retries, so it serves all three modules and a slow proxy no longer reports a good release as broken.

RELEASING.md documents the sequence, including the ordering constraint that falls out of the above: go/vX must be tagged and on the proxy before go/fiber/vX and go/gin/vX.

Release readiness — and what is deliberately NOT done

No first publish. crates.io, PyPI and NuGet first publishes are irreversible and are the user's call.

Verified ready:

check result
name free on crates.io smooai-observability does not exist
name free on PyPI ✅ 404
name free on NuGet ✅ BlobNotFound
cargo publish --dry-run --locked ✅ packaged 29 files, built from the tarball
uv build + twine check ✅ PASSED on wheel and sdist
dotnet pack .nupkg + .snupkg, README embedded, all three TFMs
Go modules resolvable check-go-modules.sh clean, all three build and test

The repo is one git tag && git push per language away. See RELEASING.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC

…blishes

`go/fiber` and `go/gin` are separate Go modules that both carried:

    require github.com/SmooAI/observability/go v0.0.0
    replace github.com/SmooAI/observability/go => ../

Go honours `replace` only in the MAIN module's go.mod. In a PUBLISHED module it
is invisible: a consumer running `go get .../go/fiber@vX` resolves the core at
`v0.0.0`, a version that has never existed, and fails. Both adapters were
unpublishable, and nothing in the repo could tell — inside the repo the replace
makes everything build.

Demonstrated rather than assumed: dropping the replace on a scratch copy and
building reproduces the consumer's exact error,

    go: downloading github.com/SmooAI/observability/go v0.0.0
    reading .../go.mod at revision go/v0.0.0: unknown revision go/v0.0.0

Fix: the adapters now require the core at its real released version and carry NO
replace. `go/go.work` supplies the sibling source for local builds and CI, and a
workspace is not published. (The replace has to be version-specific — Go rejects
an all-versions replace of a workspace module — so the go.work line is
version-bearing too and joins sync-versions.mjs's TARGETS, alongside both
require lines. 14 files now, up from 11.)

`scripts/check-go-modules.sh` is the guard, run by BOTH pr-checks and the
publish gate so the two cannot drift:

  1. no `replace` in any published go.mod
  2. each module path matches its directory
  3. Spec B's /vN rule, checked in BOTH directions — a major >= 2 must carry the
     suffix, a 0.x/1.x must not. It reads the major from package.json, so it
     flips over automatically at the 2.0 bump instead of waiting to be
     remembered. Today it asserts the suffix is ABSENT, which is correct at
     0.19.x and is the check that would have caught fetch/file/logger.

Negative-controlled by hand: adding a replace back to go/fiber exits 1; setting
package.json to 2.0.0 exits 1 naming all three modules.

publish.yml also gains:

- `go/fiber/v*` and `go/gin/v*` tag triggers, and a `go` job condition widened
  to `refs/tags/go/` — the adapters had no way to be published at all
- a `verify` gate every publish job depends on: all 14 version-bearing files
  agree with package.json AND the tag names that same version. A mistyped tag
  now fails on a bare runner before any toolchain boots, which matters because
  crates.io/PyPI/NuGet publishes are irreversible
- `cargo package/publish --locked` instead of bare. --locked, never
  --allow-dirty: a publish that has to mutate the lockfile is publishing
  something the tag never built
- proxy warming that derives the module path from the tag and retries, so it
  serves all three modules and a slow proxy no longer reports a good release as
  broken

RELEASING.md documents the whole sequence, including the ordering constraint
that falls out of the above: `go/vX` must be tagged and on the proxy BEFORE
`go/fiber/vX` and `go/gin/vX`, because the adapters require it.

DELIBERATELY NOT DONE: no first publish. crates.io, PyPI and NuGet first
publishes are irreversible and are the user's call. Names verified free on all
three; dry runs all clean (`cargo publish --dry-run --locked` packaged 29 files
and built from the tarball, `uv build` + `twine check` PASSED on both artifacts,
`dotnet pack` produced .nupkg + .snupkg with README and all three TFMs). The
repo is one `git tag && git push` per language away.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152bbE1veqfG1SVJdyLCBxC
@changeset-bot

changeset-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 28804f5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@brentrager
brentrager merged commit fc8afb6 into main Aug 20, 2026
8 checks passed
@brentrager
brentrager deleted the fix/go-modules-releasable branch August 20, 2026 18:53
Sign up for free to 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