# Changelog

All notable changes to mgf-brand-qt are documented here. The format
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
once it leaves the `0.x` series.

---

## [0.1.3] - 2026-08-08

### Fixed
- **The get-or-create registry holds the manager STRONGLY.** 0.1.2's
  `_ACTIVE` was a weakref, so any caller that dropped the returned
  manager (every test suite; any consumer wanting only the side
  effect) let it be collected — and the next `apply_theme` walked the
  full construction path again, resurrecting the PAPER-11 crash class
  the release existed to foreclose. Found by figrecovery's suite
  within the hour, on the pin bump. One process-scoped manager is the
  design; a fresh QApplication still replaces the entry via the
  identity check. Pinned by
  `test_the_registry_keeps_the_manager_alive`.

## [0.1.2] - 2026-08-07

The consumer-court hardening release: ten of the eleven open FEEDBACK
papers ship (PAPER-06, the widget-roadmap paper, stays open by design).

### Fixed
- **A second `apply_theme()` no longer segfaults** (PAPER-11 🔴).
  `apply_theme` is get-or-create per QApplication: repeat calls update
  the live manager's mode and persistence callback and re-apply, but
  never re-run `setStyle` — the `setStyle x 2 + setStyleSheet x 2`
  crash path with a live `QWizard` is unconstructable. Consumer
  memoization workarounds (figrecovery `app.py::_THEME`) can be deleted.
- **`set_mgf` rejects unknown keys AND values** (PAPER-10). Both halves
  of the vocabulary are validated against the new
  `mgf.brand_qt.qss.MGF_PROPS` registry, with a targeted message for
  the prefixed-key mistake (`mgfChrome=` → "pass the bare key") that
  once shipped an entire shell unstyled through four green gates. All
  ~60 call sites across the three consumers were verified legal first.
- **Four chip recipes reach WCAG-AA strong-on-tint** (PAPER-07): light
  warning 4.40→4.63, dark info 3.63→4.60, dark busy 4.13→4.60, dark
  derived 3.68→4.59. Minimal-drift changes to kit-owned mix()
  derivations — tint surfaces kept where possible, the locked RAW
  palette untouched. A new 4.5:1 gate joins the 3:1 floor in
  `test_contrast.py`; hrb-app's G10 shrink can be retired.
- **The busy pulse respects visibility** (PAPER-02): the infinite
  `QVariantAnimation` stops on `hideEvent` and resumes on `showEvent`,
  so chips hidden in docks/stacks no longer tick the event loop.
- **`bind_empty_state` returns a real binding** (PAPER-01): watches
  `dataChanged` too, judges emptiness by the view's CURRENT model (the
  bind-time-closure bug), and the returned `EmptyStateBinding.unbind()`
  releases every connection, idempotently.

### Added
- **`widgets.confirm_action`** (PAPER-04) — the house confirm: the
  affirmative button carries the VERB, Cancel is default and escape,
  `danger=True` paints the verb in the danger variant.
- **The kit motion policy** (PAPER-02 sub-ask): `motion.set_reduce_motion`
  / `motion.reduce_motion` — the setting the module docstring had been
  promising; `fade_in` defaults to it and the busy pulse consults it.
- **`StatusChip.set_animate`** — the pulse is no longer constructor-frozen.
- **`EmptyState.set_title` / `set_reason` / `set_icon`** (PAPER-08);
  the labels are attributes now, so honest copy changes stop costing a
  rebuild (hrb-app's `replace_empty_copy` workaround retires).
- **Five PAPER-05 promotions**: `theme.to_qcolor`, top-level `mix`,
  `icons.logo_pixmap` (three Cornerstone Orbit marks),
  `widgets.lattice_tile`, and `ThemeManager.set_extra_qss` (consumer
  QSS that survives every theme flip).
- **`icon(..., ratio=)`** (PAPER-03): per-screen DPR override; the
  app-level ratio is re-read per call, never baked in.
- **`Mode` lives in the Qt-free core** (PAPER-09): defined in `tokens`,
  re-exported from `theme` unchanged — a pydantic settings model can
  finally annotate with the kit's own vocabulary. hrb-app's
  `GuiThemeMode` duplicate can be deleted.

### Notes
- Public surface: 21 → 24 top-level names (`MGF_PROPS`, `Mode`, `mix`);
  PUBLIC_API.json regenerated.
- The strengthened chip recipes intentionally diverge from the web
  kit's mixes for those four pairs pending the mgf-brand LOCK
  amendment; routing per SCOPE.md — the brand source of record owns
  the values, and a matching paper belongs in mgf-brand's ledger.

## [0.1.1] - 2026-07-14

### Changed
- **Released what accumulated on `main` since v0.1.0.** Ships the Apache-2.0 relicence (the published v0.1.0 wheel still carried `License: MIT` with no `NOTICE`) plus the fixes and pin updates merged since. A fix that isn't released isn't shipped; `mgf/tools/verify_release_currency.py` (now devpi-aware) flags this class.

## [0.1.0] — 2026-07-10

### Added

- **Initial extraction** of the Magogi Qt design system from
  vm-vmanager-app's `vmanager.gui.design` (proven across its
  desktop-UI redesign, chunks C0–C10): Qt-free token core
  (`tokens`/`_mix`/`qss` — raw palette, light/dark semantic maps with
  computed color-mix parity, scales, viz palettes, generated
  stylesheet), `fonts` (OFL statics + loaders), `icons` (the 42-icon
  set, recolorable, DPR-aware, cached), `theme`
  (Fusion + QPalette + QSS engine with OS colour-scheme watching),
  `motion` (`fade_in` + the restrained-motion doctrine), `widgets`
  (StatusChip/Badge, StatTile, EmptyState + `bind_empty_state`,
  StatusChipDelegate + `STATUS_ROLE`, `set_mgf`/`apply_label_class`),
  and the vendored brand assets with sha256 provenance.
- GUI-01 UI-kit conditions enforced mechanically: import-linter
  contracts (no domain/consumer imports; Qt-free core) + a
  fresh-interpreter Qt-freeness test; palette lint; WCAG contrast
  guard (body 4.5:1 / chip-label 3:1 tiers).
