# Engineering Standards — Master Index

> **Audience:** Human engineers AND AI coding agents.
> **Reference implementation:** [`mgf-common`](../../README.md) — every standard in this folder is grounded in code that ships in this repository.
> **Reference consumer:** [VManager](https://codeberg.org/magogi-admin/VManager) — the first project built on top of `mgf-common`; cited throughout the docs as the canonical "real-world example".
>
> **⚠️ Consumer-specific examples are illustrative.** Several topic docs cite VManager modules by name to ground a principle in a real codebase. These citations describe the *shape* of the pattern at the time the doc was written — they may be reorganised, refactored, or replaced as VManager evolves. Treat them as "this is how a real consumer applied the rule," not as "this is the canonical line of code." If a citation drifts, prefer fixing the description over chasing the specific reference. The full restructure of consumer examples into a separate `docs/reference-consumer/` directory is tracked in [`FEEDBACK.md`](../../FEEDBACK.md).

---

## Why this folder exists

This folder is the **single source of truth** for the cross-cutting engineering standards used by the owner across all desktop and mobile application projects.

The standards do three things at once:

1. **Define the bar.** What "world-class" means for error handling, logging, configuration, and component design — independent of any one project.
2. **Document the reference implementation.** What `mgf.common` ships *today*, with concrete file:line citations so you can read the code, not just the description.
3. **Provide drop-in templates.** Every topic doc ships paste-able skeletons (typed, mypy-strict-clean, no surprises) that a new project can lift directly. For most components the recommended action is now "depend on `mgf-common`" rather than "copy the template" — copy is the fallback when you genuinely need a divergent shape.

If you are **starting a new desktop / mobile / CLI project**, this folder is your starting point. Read the standards, then add `mgf-common` to your dependencies. If you are **extending an existing consumer (e.g., VManager)**, the standards are the bar — do not regress a feature below what they prescribe.

---

## How to navigate this folder

```
docs/standards/
├── README.md ← you are here (master index, conformance keywords, glossary)
├── DESIGN_PRINCIPLES.md ← layering, separation of concerns, replaceability, testability,
│ security/reliability/performance as first-class concerns,
│ async/concurrency rules, time + resource management
├── ERROR_HANDLING.md ← typed exception hierarchy, translation seams, top-level handlers
│ (CLI / sys.excepthook / threading / asyncio / Qt), GUI worker
│ error pipeline, crash reporter, async error paths,
│ user-facing error message style guide
├── LOGGING.md ← stdlib + JSON formatter, hierarchical logger naming, levels,
│ OpenTelemetry trace correlation, redaction, sinks (console +
│ rotating file + optional OTLP / syslog / HTTP), GUI log viewer,
│ log volume control (rate-limit / sample / dedup),
│ async-context propagation via contextvars
├── CONFIGURATION.md ← pydantic-settings, precedence (CLI > env > file > defaults),
│ schema versioning + migrations, atomic writes, lazy path
│ expansion, secrets→vault separation, discriminated unions,
│ environment-tier layering, field aliases for safe renames
├── SECURITY_STANDARD.md ← cross-project security standard: secrets management, subprocess
│ security, deserialization safety, file-system security, crypto
│ choices, network security (TLS / pinning / timeouts), input
│ validation, logging hygiene, dependency security, vulnerability
│ response, threat-model template, mechanical enforcement matrix
├── TESTING.md ← cross-project testing standard: test layout, fixture hierarchy,
│ mock-provider pattern, property tests (Hypothesis), GUI testing
│ (pytest-qt), async testing (pytest-asyncio), performance
│ benchmarks, coverage, test isolation, smoke tests, security pins
├── API_DESIGN.md ← cross-project API-design standard: __all__ discipline, semver
│ rigor, deprecation cycle, type stability + py.typed, stability
│ tiers (experimental/stable/deprecated), PUBLIC_API.md contract,
│ CHANGELOG migration recipes, backward-compat shim discipline
├── RELEASING.md ← cross-project release-engineering standard: PyPI-is-the-contract,
│ tag discipline, version-bump flow, token storage (~/.pypirc + Trusted
│ Publisher), local-dist hygiene, recovery from a botched upload
├── WORKFLOWS.md ← cross-project CI standard: WF-01..WF-12 rules covering
│ four-gate baseline, tag-driven publish, secret-store discipline,
│ tag-version coherence, pre-publish smoke, post-publish verify
├── WORKFLOWS_PATTERNS.md ← paste-ready Woodpecker snippets implementing every
│ WF-* rule; canonical full-pipeline recipe at the bottom
├── SCOPE.md ← cross-project scope policy: IN scope / OUT of scope (with cited
│ ecosystem alternatives) / Adjacent (with promotion criteria);
│ the "scope creep" review question every new-module PR must answer
└── COMMON_COMPONENTS.md ← catalogue of currently-supported common components, where they
                               live in mgf.common, and how to plug them into a new project
```

---

## Suggested reading order

| If you are… | Read in this order |
|---|---|
| **Starting a new project from scratch** | `DESIGN_PRINCIPLES.md` → `SECURITY_STANDARD.md` Rules box → `CONFIGURATION.md` → `ERROR_HANDLING.md` → `LOGGING.md` → `TESTING.md` Rules box → `API_DESIGN.md` Rules box (if publishing a library) → `COMMON_COMPONENTS.md` §"How to bootstrap". Then add `mgf-common` to your dependencies. |
| **Publishing a library** | `API_DESIGN.md` Rules box + §1 mental model + §3 stability tiers + §10 CHANGELOG contract — then walk the AP-* matrix against your repo |
| **Cutting a release** | `RELEASING.md` Rules box (REL-01..REL-08) + §2 release flow — print the §2 checklist for the actual upload session |
| **Setting up CI for a new project** | `WORKFLOWS.md` Rules box (WF-01..WF-12) + `WORKFLOWS_PATTERNS.md` §8 (canonical full pipeline) — copy the recipe, parameterise, commit |
| **Extending an existing consumer (e.g. VManager)** | The relevant topic doc → `COMMON_COMPONENTS.md` → the cited code in `src/mgf/common/` (or in the consumer's own `src/`) |
| **Reviewing a PR for compliance** | `DESIGN_PRINCIPLES.md` (rules) → topic docs (specifics) — every PR claim must map to a MUST/SHOULD here. The §"Self-review checklist" at the bottom of each doc is the PR author's contract. |
| **An AI agent given a vague task** | `README.md` (this file) → `DESIGN_PRINCIPLES.md` → only the topic doc the task touches. The "Rules box" at the top of each topic doc is agent-readable. The mechanical-enforcement matrix at the bottom of each doc tells the agent which rules are CI-enforceable vs review-only. |
| **Auditing security posture** | `SECURITY_STANDARD.md` Rules box + §15 mechanical-enforcement matrix → §12 threat-model template → walk the SC-01..SC-18 list against the project |
| **Setting up a new test suite** | `TESTING.md` Rules box → §3 fixture patterns → §11 isolation → §10 security pins. Then write the first failing test. |
| **Just looking up a fact** | Use the COMMON_COMPONENTS.md table of contents — it indexes every component by name and points at code |

---

## Conformance keywords

These docs use [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) keywords throughout. Every rule is tagged. Treat them as load-bearing — violations should be caught in code review.

| Keyword | Meaning |
|---|---|
| **MUST** / **MUST NOT** | Absolute requirement. A violation is a bug. Tooling (lint, mypy, tests) MUST enforce where mechanically possible. |
| **SHOULD** / **SHOULD NOT** | Strong recommendation. A deviation requires written justification in code or PR description. |
| **MAY** | Optional. Use your judgment. |

Every topic doc opens with a **Rules box** — a one-page summary of every MUST/SHOULD in that document. Skim that first; the body of the doc is rationale and templates.

---

## Conformance levels for projects

Not every project needs every standard at full strength on day one. Three published levels:

| Level | What you commit to | Typical use |
|---|---|---|
| **L0 — Bootstrap** | Hierarchical logging, base exception class, env-var-driven config (no schema). MUST NOT log secrets. MUST NOT swallow exceptions silently. | Spike, prototype, throwaway tool |
| **L1 — Production-Ready** | Full typed exception hierarchy, JSON-capable structured logging with correlation IDs, `pydantic-settings` config with schema versioning, top-level error handlers wired (CLI + GUI/threading/asyncio as applicable), local crash reporter writing JSON. | Any tool a real user will run |
| **L2 — Observability-Native (Tier C)** | Everything in L1 + OpenTelemetry traces/metrics/logs wired (OTLP exporter, off by default but flip-able via env), optional Sentry/GlitchTip handler, log redaction on by default, GUI log viewer dialog, remote log shipping handler available. | Any tool that runs unattended, in production, on a user's machine, or as a service |

**`mgf-common` ships at L2** — every consumer that depends on it is L1 by default and reaches L2 by enabling the `[observability]` extra and calling `mgf.common.observability.setup_otel()`.

**VManager target:** L2 (achieved via the `mgf-common[observability]` extra).

When you start a new project, declare its target level in its top-level README (e.g., "Conformance: L1 per `mgf-common/docs/standards/`"). This sets the bar for code review.

**Documented non-adoption preserves conformance.** A project at L1 / L2 may consciously decline a specific primitive when adopting it would conflict with a deployment-coupled, policy-specific, or framework-architectural constraint — provided the rationale is recorded (ADR, tracker entry, or `FEEDBACK.md` paper). See [`principles/non-adoption-is-valid.md`](principles/non-adoption-is-valid.md) for the named principle, the three components (conscious decline / documented rationale / feedback if generalizable), and the worked examples (LOG-01, BOOTSTRAP-01, "small consumer" scope discipline). This is the framing behind every shipped carve-out.

**Per-kind subtrees.** For consumers building **web applications and APIs** (Django / FastAPI / Flask / Pyramid), see [`web/README.md`](web/README.md) — the web-domain narrative wrapper that says "for a web consumer, here's how the canonical rules land + which carve-outs apply." The canonical topic docs remain authoritative; the subtree is the discoverable front door for web-shaped consumers.

---

## The component catalogue (one-line summary)

The full list lives in [`COMMON_COMPONENTS.md`](COMMON_COMPONENTS.md). The TL;DR:

| Component | Status in `mgf.common` today | Where it lives | Standard doc |
|---|---|---|---|
| **Exception hierarchy + base class** | ✅ Strong (L1) | `src/mgf/common/exceptions/` (`AppError` base + 7 categories + 7 generic concretes) | [`ERROR_HANDLING.md`](ERROR_HANDLING.md) |
| **Typed application config** | ✅ Strong (L1) | `src/mgf/common/config/` (`BaseAppSettings` + `make_settings_config` + `load_settings`) | [`CONFIGURATION.md`](CONFIGURATION.md) |
| **Logging** | ✅ Strong (L1) | `src/mgf/common/observability/logging_setup.py` + `json_formatter.py` + `text_formatter.py` | [`LOGGING.md`](LOGGING.md) |
| **GUI worker pattern** | 🟡 Documented; concrete code in consumer (VManager) | `src/vmanager/gui/workers/core_worker.py` | [`DESIGN_PRINCIPLES.md`](DESIGN_PRINCIPLES.md) §"GUI threading" |
| **Provider abstraction (replaceability)** | 🟡 Documented; per-project ABCs in consumers | example: `src/vmanager/providers/base.py` | [`DESIGN_PRINCIPLES.md`](DESIGN_PRINCIPLES.md) §"Replaceability" |
| **Crash reporter (local + remote)** | ✅ Strong (L1; remote sinks via `[observability]` extra) | `src/mgf/common/observability/crash_reporter.py` | [`ERROR_HANDLING.md`](ERROR_HANDLING.md) §"Crash reporter" |
| **Excepthooks (sys + threading)** | ✅ Strong (L1) | `src/mgf/common/observability/excepthook.py` + `threading_excepthook.py` | [`ERROR_HANDLING.md`](ERROR_HANDLING.md) §"Top-level handlers" |
| **OpenTelemetry tracing** | ✅ Strong (L2 via `[observability]` extra) | `src/mgf/common/observability/otel_setup.py` | [`LOGGING.md`](LOGGING.md) §"Correlation" |
| **Sensitive-field redaction** | ✅ Strong (L1) | `src/mgf/common/observability/redaction.py` (Bearer/JWT/PEM + named-key policy) | [`LOGGING.md`](LOGGING.md) §"Redaction" |
| **Log viewer dialog (GUI)** | 🟡 Documented; concrete code in consumer (VManager) | `src/vmanager/gui/dialogs/log_viewer_dialog.py` | [`LOGGING.md`](LOGGING.md) §"GUI log viewer" |

Each topic doc ends with a **"How to consume from your project"** section — the concrete `mgf.common.*` symbols to import and the entry-point wiring required (e.g., `mgf.common.configure(app_name=...)`).

---

## How AI agents should use this folder

If you are an AI coding agent:

1. **Before writing or editing code in any of these areas** — error handling, logging, config, threading/worker — read the corresponding topic doc.
2. **The Rules box at the top of each doc is your contract.** Every MUST is non-negotiable.
3. **Templates are paste-able.** When asked to "add logging" or "add a config field," you SHOULD lift the template and adapt it, not invent a new shape.
4. **When the task hints at a gap** ("add crash reporting", "make logs work with Loki", "wire tracing"), check the gap-closure plan in the relevant doc — it lists the exact files and changes.
5. **If a new pattern emerges** that the standard doesn't cover, propose an addition to the standard *before* applying it. Standards diverge fast if every project invents its own conventions.
6. **A consumer project's `docs/claude/CLAUDE.md`** is the *project-specific* lookup (what's been built, what's broken, gotchas — VManager's is the canonical example). The `mgf-common/docs/standards/` folder is the *cross-project* standard. They complement each other.

---

## How humans should use this folder

For new projects:
1. Add `mgf-common` to your dependencies. The full L1 surface (exception base, config loader, logging stack, crash reporter, excepthooks) lands in one import.
2. Add `mgf-common[observability]` if you want L2 (OpenTelemetry traces + Sentry-style remote crash sink).
3. Call `mgf.common.configure(app_name=..., app_version=...)` once in every entry point, before any logging or observability function runs.
4. Subclass `mgf.common.exceptions.AppError` for your project's domain exceptions, and `mgf.common.config.BaseAppSettings` (via `make_settings_config(env_prefix="YOURAPP_")`) for your typed config.
5. Write your first feature *only* after the bootstrap files are in place.
6. Declare your conformance level in your README (e.g., `"Conformance: L1 per mgf-common/docs/standards/"`).

For an existing consumer (e.g. VManager):
1. Use the standards as the bar for every PR. When a PR touches one of the catalogued components, the relevant topic doc's MUSTs apply.
2. Track gap-closure work as roadmap items, not ad-hoc commits — each gap is a discrete, reviewable change.
3. When `mgf-common` adds a new component or relaxes/tightens a rule, bump the consumer's `mgf-common` pin in the same PR that updates the consuming code.

---

## Versioning

The standards version (top of this file) bumps when:

- **MAJOR** — A MUST is added, removed, or relaxed (existing code in any project may be non-compliant).
- **MINOR** — A SHOULD or template changes (existing code stays compliant; new code SHOULD adopt).
- **PATCH** — Wording, examples, or AS-IS code references updated.

Each topic doc carries its own version line in its header. The master `README.md` version is the maximum of all topic doc versions.

---

## Glossary

| Term | Definition |
|---|---|
| **Cornerstone (this project)** | The reference implementation pattern — `mgf-common` is the cornerstone library, VManager is the first consumer, future projects depend on `mgf-common` and inherit the standards. |
| **Lingua franca** | A small set of frozen domain types (e.g., `VMHandle`) passed between modules so APIs are not stringly-typed. See `DESIGN_PRINCIPLES.md`. |
| **Provider / driver / adapter** | An abstract base class isolating a third-party dependency (libvirt, a database, a cloud SDK) so the rest of the codebase is testable and replaceable. |
| **Translation seam** | The single place where a third-party exception is converted to a typed application exception. See `ERROR_HANDLING.md`. |
| **Top-level handler** | The outermost catch in each entry point (CLI `main`, `sys.excepthook`, `threading.excepthook`, asyncio loop handler, Qt event loop) that converts an unhandled exception into a clean exit / dialog / log entry. |
| **Correlation ID / trace ID** | An identifier propagated across log records so a single user action can be reconstructed end-to-end. In Tier C, this is the OpenTelemetry trace ID. |
| **Sink** | A destination a log record is written to (console, rotating file, OTLP exporter, syslog, etc.). |
| **Lift-and-shift** | Copying a template from a standard into a new project verbatim or with mechanical edits (rename the package, swap the brand). With `mgf-common`, lift-and-shift is the FALLBACK — preferred path is "depend on `mgf-common`". |
| **Gap-closure** | A planned, file-specific change list to bring a consumer project from its current state to the L2 standard. Lives at the bottom of each topic doc when relevant. |

---

## Index of MUSTs

A flat, sortable list of every absolute requirement across the standards. Use this as a code-review checklist or as input to a linter rule when you write one.

| ID | Source | Rule |
|---|---|---|
| DP-01 | DESIGN_PRINCIPLES | Layering MUST be enforced: UI layers MUST NOT be imported by core; core MUST NOT import third-party SDKs that have a provider in front of them. |
| DP-02 | DESIGN_PRINCIPLES | Every third-party dependency that owns I/O (DB, hypervisor, cloud, ML model, OS process) MUST sit behind an ABC with at least one production and one mock implementation. |
| DP-03 | DESIGN_PRINCIPLES | Domain types passed between modules MUST be frozen dataclasses (or pydantic models with `frozen=True`); never bare strings or dicts. |
| DP-04 | DESIGN_PRINCIPLES | Every public function MUST have a type-annotated signature. mypy --strict MUST pass on `src/`. |
| DP-05 | DESIGN_PRINCIPLES | Tests MUST mirror `src/` structure 1:1 and MUST run without any production credentials, network calls, or third-party daemons. |
| DP-06 | DESIGN_PRINCIPLES | Security, reliability, performance, and error reporting are first-class concerns; every PR description MUST address all four when touching new surface. |
| DP-07 | DESIGN_PRINCIPLES | Rich inline documentation: every public class/function MUST have a docstring explaining intent and invariants. |
| DP-08 | DESIGN_PRINCIPLES | Code SHOULD be replaceable; for each major component the doc near it MUST describe the swap recipe. |
| DP-09 | DESIGN_PRINCIPLES | Cancellation MUST be explicit. Long-running ops take an explicit `CancellationToken`-like parameter; never a thread-global. |
| DP-10 | DESIGN_PRINCIPLES | No silent fallbacks. If a fallback path exists, the active backend MUST be queryable and SHOULD be logged at startup. |
| EH-01 | ERROR_HANDLING | Every exception raised by application code MUST be a subclass of the application's base error class. |
| EH-02 | ERROR_HANDLING | Third-party exceptions MUST be translated to typed application exceptions at the boundary that owns the third-party call (provider, shell wrapper, HTTP client). |
| EH-03 | ERROR_HANDLING | When re-raising a translated exception, the original cause MUST be chained via `raise NewError(...) from original`. |
| EH-04 | ERROR_HANDLING | Every entry point MUST install a top-level handler: CLI `main`, `sys.excepthook`, `threading.excepthook`, `asyncio.get_event_loop().set_exception_handler`, and Qt's `qInstallMessageHandler` + `sys.excepthook` integration when GUI is present. |
| EH-05 | ERROR_HANDLING | Unhandled exceptions MUST produce a local crash report (JSON file under the application's state dir) AND, if remote reporting is enabled, MUST be forwarded to the configured remote sink. |
| EH-06 | ERROR_HANDLING | GUI workers MUST catch every exception (typed AND untyped), forward via signal, and never crash the worker thread silently. |
| EH-07 | ERROR_HANDLING | `except Exception:` (without re-raise or typed translation) MUST NOT appear except in: (a) cleanup paths inside `finally:` / `contextlib.suppress(...)`, (b) "best-effort observer" loops that log + continue and document the invariant. |
| EH-08 | ERROR_HANDLING | Every typed exception MUST carry machine-readable fields as constructor args (e.g., `CommandError.argv`, `SchemaValidationError.errors`), not just a formatted message string. |
| EH-09 | ERROR_HANDLING | User-facing error messages MUST end in an actionable next step where possible; the hint MUST be pinned by a substring test (see §14.7). |
| EH-10 | ERROR_HANDLING | Best-effort observer code (hook executors, scheduler tick loops, alert evaluators, libvirt event callbacks) MUST follow the never-raises invariant. |
| LG-01 | LOGGING | Every module MUST acquire its logger via `logging.getLogger(__name__)` (or the equivalent canonical name); no bare `logging.info(...)`. |
| LG-02 | LOGGING | The application MUST configure logging in exactly one place (per entry point) and MUST emit JSON when stdout is not a TTY (so log aggregators can parse it). |
| LG-03 | LOGGING | Every log record MUST carry the OpenTelemetry trace_id and span_id when a span is active (added automatically by the standard formatter). |
| LG-04 | LOGGING | Sensitive fields (passwords, tokens, private keys, session cookies) MUST be redacted by the formatter before any sink sees them. The redaction set MUST be configurable. |
| LG-05 | LOGGING | Error-level logs MUST include the exception via `LOG.exception(...)` or `exc_info=True` — never just the stringified exception in the message. |
| LG-06 | LOGGING | A rotating file sink MUST be configured by default (under the application's state dir). Console MUST also receive logs. Remote sinks (OTLP, syslog, HTTP) MUST be opt-in via config/env. |
| LG-07 | LOGGING | GUI applications MUST ship a log-viewer dialog that reads the rotating file sink (so users can view logs without a terminal). |
| LG-08 | LOGGING | Log messages MUST use lazy %-style formatting (`LOG.info("processing %s", x)`), NOT f-strings. |
| LG-09 | LOGGING | Structured fields MUST be passed via `extra={...}`, NOT concatenated into the message. |
| LG-10 | LOGGING | Headless services MUST configure logging at their entry point with `JournalHandler` (Linux) / equivalent OS sink in addition to the file sink. |
| LG-11 | LOGGING | Operation start/end SHOULD be logged with a stable `operation` name field at INFO so traces of complex flows are reconstructable from logs alone. |
| LG-12 | LOGGING | Log emission MUST be cheap (≤100 µs per record). Heavy formatting / IO MUST happen in the handler, not the call site. |
| CF-01 | CONFIGURATION | Application configuration MUST live in a single typed object (`pydantic-settings.BaseSettings` subclass). No module reads the config file or env vars directly. |
| CF-02 | CONFIGURATION | Precedence MUST be, top-to-bottom: CLI flags → environment variables → `.env` file → on-disk config file → typed defaults in code. |
| CF-03 | CONFIGURATION | The config schema MUST carry a version field. Loading a higher version than known MUST fail loud. Loading a lower version MUST run a migration chain. |
| CF-04 | CONFIGURATION | Writes MUST be atomic (temp file + rename) with mode 0o600. Path expansion MUST happen lazily (not at module import). |
| CF-05 | CONFIGURATION | Secrets MUST NOT live in the config file. They live in a vault (system keyring or encrypted file) accessed through a separate `Vault` interface. |
| CF-06 | CONFIGURATION | Loading an unknown key from the config file MUST raise (typo protection). Missing keys MUST fall back to typed defaults silently. |
| CF-07 | CONFIGURATION | Sub-config files (hooks, schedules, alerts, profiles, lab specs) MUST follow the same shape: typed model + atomic write + version field + unknown-key rejection. |
| CF-08 | CONFIGURATION | The `Settings` object MUST be loaded once at the entry point and passed down by constructor injection. Module-global singletons are forbidden. |
| CF-09 | CONFIGURATION | A `--config <path>` CLI flag MUST always exist. The default path MUST honour XDG / OS conventions. |
| CF-10 | CONFIGURATION | Tests MUST construct `Settings` with explicit values (no env-var leakage). |
| CF-11 | CONFIGURATION | Renaming a config field MUST NOT break existing on-disk configs — use `Field(validation_alias=AliasChoices(...))` and rewrite-on-next-save. |
| CF-12 | CONFIGURATION | Mutually-exclusive backend variants MUST be modelled as a discriminated union with a `kind` discriminator field. |
| DP-11 | DESIGN_PRINCIPLES | Async tasks MUST have an owner. Bare `asyncio.create_task(...)` without retention is a defect. |
| DP-12 | DESIGN_PRINCIPLES | Time MUST be UTC at every boundary. `datetime.now()` is forbidden; use `datetime.now(UTC)`. Naive datetimes MUST NOT cross any module boundary. |
| DP-13 | DESIGN_PRINCIPLES | Every owned external resource MUST be released deterministically via context manager or `try / finally`. GC-based cleanup is a defect. |
| LG-13 | LOGGING | High-frequency log sites MUST use rate-limiting, sampling, dedup, or be re-classified as metrics. |
| LG-14 | LOGGING | Custom correlation context MUST propagate via `contextvars.ContextVar`, not thread-local storage. |
| SC-01 | SECURITY_STANDARD | Secrets MUST live in a Vault, never in config / env files / source / logs / crash reports. |
| SC-02 | SECURITY_STANDARD | Subprocess invocation MUST use `argv` lists with `shell=False`. |
| SC-03 | SECURITY_STANDARD | YAML/JSON loading from any external source MUST use `yaml.safe_load` / `json.loads`. `pickle` is forbidden for IPC / persistence / untrusted data. |
| SC-04 | SECURITY_STANDARD | Files with private data MUST be written with mode `0o600` and atomically. |
| SC-05 | SECURITY_STANDARD | Cryptographic primitives MUST come from `cryptography` (or stdlib `hashlib`/`hmac`/`secrets`). No DIY crypto. |
| SC-06 | SECURITY_STANDARD | TLS verification MUST be enabled on every outbound connection. |
| SC-07 | SECURITY_STANDARD | Every external request MUST carry a finite timeout. |
| SC-08 | SECURITY_STANDARD | Untrusted input MUST be validated at the boundary (typed, range-checked, length-bounded, allow-listed). |
| SC-09 | SECURITY_STANDARD | Sensitive fields MUST be redacted by the formatter before any log sink sees them. |
| SC-10 | SECURITY_STANDARD | Dependencies MUST be pinned via lockfile + scanned for CVEs in CI. |
| SC-11 | SECURITY_STANDARD | Tracebacks / exception messages / crash reports MUST NOT leak secret material. |
| SC-12 | SECURITY_STANDARD | A `SECURITY.md` MUST exist at the repository root with vulnerability-reporting policy. |
| SC-13 | SECURITY_STANDARD | Cryptographic keys at rest MUST be derived from a passphrase via KDF or held in the system keyring. Never embedded in source. |
| SC-14 | SECURITY_STANDARD | Authentication failures MUST NOT enumerate. Repeated failures MUST be rate-limited. |
| SC-15 | SECURITY_STANDARD | Filesystem operations MUST validate against directory traversal via `Path.resolve()` + `is_relative_to()`. |
| SC-16 | SECURITY_STANDARD | Privileged operations MUST be confined to a narrow, audited surface, documented per call site. |
| SC-17 | SECURITY_STANDARD | Security-relevant actions MUST emit an `audit=true` structured log record. |
| SC-18 | SECURITY_STANDARD | Releases MUST be reproducible from source. |
| TS-01 | TESTING | `tests/` MUST mirror `src/` 1:1. CI MUST lint that no source file lacks a mirror. |
| TS-02 | TESTING | The unit suite MUST run with no production credentials, no network, and no real third-party daemon. |
| TS-03 | TESTING | Every test MUST run in isolation. Process-global state MUST be saved + restored via fixtures. |
| TS-04 | TESTING | `filterwarnings = ["error"]` MUST be set in `pyproject.toml`. |
| TS-05 | TESTING | `--strict-markers` and `--strict-config` MUST be set. |
| TS-06 | TESTING | Coverage gate ≥80% project-wide; ≥90% on changed lines in a PR. |
| TS-07 | TESTING | Every typed exception MUST have a unit test asserting message format + field values. |
| TS-08 | TESTING | Every translation seam MUST have tests for success + each typed translation + the catch-all. |
| TS-09 | TESTING | Every "best-effort observer" MUST have a test that injects a raising observer and asserts the loop continues. |
| TS-10 | TESTING | Every security-relevant rule MUST be pinned by a test where mechanically possible. |
| TS-11 | TESTING | GUI workers MUST have tests for the success path AND the untyped-exception path. |
| TS-12 | TESTING | Async code MUST be tested with `pytest-asyncio` (or `anyio` plugin). |
| TS-13 | TESTING | Property tests (Hypothesis) MUST cover any code that round-trips data. |
| TS-14 | TESTING | Performance budgets MUST be pinned by a benchmark in the unit suite. |
| TS-15 | TESTING | Smoke tests against real backends MUST be opt-in (separate marker, separate CI job) and read-only by default. |
| TS-16 | TESTING | Every test failure message MUST be self-explanatory. |
| TS-17 | TESTING | Test fixtures MUST be discoverable via the conftest hierarchy, never imported across test packages. |
| TS-18 | TESTING | Slow tests (>1 s) MUST be marked `@pytest.mark.slow` and excluded from the default `pytest` invocation. |
| EH-11 | ERROR_HANDLING | Retries MUST use exponential backoff with full jitter and a finite cap. Linear / immediate retry forbidden. |
| EH-12 | ERROR_HANDLING | Operations against external systems with multi-attempt cost MUST be idempotent. |
| EH-13 | ERROR_HANDLING | A circuit breaker MUST guard any external call that, when failing, can amplify load on the upstream. |
| AP-01 | API_DESIGN | The public API surface MUST be enumerated explicitly via `__all__` at every package and module boundary. |
| AP-02 | API_DESIGN | Every public name MUST have a docstring stating intent, invariants, and at least one usage example. |
| AP-03 | API_DESIGN | The package MUST follow Semantic Versioning. Public-API breaks happen ONLY in MAJOR (or in MINOR pre-1.0). |
| AP-04 | API_DESIGN | Deprecation cycle MUST be: announce → still works (≥1 MINOR) → removed; deprecated names emit `DeprecationWarning`. |
| AP-05 | API_DESIGN | Public function signatures MUST be stable. New parameters MUST be keyword-only with defaults. |
| AP-06 | API_DESIGN | Return types MUST NOT narrow in non-MAJOR releases. |
| AP-07 | API_DESIGN | Exceptions raised by public functions are part of the public API; MUST be documented and from the typed hierarchy. |
| AP-08 | API_DESIGN | Public modules MUST use `from __future__ import annotations`; runtime-unused imports go in `if TYPE_CHECKING:`. |
| AP-09 | API_DESIGN | A PEP 561 `py.typed` marker MUST exist for any package that ships type annotations. |
| AP-10 | API_DESIGN | A `PUBLIC_API.md` MUST list every public name with its stability tier. |
| AP-11 | API_DESIGN | Stability tiers MUST be declared per public name: `experimental` / `stable` / `deprecated`. |
| AP-12 | API_DESIGN | Breaking changes MUST be documented inwith the four-part migration recipe (symptom / before / after / why). |
| AP-13 | API_DESIGN | A `__version__` attribute MUST be present on every distribution package, in sync with `pyproject.toml`. |
| AP-14 | API_DESIGN | Internal modules MUST NOT be imported by consumers. Single-underscore module names are private. |
| AP-15 | API_DESIGN | Backward-compatibility shims MUST emit `DeprecationWarning` AND log at INFO once per process. |
| SP-01 | SCOPE | The library MUST publish an explicit IN-scope list. Without it, "scope creep" arguments collapse into taste arguments. |
| SP-02 | SCOPE | The library MUST publish an explicit OUT-of-scope list with reasoning + cited ecosystem alternative per entry. |
| SP-03 | SCOPE | Every PR adding a new module or top-level function MUST justify against §1 (IN) or §3 (Adjacent). PRs whose answer is "OUT" are rejected. |
| SP-04 | SCOPE | Adjacent-scope items MUST require a documented consumer-demand signal before promotion to IN. |
| SP-05 | SCOPE | The OUT-of-scope list MUST cite the ecosystem alternative for every cut. |
| SP-06 | SCOPE | Scope policy MUST be revisited on every MAJOR release; items move between IN / Adjacent / OUT as the ecosystem and consumer demand shift. |

---

## What's new in v2.1

The v2.0 → v2.1 bump introduces a single new freestanding document
that codifies what was previously a one-off section in the
-redesign doc:

- [`SCOPE.md`](SCOPE.md) — six MUSTs (SP-01..SP-06) defining the
  scope policy a "cornerstone" library must publish: explicit IN
  list, explicit OUT-of-scope list with cited alternatives,
  Adjacent list with promotion criteria, the per-PR scope-review
  question, and the every-MAJOR revisit cadence. Lifted from
  `docs/CLOSED_BOX_REDESIGN.md` §8 into the standards folder so
  it lives alongside the rest of the cross-project rules.

The v2.1 bump is a MINOR (six new MUSTs, no removals) per the
versioning policy below — existing consumer code stays compliant;
new modules added to `mgf-common` (or any project that follows
this standard) MUST clear the SP-03 review question.

## What's new in v2.0

The v1.x → v2.0 bump is driven by the introduction of two new
topic docs and the addition of new MUSTs across existing docs.
Existing code in any project MAY be non-compliant against the new
MUSTs — the version policy (below) requires a MAJOR bump for that
case.

**New documents:**

- [`SECURITY_STANDARD.md`](SECURITY_STANDARD.md) — eighteen security MUSTs
  (SC-01..SC-18), threat-model template, mechanical-enforcement
  matrix, repository-root SECURITY.md template.
- [`TESTING.md`](TESTING.md) — eighteen testing MUSTs
  (TS-01..TS-18), consolidated fixture patterns, async / GUI /
  property-test patterns, performance benchmark shape.
- [`API_DESIGN.md`](API_DESIGN.md) — fifteen API-design MUSTs
  (AP-01..AP-15), `__all__` discipline, semver rigor, deprecation
  cycle, type stability, stability tiers (experimental / stable /
  deprecated), `PUBLIC_API.md` contract, CHANGELOG migration
  recipes, backward-compat shim discipline. Addresses the
  [`FEEDBACK.md`](../../FEEDBACK.md) 🔴 Blocker
  ("no PUBLIC_API.md").

**New MUSTs in existing documents:**

- `DESIGN_PRINCIPLES.md` — DP-11 (async task ownership), DP-12
  (UTC time), DP-13 (resource release).
- `ERROR_HANDLING.md` — EH-11 (retry with exponential backoff +
  jitter), EH-12 (idempotency), EH-13 (circuit breaker).
- `LOGGING.md` — LG-13 (volume control), LG-14 (contextvars-based
  correlation).
- `CONFIGURATION.md` — CF-11 (renames-without-breaks), CF-12
  (discriminated unions for backends).

**Substantial new sections:**

- `DESIGN_PRINCIPLES.md` §11 (async/concurrency), §12 (time + dates),
  §13 (resource management), §14 (mechanical enforcement matrix).
- `ERROR_HANDLING.md` §13 (async error handling: gather discipline,
  TaskGroup, ExceptionGroup, contextvars correlation), §14 (error
  message style guide: tone, structure, identifier formatting,
  pinning the actionable-hint suffix), §15 (resilience patterns:
  retry with exponential backoff + jitter, circuit breaker,
  bulkhead, timeout cascades, idempotency).
- `LOGGING.md` §17 (rate-limit / sample / dedup), §18
  (contextvars-based correlation across `await` points).
- `CONFIGURATION.md` §16 (discriminated unions), §17 (env-tier
  layering: dev / staging / prod), §18 (field aliases for
  renames-without-breaks).
- `COMMON_COMPONENTS.md` §15 (Security infrastructure), §16 (Test
  infrastructure).

**Migration for existing consumers:**

VManager (the reference consumer) is at v1.2 compliance today.
Bringing it to v2.0 is a multi-round audit across SC-* and TS-*:

1. **Audit** the SC-* matrix against the codebase (single Explore
   agent run).
2. **Adopt** the mechanical checks: `gitleaks` pre-commit,
   `pip-audit` CI step, ruff `DTZ` rules, ruff `RUF006`.
3. **Add** `tests/unit/security/` with the SC-* pin tests.
4. **Add** the repository-root `SECURITY.md` template.
5. **Audit** the TS-* matrix; close gaps.
6. **Update** `docs/STANDARDS_COMPLIANCE.md` with rows for every
   new MUST.

The estimated cost (per the cornerstone-rhythm pattern in
`COMMON_COMPONENTS.md` §"Maintaining compliance over time") is
3–4 audit→close rounds; each round is one session.

---

## Cross-references

- `mgf-common` package documentation: [`../../README.md`](../../README.md)
- Extraction history (Round 5 archive): [`../internal/EXTRACTION_HISTORY.md`](../internal/EXTRACTION_HISTORY.md)
- Per-release notes: [`../../CHANGELOG.md`](../../CHANGELOG.md)
- Release-engineering discipline: [`RELEASING.md`](RELEASING.md)
- Reference consumer (VManager) project-specific lookup: [`VManager/docs/claude/CLAUDE.md`](https://codeberg.org/magogi-admin/VManager/src/branch/master/docs/claude/CLAUDE.md)

---

*This is a living document. When a consumer surfaces a missing standard or `mgf.common` ships a new component, update the relevant topic doc and the catalogue table above.*
