Files
docs/standards/mcp/modules/versioning_and_changelog.json
Vishesh 'ironeagle' Bangotra 104bf3eb1e feat(standards): drop the site CI variant + require changelog reconciliation before release
- Remove the push-triggered build-and-deploy-site pipeline and every "site"
  reference; Type B is now a single tag-triggered service pipeline
  (service-docker.yaml).
- Inventory now covers packages + the auth-server service only (repos.json
  11 -> 9; docs/mcp are no longer part of the standard).
- Versioning standard: reconcile [Unreleased] against the last tag before
  promoting, and always show proposed entries to the user for approval.
- Update registry.py compliance/release text and list_repos types, build.py
  component descriptions, and rebuild the MCP bundle + lib/wiki HTML.
2026-10-17 00:41:52 +05:30

8 lines
7.4 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"module": "versioning_and_changelog",
"content": {
"path": "versioning_and_changelog",
"docstring": "# Versioning & Changelog\n\n## Summary\n\nEvery Aetos artifact — library or service — is versioned with\n[Semantic Versioning](https://semver.org/spec/v2.0.0.html) and documents its\nreleases in a [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) file.\nThe **version file is the source of truth**, the **git tag must equal it**, and\na Drone guard enforces that equality before anything is published. Releases are\ncut manually; a tag is what triggers the pipeline.\n\nThis page pairs with [10 – Drone Pipelines](10_drone_pipelines.md): the version\nand tag contract is exactly what those two CI shapes consume.\n\n---\n\n## The version contract\n\n| Artifact | Source of truth | Notes |\n|----------|-----------------|-------|\n| Library (PyPI package) | `version` in `pyproject.toml` | `check-version` also reads it to skip duplicates |\n| Service (Docker) | `VERSION` file at the repo root | one line, `x.y.z`; the service **reads** it (build-arg) — never hardcode the version |\n\nRules:\n\n1. **One version per repository.** No per-module versions.\n2. **Tag = version.** The git tag is bare SemVer (`0.0.6`), no `v` prefix, and\n it MUST match the version file byte-for-byte. The Drone guard fails the\n build otherwise — this is what stops a tag from silently publishing nothing.\n3. **A release is a tag, created after the change is merged.** The version bump\n and the changelog promotion travel inside the merge request (MR); the tag is\n added on the merged commit and pushed. See [Tagging strategy](#tagging-strategy-mr-based).\n4. **Never reuse a tag.** If a release is wrong, cut a new patch version.\n\n### Pre-1.0 (0.y.z)\n\nWhile a package is `0.y.z`, **`0.y` is treated as the major line**:\n\n- breaking change → `0.(y+1).0`\n- new feature → `0.y.(z+1)`\n- bug fix → `0.y.(z+1)`\n\nOnce a package reaches `1.0.0`, normal SemVer applies. Do not ship `1.0.0`\nuntil the public API is considered stable.\n\n---\n\n## The changelog\n\n`CHANGELOG.md` at the repo root, in Keep a Changelog form. It always has exactly\none open `[Unreleased]` section with the change categories that apply:\n\n```markdown\n## [Unreleased]\n\n### Added\n### Changed\n### Deprecated\n### Removed\n### Fixed\n### Security\n```\n\nOn release you **promote** it — never delete history:\n\n```markdown\n## [0.0.6] - 2026-03-07\n\n### Added\n- ...\n```\n\nand add a link reference at the bottom:\n\n```markdown\n[Unreleased]: https://git.aetoskia.com/aetos/<repo>/compare/0.0.6...HEAD\n[0.0.6]: https://git.aetoskia.com/aetos/<repo>/compare/0.0.5...0.0.6\n```\n\nConventions:\n\n- Write entries for humans: one line each, imperative, referencing the user\n impact, not the commit hash.\n- Categories: **Added**, **Changed**, **Deprecated**, **Removed**, **Fixed**,\n **Security**. Omit empty categories.\n- Security fixes get their own entry even if the change is otherwise a bug fix.\n- Keep `[Unreleased]` current: add an entry in the same change that introduces\n the behaviour, not later.\n- The `[Unreleased]` heading is never renamed; copy its content into the new\n version heading and clear it.\n\n### Reconcile before releasing\n\n`[Unreleased]` is a **draft, not the source of truth**. It is only trustworthy\nwhen it was maintained alongside each change; a long-running branch or a change\nthat skipped the changelog leaves it stale, so it can silently under-report a\nrelease. Verify it against the change before you promote:\n\n1. List what actually changed since the last release:\n `git log <last-tag>..HEAD` and `git diff --stat <last-tag>..HEAD`.\n2. Compare that against `[Unreleased]`; add an entry for every user-facing change\n that is missing.\n3. **Always show the proposed additions to the user and wait for approval**\n before promoting. If an entry is ambiguous, ask rather than guess.\n\nOnly then promote. Never cut a release with a known gap between the diff and the\nchangelog.\n\n---\n\n## Tagging strategy (MR-based)\n\nThe release version is known while the change is still a merge request, so the\nbump travels with the change and only the tag is added afterwards:\n\n1. **In the MR** — reconcile `[Unreleased]` against the change (see\n [Reconcile before releasing](#reconcile-before-releasing)) and get the user's\n approval for any additions. Then set the intended release version: `version`\n in `pyproject.toml` (or the `VERSION` file) to `x.y.z`, and promote the\n changelog (below). Changelog entries and link references name the\n **version/tag**, never a commit id.\n2. **Merge or squash** the MR into `main`.\n3. **Create the tag** `x.y.z` on the resulting commit (the merge/squash commit).\n4. **Push the tag** (`git push origin x.y.z`) — Drone builds the release.\n\nBecause the version bump is inside the tagged commit, the guard's\n`tag == version` check can only fail if the wrong commit was tagged.\n\n### Agent-assisted tagging\n\nThe agent neither authors nor merges the MR, and never tags before the merge.\nAfter the user confirms the MR is merged/squashed and says to proceed:\n\n1. **Wait** for that explicit go-ahead.\n2. Find the commit that introduced the version bump:\n - packages:\n `git log -S 'version = \"x.y.z\"' -n 1 --format='%H %s' -- pyproject.toml`\n - services:\n `git log -S 'x.y.z' -n 1 --format='%H %s' -- VERSION`\n3. Confirm that commit's version file equals `x.y.z`, then tag **only** that\n commit, lightweight and bare: `git tag x.y.z <sha>`.\n4. **Do not push.** Ask the user to push the tag: `git push origin x.y.z`.\n\n---\n\n## Release checklist\n\n1. Confirm the quality gate is green and `main` is up to date.\n2. In the MR: reconcile `[Unreleased]` against the change being released —\n `git log <last-tag>..HEAD` and `git diff --stat <last-tag>..HEAD` — add any\n missing user-facing entries, and get the user's approval for the additions.\n Then move every `[Unreleased]` entry under the new version heading with the\n target date (`## [x.y.z] - YYYY-MM-DD`) and restore an empty `[Unreleased]`\n on top.\n3. In the MR: add the two compare-link references at the bottom of the\n changelog, naming the version/tag (never a commit id).\n4. In the MR: set the version file — `pyproject.toml` (`version = \"x.y.z\"`) or\n `VERSION` — to the intended release version.\n5. Merge or squash the MR into `main`.\n6. Create the tag on the resulting commit: lightweight `git tag x.y.z`.\n7. Push the tag (`git push origin x.y.z`). Watch Drone: Type A publishes the\n wheel/sdist, Type B builds and deploys the image; both first assert\n `tag == version`.\n8. Do not reuse the tag if the run fails — fix and cut `x.y.(z+1)`.\n\n---\n\n## Why the guard matters\n\nThe version file and the tag are two facts that must agree; nothing in git\nenforces that by itself. A mismatch is not a theoretical risk — a package can be\ntagged `0.0.2` while its `pyproject.toml` still says `0.0.1`, and the publish\nstep (which compares the **file** against the index) then skips the build\nentirely, so `0.0.2` never reaches the index while looking like a release. The\nDrone guard turns that silent no-op into a hard failure.\n\n---\n\n## Related\n\n- [10 – Drone Pipelines](10_drone_pipelines.md) · [15 – Repository Inventory](15_repository_inventory.md) · [01 – Build Recipe](01_build_recipe.md) · [13 – Library Registry](13_library_registry.md)\n",
"objects": {}
}
}