Skip to content

Prepare 0.1.0: cut the changelog, and fix three things the first release would have shipped - #110

Merged
kingchenc merged 4 commits into
mainfrom
release/0.1.0-changelog
Aug 28, 2026
Merged

Prepare 0.1.0: cut the changelog, and fix three things the first release would have shipped#110
kingchenc merged 4 commits into
mainfrom
release/0.1.0-changelog

Conversation

@kingchenc

Copy link
Copy Markdown
Contributor

Everything here came out of dry-running the release before it runs for real. A tag publishes to six registries and cannot be undone, so each assembly step was executed by hand first.

The changelog now has [0.1.0] - 2026-08-28 holding all 161 entries, with an empty Unreleased above it. No version bump is needed: all 18 declarations already say 0.1.0 and nothing was ever tagged, so the first tag is v0.1.0. The link uses the first-release shape the indicator library used — a release-tag link, not a compare.

Three defects the dry-run found:

  1. The Go module shipped tests that cannot run. Its two golden test files read ../../golden, a path that exists in this repository and nowhere in the published module, so go test ./... failed for every consumer. Assembled the module as the release job does and ran it outside the workspace to confirm; with those two excluded it vets clean and its twelve remaining tests pass. Third instance of one pattern — the R package had it, the CLI tests were written to avoid it.

  2. The main npm package shipped every platform binary. napi artifacts writes each one to the package root as well as to npm/<rid>/, and files also listed npm, pulling the scaffolding directory in with them. 3903 KB → 64 KB on a tree staging two platforms; six arrive on CI. Nothing reads that directory at run time — index.js resolves the local file or the optionalDependency.

  3. The GitHub Release did not wait for the job producing one of its assets. csharp-publish uploads the nupkg the release stages, and was not in its needs; with fail_on_unmatched_files false it would have gone out without it silently. It now gates on every publish job.

Verified: all ten binding suites, all five parity scripts, the metadata audit, fmt/clippy/tests, and all 49 README URLs (the only non-answers are the three registry pages for packages that do not exist yet).

Recorded, not acted on: the indicator library publishes with the same npm configuration and its current release is 98.64 MB unpacked across 22 files. Same one-line cause.

The file has carried a single [Unreleased] block since the repository started:
161 entries, no version section, and a link pointing at the commit log because
there was no tag to compare against.

Nothing has ever been released, so there is no previous version to increment
from. Every one of those entries belongs to the first release, and every one of
the eighteen version declarations already says 0.1.0 -- which means the first tag
is v0.1.0 and no bump runs at all, only this.

The link follows the shape the indicator library used for its own first release:
a release-tag link rather than a compare, because there is nothing behind it.
Unreleased stays, empty, pointing forward from the tag.
The Go module mirror ships every `*.go` from the binding, which includes two test
files that read the shared golden corpus at `../../golden`. That path exists in
this repository and nowhere inside the published module, so `go test ./...` after
a `go get` fails on three tests for a directory that was never the consumer's.

Reproduced by assembling the module exactly as the release job does and running
it outside this workspace: vet and build pass, the golden tests fail on the
missing path. With the two excluded, the same tree vets clean and its twelve
remaining tests pass -- backtest_test.go and streaming_test.go build their own
data and travel fine.

This is the third instance of one pattern. The R package had it (tests/golden.R,
now in .Rbuildignore), the CLI integration tests were written to avoid it, and
here it was shipping. A test that reads the repository is a repository test; it
does not belong in the artefact.

Worth stating plainly while here: the mirror is currently stale in a way this
does not fix. It has no tags, no streaming.go, and a lib/ holding only .gitkeep,
so `go get` today yields a module that cannot link at all. Only a release
repairs that -- this makes sure that when one runs, what it pushes is testable.
The package exists to be small. Six per-platform packages carry the native
binaries, they are declared as optionalDependencies, and index.js resolves them:
it tries a local file first and falls through to the matching package. A consumer
should download some JavaScript and exactly one binary.

Two things defeated that, and neither was visible without packing.

`napi artifacts` writes each binary twice -- into npm/<rid>/ where the
per-platform package needs it, and into the package root. The `*.node` glob in
`files` then sweeps every one of them in. And `files` also listed `npm`, which
pulls the whole scaffolding directory in with the binaries it now contains, so
removing the root copies alone changed nothing.

Nothing reads that directory at run time. index.js requires either `./<name>.node`
or the optionalDependency by package name; its single mention of `npm/` is a URL
inside an error message. The directory is build-time scaffolding for publishing
the six packages, not something a consumer receives.

So `npm` leaves `files`, and the release job clears the root copies after
distributing them. Measured on a tree staging two platforms: 3903 KB before, 64
KB after, six files. On CI, where all six arrive, the difference is larger.

The `*.node` glob stays, because a local `npm pack` after a local build should
still include the binary it just made -- verified, along with the binding's tests,
the example and the benchmark.

Recorded, not acted on: the indicator library publishes with this same
configuration, and its current release is 98.64 MB unpacked across 22 files.
That is where the effect was confirmed rather than argued.
The GitHub Release stages a nupkg into its assets and did not wait for the job
that produces one. csharp-publish uploads it after staging natives, packing,
authenticating through OIDC and pushing -- comfortably slower than the path
github-release takes -- so the release would have been assembled before the
package existed. With fail_on_unmatched_files left false, it would have gone out
without it and said nothing.

java-publish and go-mirror upload no asset, so they were a different question,
and the answer is the same. The release notes tell readers that Java is on Maven
Central and that `go get` works. A release should not make those claims while the
jobs behind them are still running, or have failed.

The trade-off is real and worth naming: gating on everything means one registry
failing leaves no GitHub Release at all, rather than an incomplete one. That is
the better failure. An absent release is obviously absent; a release that lists
six install commands and quietly omits one artefact is not.

Checked that the graph is still acyclic and that no publish job is left ungating.
@kingchenc
kingchenc merged commit 58a04f2 into main Aug 28, 2026
52 checks passed
@kingchenc
kingchenc deleted the release/0.1.0-changelog branch August 28, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant