# ADR-0073: Nx Release Owns Versioning and Publishing

**Status**: Accepted **Date**: 2026-07-18 **Authors**: Development Team
**Supersedes**: ADR-0006 (Versioning and Release Strategy) **Superseded by**:
N/A

## Context and Problem Statement

ADR-0006 (2026-01-10) selected Changesets as the monorepo's versioning and
release mechanism. Its implementation plan was never executed: no
`.changeset/config.json` was ever created, no changeset files were ever
authored, and no CI workflow invokes the changesets CLI. Meanwhile the release
pipeline that actually shipped — `.github/workflows/release.yml` — was built on
**`nx release`**: `pnpm nx release version <v> --git-commit --git-tag` followed
by `pnpm nx release publish --tag latest`, driven by the `release` block in
`nx.json` (conventional commits, per-project changelogs, GitHub release
creation).

The 2026-07-16 monorepo architecture audit (finding **C-8**) flagged the
resulting ambiguity: two release mechanisms coexisted in `package.json` (the
dead `changeset`/`version-packages`/`release` scripts plus the `@changesets/cli`
devDependency) with no explicit decision on which owns releases.

## Decision

**`nx release` owns versioning, changelogs, and publishing.** The changesets
scripts and the `@changesets/cli` devDependency are removed. ADR-0006 is
superseded: its analysis remains a valid record, but its chosen option was never
implemented and the de facto standard is the one wired into CI.

Rationale:

1. **Reality wins.** `release.yml` has only ever released via `nx release`;
   changesets never progressed past a devDependency. Re-platforming the working
   pipeline onto the unimplemented choice would be churn without benefit.
2. **Conventional commits are already enforced** (commitlint with the
   registry-generated scope enum), so `nx release`'s commit-parsing changelog
   input is trustworthy here — the "explicit intent" advantage ADR-0006 credited
   to changesets is substantially covered by the commit convention.
3. **One less toolchain.** Nx already orchestrates build/test/lint; keeping
   version/publish in the same tool removes a second config surface.

## Release scope

`nx.json` `release.projects` is `["libs/*", "apps/*"]`. Because slash-containing
globs match project **roots**, this deliberately reaches only the single-level
packages (`libs/contracts`, `libs/proto`, `libs/openapi`, …) — the public
interface surface — and none of the ~3,300 nested internal workspace packages.
**Widening this scope is a deliberate per-package publishing decision, not a
config cleanup** (audit C-8): adding a nested glob would put every internal
package into the publish set.

## Consequences

- `package.json` no longer carries `changeset`, `version-packages`, or `release`
  scripts; `@changesets/cli` is removed from devDependencies.
- Releases are dispatched via `release.yml` (workflow_dispatch) which computes
  the version and runs `nx release version`/`publish`.
- Any future desire for changeset-style explicit intent files should be
  re-proposed as a new ADR rather than resurrecting the dormant tooling.
