Skip to content

docs: establish contribution, changelog, and release procedures#17

Merged
fedorov merged 4 commits into
mainfrom
docs/contributing-changelog
Jul 9, 2026
Merged

docs: establish contribution, changelog, and release procedures#17
fedorov merged 4 commits into
mainfrom
docs/contributing-changelog

Conversation

@fedorov

@fedorov fedorov commented Jul 9, 2026

Copy link
Copy Markdown
Member

Establishes the contribution and release process, which until now lived only in people's heads:
there was no CONTRIBUTING.md, no CHANGELOG.md, and no tags.

Rebased onto main after #16 merged; the docs describe the merged /mcp trailing-slash fix and
the ruff format CI step, both now on main.

What's here

  • CONTRIBUTING.md — branching, Conventional Commits (documented, not CI-enforced — the last
    ~22 commits already conform), the changelog rule, and the versioning policy.
  • CHANGELOG.md — hand-curated Keep a Changelog, seeded with a
    [3.0.0b1] section describing the actual v3 surface. Deliberately not generated from commit
    subjects: ci: rework multi-tier deploy is not what a caller of the API needs to read.
  • dev/deployment.md → "Cutting a release" — the runbook, placed with the tier machinery,
    promote dispatch, and approval gate it depends on. Includes the v3 beta plan.
  • promote.yml — a guard that fails a prod tag whose version disagrees with pyproject.toml.

Versioning: MAJOR pinned to the URL prefix

SemVer with one house rule: /v33.y.z, always. Additive change → MINOR; bugfix → PATCH;
breaking the contract → a new /v4 prefix and 4.0.0, never a silent break under /v3. This
keeps api_version predictive of the URL and matches the clean break v3 already made from v1/v2.

Two traps in the existing release pipeline

Both are now documented, and the second is enforced:

  1. A v* tag must point at a commit already promoted to test — prod redeploys test's digest
    and never rebuilds. (This was already noted in deployment.md; the runbook absorbs it.)
  2. The version is baked into the image when test builds it. Tagging v3.0.0 on the commit that
    shipped as 3.0.0b1 would deploy cleanly and quietly serve 3.0.0b1 at /v3/version.
    resolve-prod now asserts tag == "v" + pyproject version and fails before the reviewer
    gate. Consequence: you can no longer tag a release without bumping pyproject.toml first.

This is also why the version is not derived from the git tag (hatch-vcs et al): the tag
triggers a promotion, not a build, so a tag-derived version could never reach the prod image.

Note that promote.yml doesn't run on pull requests, so this guard's first live exercise will be
the v3.0.0b1 tag. Its logic is verified below, but that run is worth watching.

Bug found along the way

src/idc_api/__init__.py hardcoded __version__ = "3.0.0.dev0", while core/version.py resolves
the served version from importlib.metadata. The literal was unused and would have gone stale on
the first release bump — a release procedure saying "bump the version" was going to be quietly
wrong. It now derives from the same distribution metadata, so pyproject.toml is the single source.

Docs reconciliation

dev/developer_guide.md told contributors CI runs ruff check and pytest. It also runs
ruff format, bandit, and pip-audit, so two docs disagreed on what CI enforces — and the one
contributors are pointed at understated it. Fixed. CONTRIBUTING.md now points at the developer
guide for setup/test/CI/invariants instead of restating them, and CLAUDE.md's doc-conventions
section (which enumerated every lane except these two new files) registers both.

Verification

Run against the rebased branch:

  • pytest: 70 passed. ruff check, ruff format --check, bandit: clean.
  • __version__ == package_version(); build stamp still appends (3.0.0.dev0+abc1234); import idc_api still pulls in neither duckdb nor fastapi (no import cycle).
  • actionlint clean on promote.yml; ran the guard's shell logic against the real pyproject.toml — rejects v3.0.0 and v3.0.0b1 against today's 3.0.0.dev0 tree, accepts only an exact match.
  • All new cross-file links and anchors resolve.

Follow-up, not in this PR

Cutting the beta means bumping pyproject.toml to 3.0.0b1 in its own commit, promoting it to
test, then tagging v3.0.0b1.


Drafted with Claude Code.

🤖 Generated with Claude Code

fedorov and others added 4 commits July 9, 2026 17:20
`__version__` hardcoded "3.0.0.dev0" while core/version.py resolves the
served version from importlib.metadata. The literal was unused and would
have gone stale on the first release bump, leaving two disagreeing answers
to "which version is this".

Read the distribution metadata instead, so `version` in pyproject.toml is
the single source of truth. Kept self-contained rather than importing
core.version, which would pull settings/pydantic into `import idc_api`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neither existed, and the conventions were only implicit: Conventional
Commits were already de facto (last ~22 commits) but written down nowhere.

- CONTRIBUTING.md: branching, commits, the hand-curated changelog rule,
  versioning (SemVer with MAJOR pinned to the URL prefix, /v3 <-> 3.y.z),
  and a release runbook.
- CHANGELOG.md: Keep a Changelog, seeded with the [3.0.0b1] surface.
- README.md: pointers only, per the doc conventions in CLAUDE.md.

The runbook records two traps in the existing pipeline: a `v*` tag deploys
prod (the glob matches pre-release tags), and it must point at a commit
already promoted to test, since prod redeploys test's digest without
rebuilding. The version bump therefore needs its own commit through test,
or /v3/version reports the previous release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prod redeploys test's existing digest and never rebuilds, so the version
the server reports is whatever test baked in from pyproject.toml. Tagging
v3.0.0 on the commit that shipped as 3.0.0b1 therefore deployed cleanly
and quietly served the wrong version at /v3/version.

resolve-prod now checks out the tagged commit and asserts that the tag
equals "v" + the packaged version, failing before the reviewer gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CONTRIBUTING duplicated content that dev/ already owned, and in one case
disagreed with it.

- Move the release runbook (and the v3 beta rationale) into deployment.md
  as "Cutting a release", absorbing the constraint paragraph that already
  sat under the trigger table. It depends on the tier machinery, the
  promote dispatch, and the approval gate -- all documented there. Cutting
  a release is a maintainer task, not a contributor one.
- CONTRIBUTING keeps the process a contributor needs -- branching, commits,
  the changelog rule, the versioning policy -- and points at the developer
  guide for setup/test/CI/invariants rather than restating them.
- developer_guide.md's CI section listed only ruff + pytest; CI also runs
  ruff format, bandit, and pip-audit. Two docs disagreed on what CI runs.
- Register CONTRIBUTING.md and CHANGELOG.md as lanes in CLAUDE.md's
  documentation conventions, which enumerated every other doc but not these.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@fedorov fedorov force-pushed the docs/contributing-changelog branch from 6f62239 to d95af26 Compare July 9, 2026 21:21
@fedorov fedorov marked this pull request as ready for review July 9, 2026 21:22
Copilot AI review requested due to automatic review settings July 9, 2026 21:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR formalizes the project’s contribution, changelog, and release processes by adding first-class documentation and tightening the production promotion workflow so release tags cannot disagree with the packaged version.

Changes:

  • Add CONTRIBUTING.md and CHANGELOG.md, and wire them into existing documentation pointers.
  • Extend the deployment runbook with a concrete “Cutting a release” procedure (including the v3 beta plan).
  • Make version reporting derive from distribution metadata (single source of truth) and add a promote.yml guard to enforce tag == "v" + pyproject.toml version for prod releases.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/idc_api/__init__.py Derives __version__ from installed distribution metadata (with a clear source-tree fallback).
README.md Adds pointers to the new contributing and changelog docs.
dev/developer_guide.md Updates CI documentation to reflect all checks (ruff format, bandit, pip-audit, pytest).
dev/deployment.md Adds a detailed “Cutting a release” runbook and documents key release constraints.
CONTRIBUTING.md New contributor process doc: branching, commit conventions, changelog rules, versioning, release safety notes.
CLAUDE.md Registers CONTRIBUTING.md and CHANGELOG.md in the documentation “lanes” conventions.
CHANGELOG.md New Keep a Changelog–style changelog seeded with v3 beta (3.0.0b1) content.
.github/workflows/promote.yml Adds a pre-gate guard on tag pushes to ensure tag/version alignment with pyproject.toml.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fedorov fedorov merged commit 8100fbf into main Jul 9, 2026
4 checks passed
@fedorov fedorov deleted the docs/contributing-changelog branch July 9, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants