# Scope

> **Conformance:** L0 / L1 / L2 (see `README.md`)
> **Audience:** Library authors deciding what to ship; reviewers
> deciding whether a PR belongs in this codebase; consumers
> looking for "what should I expect this library to handle, and
> what do I need to bring myself".

> **Scope.** Cross-project scope policy for any shared
> infrastructure library — what it ships, what it deliberately
> does NOT ship, and the reasoning behind each cut. Written for
> the `mgf-common` shape but applies to every "cornerstone"
> library that aspires to be a stable foundation for downstream
> consumers without becoming a kitchen-sink. Lifted from
> `docs/CLOSED_BOX_REDESIGN.md` §8 as the canonical scope
> statement.

---

## Rules box (read this first)

| ID | Rule |
|---|---|
| **SP-01** | **The library MUST publish an explicit IN-scope list.** Without it, "scope creep" arguments collapse into taste arguments. The list is the bar new modules clear. |
| **SP-02** | **The library MUST publish an explicit OUT-of-scope list with reasoning.** "Why we don't ship X" + "what you should use instead" are non-negotiable per entry. The reasoning answers the inevitable "but couldn't you also..." pitches. |
| **SP-03** | **Every PR adding a new module or top-level function MUST justify against §1 (IN scope) or §3 (Adjacent).** A PR whose answer is "OUT" is rejected with a pointer to the existing ecosystem solution. |
| **SP-04** | **Adjacent-scope items MUST require a documented consumer demand signal** before promotion to IN. "We might want this someday" is not a signal; "consumer X is forking the library to add this" or "≥2 consumers ask in FEEDBACK.md" is. |
| **SP-05** | **The OUT-of-scope list MUST cite the ecosystem alternative.** Every cut belongs to a function someone in the ecosystem already does well — say which one. Without the citation, the cut looks lazy instead of considered. |
| **SP-06** | **Scope policy MUST be revisited on every MAJOR release.** Items move between IN / Adjacent / OUT as the ecosystem evolves and consumer demand shifts. The MAJOR boundary is the only place a previously-IN item can be removed (with a deprecation cycle per AP-04). |

---

## 1. IN scope

The library ships **infrastructure that every Python desktop /
service / mobile project needs once it crosses the
spike-to-production boundary**:

- **Identity + lifecycle** — configure once; resolve everywhere.
- **Typed configuration** with file + env + CLI layering.
- **Typed exception hierarchy** with translation seams.
- **Structured logging** + redaction + sinks.
- **OpenTelemetry tracing** / metrics integration.
- **Crash reporting** (local + remote).
- **Excepthook installation** for every entry-point shape (sys,
  threading, asyncio).
- **Vault abstraction** for secrets storage.
- **Cancellation + progress** primitives.
- **Subprocess + SSH + service-management** cross-platform
  wrappers (per FEEDBACK §3.4–§3.5; landed in later phases).
- **Resilience patterns** — retry with jitter, circuit breaker,
  bulkhead concurrency limiting.
- **Cross-platform path conventions** — XDG / macOS Application
  Support / Windows AppData.
- **A diagnostic CLI** for self-introspection (`mgf-common
  explain / validate / doctor`).
- **A scope policy** — *this document*. Other libraries that
  follow this standard ship their own `SCOPE.md`.

The unifying property: every IN-scope item is something **every**
consumer needs by the time they go to production, AND has no
single ecosystem alternative the library can defer to. Logging
has the stdlib but you build a structured-logging stack on top of
it. Config has pydantic-settings but you build a layered loader on
top. Exceptions have Python's hierarchy but you build a typed,
translation-seamed hierarchy on top.

If the bullet point above could read "use library X" without loss
of generality, it belongs in §2.

## 2. OUT of scope (we will NOT ship these)

| Out-of-scope | Why we don't | What you should use instead |
|---|---|---|
| **GUI framework** | Domain-specific; PySide6 / Tk / Flet / Toga have non-overlapping ecosystems. We CAN ship `mgf.common.gui.<framework>` adapters when a consumer needs one. | Bring your own |
| **ORM / data layer** | Already has SQLAlchemy / SQLModel / Django / Tortoise / etc.; no value-add we can offer. | SQLAlchemy is the ecosystem default |
| **HTTP server framework** | FastAPI / Flask / Litestar / Starlette / aiohttp — every shape covered. | Pick one; integrate via `mgf.common.observability` for shared logging / tracing |
| **HTTP client (general-purpose)** | `httpx` is the ecosystem default; we ship `httpx` instrumentation but not our own client. | `httpx` |
| **Full async runtime** | `asyncio` / `trio` / `anyio` are the language; we provide async adapters where relevant. | stdlib `asyncio` (or trio via anyio shim) |
| **Cloud-provider deployment recipes** | AWS / GCP / Azure are non-overlapping; per-provider tooling exists. | provider's own SDK + IaC tool |
| **AI / ML utilities** | Orthogonal domain. | use the relevant ML library directly |
| **Plugin loading / discovery framework** | We use registries for OUR extensions; consumer plug-in loaders use stdlib `importlib.metadata.entry_points`. | stdlib `importlib.metadata` |
| **i18n translation engine** | We provide a hook (`_localise(msg, **vars)`) per FEEDBACK §3.13; consumer brings the catalog. | stdlib `gettext` or `babel` |
| **Job queue / task scheduler** | Celery / RQ / arq / dramatiq cover this; we provide cancellation + progress primitives that integrate with any of them. | celery / rq / arq |
| **Database migration tool** | Alembic / aerich / etc. cover this. | alembic |
| **Testing framework** | pytest is the ecosystem default; we ship pytest fixtures (FEEDBACK §3.7) but not our own runner. | pytest |
| **Build / packaging tool** | hatchling / setuptools / poetry / uv cover this. | hatchling (the library's own choice) |
| **Linter / formatter** | ruff / black / isort cover this. | ruff |

The pattern: every cut has a citation. If a future PR proposes
adding one of these, the response is the cited tool — not "no, we
just don't want to". Citations age; this list MUST be revisited
per rule **SP-06**.

## 3. Adjacent scope (we MAY ship later, requires consumer demand)

Items that fit the cornerstone shape but lack a consumer demand
signal yet (per **SP-04**, "consumer X is forking the library to
add this" or "≥2 consumers ask in FEEDBACK.md").

- **OpenAPI generation from typed Settings.** Could lift the
  `BaseAppSettings` schema as an OpenAPI components schema for
  HTTP servers using our config. Wait for a consumer to ask.
- **Conda-forge / Homebrew packaging.** When ≥10% of consumer
  demand lives outside PyPI.
- **Containerised base image.** When the release cadence
  stabilises post-1.0.
- **A `qt` extra** — Qt-specific helpers (`CoreWorker`,
  `qt_excepthook`, log-viewer dialog) lifted from the reference
  consumer. Lift when a second Qt consumer arrives.
- **A `provider_pattern` module** — generic Provider ABC +
  MockProvider + FailurePlan extracted from VManager's
  hypervisor-provider shape. Lift when a second project would
  benefit from the pattern.

The pattern: each entry has a clear "promotion criterion". Until
that criterion fires, the item lives here, not in §1. The library
deliberately does NOT pre-build adjacent scope items "just in
case" — speculative additions become maintenance burden without
matching consumer payoff.

## 4. The "scope creep" review question

Every PR that adds a new module or top-level function MUST answer:

> *"Is this in §1 IN scope, in §3 Adjacent, or in §2 OUT?"*

Acceptable answers:

- **"§1 IN scope, slot N"** — the PR clears the bar. Proceed
  with normal review.
- **"§3 Adjacent, promotion criterion C now satisfied because
  ..."** — promote the item from §3 to §1 in the same PR (move
  the bullet, ship the code, update CHANGELOG). The criterion
  is what moved, not the bar.
- **"§2 OUT"** — the PR is rejected with a pointer to the cited
  alternative. The PR author is encouraged to file a FEEDBACK.md
  entry if they think the OUT decision is wrong; the standards
  doc may then change for the next MAJOR cycle (per **SP-06**).

Unacceptable answers:

- **"It's small / it's only one function / I already wrote it"**
  — scope is about boundaries, not effort.
- **"We could fold it under §1 slot N if you squint"** — slots
  are intentionally specific. If the squint is required, the
  item is §3 or §2.
- **"Other libraries do it"** — relevance to scope is independent
  of what other libraries chose; their scope policy is theirs.

## 5. Closed-box implications

The closed-box principle (rule **DP-01**, see
`DESIGN_PRINCIPLES.md`) and the scope policy interact:

- **Wider scope** means more closed-box surface to maintain. Every
  IN-scope item is one more import-path consumers depend on. Every
  Adjacent-scope item is a future surface bump.
- **Narrower scope** means consumers reach past the library
  boundary more often. Every OUT-of-scope item is a deferral that
  preserves the closed box at the cost of consumer integration
  work.

The scope policy resolves the tension: OUT items are deferred
because the *ecosystem* solution is good enough that the
closed-box cost would not pay for itself. IN items are accepted
because the closed-box value (one canonical way to do X across
every consumer) outweighs the surface cost.

The diagnostic CLI (`mgf-common explain / validate / doctor`) is
the canonical example of an item that EARNED its IN-scope slot:
without it, every consumer reinvents the same "show me the
config / validate this YAML / check the install state" tooling
locally, which fragments behaviour across consumer codebases —
exactly the closed-box leak the library exists to prevent.

## 6. Versioning of this document

| Version | Change |
|---------|--------|
| v1.0 | Introduced in standards v2.1. Codifies §8 of `docs/CLOSED_BOX_REDESIGN.md` as a freestanding policy. |

Future entries land here as scope items move between §1 / §2 /
§3 (per **SP-06**, every MAJOR release boundary).

---

*See [`README.md`](README.md) for the master standards index and
the conformance keyword definitions. See
[`API_DESIGN.md`](API_DESIGN.md) for the deprecation cycle that
governs how OUT/Adjacent/IN transitions are surfaced to
consumers.*
