# Changelog

All notable changes to `mgf-alembic` are documented here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
the project follows [SemVer](https://semver.org/spec/v2.0.0.html). Per
the 0.x window ([SemVer 0.x](https://semver.org/#spec-item-4) and rule
**AP-03** from `mgf-standard/docs/standards/API_DESIGN.md`), MINOR
releases MAY break the public API. Pin tightly:

```toml
mgf-alembic = ">=0.X.0,<0.Y"   # one minor at a time
```

The release-engineering discipline that produces this changelog is in
[`mgf-standard/docs/standards/RELEASING.md`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/RELEASING.md).

---

## [0.4.10] - 2026-06-26

### Changed
- Release the **mgf-common 0.49** pin (`<0.50`) onto devpi so the full
  fleet co-installs at the 0.49 cornerstone (devpi backfill; no API change).

## [0.4.9] - 2026-06-16

### Changed
- Widened the `mgf-common` pin to `<0.48` — mgf-common 0.47 is the pure-library release (the end-user CLI moved to `mgf-fed[cli]`); the importable API is unchanged.
- Regenerated `.woodpecker` so the supervisor lane calls `mtest` (the moved `mgf-common test` frontend is gone).

## [Unreleased]

Nothing yet.

---


## [0.4.8] — 2026-06-08 — depth-audit close-out (public API + EH/SC/LG)

### Added
- `mgf.alembic.__version__` (AP-13); CI tag-coherence asserts it.
- `PUBLIC_API.json` + generator + CI pins; `PUBLIC_API.md` lists every public
  name with tiers + an Exceptions section (AP-10/11/07, DOC-08/09).
- Fast canonical smoke test (TS-21).
- Online migration runs emit an audit=true `operation=alembic.migrate` record
  with start/complete events (SC-17, LG-11).

### Changed
- The RA-01 running-loop guard raises `mgf.common.exceptions.OperationError`
  instead of a bare `RuntimeError` (EH-01).
- Declined (CFM-04 §3): AP-14 (consumer-fixture import-linter), EH-02 (deliberate
  DB-exception-type preservation), SC-07 (driver-specific connection timeout).

## [0.4.7] — 2026-06-06 — federation cohort: mgf-common 0.46 walk

Walk the `mgf-common` pin ceiling `<0.46 → <0.47` to accept the
library-API-neutral `mgf-common 0.46.0` (CLI-only release: new
`federation`/`design` commands + a `doctor --standards` gate; no library
surface change). Verified: full test suite green on 0.46.0.

---

## [0.4.6] — 2026-06-04 — federation cohort: mgf-common 0.45 walk

PATCH: pin widened to `mgf-common>=0.41,<0.46` to accept mgf-common 0.45 (the
Codeberg package-distribution cutover — PKG-01..12). `mgf-*` resolve from the
`codeberg-mgf` index (PKG-06). No API change.

---

## [0.4.5] — 2026-06-01 — federation cohort: adopt mgf-common 0.44

PATCH: pin widened to `mgf-common>=0.41,<0.45` to accept the mgf-common 0.44 line
(which extracted the standards corpus + federation contract to the
`mgf-standard` sibling; pulled in transitively). `FEDERATION.md` stub +
`.claude/commands/sync.md` repointed at `mgf-standard`. No API change.

---

## [0.4.4] — 2026-05-28 — federation cohort publish (mgf-common 0.42.x)

Federation cohort wave: mgf-alembic accepts **mgf-common 0.42.x** (pin widened to
`>=0.41,<0.43`) and ships to PyPI, carrying the previously-unpublished 0.4.3 work.

---

## [0.4.3] — 2026-05-28 — live Postgres upgrade/downgrade + offline-mode tests

### Added

- `tests/integration/test_postgres_migrations.py` — upgrade head → downgrade
  base round-trip + offline-mode (`--sql`) DDL emission against a real
  Postgres (ran live). A concurrent-migration test is skipped with a full
  rationale (the serialization guarantee is alembic+Postgres', not this
  wrapper's; a timed assertion would be flaky without `lock_timeout`).
- `psycopg2-binary` dev dependency (drives the integration test).

### Notes

- Test + dev-dep only; no public API change.

---

## [0.4.2] — 2026-05-26 — federation pin walks (mgf-common 0.41.x + mgf-test-supervisor PyPI)

Federation cohort walk: mgf-alembic now accepts mgf-common 0.41.x.
Previously pinned `mgf-common>=0.40,<0.41`, which is what made
PAPER-84 (cross-sibling consistency check in mgf-common 0.41.2)
correctly REFUSE bumps for consumers depending on both mgf-alembic
and mgf-common. This release widens mgf-alembic's pin to `<0.42`
so the federation cohort gate opens for downstream consumers.

### Changed

- `pyproject.toml`: `mgf-common>=0.40,<0.41` → `mgf-common>=0.40,<0.42`.
- `pyproject.toml`: `mgf-test-supervisor @ git+ssh://...` →
  `mgf-test-supervisor>=0.1.3,<0.2`. mgf-test-supervisor v0.1.3
  is now on PyPI.
- `pyproject.toml`: removed `[tool.hatch.metadata]
  allow-direct-references = true` block.

### Source-level changes

None — mgf-alembic's source has zero usage of mgf-common 0.41
deletions. Verified by grep.

### Note: mgf-sqlalchemy pin unchanged

mgf-alembic's `mgf-sqlalchemy>=0.1,<0.2` pin is unaffected by
today's mgf-common cohort walk. mgf-sqlalchemy 0.4.2 (released
today) widens its OWN mgf-common pin but doesn't change its own
version namespace.

---

## [0.4.1] — 2026-05-18

**Federation sync v2.10** — docs + tooling refresh; no library surface changes.

### Added
- `STARTHERE.md` + `CONTRIBUTING.md` (DOC-01 sibling MUSTs).
- `docs/CLAUDE.md` + `.claude/settings.json` (managed by `mgf-common catch-up`).

### Changed
- `mgf-common` pin: `>=0.36,<0.37` → `>=0.37,<0.38`.

### Federation
- Aligned with mgf-common v0.38.0 contract (DOC-13/14/15/16/17). Catch-up clean.

---

## [0.4.0] — 2026-05-18

PyPI: <https://pypi.org/project/mgf-alembic/0.4.0/> · Tag: `v0.4.0`

> **Wave 2 sibling release — A-1 migration drift detector
> ships.** Pin bump: mgf-common ≥0.34 → ≥0.36.

### Added — `detect_drift()` + `DriftReport` (A-1)

Closes the A-1 federation row. Catches the canonical
"I added a column to the model but forgot to autogenerate
the migration" footgun. CI-friendly: assert
``report.is_clean, report.summary()`` and the failure
message walks the consumer through the fix.

Two public names (both `experimental` per AP-11):

- **`detect_drift(*, target_metadata, url, include_object=None)`** —
  synchronous API. Wraps alembic's
  `compare_metadata`. Connects to the live DB, returns a
  categorised :class:`DriftReport`. Ignores alembic's own
  `alembic_version` bookkeeping table (otherwise the
  detector would flag it every time).
- **`DriftReport`** — frozen dataclass with categorised
  differences: `missing_tables`, `extra_tables`,
  `missing_columns`, `extra_columns`, `type_mismatches`,
  `index_differences`, `foreign_key_differences`, `other`.
  `.is_clean` is the CI-gate property; `.summary()` renders
  a multi-line failure message including the
  `alembic revision --autogenerate -m "..."` remediation
  hint.

8 new unit tests pin: empty-report-is-clean, missing-table /
missing-column / type-mismatch shapes, alembic_version
ignored, multi-category aggregation, summary message
content.

### Changed — pin bump

- **`mgf-common>=0.34,<0.35` → `mgf-common>=0.36,<0.37`**
  (Wave 1 catch-up).

### Verification

- pytest tests/: 41 passed (33 + 8 new).
- ruff: clean.
- mypy --strict: clean.

---

## [0.3.0] — 2026-05-17

PyPI: <https://pypi.org/project/mgf-alembic/0.3.0/> · Tag: `v0.3.0`

> **Quality release** — closes every P0/P1/P2 reliability,
> security, and performance tracker item to v1.0-ready
> state. Two new optional kwargs on `configure_env` (non-
> breaking); all other changes are docstring additions + new
> tests. No public-API removals or renames.

### Added — new optional kwargs on `configure_env`

- **`is_async: bool | None = None`** (RA-03 / RA-04). Explicit
  override for the URL-prefix-based async detection heuristic.
  Default `None` consults the prefix list as before; consumers
  using psycopg 3 in sync mode pass `is_async=False`; consumers
  on cutting-edge async drivers pass `is_async=True`. Solves
  the dual-mode-routing surprise (`postgresql+psycopg://` was
  always treated as async).
- **`transaction_per_migration: bool = False`** (RA-05).
  Threads through to alembic's `context.configure(...)`. MySQL
  consumers (where DDL auto-commits and the outer
  `begin_transaction()` is meaningless) opt in by passing
  `True`; alembic wraps each migration in its own transaction-
  or-equivalent unit instead of one transaction across the
  whole batch. Default `False` keeps Postgres-shaped one-
  transaction-for-all-migrations behaviour.

### Added — regression-protection tests

- **PC-01** — `configure_env` per-call Python overhead pinned
  at ≤ 100 µs/call. New `tests/perf/test_configure_env_overhead.py`
  with three pinned dispatch shapes.

### Changed — internal-only

- **RA-01** — Embedded-use safety. `configure_env`'s async
  dispatch now probes for a running event loop (via
  `asyncio.get_running_loop()`) and raises an actionable
  `RuntimeError` naming the public alternative
  (`run_async_migrations`) if a loop is active. New public
  `run_async_migrations` async entry point bypasses the
  `asyncio.run` shape; consumers in pytest-asyncio /
  notebooks await it directly.
- **RA-02** — `naming_convention` mutation side-effect on
  `target_metadata` documented. Mutation IS the contract
  (alembic's metadata-diff machinery needs the convention to
  exist on the metadata); workaround for isolation:
  `copy.copy(Base.metadata)`.
- **SH-01** — DB-URL redaction. `_safe_url(url)` helper +
  `_safe_error_context(url)` wrapper substitute the masked
  URL form in every `str` element of `exc.args` on connect
  failures. Silent-by-design — does nothing if the URL isn't
  in the message. Exception type preserved.
- **SH-02** — Offline-mode credential-leak warning. Emits a
  stderr warning at `configure_env` offline-mode entry
  (BEFORE alembic generates SQL output) surfacing the
  credential-bearing DDL concern (`CREATE USER ... WITH
  PASSWORD '<secret>'`) for operators piping output to a
  file or DBA review channel.
- **SH-03** — Migration audit-trail expectations documented
  in `configure_env`'s docstring. Library-side `audit=true`
  emission tracked as v1.1+ follow-up; alembic's own stdout
  output is operator-readable.
- **SH-04** — `include_object` trust contract documented.
  The callable runs inside the migration process with full
  Python access; SHOULD be pure, deterministic, idempotent;
  raised errors propagate to alembic.
- **PC-02** — `asyncio.run` startup cost (~5-20 ms per async-
  path invocation) documented; `run_async_migrations` is the
  workaround for repeated invocations.
- **PC-03** — Autogenerate-cost expectations documented in
  the `include_object` docstring (callback runs once per
  schema object; budget ≤10 µs).
- **PC-04** — Offline-mode SQL generation throughput
  documented (operator awareness; alembic's own iteration
  cost dominates).
- **PC-05** — Engine-construction NullPool choice documented
  (correct for the migration-as-one-shot shape).

### Changed — pin

- **`mgf-common>=0.33,<0.34` → `mgf-common>=0.34,<0.35`**.
  Pairs with mgf-common 0.34.0 (perf gates + standards
  v2.6 / v2.7). No code change required in this sibling;
  the pin shift unlocks consumer co-installation.

### Notes for consumers

- The two new kwargs default to the previous behaviour — no
  consumer code change required to upgrade.
- Async-from-running-loop now raises an actionable error
  instead of silently failing. If your test fixtures wrap
  `configure_env` from inside an event loop, switch to
  `run_async_migrations` (new public name) or restructure
  per the docstring's RA-01 note.

---

## [0.2.0] — 2026-05-15

PyPI: <https://pypi.org/project/mgf-alembic/0.2.0/> · Tag: `v0.2.0`

> **v2.6 + v2.7 standards-compliance release.** Brings
> `mgf-alembic` to the federation-sibling compliant shape:
> SECURITY.md + docs/claude/CLAUDE.md + docs/standards/README.md
> pointer-only stub. No code changes; documentation-only.

### Added — standards-compliance shape (v2.6 + v2.7)

- **`SECURITY.md`** — vulnerability-reporting policy.
  Highlights async-vs-sync URL detection + `include_object`
  / `include_schemas` pass-through as the in-scope security
  surfaces; consumer-authored migration content is
  explicitly out-of-scope.
- **`docs/claude/CLAUDE.md`** — AI-agent dense reference.
  File map; cross-cutting patterns (URL-prefix detection,
  offline-mode behaviour, naming-convention discipline,
  flipped `compare_type` / `compare_server_default`
  defaults, pass-through kwargs); build + release recipe;
  common pitfalls.
- **`docs/standards/README.md`** — pointer-only stub per
  **DOC-02** §2.0.4 Shape A. Conformance target: L2.

### Engineering

- No code changes. `src/mgf/alembic/` byte-identical to
  v0.1.1. `mgf-common>=0.33,<0.34` unchanged.

---

## [0.1.1] — 2026-05-11

PyPI: <https://pypi.org/project/mgf-alembic/0.1.1/> · Tag: `v0.1.1`

> **Pin-walk patch release — no source change.** Walks the
> `mgf-common` pin forward to `>=0.33,<0.34`, the AP-12
> deprecation-removal release. `mgf-alembic` source is clean of the
> three removed names (`mgf.common.configure`,
> `mgf.common.config.make_settings_config`,
> `mgf.common.exceptions.EnvironmentError`), so no code change is
> needed — only the dependency declaration moves.

### Changed

- **Dependency pin** — `mgf-common>=0.30,<0.31` → `mgf-common>=0.33,<0.34`.
  Lets consumers install `mgf-alembic` alongside the current
  `mgf-common` line.

---

## [0.1.0] — 2026-05-10

PyPI: <https://pypi.org/project/mgf-alembic/0.1.0/> · Tag: `v0.1.0`

> **Maiden voyage** — extracted from `mgf-common` v0.29.0 per the
> federation split plan ([mgf-common/docs/release/federation_roadmap.md](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/docs/release/federation_roadmap.md)).
> Paired ship with mgf-sqlalchemy v0.1.0 (this sibling depends on it).
> Cutover guide: [`docs/cutover/v0.1.0.md`](docs/cutover/v0.1.0.md).

### Added

- **`mgf.alembic.configure_env`** — one call replaces the ~40-line
  `env.py` boilerplate every async-SQLAlchemy + alembic project
  ships. Detects sync vs async drivers from the URL prefix
  (`postgresql+asyncpg://`, `postgresql+psycopg://`,
  `mysql+aiomysql://`, `mysql+asyncmy://`, `sqlite+aiosqlite://`)
  and runs the migration via `asyncio.run` for async URLs;
  falls through to the sync path otherwise. Plumbs
  `compare_type`, `compare_server_default`, `naming_convention`,
  `include_object`, `include_schemas` through to
  `alembic.context.configure` (PAPER-22 — `include_object` /
  `include_schemas` were added in mgf-common v0.19; carried over
  byte-identical).

### Engineering

- 11 tests carried over from `mgf-common/tests/unit/alembic/test_env.py`
  — every pre-extraction failure mode stays green at parity. Coverage
  threshold ≥80% (matches mgf-common's standard).
- Imports rewrite from `mgf.common.alembic.*` to `mgf.alembic.*`.
  No private-import leaks; the sibling reaches into mgf-common only
  through public names.
- `mgf-common>=0.30,<0.31` + `mgf-sqlalchemy>=0.1,<0.2` runtime
  dependencies. AP-03 0.x window pin discipline applies — bump in
  lock-step with mgf-common's next minor.
- PEP 420 namespace package (no top-level `mgf/__init__.py`); the
  wheel ships `src/mgf/` as-is so `mgf.alembic`, `mgf.sqlalchemy`,
  `mgf.fastapi`, `mgf.http`, and `mgf.common` coexist as siblings.
