# Versioning Policy

This document defines the versioning and distribution contract for `entr-adapter-core`.

## Semantic Versioning

This package follows [Semantic Versioning 2.0.0](https://semver.org/):

- **Major** (e.g., `1.0.0` → `2.0.0`): Breaking changes that require adapter code modifications
- **Minor** (e.g., `1.0.0` → `1.1.0`): New features, backward-compatible. No adapter code changes required.
- **Patch** (e.g., `1.0.0` → `1.0.1`): Bug fixes, backward-compatible. No adapter code changes required.

## Distribution

The package is published on [PyPI](https://pypi.org/project/entr-adapter-core/). Adapters depend on it using standard version specifiers in `pyproject.toml`:

```toml
[project]
dependencies = [
    "entr-adapter-core>=1.0,<2",
]
```

To pick up new versions, run `uv lock && uv sync`. The version specifier controls which versions are accepted — no custom auto-update mechanism is needed.

## Git Tag Format

- Tags use the format `v{major}.{minor}.{patch}` (e.g., `v1.0.0`)
- The `v` prefix is **mandatory** for git tags
- The `pyproject.toml` `version` field omits the `v` prefix (e.g., `1.0.0`)
- Tags are immutable — once pushed, a tag is never moved or deleted

## Breaking Change Table

This table is the authoritative reference for version bump decisions.

| Change Type | Breaking? | Version Bump | Example |
|-------------|-----------|-------------|---------|
| New required parameter on public function | **Yes** | Major | `create_adapter_app()` gains a required arg |
| `BaseHandler.process()` signature change | **Yes** | Major | Adding a required parameter |
| Removing or renaming a public export | **Yes** | Major | Moving `BaseHandler` to a different module |
| Schema field removal or type change | **Yes** | Major | Removing `AdapterResponse.notifications` |
| Override directory path change | **Yes** | Major | `deploy/` → `overrides/` |
| New optional parameter with default | No | Minor | `create_adapter_app(debug=False)` |
| New optional schema field | No | Minor | Adding `AdapterResponse.warnings` |
| New public function or class | No | Minor | Adding `resolve_prod_files()` |
| Bug fix in dispatch/resolution logic | No | Patch | Fixing edge case in `resolve_file()` |
| Internal refactoring (no API change) | No | Patch | Restructuring private modules |
| Dependency minimum version bump | Potentially | Minor or Major | Documented in CHANGELOG; adapters assess impact |
| Default deployment file changes | No* | Minor | Updated nginx timeout; adapters receive automatically |

\* Deployment file changes are non-breaking because adapters can override any file. However, these changes are **always explicitly documented** in the CHANGELOG since they affect all adapters.

## Migration Path Requirement

Every breaking change **must** include in the CHANGELOG:

1. **What changed** — the specific API, schema, or behavior that changed
2. **Why it changed** — the motivation for the breaking change
3. **Migration path** — exact code changes required for adapters to upgrade

Example:

```markdown
### Breaking Changes

- **BaseHandler.process() now requires a `context` parameter**
  - Why: Enables handlers to access request metadata (tenant info, correlation ID)
  - Migration: Add `context: ProcessContext` as the second parameter to all `process()` implementations
    ```python
    # Before (v1.x)
    async def process(self, payload: DocumentPayload) -> AdapterResponse:

    # After (v2.0)
    async def process(self, payload: DocumentPayload, context: ProcessContext) -> AdapterResponse:
    ```
```

## Version Specifiers (for Adapters)

Adapters control their update policy using standard Python version specifiers in `pyproject.toml`:

| Specifier | Matches | Use Case |
|-----------|---------|----------|
| `>=1.0,<2` | Any `1.x.x` | "Give me everything, new features included" |
| `>=1.0,<1.1` | Any `1.0.x` | "Keep me patched, no new features" |
| `==1.0.3` | Only `1.0.3` | "Don't touch anything" |

Running `uv lock` resolves the latest version matching the specifier. Major version boundaries are controlled by the upper bound (e.g., `<2`).

## Release Process

```bash
# 1. Update version in pyproject.toml
# 2. Update CHANGELOG.md with release notes
# 3. Commit: "release: v1.0.0"
# 4. Tag: git tag v1.0.0
# 5. Push: git push origin main --tags
```
