# Releasing Nanocodex

Nanocodex releases six crates.io packages in lockstep with the CLI binaries and
npm package. The process combines Alloy's conventional-commit changelog with
Foundry's label-grouped, contributor-attributed GitHub release notes.

## Nightly releases

The `Nightly Release` workflow runs daily and may also be dispatched manually.
Each successful run publishes an immutable `nightly-<full SHA>` prerelease and
refreshes the rolling `nightly` prerelease with the same binaries and
`SHA256SUMS`. The rolling tag is what `nanocodex update --nightly` follows.

## JavaScript package previews

Every pull request and every commit merged to `master` builds and tests the
actual Node/browser WASM package, then publishes an immutable SHA-addressed
preview through pkg.pr.new. The workflow can also be dispatched manually for a
selected ref. Preview package versions are rewritten to
`0.0.0-preview-<sha>` so a lockfile cannot confuse them with an npm release.

Install the pkg.pr.new GitHub App on `gakonst/nanocodex`; the preview CLI is a
pinned development dependency in `js/bindings/package-lock.json`. Pull-request
comments use commit URLs, so every tested artifact remains reproducible after
new commits are pushed.

## Changelogs

There are two complementary kinds of release record:

- The root `CHANGELOG.md` is generated by `git-cliff` from every commit, while
  each of the six published crates carries its own path-filtered
  `crates/*/CHANGELOG.md`. Conventional prefixes group changes into Features,
  Bug Fixes, Documentation, Dependencies, Performance, Refactor, Styling,
  Testing, Miscellaneous Tasks, and Other. This also records direct commits
  that did not arrive through a pull request.
- The GitHub Release is generated from merged pull requests by the same
  changelog builder used by Foundry. Pull requests are grouped by label, every
  line ends in `by @author`, uncategorized pull requests remain visible under
  Other, and the notes end with the full comparison link.

Use conventional commit subjects (`feat:`, `fix:`, `docs:`, `perf:`,
`refactor:`, `test:`, `chore:`, `ci:`, or `build:`). Before merging a pull
request, apply one release-note label:

- `breaking-change`
- `feature` or `enhancement`
- `fix` or `bug`
- `performance`
- `documentation`
- `dependencies`
- `internal`
- `ignore-for-release` only when the pull request should not appear

The label is for the readable GitHub Release; the commit prefix is for the
complete repository changelog. Neither path silently drops uncategorized work.

## Prepare a release

Install the release tools once:

```sh
cargo install git-cliff --locked
cargo install cargo-semver-checks --locked
```

Then prepare a release pull request from the latest `master`:

1. Choose a new semantic version and update `workspace.package.version` plus every
   `nanocodex*` entry in `workspace.dependencies` in `Cargo.toml`, and keep
   `js/bindings/package.json` on that same version. Never reuse a version
   already published to crates.io; the stable-API refactor after `0.2.0` is
   source-breaking and therefore requires a new version.
2. Run `cargo check --workspace` to refresh `Cargo.lock`.
3. Generate the committed changelog after all intended feature commits are in
   the branch:

   ```sh
   just changelog x.y.z
   ```

   This runs the same `WORKSPACE_ROOT`/`CRATE_ROOT` hook used by Alloy and by
   `cargo-release`, refreshing the root changelog and all six crate-specific
   changelogs. Review the generated groups and wording. Fix misleading commit
   subjects in the release branch when necessary, then regenerate; do not
   hand-maintain a second grouping scheme. A short editorial Highlights section
   may be added to the root changelog above the generated groups, but it must
   not replace or reorder them.
4. Starting with the second published version, run
   `cargo +stable semver-checks` and review every reported API break. A breaking
   result must either be intentional and reflected in the chosen version, or
   fixed before release.
5. Run `just release-check x.y.z` and the normal `just check` gate. The release
   check packages every crate and builds its all-features documentation with
   rustdoc warnings denied from the normalized `.crate` archives—the dependency
   view docs.rs will actually receive.
6. Merge the release preparation through normal review. Verify the release
   commit is the exact commit to ship.

## Trigger a release

Create and push one annotated tag matching the workspace version:

```sh
git tag -a vx.y.z -m "Nanocodex x.y.z"
git push origin vx.y.z
```

The tag starts the release workflow. It:

1. rejects a tag/version mismatch or any root/crate changelog not generated by
   `git-cliff`;
2. validates all crate packages and archive documentation;
3. creates a **draft** GitHub Release with grouped PR notes and contributor
   attribution;
4. builds optimized native CLI binaries for x86_64 Linux and Apple Silicon macOS;
5. publishes the six crates to crates.io in dependency order;
6. builds, tests, and publishes the Node/browser WASM package to npm with
   provenance;
7. attaches the binaries and `SHA256SUMS` to the draft.

Open the draft at <https://github.com/gakonst/nanocodex/releases>, inspect the
notes, verify `SHA256SUMS`, and smoke-test a downloaded platform binary. Then
click **Publish release** and immediately smoke the public curl installer and
`nanocodex update`. Draft assets are not exposed through GitHub's public
`releases/latest` URL, so that final installer smoke necessarily follows
publication. The manual publish is deliberate: the tag starts irreversible
crates.io publishing, but the public GitHub announcement still gets a final
human editorial check.

## GitHub configuration

The Actions secret `CARGO_REGISTRY_TOKEN` must contain a crates.io token allowed
to publish all six `nanocodex*` crates. Configure `nanocodex` on npm with the
GitHub trusted publisher `gakonst/nanocodex`, workflow `release.yml`, allowed to
run `npm publish`. The publishing job uses OIDC and emits npm provenance. The
first package publication must claim the unscoped name using an npm account
with two-factor authentication; until trusted publishing is configured, an
`NPM_TOKEN` repository secret may authenticate that first workflow run.

The workflow otherwise uses the short-lived repository `GITHUB_TOKEN`; write
permission is restricted to the draft-release and asset-upload jobs.

The repository labels and `.github/changelog.json` are part of the release
contract. When adding or renaming a category, update both together.

## Recovery

The crate publisher queries crates.io and skips package versions already
present, so a registry propagation failure can be retried by rerunning the tag
workflow. An existing draft is reused, its notes are refreshed, and assets are
uploaded with `--clobber`. A published release is never mutated by a rerun.

Published crate and npm versions are immutable. Fix a bad release with a new
patch version; only yank a version when continuing to resolve it would harm
users.
