# Public API — `mgf-apiprobe`

> **Master-HEAD banner (REL-03):** this file + [`PUBLIC_API.json`](PUBLIC_API.json) reflect the
> CURRENT `main`/release surface, not the published one. Verify your pin via
> `mgf.apiprobe.__version__` (mirrors `pyproject.toml`). `PUBLIC_API.json` is generated
> from `__all__` and pinned in CI.


This document is the **contract list** for `mgf-apiprobe`. Every
name listed below is a public name that consumers MAY depend on.

The contract terms mirror `mgf-common`'s
[`docs/standards/API_DESIGN.md`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/API_DESIGN.md).
In short:

- **Stability tiers:**
  - `experimental` — MAY change shape in any MINOR release. The
    pre-1.0 window keeps everything experimental in practice.
  - `stable` — follows the deprecation cycle; removal only in MAJOR.
  - `deprecated` — slated for removal; emits `DeprecationWarning`.
- **Names not listed below are private.** Anything starting with
  `_` (underscore-prefixed module names like `_version.py` or
  underscore-prefixed module-internal symbols) is internal and
  MAY change without notice.
- **Pre-1.0:** per [SemVer](https://semver.org/) 0.x semantics,
  MINOR releases MAY break the public API. Pin tightly:
  `mgf-apiprobe = ">=0.X,<0.Y"`.

This file MUST stay in sync with the `__all__` of every public
module — pinned by `tests/unit/test_public_api_doc.py`.

---

## `mgf.apiprobe`

Top-level surface — re-exports of the per-subpackage public names
plus the version string. Consumers MAY import any of the names
below from `mgf.apiprobe` directly OR from the per-subpackage
module they live in.

| Name | Tier | Description |
|---|---|---|
| `__version__: str` | stable | Package version string. Mirrors `pyproject.toml::project.version`. |
| `cli_main` | experimental | Console-script entry point — equivalent to `mgf.apiprobe.cli.main`. Exposed at the top level for `python -m mgf.apiprobe` invocations. |
| `factories` | experimental | Re-export of the `mgf.apiprobe.factories` submodule itself, so `mgf.apiprobe.factories.uuid()` works without an explicit submodule import. The individual factory functions (`uuid`, `iban`, …) are also re-exported as top-level names. |

All other names in `mgf.apiprobe.__all__` are re-exports of the
per-subpackage public names documented in their own sections
below.

---

## `mgf.apiprobe.exceptions`

Typed exception hierarchy. One root + 6 category bases. Subclasses
live in the consumer's own code; the root + categories are the
documented seam.

| Name | Tier | Description |
|---|---|---|
| `ApiprobeError` | experimental | Root of the apiprobe-specific exception hierarchy. Subclass of `mgf.common.exceptions.AppError`, so the standard CLI exit-code translator handles it. Domain code SHOULD NOT raise this directly; pick a category subclass. |
| `ApiprobeConfigError` | experimental | Configuration / settings failures. Subclass of `mgf.common.exceptions.AppConfigError` (caught by the same handlers as upstream config errors). Raised when `ApiprobeSettings` validation fails or a required field is missing. |
| `AuthError` | experimental | Failures during authentication-flow resolution. Raised by `AuthFlow` implementations when credentials cannot be obtained / refreshed / attached to a request. |
| `MatcherError` | experimental | Matcher-DSL evaluation failures. Raised by matchers when the runtime value cannot be inspected (e.g., type mismatch, missing field) — not used for normal mismatch (those produce `Finding` records). |
| `SchemaError` | experimental | Schema-source failures. Raised by `SchemaSource` implementations when a registered schema cannot be loaded / parsed / validated. |
| `SuiteLogicError` | experimental | Suite-level invariant violations. Raised when a probe / check / context references a name that does not exist, or two primitives collide on the same identifier. |
| `TransportError` | experimental | Transport-layer failures. Subclass of `mgf.common.exceptions.OperationError`. Wraps the underlying httpx / network failure with apiprobe context. |

**Total in `mgf.apiprobe.exceptions.__all__`: 7 names.**

---

## `mgf.apiprobe.config`

Project-local typed settings root, composing `mgf.common`'s
`BaseAppSettings`.

| Name | Tier | Description |
|---|---|---|
| `ApiprobeSettings` | experimental | `BaseAppSettings` subclass with `env_prefix="APIPROBE_"`. Fields: `timeout_seconds`, `max_retries`, `default_user_agent`, `verify_tls`, `fail_on_severity`, `max_concurrency`. |

**Total in `mgf.apiprobe.config.__all__`: 1 name.**

---

## `mgf.apiprobe.core`

Core primitives — the eight load-bearing types every suite uses,
plus the matcher DSL re-exported from `mgf.apiprobe.core.matchers`.

### Primitives

| Name | Tier | Description |
|---|---|---|
| `Probe` | experimental | Typed description of an HTTP request + the expected response shape. Fluent builder: `Probe.get(url).expects_status(200).expects_json_shape({...})`. Frozen after construction. `probe_id` is auto-derived from method + path (e.g. `GET /api/v1/me/` → `GET_api_v1_me`) when the consumer doesn't call `.id()` — PAPER-42. `Probe.depends_on(probe_id, extract={...})` declares a data dependency on another probe; the Suite topologically orders probes by these declarations and threads extracted values into `{var}` template substitutions in path / header / query values — PAPER-39. |
| `ProbeDependency` | experimental | Frozen dataclass — one entry on `Probe.depends_on_probes`. Carries the upstream `probe_id` and a tuple of `(var_name, jsonpath_expr)` pairs. Constructed indirectly via `Probe.depends_on()`; rarely instantiated directly. PAPER-39. |
| `Check` | experimental | A verifier that produces a `Finding` for one aspect of a `Response`. Concrete checks live in `mgf.apiprobe.checks`; consumers MAY subclass for project-specific checks. |
| `Suite` | experimental | An ordered collection of probes that runs async via a `Transport` and emits a `Report`. Suites with any `Probe.depends_on` declarations run probes serially in topological order; suites with no declarations use the fast parallel-gather path. Cycles + dangling-ref dependency declarations raise `SuiteLogicError` at construction. |
| `Context` | experimental | Per-suite shared state — variables, factories, AuthFlow chain. Threaded through every probe at execution time. `Context.with_added(name, value)` returns a new Context with the variable added — used internally by the Suite runner to thread extracted values; consumers MAY use it to seed the initial Context. PAPER-39. |
| `Tag` | experimental | Probe / check tag for filtering and reporting. Frozen string. |
| `AuthFlow` | experimental | Protocol for authentication flows. Concrete implementations in `mgf.apiprobe.auth`. |
| `AuthCredentials` | experimental | Typed credential carrier — what an `AuthFlow` returns when resolved. |
| `Transport` | experimental | Protocol for the HTTP transport. Concrete impl: `mgf.apiprobe.transport.HttpxTransport`. |
| `Response` | experimental | Typed snapshot of an HTTP response — `status`, `headers`, `body` (bytes), `elapsed_ms`, `url`. The unit a `Check` operates on. |
| `Matcher` | experimental | The matcher-callable type. Functions in `mgf.apiprobe.core.matchers` produce these. |
| `MISSING` | experimental | Sentinel used to distinguish "field is None" from "field is absent" in matcher DSL. |

### Result shapes

| Name | Tier | Description |
|---|---|---|
| `Finding` | experimental | One verifier result. Frozen dataclass: `code`, `severity`, `root_cause`, `message`, `evidence`, `remediation`, `threat_refs`, `tags`. |
| `Severity` | experimental | `StrEnum`: `INFO`, `WARN`, `CRITICAL`. |
| `RootCause` | experimental | `StrEnum` of fourteen root-cause categories spanning network / auth / rate-limit / provider {5xx, contract, quality, security, observability} / client request shape / cassette + spec drift / suite logic / infrastructure / unknown. |
| `Report` | experimental | The output of a `Suite.run()`. Holds findings + per-probe summaries. |

### Matcher DSL

Re-exported from `mgf.apiprobe.core.matchers` for convenience.

| Name | Tier | Description |
|---|---|---|
| `equals(value)` / `not_equals(value)` | experimental | Equality matchers. |
| `gt` / `gte` / `lt` / `lte` | experimental | Numeric comparison matchers. |
| `between(low, high)` | experimental | Inclusive numeric range. |
| `in_(*allowed)` / `not_in(*forbidden)` | experimental | Membership matchers (varargs). |
| `matches(pattern)` | experimental | Regex-match matcher. |
| `is_uuid` / `is_email` / `is_url` / `is_iso8601_z` | experimental | Format matchers. |
| `is_iban` / `is_imei` / `is_e164` | experimental | Semantic matchers (telecom + finance — load-bearing for those domains). |

**Total in `mgf.apiprobe.core.__all__`: 31 names** (15 primitives /
result shapes + 16 matcher DSL re-exports).

---

## `mgf.apiprobe.core.matchers`

The matcher DSL submodule. Every name here is also re-exported from
`mgf.apiprobe.core` and `mgf.apiprobe`.

| Name | Tier | Description |
|---|---|---|
| `equals` / `not_equals` | experimental | Equality matchers. |
| `gt` / `gte` / `lt` / `lte` | experimental | Numeric comparison. |
| `between` | experimental | Inclusive numeric range. |
| `in_` / `not_in` | experimental | Membership. |
| `matches` | experimental | Regex match. |
| `is_uuid` / `is_email` / `is_url` / `is_iso8601_z` | experimental | Format matchers. |
| `is_iban` / `is_imei` / `is_e164` | experimental | Semantic matchers. |

**Total in `mgf.apiprobe.core.matchers.__all__`: 16 names.**

---

## `mgf.apiprobe.auth`

Five built-in authentication flows. Each is a frozen dataclass
implementing the `AuthFlow` protocol.

| Name | Tier | Description |
|---|---|---|
| `BearerAuth(*, token: str | None = None, env: str | None = None, scheme: str = "Bearer")` | experimental | `Authorization: <scheme> <token>` header. Pass `token=` directly OR `env=` to read from an environment variable. `scheme=` defaults to `"Bearer"` (RFC 6750); override for DRF's `Token`, GitHub PATs' lowercase `token`, or vendor-specific schemes like `AWS4-HMAC-SHA256`. PAPER-40. |
| `BasicAuth(*, username: str, password: str | None = None, password_env: str | None = None)` | experimental | RFC 7617 Basic auth. Pass `password=` directly OR `password_env=` to read from an environment variable. |
| `ApiKeyAuth(*, header: str | None = None, query: str | None = None, value: str | None = None, env: str | None = None)` | experimental | API-key flow. Specify exactly one of `header=` or `query=` to choose location. |
| `CookieAuth(*, cookie_name: str, value: str | None = None, env: str | None = None)` | experimental | Sets `Cookie: <cookie_name>=<value>`. Pass `value=` directly OR `env=` to read from an environment variable. |
| `CustomAuth(*, name: str, prepare_func: Callable[[], AuthCredentials])` | experimental | Escape hatch: a callable returns `AuthCredentials` — for OAuth2-style flows (future add) and bespoke transports. |

**Total in `mgf.apiprobe.auth.__all__`: 5 names.**

---

## `mgf.apiprobe.checks`

The default check catalogue — eighteen verifiers covering schema,
contract, initial security, and initial quality concerns. Plus
`DEFAULT_CHECKS` — the curated list every probe gets unless
overridden.

### The default list

| Name | Tier | Description |
|---|---|---|
| `DEFAULT_CHECKS` | experimental | Tuple of every check in this module, in the order suites apply them. The recommended starting point for any probe. |

### Status / contract checks

| Name | Tier | Description |
|---|---|---|
| `StatusUnexpected` | experimental | Response status differs from `Probe.expects_status(...)`. |
| `Server5xx` | experimental | 5xx responses raise an error finding regardless of expected status. |
| `ContentTypeMissing` | experimental | Response has no `Content-Type` header. |
| `ContentTypeJsonExpected` | experimental | Response declared something other than `application/json` when JSON was expected. |
| `HeaderMissing` | experimental | A header listed in the probe's `expects_headers([...])` is absent. |

### Body / schema checks

| Name | Tier | Description |
|---|---|---|
| `BodyEmptyOnSuccess` | experimental | 2xx response with empty body where one was expected. |
| `BodyInvalidJson` | experimental | `Content-Type: application/json` but the body fails JSON parse. |
| `BodySizeOverBudget` | experimental | Response body exceeds `Probe.expects_body_size_under(...)`. |
| `BodyEchoesSecret` | experimental | The response body echoes a request-side secret value (auth header, query-string token). |
| `SchemaShapeMismatch` | experimental | Response JSON shape does not match the registered `SchemaSource`. |

### Quality / latency checks

| Name | Tier | Description |
|---|---|---|
| `LatencyOverBudget` | experimental | Response latency exceeds `Probe.expects_latency_under(...)`. |
| `LatencySuspiciousZero` | experimental | Response latency is reported as zero — usually an instrumentation bug, not a real measurement. |
| `MissingRequestId` | experimental | Response is missing `X-Request-Id` (or the configured request-id header). |
| `MissingRateLimitHeaders` | experimental | Response is missing rate-limit headers (`X-RateLimit-Limit`, etc.). |

### Security checks

| Name | Tier | Description |
|---|---|---|
| `MissingHsts` | experimental | HTTPS response missing `Strict-Transport-Security`. |
| `MissingFrameOptions` | experimental | Response missing `X-Frame-Options` / `Content-Security-Policy: frame-ancestors`. |
| `MissingContentTypeOptions` | experimental | Response missing `X-Content-Type-Options: nosniff`. |
| `MissingCsp` | experimental (v0.5.0) | Browser-shaped response missing `Content-Security-Policy` (closes deferred SH-05 / P-1). |
| `MissingReferrerPolicy` | experimental (v0.5.0) | Response missing `Referrer-Policy` header (P-1). |
| `MissingPermissionsPolicy` | experimental (v0.5.0) | Browser-shaped response missing `Permissions-Policy` (P-1). |
| `InsecureCookieAttributes` | experimental (v0.5.0) | `Set-Cookie` missing `Secure` / `HttpOnly` / `SameSite` (P-1). Multi-cookie capable. |
| `MissingServerHeader` | experimental | Response advertises `Server: <version>` (information disclosure). |

**Total in `mgf.apiprobe.checks.__all__`: 23 names** (22 checks +
`DEFAULT_CHECKS`).

---

## `mgf.apiprobe.factories`

Built-in value generators for probe inputs.

| Name | Tier | Description |
|---|---|---|
| `uuid() -> str` | experimental | Random UUIDv4 in canonical form. |
| `iso8601_z(*, when: datetime | None = None) -> str` | experimental | UTC instant as ISO 8601 with `Z` suffix. Defaults to "now" when `when` is omitted. |
| `iban(*, country: str = "DE") -> str` | experimental | Synthetic-but-valid IBAN with passing MOD-97 checksum. Tests only — does not correspond to a real account. |
| `imei() -> str` | experimental | Synthetic-but-valid IMEI with passing Luhn checksum. |
| `e164(*, country_code: int = 1, length: int = 10) -> str` | experimental | Synthetic E.164 phone number with the given country code + national-number length. |

**Total in `mgf.apiprobe.factories.__all__`: 5 names.**

---

## `mgf.apiprobe.schema`

Schema sources for response-shape validation.

| Name | Tier | Description |
|---|---|---|
| `SchemaSource` | experimental | Protocol that a schema-source impl satisfies. Returns `SchemaValidationIssue`s for a given response payload. |
| `PydanticSchemaSource(model)` | experimental | Pydantic-backed schema source. The first concrete impl. |
| `SchemaValidationIssue(path: str, message: str, expected: str, actual: str)` | experimental | Frozen dataclass — the unit `SchemaShapeMismatch` records as evidence. |

**Total in `mgf.apiprobe.schema.__all__`: 3 names.**

---

## `mgf.apiprobe.transport`

Concrete HTTP transport.

| Name | Tier | Description |
|---|---|---|
| `HttpxTransport(settings: ApiprobeSettings | None = None)` | experimental | The real-network `Transport` impl. Wraps `mgf.common.http.AsyncHttpClient` so the redaction + retry posture is shared with the rest of the federation. Defaults pull from a fresh `ApiprobeSettings()` when no settings are passed. |

**Total in `mgf.apiprobe.transport.__all__`: 1 name.**

---

## `mgf.apiprobe.reporting`

Report writers.

| Name | Tier | Description |
|---|---|---|
| `ReportWriter` | experimental | Protocol for report writers. Each implementation provides a `write(report: Report)` method returning either a `str` (text writers) or a `dict[str, Any]` (structured writers). |
| `HumanReportWriter` | experimental | Terminal-friendly text writer. `write(report) -> str`. No ANSI today (a future add when the CLI grows a `--color` flag). |
| `JsonReportWriter` | experimental | Machine-readable JSON writer. `write(report) -> dict[str, Any]`. The dict shape is part of the public contract — additions OK; renames / removals are breaking. |

**Total in `mgf.apiprobe.reporting.__all__`: 3 names.**

---

## `mgf.apiprobe.cli`

Console-script entry point.

| Name | Tier | Description |
|---|---|---|
| `main(argv: list[str] | None = None) -> int` | experimental | The console-script entry. Argparse-based, three subcommands: `run`, `checks`, `doctor`. Handles exit-code translation via `mgf.common.cli`. |

**Total in `mgf.apiprobe.cli.__all__`: 1 name.**

---

## Grand totals

| Module | Public names |
|---|---|
| `mgf.apiprobe` | 70 (62 re-exports + `__version__` + `cli_main` + `factories` submodule) |
| `mgf.apiprobe.exceptions` | 7 |
| `mgf.apiprobe.config` | 1 |
| `mgf.apiprobe.core` | 31 (15 + 16 matcher re-exports) |
| `mgf.apiprobe.core.matchers` | 16 |
| `mgf.apiprobe.auth` | 5 |
| `mgf.apiprobe.checks` | 19 |
| `mgf.apiprobe.factories` | 5 |
| `mgf.apiprobe.schema` | 3 |
| `mgf.apiprobe.transport` | 1 |
| `mgf.apiprobe.reporting` | 3 |
| `mgf.apiprobe.cli` | 1 |

The top-level `mgf.apiprobe` count includes every per-subpackage
re-export — when a name is added to a subpackage's `__all__`, it
SHOULD also be added to `mgf.apiprobe.__all__` so consumers can
import it from either path.

---

## Notes on the experimental tier

Every public name is `experimental` — this is the pre-publish,
pre-1.0 posture. Promotion to `stable` happens once the API has
stabilised and a second consumer has audited the surface.

The promotion path:

1. Land the name as `experimental`.
2. Get usage signal from at least one real consumer.
3. Write a `tests/public_surface/` test exercising the consumer
   shape (already in scope for every public name, see the
   public-surface test suite).
4. Promote to `stable` in this document.
5. Removal becomes a deprecation cycle from this point on.

---

## Notes on the namespace package

`mgf-apiprobe` ships as a sibling under the `mgf.*` PEP 420
namespace. Importing `mgf.apiprobe` does NOT import `mgf.common`
implicitly — they are separately-installable packages that share
only the `mgf.*` umbrella. The dependency direction is enforced:
`mgf-apiprobe` depends on `mgf-common` (one-way), never the
reverse. See `LIFT_CHECKLIST.md` §1.1.
