# Changelog — mgf-vm-interchange

All notable changes land here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.5] - 2026-07-14

### Changed
- **Released what was stranded on `main`.** `main` had moved past `v0.2.4` while still
  declaring `0.2.4`, so the *published* `0.2.4` was different code under the same version
  number. Two things consumers never received:
  - the **Apache-2.0 relicence** (landed on main 2026-07-12; every published wheel still
    carried `License: MIT`, with no `NOTICE` — a relicence is not real until it is released);
  - the **widened `mgf-common` pin** (`<1.0`, was `<0.50`). The stale published cap
    backtracked the whole federation's co-install to `mgf-common` 0.49.2.

  `REL-13` could not see this: it compares declared version to *registry* version, and both
  said `0.2.4`. The drift was main-vs-tag content. `mgf/tools/verify_release_currency.py`
  now catches the class — *a fix that isn't released isn't shipped.*

## [0.2.4] - 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.2.3] - 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.

## [Unreleased]

## [0.2.2] - 2026-06-09

### Added
- **AP-13**: `mgf.vm.interchange.__version__` now present (mirrors `pyproject.toml`), exported in `__all__`, CI tag-coherence-gated.
- Full Woodpecker CI (ruff + import-linter + mypy + pytest matrix + vuln/secret scans + tag-driven Codeberg publish chain + verify-codeberg + sbom); SCOPE.md; [standards] extra; PR-01 UI-forbid import-linter contract; doc-bucket READMEs.

### Fixed
- **REL-03 / DOC-08/09**: PUBLIC_API.json regenerated to HEAD (was stale at 0.2.0).


## [0.2.1] — 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).

---

## [0.2.0] — 2026-06-05 — drain off the mgf-vm umbrella

### Changed (BREAKING)
- **`export_ova` / `import_ova`: `convert_fn` is now REQUIRED** (was optional,
  defaulting to the umbrella's `mgf.vm.operations.disk_ops.convert`). The
  interchange no longer bundles a qemu-img converter — the caller injects one
  (the app passes its own `disk_ops.convert`). Removes the last impure
  dependency on the retiring umbrella.

### Internal
- Drained entirely off the **`mgf-vm` umbrella** — depends on `mgf-vm-core` only.
  `mgf.vm.{domain,exceptions,common.safe_tar,common.progress}` retargeted to
  `mgf.vm.core.*`; the secure XML parsers (`parse_xml_string`/`parse_xml_file`)
  are owned locally in `interchange._xml` (defusedxml — which core's purity
  contract forbids). Tests use an app-local `MockProvider` double. `mgf-vm`
  removed from dependencies + lockfile.

## [0.1.3] — 2026-06-05 — mgf-common 0.45 cohort-walk

### Changed
- Walk the `mgf-common` pin `>=0.41,<0.45` → `>=0.41,<0.46` (adopt 0.45.x; no
  library-API break) and add the PKG-06 `[[tool.uv.index]] codeberg-mgf` +
  `mgf-common` source mapping from the 0.45 Codeberg cutover. Clears this
  sibling's REL-13 RED. Lockstep with the `mgf-vm-*` cohort.

## [0.1.2] - 2026-06-05 — structural OVA backend (D-G24)

### Changed
- `exporter.export_ova` + `importer.import_ova` retype their `provider` param
  from the hard `VMProvider` to per-file structural Protocols (`_DomainReader`:
  `domain_xml` + `domain_disk_paths`; `_DomainDefiner`: `define_domain`). A thin
  adapter over an SDK client + the libvirt raw-XML escape hatch now satisfies
  them, so the consumer's OVA dialogs drain off `mgf.vm.providers`. Behaviour
  unchanged.

## [0.1.1] - 2026-06-04

### Changed
- **`mgf-common` ceiling at `>=0.41,<0.45`** (REL-10/11 cohort-walk). The
  published 0.1.0 pinned `<0.44`, now unsatisfiable (mgf-common is at `0.44.5`,
  older minors pruned); this release publishes the widened window so the
  umbrella + app graph resolves. Ships alongside the D-G19 sibling wave and the
  accumulated federation-conformance work below.

### Conformance (federation-sync vs mgf-common 0.42.0, 2026-05-29)
- **`PUBLIC_API.md` + `PUBLIC_API.json` added** (AP-10 / DOC-08) with a
  generator (`tools/generate_public_api_json.py`) and a pin test
  (`tests/unit/test_public_api_pin.py`) tying both to every module's
  `__all__`. Previously absent — a required library doc.
- **DP-01 import-linter contract added** (`.importlinter`,
  `interchange-is-a-federation-leaf`): forbids importing any consumer
  app. `lint-imports` previously exited non-zero with zero contracts;
  now green (1 kept, 0 broken). Uses `root_packages = mgf` because
  grimp rejects a deep namespace subpackage as a top-level root.
- **`mypy --strict` now passes on `tests/` too** (was 46 errors): typed
  the `_fake_convert_factory` return as `Callable[..., None]` and added
  `-> None` to the test methods.
- **Stale docs corrected:** conformance tracker pin `0.38`→`0.41,<0.43`
  and removed phantom `VmSpec`/`domain.py`/`VmManagerError` rows;
  `DEPS.md` pin `<0.42`→`<0.43`, `VmSpec` output claim and the bogus
  "mgf-vm imports interchange (13 sites)" row corrected (mgf-vm ships
  but does not consume it).
- **Cross-repo blocker logged (deferred to supervisor / mgf-vm):**
  `mgf-vm` still ships `mgf.vm.interchange` and shadows this repo's
  `src/` at runtime via the shared `mgf.vm` namespace.

### Added
- **Module port from original vm-vmanager-app (2026-05-24).** The full
  interchange surface from `mgf-vm/src/mgf/vm/interchange/` is now
  in this repo: OVA tar packing/unpacking with safe-tar discipline
  (SH-04), OVF XML parsing via `defusedxml` (SH-03), import/export
  pipelines, format conversion. 4 source files, 4 test modules;
  **32 tests passing** against the `mgf-vm` umbrella as a
  transitional dependency.
- Tests permit `S108` (`/tmp/*` paths used as adversarial fixtures
  in safe-tar path-traversal-defense tests). Same justification as
  forensics — the paths are inside test scenarios that verify
  SH-04 *refuses* them, never written to disk.
- Initial repo skeleton (earlier, same day): `pyproject.toml` +
  four-gate scaffolding, MIT license, README, federation discipline
  files, `docs/claude/CLAUDE.md`.

### Transitional
- **Depends on `mgf-vm` umbrella, not `mgf-vm-core`.** The extracted
  modules reference `mgf.vm.{domain,exceptions,common,operations,providers}`
  which currently live in the old umbrella. Phase 0 Stream A migrates
  that surface into `mgf-vm-core`; this repo's dependency flips then.
- **`mgf-vm` umbrella still ships `mgf/vm/interchange/`** for now to
  avoid destabilizing `vm-vmanager-app`'s imports.

### Status
All four gates green on Python 3.12:
- pytest: 32 passed
- `mypy --strict`: 4 files clean
- ruff: All checks passed
- lint-imports: exit 0
