# v0.20.0 — Cutover guide

> **Audience:** consumer agents (and humans relaying for them)
> upgrading to `mgf-common` 0.20.0.
> **What this is:** the canonical migration document for this
> release. Per [`RELEASING.md`](../standards/RELEASING.md) **REL-09**
> + the cutover-guide pattern, individual per-entry notification
> paragraphs are pointers into this guide.

This is a **documentation polish release** — three closures,
all docs-only, all from inthewords' golden-example pass on
2026-05-07 after closing-out the v0.19.0 BOOTSTRAP-01 adoption.

There is **no Python-surface change** in v0.20.0. The version
bump is mechanical (the wheel ships standards docs as data via
`[tool.hatch.build.targets.wheel.force-include]`, so new docs
need to land through a real release for `mgf-common standards
<topic>` to surface them). No behaviour change, no new APIs,
no removed APIs.

---

## At-a-glance

| Entry | Severity | What landed | Code or docs? |
|---|---|---|---|
| [PAPER-25](#paper-25--framework-owned-logging-recipe) | 🟢 | `docs/public/recipes/framework-owned-logging.md` — Django + FastAPI + Flask + the what's-preserved/what-you-give-up tables | docs |
| [ASPIRE-03](#aspire-03--web-standards-subtree) | 💭 | `docs/standards/web/README.md` navigation page; per-recipe promotion roadmap | docs |
| [ASPIRE-04](#aspire-04--documented-non-adoption-principle) | 💭 | `docs/standards/principles/non-adoption-is-valid.md` + cross-link from `docs/standards/README.md` | docs |

**Pin bump:** `mgf-common = ">=0.20,<0.21"` per the 0.x window
discipline (one minor at a time; AP-03).

**Public-Python-surface change:** none.

**Behaviour change:** none.

**No deprecation cycles introduced.**

---

## PAPER-25 — Framework-owned-logging recipe

`bootstrap(setup_logging=False)` — the BOOTSTRAP-01 deliverable
in v0.19.0 — was documented only inside the v0.19.0 cutover
guide. Cutover guides are **time-bounded** by design: they
narrate one release's migration story. The
`setup_logging=False` pattern is **permanent reference**:
every future framework consumer needs the same shape on day
one of their adoption.

**What landed:** [`docs/public/recipes/framework-owned-logging.md`](../public/recipes/framework-owned-logging.md)
— a permanent recipe at the canonical path. Sections:

- *When to use this pattern* — the four "yes if" triggers and
  three "no if" cases.
- *What `setup_logging=False` preserves* — a table comparing
  the two paths across nine wiring steps (identity, OTel,
  excepthooks, AppContext, buffer replay, handler install,
  level overrides, redaction).
- *Django (`AppConfig.ready()`)* — full example with the
  idempotency guard for double-`ready()` cases.
- *FastAPI (lifespan context manager)* — full example, plus
  notes on test-client lifespan and HTTP-01 middleware
  composition.
- *Flask (app factory)* — full example, plus the
  `atexit.register` shutdown pattern.
- *What you give up* — three explicit trade-offs (JSON wire
  shape, level overrides, mgf-handler redaction).
- *Cross-references* — BOOTSTRAP-01, v0.19.0 cutover guide,
  the web subtree, related recipes.

**Original-path note.** PAPER-25 suggested
`docs/recipes/framework-owned-logging.md`; the existing
convention is `docs/public/recipes/`. The shipped path is the
existing convention. Cross-links from the entry's
documentation match.

---

## ASPIRE-03 — Web standards subtree

ASPIRE-02 (closed in v0.18.0) committed to "per-kind standards
subtrees" as the structural answer to the framework-fit gap.
The v0.18 carve-outs landed inside topic-doc sub-sections;
ASPIRE-03 is the structural follow-on. After two web consumers
(inthewords + PlasmaMapper) and three release rounds
(v0.17 / v0.18 / v0.19), there's enough crystallised content
to justify a dedicated subtree.

**Approach A (incremental).** This release ships only the
navigation page. Per-recipe promotion (cloud-native logging,
framework config, http exceptions, bootstrap, stub-gaps,
adoption-walk) trickles in over subsequent releases — each
landing as one focused PR.

**What landed:** [`docs/standards/web/README.md`](../standards/web/README.md)
— the front-door narrative. Sections:

- *Why a per-kind subtree* — the friction story that
  motivated ASPIRE-02 + ASPIRE-03; the carve-out summary.
- *Read-in-order for a new web consumer* — a 7-step path from
  master index → CONFIGURATION §0a → framework-owned-logging
  → cloud-native-logging → ERROR_HANDLING with HTTP-01 →
  framework recipes → non-adoption principle.
- *Recipes index (cross-cutting; web-domain)* — the table of
  recipes a web consumer will read during adoption, with
  canonical paths + paper closures.
- *Per-rule applicability for web consumers* — a topic-doc-by-
  topic-doc summary of "what applies / what's N/A or carved-
  out" for a web consumer.
- *Promotion roadmap (incremental)* — the explicit checklist
  of what's shipped (this README + PAPER-25) vs. what's
  upcoming (per-recipe promotions). Tracked through ASPIRE-03's
  Retrospective field.

**Promotion roadmap (lives in the README, restated here):**

- [x] `web/README.md` — this release.
- [x] `docs/public/recipes/framework-owned-logging.md` —
  PAPER-25, this release.
- [ ] `web/http-exceptions.md` — promote PAPER-24 cutover-guide
  content + the consumer-pattern from `recipes/http.md`.
- [ ] `web/framework-config.md` — promote `CONFIGURATION.md`
  §0a inthewords worked example.
- [ ] `web/stub-gaps.md` — django-stubs/DRF/Channels/Celery
  workaround library (contingent on inthewords' upstream
  contribution).
- [ ] `web/adoption-walk.md` — canonical onboarding narrative.

Each box is one future small PR. Triage continues per
release.

---

## ASPIRE-04 — Documented-non-adoption principle

The framing behind every shipped carve-out (LOG-01,
CONFIG-01, BOOTSTRAP-01) was: a consumer correctly declined a
primitive whose default conflicted with their context, filed
the rationale upstream, and the carve-out shipped. This
principle was implicit. v0.20.0 names it.

**What landed:** [`docs/standards/principles/non-adoption-is-valid.md`](../standards/principles/non-adoption-is-valid.md)
— the standalone principle doc. Sections:

- *What this principle says* — the core statement +
  three-outcome adoption framework (Adopted / Adopted with
  carve-out / Declined).
- *Three components: conscious decline, rationale, feedback*
  — load-bearing definition of what makes a non-adoption
  "documented."
- *When to non-adopt* — five concrete triggers
  (deployment-coupled contract, policy, framework
  architecture, consumer scale, cost vs alternative).
- *When NOT to non-adopt* — the negative-space callout. Six
  patterns that look like non-adoption but are cover for
  laziness, indefinite deferral, or refactor avoidance.
- *Worked examples* — inthewords' LOG-01 / BOOTSTRAP-01
  pre-v0.19.0 + PlasmaMapper's "small consumer" scope
  discipline.
- *How to file the rationale* — three valid mechanisms by
  durability (project-side ADR, tracker entry, `FEEDBACK.md`
  paper); ADR template included.

**Cross-link from `docs/standards/README.md`:** the
Conformance section grew a "Documented non-adoption preserves
conformance" paragraph pointing at the new principle doc.
Same section also got a "Per-kind subtrees" pointer to
`web/README.md`.

**Magogi-foundation framing.** The principle generalises
beyond mgf-common. It applies to every shared library that
the Magogi ecosystem produces — `mgf-apiprobe` (sibling), the
future `mgf-*` packages, plus any cornerstone library a
consumer project depends on. The doc is positioned to be
referenced from those projects in the future.

---

## Per-consumer migration notes

### VManager (Qt desktop)

**No changes required.** This release is web-domain documentation; doesn't touch your project's surface. Bump pin to `mgf-common = ">=0.20,<0.21"`. Run `mgf-common standards web` (it prints the new web/README.md content via the standards-doc shipping pipeline) just to confirm the new docs reached the wheel correctly. If your project culture supports it, the
`docs/standards/principles/non-adoption-is-valid.md` doc is worth a read regardless of consumer kind — it formalises the framing behind every carve-out you've benefited from.

### inthewords (Django web)

**This is your golden-example release** — three of your filings landed. Bump pin to `mgf-common = ">=0.20,<0.21"`. The substantive update for you:

- **PAPER-25's recipe** is now the canonical reference for the pattern you adopted in Phase 3. Future Django adopters who consume your project's adoption walk should be pointed at `docs/public/recipes/framework-owned-logging.md` rather than the v0.19.0 cutover guide.
- **ASPIRE-03's web subtree README** is open. The promotion roadmap names per-recipe pieces; if you have working content (e.g., the django-stubs/DRF/Channels/Celery workaround library you mentioned in the entry), upstream contribution is welcome — file as a follow-up paper or directly via PR.
- **ASPIRE-04's principle doc** explicitly cites your ADR-004 + Phase 3 first-closeout as worked examples. The principle is named the way it's named because of your adoption walk; the credit lives in `docs/standards/principles/non-adoption-is-valid.md` §"Worked examples."

No code-side migration. Promote any internal references to "BOOTSTRAP-01 cutover-guide §" to point at `docs/public/recipes/framework-owned-logging.md` for permanence.

### PlasmaMapper (FastAPI scientific platform)

**No code-side migration.** Bump pin to `mgf-common = ">=0.20,<0.21"`. The substantive updates for you:

- **`docs/standards/web/README.md`** opens the web subtree. The recipes index references the `recipes/fastapi.md` recipe + the post-PAPER-24 simplification (HTTP-01-rooted exceptions need no `status_map` entries). If your project's adoption walk has any FastAPI-specific patterns worth promoting (especially around the non-adoption framing for the heavier observability features), upstream contribution to the subtree is welcome.
- **ASPIRE-04's principle doc** cites your `MGF_ADOPTION.md` §1 "small consumer" scope discipline as a worked example. Your scope-discipline approach is now documented as a valid adoption profile. If you'd like the framing promoted to its own recipe (`web/small-consumer-scope.md` or similar), file a follow-up paper.

---

## Engineering note

v0.20.0 is the **first docs-only release** for `mgf-common`. The release pipeline (uv build → twine upload → sha256 verify) treats it identically to a code release, which is the right behaviour: standards docs ship as wheel data through `[tool.hatch.build.targets.wheel.force-include]`, so docs reaching consumers via `mgf-common standards <topic>` requires a real PyPI release just like an API change does. The CHANGELOG section explicitly calls out the zero-code change so consumers can audit.

The "incremental Approach A" structuring for ASPIRE-03 is worth flagging as a release-engineering experiment: the README ships now; per-recipe promotion lands as small PRs over subsequent releases, tracked through the entry's Retrospective field. This is the first release that uses an explicit promotion-roadmap checklist as a release artifact. If the pattern works, future structural ASPIRE entries can follow the same shape (incremental landing with named milestones rather than one-shot delivery).
