# mgf-common v0.31.0 — Cutover guide

> **Audience:** consumer agents (and humans relaying for them)
> migrating from `mgf-common` v0.30.0 to v0.31.0.
> **What this is:** the canonical migration document for the v0.31
> federation extraction. Companion guide:
> [`mgf-django/docs/cutover/v0.1.0.md`](https://codeberg.org/magogi-admin/mgf-django/src/branch/main/docs/cutover/v0.1.0.md).

The fourth and final framework-adapter sibling extraction under
the federation split plan recorded in
[`docs/release/federation_roadmap.md`](../release/federation_roadmap.md).
After this release, mgf-common settles into its v1.0 target shape:
**pure-Python infrastructure + standards source-of-truth, no
framework-coupled adapters**. Every web framework (FastAPI,
Django) and every storage adapter (SQLAlchemy, alembic) and the
HTTP-client wrapper now ships from its respective sibling package.

The `mgf.common.django` subpackage moves to a new sibling
distribution **`mgf-django`** (import path `mgf.django`). 🔴
**breaking** for any consumer importing from `mgf.common.django.*`
or installing the `mgf-common[django]` extra. The migration is a
rename + dependency swap PLUS one runtime config change (the
Django app label).

---

## At-a-glance

| Was (≤ mgf-common v0.30) | Is (mgf-common v0.31 + mgf-django v0.1) |
|---|---|
| `pip install 'mgf-common[django]'` | `pip install mgf-django` |
| `INSTALLED_APPS = [..., "mgf.common.django"]` | `INSTALLED_APPS = [..., "mgf.django"]` |
| `MIDDLEWARE = ["mgf.common.django.MgfRequestIdMiddleware", ...]` | `MIDDLEWARE = ["mgf.django.MgfRequestIdMiddleware", ...]` |
| `MIDDLEWARE = ["mgf.common.django.MgfContextMiddleware", ...]` | `MIDDLEWARE = ["mgf.django.MgfContextMiddleware", ...]` |
| `LOGGING = {"formatters": {"json": {"()": "mgf.common.django.JsonFormatter"}}}` | `LOGGING = {"formatters": {"json": {"()": "mgf.django.JsonFormatter"}}}` |
| `from mgf.common.django import …` | `from mgf.django import …` |
| `apps.get_app_config("mgf_common")` ⚠️ | `apps.get_app_config("mgf_django")` (label renamed) |

**One BREAKING runtime change beyond the import-rename:** the
Django app **label** changes from `"mgf_common"` to `"mgf_django"`
to match the new module path. Full rationale + sed in
[`mgf-django/docs/cutover/v0.1.0.md`](https://codeberg.org/magogi-admin/mgf-django/src/branch/main/docs/cutover/v0.1.0.md#the-label-rename).

---

## Migration steps

### 1. Update your `pyproject.toml`

```toml
# Before
dependencies = [
    "mgf-common[django]>=0.30,<0.31",
]

# After
dependencies = [
    "mgf-common>=0.31,<0.32",
    "mgf-django>=0.1,<0.2",
]
```

### 2. Rewrite imports + config strings

```bash
# At your repo root.

git ls-files '*.py' | xargs sed -i \
    -e 's|from mgf\.common\.django\b|from mgf.django|g' \
    -e 's|import mgf\.common\.django\b|import mgf.django|g' \
    -e 's|mgf\.common\.django\.|mgf.django.|g' \
    -e 's|"mgf\.common\.django"|"mgf.django"|g' \
    -e "s|'mgf\\.common\\.django'|'mgf.django'|g" \
    -e 's|get_app_config("mgf_common")|get_app_config("mgf_django")|g' \
    -e "s|get_app_config('mgf_common')|get_app_config('mgf_django')|g"

# Audit:
git grep -n 'mgf\.common\.django\|mgf_common'
# Manually inspect — `mgf_common` may legitimately appear in unrelated
# contexts (env var names like MGF_COMMON_APP_NAME stay with that name
# regardless).
```

### 3. Update `settings.py`

Verify after the sed:

- `INSTALLED_APPS` lists `"mgf.django"` (not `"mgf.common.django"`).
- `MIDDLEWARE` lists the two middlewares under `"mgf.django.*"`.
- `LOGGING` (if you use `mgf.django.JsonFormatter`) references the
  new path.
- `MGF_COMMON_APP_NAME` and `MGF_COMMON_APP_VERSION` (if set) keep
  those names — Django settings keys aren't affected by the
  rename.

### 4. Re-run the four gates

```bash
uv sync
uv run ruff check
uv run mypy --strict src/
uv run pytest
python manage.py check
```

### 5. Re-run `mgf-fed catch-up`

```bash
mgf-fed catch-up
```

---

## What changed in mgf-common v0.31.0

### Removed (BREAKING)

- **`mgf.common.django.*`** — every name (`MgfCommonConfig`,
  `MgfRequestIdMiddleware`, `MgfContextMiddleware`, `JsonFormatter`,
  `DjangoSettingsBridge`) moves to `mgf.django.*` in the new
  **`mgf-django`** sibling distribution.
- **`[django]` and `[django-test]` extras** in `mgf-common` are
  deleted. Consumers install `mgf-django` directly.

### Engineering

- 18 unit tests removed from mgf-common (the `tests/unit/django/`
  suite moved to `mgf-django/tests/unit/`).
- PUBLIC_API.json: modules 16 → 15, names 175 → 170.
- `_init_project.py` scaffold: `[django]` kind now emits
  `mgf-django>=0.1,<0.2` instead of `mgf-common[django]`; pin
  floors bump from `>=0.30,<0.31` to `>=0.31,<0.32` across all
  five kinds.
- Version bump: 0.30.0 → 0.31.0. Parallel bumps in pyproject.toml +
  `src/mgf/common/__init__.py` keep the AP-13 version-sync test
  green.

### Documentation

- `docs/cutover/v0.31.0.md` (this file) — full migration map.
- `docs/recipes/django.md` removed from mgf-common; the canonical
  recipe now lives at
  `mgf-django/docs/recipes/django.md`.
- `docs/release/federation_roadmap.md` retrospective row filled
  for v0.31.0; ASPIRE-06 status updated.
- `docs/standards/web/README.md` Django row points at the sibling.
- `docs/qa/coverage.md` updated.
- `docs/internal/lift_checklist.md` — the historical "remaining
  framework adapters" row is updated (no more remaining).

### Federation milestone

This is the **fourth and final** framework-adapter sibling
extraction:

| Release | Sibling | Status |
|---|---|---|
| v0.28.0 | mgf-fastapi v0.1 | shipped |
| v0.29.0 | mgf-http v0.1 | shipped |
| v0.30.0 | mgf-sqlalchemy v0.1 + mgf-alembic v0.1 + mgf-fastapi v0.2 | shipped |
| **v0.31.0** | **mgf-django v0.1** | **this release** |
| v0.32+ | stabilization | next |
| v1.0.0 | lock the federated surface | future |

After this ship, mgf-common is the **federation leaf**: pure-Python
infrastructure (exceptions, config, settings, observability,
bootstrap, vault, versioned, cli, process, providers, registry,
pytest_plugin, progress, typing) + the
[`docs/standards/`](../standards/) source-of-truth that every
sibling references. The v0.32+ stabilization window is the time to
exercise the full federation through real consumers, gather
friction, promote `experimental` → `stable` per AP-09, then lock at
v1.0.

---

## Per-consumer migration notes

### inthewords (Django web)

**Live config not affected.** inthewords doesn't import from
`mgf.common.django` in its live `config/settings/base.py` — they
implemented their own `apps.core.middleware.RequestLoggingMiddleware`
and `apps.core.middleware.AppErrorMiddleware`. Just bump the
mgf-common pin:

```toml
# pyproject.toml
"mgf-common>=0.31,<0.32",
```

```text
# requirements/base.txt
mgf-common[observability]>=0.31,<0.32
```

Then `make lock` to regenerate the lockfiles.

**Doc cosmetics only.** `docs/CLAUDE.md` references the canonical
mgf.common.django pattern as an example for future adoption; those
references are updated to the new sibling path at the v0.31 cutover.

### PlasmaMapper (FastAPI)

**Not affected.** No Django surface in use. Pin bump only:

```toml
"mgf-common>=0.31,<0.32"
```

### vm-vmanager-app (Qt desktop)

**Not affected.** No Django surface in use.

### mgf-apiprobe

**Not affected.** No Django surface in use.

---

## What stays in `mgf-common` after v0.31

The federation leaf. These do NOT extract:

| Submodule | Why it stays |
|---|---|
| `mgf.common.exceptions` | The federation-wide typed-exception contract; every sibling raises through it. |
| `mgf.common.config`, `.settings` | Pure pydantic-settings; no framework coupling. |
| `mgf.common.observability` | Stdlib `logging` + optional OTel; framework-agnostic. |
| `mgf.common._lifecycle` (`bootstrap`) | The transactional wiring entry point; framework-agnostic. |
| `mgf.common.providers` | DP-02 implementation; pure ABC pattern. |
| `mgf.common.process` | Subprocess + service lifecycle; stdlib only. |
| `mgf.common.vault` | Optional encrypted file vault. |
| `mgf.common.versioned` | Versioned satellite-config files. |
| `mgf.common.cli` | CLI primitives (exit codes, structured handler). |
| `mgf.common.registry` | Tiny registry pattern. |
| `mgf.common.pytest_plugin` | pytest fixtures (entry-point auto-registers). |
| `mgf.common.progress` | Cancellation tokens. |
| `mgf.common.typing` | Type aliases. |
| `docs/standards/*` | The source of truth for the federation. |
| `mgf-fed init-project` | Federation orchestrator — scaffolds projects of any kind. |

Plus the cross-sibling shared `mgf.common._request_id` contextvar
that `mgf.fastapi.RequestIdMiddleware` and
`mgf.django.MgfRequestIdMiddleware` both read/write (deliberate
exception to the closed-box rule, mirrored on both sides).
