{
  "uid": "cogitave.learn.commits-and-versioning.versioning-and-releases",
  "kind": "moduleUnit",
  "href": "/modules/commits-and-versioning/versioning-and-releases/",
  "title": "Versioning and releases",
  "summary": "",
  "type": null,
  "products": [],
  "roles": [],
  "levels": [],
  "subjects": [],
  "headings": [
    "Types drive Semantic Versioning",
    "release-please assembles the release",
    "The branching model gates the release"
  ],
  "source": "You now write the commit; this unit follows it all the way to a released version.\nThe path is: commit types set the **version number**, an engine assembles a\n**Release-PR** and changelog, and the **branching model** gates when the release\nhappens. All of it is grounded in the\n[commits-versioning](../../../../standards/docs/standards/commits-versioning.md)\nand [branching-release](../../../../standards/docs/standards/branching-release.md)\nstandards.\n\n## Types drive Semantic Versioning\n\nCogitave versions with **Semantic Versioning 2.0.0** - `MAJOR.MINOR.PATCH` - and\nyour commit types decide which number moves:\n\n- a `fix` bumps **PATCH** (`1.4.2` to `1.4.3`);\n- a `feat` bumps **MINOR** (`1.4.2` to `1.5.0`);\n- a breaking change (`!` or a `BREAKING CHANGE:` footer) bumps **MAJOR**\n  (`1.4.2` to `2.0.0`).\n\nThere is one rule that overrides all of this: **pre-1.0.0**. While a package is\nstill `0.y.z`, *everything - including breaking changes - bumps MINOR or PATCH,\nand MAJOR stays at 0 until the project declares 1.0.0*. Pre-release identifiers\norder as `1.0.0-alpha.1 < -beta < -rc.1 < 1.0.0`. So a break in a `0.y.z` package\ndoes **not** produce a `1.0.0`; that first major is a deliberate decision.\n\n## release-please assembles the release\n\nThe org engine is **release-please in manifest mode**. It drives Rust, Go, and TS\nfrom a single config and, as commits with releasable types land on `main`, it\nopens a **Release-PR**: a pull request that proposes the next SemVer number and a\n**Keep a Changelog 1.1.0** entry drained from the `[Unreleased]` section, grouped\ninto Added / Changed / Deprecated / Removed / Fixed / Security with ISO-8601\ndates. The release is **human-approved** - merging that Release-PR is what cuts\nthe tag and artifact. Agents propose the release; a human enacts it.\n\nA few repo types use a different engine, per the standard's decision table:\n\n| Repo | Versioning engine |\n|---|---|\n| Rust crate (API breaks matter) | **release-plz** with `cargo-semver-checks` |\n| Go binary | release-please tag + **goreleaser** artifact |\n| JS-only multi-package monorepo | **Changesets** |\n\nThe commit convention and Keep a Changelog output stay the same across all of\nthem; only the release tooling differs.\n\n## The branching model gates the release\n\nReleases ride on a **trunk-based** flow: `main` is the single long-lived branch\nand it is **protected**. You do short-lived feature branches, open a mandatory\nPR, and merge with **linear history** and conversations resolved. Force-push is\nblocked and deletion restricted by the org ruleset.\n\nProtected `main` requires a PR with at least one **CODEOWNER approval**, stale\napprovals dismissed, last-push approval, **signed commits**, and required status\nchecks - CI, security, and `docs-required` - green. Releases then promote through\n**dev to staging to prod**, and the prod environment adds required reviewers, a\nwait timer, prevent-self-review, and **admin bypass disabled** for SOC2 CC8.1\nseparation of duties. Each release drains the changelog, cuts a SemVer tag, and\nships a signed artifact with provenance.\n\n> [!NOTE]\n> This is why the commit matters so much: a single mis-typed message flows\n> unattended through release-please into a wrong version number. The gates check\n> that the release is signed, reviewed, and documented - they do not second-guess\n> whether you called a `feat` a `fix`. That judgement is yours.\n",
  "partOf": "cogitave.learn.commits-and-versioning",
  "durationInMinutes": 8,
  "quiz": null
}