# Releases and versioning

cntrdct follows [Semantic Versioning](https://semver.org/) on the
`cntrdct` crate. Detector identifiers, the SARIF schema mapping, the
ranker prior-shape contract, and the `cntrdct.toml` schema are all
covered by SemVer. Internal modules under `src/detectors/` are not
public API and can change between minor versions.

## Where releases live

| Surface | Location |
|---|---|
| Source archive + checksums | [GitHub Releases](https://github.com/ktrysmt/cntrdct/releases) |
| Crate | [crates.io/crates/cntrdct](https://crates.io/crates/cntrdct) |
| Homebrew tap | [ktrysmt/homebrew-cntrdct](https://github.com/ktrysmt/homebrew-cntrdct) |
| Pre-built binaries (Linux x86_64/aarch64, macOS aarch64, Windows x86_64) | GitHub Releases archives |
| Per-release notes | GitHub Release body (auto-generated from Conventional Commits) |
| Cumulative changelog | [`CHANGELOG.md`](https://github.com/ktrysmt/cntrdct/blob/master/CHANGELOG.md) at repo root |

## Installing a specific version

```sh
# crates.io stable
cargo install cntrdct --version 0.4.2 --locked

# Pre-release versions (cargo install ignores them by default —
# the explicit --version qualifier is required)
cargo install cntrdct --version 0.2.0-rc.1 --locked

# Homebrew tap (always tracks the latest non-pre-release tag)
brew install ktrysmt/cntrdct/cntrdct

# Pre-built archive (no compile)
cargo binstall cntrdct
```

## Release notes vs. CHANGELOG.md

Two surfaces are generated by `git-cliff` from `cliff.toml` on every
`v*` tag push:

- The **GitHub Release body** is `--latest --strip header` — only the
  commits since the previous tag, grouped by Conventional Commits
  prefix (Features, Bug Fixes, Performance, Refactor, Promotions,
  Documentation, Tests, CI, Chores). This is what `gh release view`
  and the Releases page show.
- The **`CHANGELOG.md` file** at the repo root is the full cumulative
  history across every release, regenerated and committed back to
  `master` after the GitHub Release publishes. The commit lands as
  `chore(changelog): update for vX.Y.Z` and the parser skips that
  prefix so the bot commit stays out of subsequent release notes.

If both surfaces drift (e.g. a tag was force-recreated), regenerate
locally with:

```sh
git cliff --config cliff.toml --output CHANGELOG.md
```

## Pre-release suffixes

Pre-release tags follow `X.Y.Z-(alpha|beta|rc).N`. Three operational
notes:

- `cargo install cntrdct` ignores pre-releases unless `--version
  X.Y.Z-suffix` is supplied explicitly.
- The Homebrew tap formula is bumped only on non-pre-release tags, so
  `brew install ktrysmt/cntrdct/cntrdct` always points at the latest
  stable line.
- The CI verify step strips the leading `v` and demands an exact
  match against `Cargo.toml`'s `version`, so the pre-release suffix
  in the tag and the manifest must agree byte for byte.

## What is not versioned

Two surfaces ship under explicit "not SemVer" labels:

- The research workspace (`research/cntrdct-research`) has its own
  version cycle and is not released through this procedure. It is not
  a public consumer surface.
- Embedded priors (`benchmarks/priors-default.json`) and the LLM
  Platt registry (`benchmarks/llm-calibration/platt-default.json`)
  are data, not code; both are regenerated by `cntrdct calibrate`
  against the labelled corpora and embedded into the binary via
  `include_str!`. Changing these does not bump major.

See also: [`docs/spec/`](https://github.com/ktrysmt/cntrdct/tree/master/docs/spec)
for per-feature contracts, and
[`ROADMAP.md`](https://github.com/ktrysmt/cntrdct/blob/master/ROADMAP.md)
for the engineering schedule.
