# Magogi Foundation Standards — Conformance Tracker (`mgf-uitest-web`)

> **Status.** v0.1 — initial audit. Last updated 2026-07-16.
> **Scope.** `mgf-uitest-web`'s conformance to the standards at
> [`mgf-standard/docs/standards/`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/)
> — corpus **mgf-standard 0.1.62, 265 MUSTs / 22 families** (audit date 2026-07-16).
> **Audience.** Maintainer-tomorrow, AI coding agents, future contributors.
> **Cross-references.**
> [README.md](../../README.md) (declared level),
> [PUBLIC_API.md](../../PUBLIC_API.md) (the AP-10 contract),
> [SCOPE.md](../../SCOPE.md) (the SP boundary).
> `MGF_ADOPTION.md` is **not** kept here — the ADP-04 carve-out exempts siblings
> (DOC-14 N/A).

---

## §1. You are here

`mgf-uitest-web` declares **L2 — Standard** in [README.md](../../README.md): conform
to every MUST, evidenced by this per-rule audit (CFM-02's expected default for a
federation sibling; L1 is for "greenfield experiments / scratch projects", which a
gated fleet library is not). It pins `mgf-common[standards]>=0.47,<1.0` as a
**`[standards]` extra only** — mgf-common is *not* a runtime dependency; the
runtime is `playwright` + `axe-playwright-python` + `pytest`.

**Audit method.** Nine parallel fresh-eyes reads — one auditor per standards
doc-group, each reading the rule's normative text and then the library's actual
code/config/docs, returning a per-rule verdict with evidence. Verdicts were then
verified against the mechanical gates (`mgf-fed app-doctor --standards`, `ruff`,
`mypy --strict`, `lint-imports`, the supervisor's tiered run + coverage) and
reconciled where the two disagreed. Nothing here is grep-derived: the curated
265-MUST list comes from `rules.json` / the corpus **Index of MUSTs** (naive
grepping finds 187 and is wrong).

**Counts (2026-07-16) — all 265 MUSTs accounted for (CFM-03):**

| Marker | Count | Meaning |
|---|---|---|
| ✅ conformant | **118** | Implemented + enforced + documented. |
| N/A | **143** | Out of shape: no service, no GUI, no config surface, no deploy target. |
| 🚫 declined | **3** | DP-02, DP-05, SC-10 — rationale in §3 (CFM-04). |
| ⏳ in progress | **1** | AP-02 — named closing action. |
| **Total** | **265** | + the 8 SHOULDs (NM-04/05, OB-06, PF-06, PR-02/06, TM-05/06) also carried below. |

**Headline: green.** Every mechanical gate passes — `ruff` clean, `mypy --strict`
clean (6 modules), `lint-imports` 1 kept/0 broken, **63 tests pass**, tier-0-2 CI
gate at **95% coverage**, `app-doctor --standards` 11 pass / 0 warn / 1 fail (the
one fail being this ledger, which this file closes). The library is small, typed,
and its own promises are mechanically pinned rather than asserted in prose.

**Holistic verdict** (per [audit-outcomes.md](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/principles/audit-outcomes.md)):
***Findings recorded*** — the first audit found real pre-publication debt and it
was closed, not papered over. What it found and fixed:

- **Scaffolding copy-contamination.** `SECURITY.md`, `STARTHERE.md` and
  `FEEDBACK.md` described **mgf-fastapi** — HMAC webhooks, bearer auth,
  `src/mgf/fastapi/`, a 0.4.x support table — none of which exists here. Publishing
  would have shipped docs describing a different package. All rewritten.
- **A CI gate that could not go green.** `[tool.coverage.run] patch=["subprocess"]`
  was absent, so the supervisor's child processes were measured as *nothing* — the
  build would have redded **with every test passing**. Fixed and verified.
- **Instruments claiming checks they never ran.** The CI lint step's comment
  advertised `import-linter`, but no contract existed and `lint-imports` never ran;
  the PUBLIC_API generator's docstring said "Pinned by CI" with no pin anywhere; the
  `prepare-commit-msg` hook was committed but inert, silently dropping the AG-03
  `Signed-off-by`. All three are now real.
- **Docstrings contradicting the code** — `browser.py`/`plugin.py` still promised a
  system-Chrome fallback the code had deliberately removed (the fallback once
  invented a phantom `/global-tokens.css` 404). Corrected.

- **🔍 Could not verify:** **WF-01** (remote Woodpecker activation) and **WF-13**
  (generated-file byte-currency) cannot be confirmed from the repo until it is
  created on Codeberg and registered — generation ≠ execution. Both are checked at
  first publish.
- **🗂 Considered and rejected:** *`pragma: no cover` on the browser-driving code
  to reach the TS-06 floor* — TS-06's exclusion is scoped to lazy sink integrations
  (Sentry/OTLP/journald) "genuinely unreachable without the real backend", not a
  library's core; the code is reachable and is tested. *Mock-a-Page unit tests to
  inflate coverage* — coverage theatre, and it contradicts the DP-02/DP-05 declines
  below. The honest fix was to give CI a real browser (see TS-06).

---

## §2. Per-standard audit

Markers per CFM-03: **✅** conformant · **🚫** declined-with-rationale (§3) ·
**⏳** in-progress · **N/A** rule doesn't apply to this project's shape.

### §2.1 DP — DESIGN_PRINCIPLES (DP-01..DP-13)

| Rule | Status | Notes |
|---|---|---|
| DP-01 layering | ✅ | Strictly downward + acyclic (plugin → console → checks/server/browser); now also mechanically pinned by `[tool.importlinter]` (see PR-01). |
| DP-02 third-party I/O behind ABCs | 🚫 | See §3 — the third-party I/O *is* the product. |
| DP-03 frozen domain types | ✅ | `ConsoleLaunch` / `Viewport` / `LiveServer` / `LayoutReport` frozen; `HealthWatch` is the documented live-accumulator exception (`checks.py:182`). |
| DP-04 typed; `mypy --strict` | ✅ | VERIFIED_BY_EXECUTION: "no issues found in 6 source files". |
| DP-05 tests mirror `src/` 1:1 + mocks | 🚫 | See §3 — a mocked browser tests nothing. |
| DP-06 four concerns per change | ✅ | argv-list subprocess, diagnosable `ServerStartError`, bounded waits, health capture. |
| DP-07 public docstrings | ✅ | Every public name documented; the two stale system-Chrome-fallback docstrings (a wrong docstring is worse than none) were corrected this pass. |
| DP-08 replaceability documented | ✅ | Browser seam isolated in `browser.py`; the `mgf-uitest-qt` sibling + extract-core-at-2nd-consumer rule stated in `__init__.py` / README. |
| DP-09 explicit cancellation | N/A | No user-cancellable long-running op; bounded `live_server` timeout + deterministic teardown. |
| DP-10 no silent fallbacks | ✅ | `launch_browser` uses ONLY the pinned bundled Chromium and fails loudly (`browser.py:28`). This rule has scar tissue: the removed fallback invented a non-reproducible 404. |
| DP-11 async tasks have an owner | N/A | Fully synchronous (`playwright.sync_api`); ruff `ASYNC` clean. |
| DP-12 UTC at boundaries | N/A | No wall-clock crosses a boundary; the one clock is `time.monotonic()` for a deadline (`server.py`). app-doctor confirms no naive datetimes. |
| DP-13 deterministic resource release | ✅ | `finally` → terminate → kill; temp log closed; fixtures close page/context/browser. |

### §2.2 EH — ERROR_HANDLING (EH-01..EH-13)

| Rule | Status | Notes |
|---|---|---|
| EH-01 project base error | ✅ | `UITestWebError` added this pass (`server.py:52`); subclasses `RuntimeError` so existing handlers keep working. |
| EH-02 translate at the seam | ✅ | Subprocess + urllib boundaries → typed `ServerStartError`; Playwright's own errors intentionally reach the test author. |
| EH-03 chain with `from` | ✅ | No re-raise drops its cause; the raises fire from poll-state checks with no active exception. |
| EH-04 entry-point handler | N/A | A pytest11 plugin owns no process entry point — pytest is the harness. |
| EH-05 crash report | N/A | pytest reports test exceptions; no application entry point. |
| EH-06 GUI workers | N/A | No GUI (the Qt half is the future `mgf-uitest-qt`). |
| EH-07 narrow `except` | ✅ | VERIFIED: 3 excepts, all specific-typed; the `TimeoutExpired` one is an EH-07(a) cleanup path. |
| EH-08 machine-readable fields | ✅ | `ServerStartError` now carries `returncode` + drained `output` (was message-only); pinned by `tests/integration/test_live_server.py`. |
| EH-09 actionable messages | ✅ | `console_launch`'s `NotImplementedError` states exactly what to provide; `ServerStartError` embeds the console's own failure output. |
| EH-10 observers never raise | N/A | No best-effort observer loop; the Playwright `page.on` listeners are Playwright-managed callbacks. |
| EH-11 backoff + jitter | N/A | No retry of a failing external call — the readiness poll targets our own child, bounded by a deadline. |
| EH-12 idempotent multi-attempt writes | N/A | Performs no external write. |
| EH-13 circuit breaker | N/A | The only "upstream" is our own localhost child; nothing to amplify load against. |

### §2.3 LG — LOGGING (LG-01..LG-17)

**No logging stack at all** — verified across all six modules: no `logging`,
`getLogger` or `print`. A short-lived pytest plugin has no log sink, entry point or
aggregator; flow and failures surface through pytest's own reporting and typed
exceptions (`ServerStartError` drains and embeds the console's output). Every row is
N/A on a "no such surface" basis, not a level carve-out.

| Rule | Status | Notes |
|---|---|---|
| LG-01 `getLogger(__name__)` | N/A | No logger is acquired anywhere in `src/` — nothing to name. |
| LG-02 configured once at entry point | N/A | A pytest11 plugin owns no entry point (no `[project.scripts]`); pytest configures logging, not us. |
| LG-03 trace/span ids in records | N/A | No log records and no OpenTelemetry — nothing to correlate. |
| LG-04 sensitive fields redacted | N/A | No formatter or sink exists, so there is no redaction path to configure. |
| LG-05 ERROR carries `exc_info` | N/A | No ERROR records; failures are raised as typed exceptions, not logged. |
| LG-06 logs reach an aggregator | N/A | No logging configuration; not a production service. |
| LG-07 GUI log-viewer | N/A | GUI-only rule; headless test plugin. |
| LG-08 lazy `%` formatting | N/A | No log call sites. |
| LG-09 structured `extra={}` | N/A | No log calls — no structured-field surface. |
| LG-10 JournalHandler for services | N/A | Service-only; not a daemon or systemd unit — it runs briefly inside pytest. |
| LG-11 operations ≥100 ms logged | N/A | The closest candidate: `live_server` crosses a process/network boundary. But there is no log sink or entry point (LG-02), and flow/failure is reconstructed from pytest's report plus `ServerStartError`'s drained output — the right channel for test code. |
| LG-12 emission cost ≤100 µs | N/A | No emission to cost. |
| LG-13 high-frequency logs sampled | N/A | The 150 ms poll loop emits nothing. |
| LG-14 correlation via contextvars | N/A | No `contextvars`/`ContextVar` anywhere. |
| LG-15 stable `event` field + EVENTS.md | N/A | No INFO+ lifecycle/security records to carry one. |
| LG-16 WARNING/ERROR answer what/why/how | N/A | No WARNING/ERROR records — failures raise. |
| LG-17 ERROR `fingerprint` | N/A | SHOULD; no ERROR records and no grouping backend in scope. |

### §2.4 SC — SECURITY_STANDARD (SC-01..SC-18)

| Rule | Status | Notes |
|---|---|---|
| SC-01 no secrets in source | ✅ | Sweep clean; gitleaks step in CI; `my_stuff/` git-ignored (app-doctor ✓). |
| SC-02 argv list, `shell=False` | ✅ | `server.py` — the single `Popen` is an argv list, default `shell=False`; ruff `S603/S607` active; pinned by `tests/unit/test_security_pins.py`. |
| SC-03 safe deserialization | ✅ | No `yaml.load`/`pickle` anywhere; pinned mechanically. |
| SC-04 private files `0o600` | N/A | Writes no private state — screenshots are public test artifacts; the server log is a transient `TemporaryFile`. |
| SC-05 crypto from stdlib/`cryptography` | N/A | Performs no cryptographic operation. |
| SC-06 TLS verify on outbound | N/A | The only outbound is `urlopen` to `http://127.0.0.1:<port>` — loopback, no TLS; no `verify=False`/`CERT_NONE` (pinned). |
| SC-07 outbound timeouts | ✅ | Every boundary bounded: `urlopen(timeout=2)`, 30 s readiness deadline, `wait(timeout=5)`, 10 s page default. |
| SC-08 validate untrusted input | N/A | No untrusted boundary — the consumer supplies a typed frozen `ConsoleLaunch`; DOM reads are defensively cast. |
| SC-09 formatter redaction | N/A | No logging framework, so no sink to redact before. |
| SC-10 pinned deps + vuln scanner | 🚫 | See §3 — a library must not lock its consumers' graph. `pip-audit` runs. |
| SC-11 tracebacks leak no secrets | N/A | Handles no secret material. |
| SC-12 `SECURITY.md` at root | ✅ | **Rewritten this pass** — it previously described mgf-fastapi (`src/mgf/fastapi/`, HMAC verifier, IP allowlist, a 0.4.x table, "PyPI auto-yanks"). Now: the real threat surface, no-secrets posture, 0.1.x support line, devpi no-auto-yank remediation. |
| SC-13 keys from KDF/keyring | N/A | No cryptographic keys. |
| SC-14 auth non-enumeration | N/A | No authentication surface. |
| SC-15 path-traversal validation | N/A | No path from untrusted input; snapshot names pass through `_slug()` (pinned in `tests/unit/test_console.py`). |
| SC-16 privileged ops narrow | N/A | No `sudo`/`setuid`/capabilities. |
| SC-17 security audit log | N/A | No logging pipeline / SIEM consumer; no untrusted-user boundary. |
| SC-18 reproducible releases | ✅ | CI builds from the tagged commit + `twine check` + reproducible CycloneDX SBOM; pure-Python `py3-none-any` wheel. |

### §2.5 CF — CONFIGURATION (CF-01..CF-12)

**The library owns no runtime configuration schema.** No `BaseSettings`/pydantic in
`src/`. The single `os.environ` use (`plugin.py`) merges the parent env with the
*console's* `ConsoleLaunch.env` to build a subprocess environment — it passes a
console's own config through; it does not read config of its own. The only
"configuration" is pytest fixture parametrization (`viewport`/`color_scheme`), which
is the test API, not an app config surface. Verified rather than assumed: that
`os.environ` hit is exactly the false positive a grep-driven audit would miscount.

| Rule | Status | Notes |
|---|---|---|
| CF-01 single typed config object | N/A | No config object exists; see the section note. |
| CF-02 precedence CLI>env>file>defaults | N/A | No owned layered config to order. |
| CF-03 schema `version` field | N/A | No config schema, so no version/migration chain. |
| CF-04 atomic writes for persisted config | N/A | Writes no config it owns. |
| CF-05 secrets not in config | N/A | No config file and no secret storage; the devpi publish password is a Woodpecker secret. |
| CF-06 unknown keys raise | N/A | No schema → no unknown-key surface. |
| CF-07 sub-config files same shape | N/A | Ships no satellite config files. |
| CF-08 loaded once, injected | N/A | No Settings singleton; per-test state arrives by fixture injection. |
| CF-09 `--config` flag + OS default path | N/A | Not a CLI application — a pytest11 plugin with no config file. |
| CF-10 tests construct Settings explicitly | N/A | No Settings object to construct. |
| CF-11 field rename via alias | N/A | No config fields to rename. |
| CF-12 discriminated union for variants | N/A | No mutually-exclusive backend variants. |

### §2.6 OP — OPERABILITY (OP-01..OP-12)

| Rule | Status | Notes |
|---|---|---|
| OP-01 rich version on demand | N/A | Library/plugin — no CLI or HTTP surface; ships the `__version__` primitive a consumer surfaces. |
| OP-02 `doctor` command | N/A | No app/CLI surface; no persistent state or config to diagnose. |
| OP-03 project URLs resolve | ✅ | Real (non-placeholder) Codeberg Homepage/Issues; CI's no-placeholder grep runs. Live-HEAD resolution is unverifiable while the org is private. |
| OP-04 headline facts match reality | ✅ | **Was the worst doc defect**: `STARTHERE.md` described "FastAPI integration adapters — request-id, exception translation, webhooks (Svix HMAC), IpAllowlist, DB-session helpers", giving every newcomer and AI a false model. Rewritten; the stale system-Chrome docstrings corrected; dead `PUBLIC_API.md` links now resolve. |
| OP-05 config introspectable | N/A | No configuration of its own, no running app. |
| OP-06 logs accessible | N/A | No logging subsystem; subprocess output surfaces inline in the raised error. |
| OP-07 diagnostic bundle | N/A | No operable surface; the supervisor writes `.gates/` bundles for test runs. |
| OP-08 bounded state growth | N/A | Owns no state store. The library-applicable part (resource cleanup) is met — temp file closed in `finally`, gallery filenames deterministic. |
| OP-09 production safety guards | N/A | Service-only (`applies to: service`); no `environment=production` path to fail fast on. |
| OP-10 versioned artefacts + rollback | N/A | Service-only; ships a versioned wheel (tag-coherence gated), not a deployable image needing a rollback runbook. |
| OP-11 alerts + runbooks | N/A | Service-only; nothing pages, so no runbook linkage. |
| OP-12 backup + restore drill | N/A | Service-only; no data store to restore. |

### §2.7 AP — API_DESIGN (AP-01..AP-16)

| Rule | Status | Notes |
|---|---|---|
| AP-01 `__all__` at boundaries | ✅ | Explicit, sorted, 15 names; every one importable — pinned by `tests/smoke/test_smoke.py`. |
| AP-02 per-name usage examples | ⏳ | Docstrings carry intent + invariants and avoid the "returns the X" anti-pattern, but most public names lack a per-name usage example (`audit_layout`, `checks.py`). **Closing action:** add examples in the 0.1.x line; `PUBLIC_API.md` §2 carries a one-line description for every name meanwhile. |
| AP-03 SemVer | ✅ | 0.1.0 in the pre-1.0 window; Pre-Alpha classifier; Keep-a-Changelog. |
| AP-04 deprecation cycle | N/A | No deprecations at first release. |
| AP-05 keyword-only new params | ✅ | Every optional param already keyword-only (`live_server(command, *, port, ...)`). |
| AP-06 return-type stability | ✅ | Concrete, narrowly-pinned returns; no prior release to narrow against. |
| AP-07 exceptions are public API | ✅ | `UITestWebError` + `ServerStartError` exported, documented, tiered in `PUBLIC_API.md`. |
| AP-08 `from __future__ import annotations` | ✅ | VERIFIED: all 6 modules; ruff `FA` clean. |
| AP-09 `py.typed` | ✅ | Present, git-tracked, and CI greps it inside the built wheel (app-doctor ✓). |
| AP-10 `PUBLIC_API.md` | ✅ | **Created this pass** — every public name with tier + one-line description; synced to `__all__` by `tests/unit/test_public_api.py`. Previously only the `.json` existed, and its generator's "Pinned by CI" docstring was false: nothing pinned it. |
| AP-11 stability tiers declared | ✅ | All 15 names `experimental` — honest at a first release: AP-11 says a new name starts `experimental` and earns `stable` after a MINOR cycle. Claiming `stable` would be an unearned promise. Tier validity is pinned by the same test. |
| AP-12 breaking changes in CHANGELOG | N/A | No breaking change at the initial release; CHANGELOG is Keep-a-Changelog and ready to carry migration recipes. |
| AP-13 `__version__` in sync | ✅ | app-doctor ✓; CI tag-coherence asserts tag == pyproject == `__version__`. |
| AP-14 internals not consumer-imported | ✅ | No `_`-prefixed public modules; enforced by the PR-01 contract + `PUBLIC_API.md` §4. |
| AP-15 compat shims warn | N/A | No shims at first release. |
| AP-16 federation pin window | N/A | mgf-common is not a runtime dep; the `[standards]` extra already uses the wide `>=0.47,<1.0` window. |

### §2.8 NM — NAMING (NM-01..NM-05)

| Rule | Status | Notes |
|---|---|---|
| NM-01 hyphenated dist name | ✅ | `mgf-uitest-web`. |
| NM-02 dotted import namespace | ✅ | PEP-420 `mgf.uitest_web`; no `src/mgf/__init__.py`; hatchling ships `src/mgf`. |
| NM-03 repo slug matches | ✅ | `codeberg.org/magogi-admin/mgf-uitest-web`. |
| NM-04 clone dir matches slug | ✅ | SHOULD — matches. |
| NM-05 domain-named modules | ✅ | SHOULD — `browser`/`checks`/`console`/`server`/`plugin`; no `utils`/`misc`/`helpers` junk drawer. |

### §2.9 PR — PRESENTATION_LAYER (PR-01..PR-07)

| Rule | Status | Notes |
|---|---|---|
| PR-01 SDK MUST NOT import a UI framework — **enforced mechanically** | ✅ | **Closed this pass.** The prohibition always held (deps are playwright/axe/pytest only) but PR-01's *mandated* import-linter enforcement was absent — and CI's lint step advertised "import-linter" while running only ruff. Now `[tool.importlinter]` forbids `fastapi`/`starlette`/`jinja2`/`flask`/`django`/`PySide6`/`PyQt6`/`textual`/`rich`/`click`/`prompt_toolkit`; `lint-imports` reports **1 kept, 0 broken**, and mgf-fed renders the CI line because the contract now exists. This also pins the black-box promise: the harness can never import a console's own stack. |
| PR-02 presentation in one `<sibling>-app` | N/A | SHOULD; activates at the 2nd UI consumer — this SDK has zero UI consumers. |
| PR-03 layer directories | N/A | No app layers (`core`/`view`/`ui`); a flat 5-module library that renders nothing. |
| PR-04 layer hierarchy via import-linter | N/A | No layer hierarchy exists; the contract PR-01 mandates is in force (see above). |
| PR-05 `ui/<framework>` isolation | N/A | No UI adapters exist. |
| PR-06 medium-agnostic `fmt` | N/A | SHOULD; no formatting need — `describe()`/`describe_a11y` are assertion-message builders, not a `fmt` surface. |
| PR-07 trackers classify PR-* | ✅ | This section. PR-01 always applies and is classified; PR-02..05 marked N/A as the rule expressly permits for a zero-UI SDK. |

### §2.10 GUI — GUI_CONSUMERS (GUI-01..GUI-10)

Qt-consumer rules. Zero `PySide6`/`PyQt6` anywhere (now contract-enforced — PR-01);
no QApplication, QThread, workers, QSettings or widgets. This is the **web** half of
`mgf-uitest`: it *drives* browsers, it is not a GUI. The Qt vocabulary lands in the
future `mgf-uitest-qt` sibling.

| Rule | Status | Notes |
|---|---|---|
| GUI-01 SDK MUST NOT import Qt | N/A | The Qt specialisation of PR-01; no Qt import exists. The framework-neutral obligation is met + enforced at PR-01. |
| GUI-02 work off the GUI thread | N/A | No Qt event loop, QThread or worker — a synchronous pytest library. |
| GUI-03 cancellation token through workers | N/A | No Qt workers to plumb one through. |
| GUI-04 typed completed/failed/cancelled signals | N/A | No GUI worker boundary. |
| GUI-05 bootstrap before QApplication | N/A | No QApplication; no `main()` to bootstrap. |
| GUI-06 widgets/windows/dialogs shape | N/A | Renders no UI of its own. |
| GUI-07 streaming worker signals | N/A | No Qt signal contract; the Playwright page events are not one. |
| GUI-08 GUI state via QSettings | N/A | L2, GUI-only; persists no GUI state. |
| GUI-09 pytest-qt + fake backends | N/A | Governs Qt GUI consumers' unit tests; this drives a real Chromium by design. |
| GUI-10 capability-gated controls | N/A | L2, GUI-only; exposes no UI controls. |

### §2.11 PF — PERFORMANCE (PF-01..PF-08)

The library ships no performance budgets and no `tests/perf/` — PF-* governs
perf-regression pins, which do not exist here. Its runtime is dominated by the
browser and console it drives, so there is no budgeted internal path to pin. The
bounds it does carry (`timeout=120` hang-guard, the 2 s bounded `networkidle`
settle, the 30 s readiness deadline) are operational timeouts, not perf assertions.

| Rule | Status | Notes |
|---|---|---|
| PF-01 absolute wall-clock budgets | N/A | No perf budget exists to violate. |
| PF-02 perf tests marked + excluded by default | N/A | No `@pytest.mark.perf` tests exist. The `perf`/`stress` markers stay registered for the taxonomy. |
| PF-03 baselines recorded | N/A | No `tests/perf/baselines.json` — nothing to baseline. |
| PF-04 re-baselining needs approval | N/A | No baselines file, so the discipline has no subject. |
| PF-05 perf result shape | N/A | No perf harness wired — nothing produces a result. |
| PF-06 annotate non-obvious cost | N/A | SHOULD; the 15 public names are browser/subprocess operations whose cost class is self-evident. |
| PF-07 failure carries the numbers | N/A | No perf tests → no perf failure message. |
| PF-08 hardware tiers | N/A | No `tests/perf/hw_tiers.md`; no tier-sensitive results recorded. |

### §2.12 TM — TIME (TM-01..TM-08)

| Rule | Status | Notes |
|---|---|---|
| TM-01 tz-aware datetimes | N/A | No `datetime` usage at all; ruff `DTZ` selected guards any future addition (app-doctor ✓). |
| TM-02 ISO-8601 on the wire | N/A | Serialises no datetime. |
| TM-03 durations via monotonic | ✅ | The readiness deadline uses `time.monotonic()` (`server.py`), not wall-clock subtraction — exactly TM-03. |
| TM-04 injectable clock | N/A | No "now" decision to inject; the only clock is a genuine monotonic wait. |
| TM-05 user-facing display | N/A | SHOULD; renders no time. |
| TM-06 event timestamps | N/A | SHOULD; emits no metrics/logs/traces. |
| TM-07 tz names via zoneinfo | N/A | No timezone names used. |
| TM-08 no blocking sleep in async | N/A | No async code; the one `time.sleep` is inside a sync context manager, which TM-08 permits. ruff `ASYNC` clean. |

### §2.13 OB — OBSERVABILITY (OB-01..OB-11)

No telemetry surface at all: no metrics, no traces, no OTel, no `LogRecord` schema,
no SLI/SLO/alert config. OB-01 expressly lets a library shape skip metrics + traces
(no continuous lifecycle to observe). Diagnostics flow through pytest and typed
exceptions.

| Rule | Status | Notes |
|---|---|---|
| OB-01 the three pillars | N/A | Library shape — OB-01 lets it skip metrics + traces; it emits no logs of its own either. |
| OB-02 emit metrics | N/A | No metric registration anywhere. |
| OB-03 canonical metric labels | N/A | No metrics → no labels. |
| OB-04 traces/spans | N/A | No OpenTelemetry SDK, no spans. |
| OB-05 SLIs defined | N/A | L2/service rule; no customer-facing operation and no service. |
| OB-06 SLO targets | N/A | SHOULD, L2; no SLIs exist to target. |
| OB-07 alerts + runbooks | N/A | L2; nothing pages — no running service. |
| OB-08 SLI/SLO config versioned with code | N/A | L2; no such config exists in-repo. |
| OB-09 LogRecord schema | N/A | Neither defines nor emits mgf-common's LogRecord wire — mgf-common is not a runtime dep. |
| OB-10 byte-exact LogRecord golden | N/A | Emits no LogRecord wire to pin. |
| OB-11 logging statistics surface | N/A | Ships no LogStatsCollector / `describe_logging`. |

### §2.14 DOC — DOCUMENTATION (DOC-01..DOC-19) + FB-05

| Rule | Status | Notes |
|---|---|---|
| DOC-01 universal root docs | ✅ | README, LICENSE, NOTICE, CHANGELOG, CONTRIBUTING, SECURITY, FEEDBACK, STARTHERE, SCOPE, DEPS, FEDERATION, LESSON_LEARNED, AGENTS + **PUBLIC_API.md** (created this pass — its absence failed the library baseline). |
| DOC-02 `docs/` layout | ✅ | `docs/standards/README.md` created — pointer-only, with the mandatory "NOT a duplicate" framing (app-doctor now reports DOC-18 pointer-only ✓). |
| DOC-03 bucket charter READMEs | ✅ | `docs/inprogress/README.md` created (charter + what-goes-here + index). |
| DOC-04 CHANGELOG discipline | ✅ | Keep-a-Changelog, `[Unreleased]` + `[0.1.0]`, authentic entries. |
| DOC-05 cutover guides | N/A | No breaking release (initial 0.1.0). |
| DOC-06 priority tracker | N/A | No DOC-06 tracker shipped; `docs/inprogress/` holds this CFM-governed ledger. |
| DOC-07 `docs/claude/CLAUDE.md` | ✅ | Present in dense-lookup format. **Caveat routed as feedback, not patched:** the generated body claims "This project depends on mgf-common… call `mgf.common.bootstrap()`" and cites `src/mgf-uitest-web/__init__.py` — both false here. It is a *generated render* (catch-up BEGIN/END markers); DOC-09 §10.3 says patch the source, never the render, and AG-13 reserves mgf-common edits to its supervisor. Filed in `pending-feedback/` (FB-05). |
| DOC-08 public-API doc + drift check | ✅ | `PUBLIC_API.md` + `PUBLIC_API.json` + `tests/unit/test_public_api.py` — which pins MD↔`__all__`, JSON reproducibility, and tier validity. The generator's "Pinned by CI" claim is now true. |
| DOC-09 docs name only real code | ✅ | **The headline fix.** Three docs described mgf-fastapi. Swept clean and re-verified: every module/API/path named in the docs was checked to exist. |
| DOC-10 feedback vs tracker separation | ✅ | `FEEDBACK.md` (intake) and `docs/inprogress/` (this ledger) are distinct. The foreign PAPER-01 **and** a fabricated §3 meta-paper (claiming this package layers `HealthRouter`/idempotency middleware on mgf-common) were removed. |
| DOC-11 archival | N/A | Initial release; nothing stale to archive. |
| DOC-12 agent-navigable docs | ✅ | README numbered `## §1.`–`## §6.` per the rule's explicit mandate and §12's anti-pattern table; relative links resolve; `file:line` citation form used. **Fleet note:** siblings currently use unnumbered headings, so this repo is the first to conform — divergence routed as feedback rather than silently matched. |
| DOC-13 repo-scoped feedback routing | ✅ | Harness bugs here; a console's UI defect to that console; federation-wide to mgf-common. |
| DOC-14 `MGF_ADOPTION.md` | N/A | ADP-04 carve-out exempts federation siblings. |
| DOC-15 conformance tracker | ✅ | **This file.** Accounts for all 265 MUSTs (CFM-03 completeness), declares the level (CFM-01), carries §3 declines (CFM-04) and the §4 audit log. |
| DOC-16 `DEPS.md` bidirectional | ✅ | Runtime deps + mgf-common-as-`[standards]`-extra + consumers (pending). |
| DOC-17 `FEDERATION.md` pointer | ✅ | Correct pointer stub; no duplicated contract. |
| DOC-18 standards ripple | ✅ | The new public surface propagated to its coupled dependents: `PUBLIC_API.md`/`.json` + the pin test + CHANGELOG. app-doctor: pointer-only sibling ✓. |
| DOC-19 `LESSON_LEARNED.md` | ✅ | Present, dated, seeded with a genuine lesson (pinned Chromium vs system-browser fallback). |
| FB-05 outbox for cross-repo findings | ✅ | `pending-feedback/mgf-common.md` carries the two findings this audit produced that generalise beyond this repo (the CLAUDE.md generator defect; the DOC-12 fleet divergence) — a lesson that crosses the repo boundary must travel, not sit in local memory. |

### §2.15 REL — RELEASING (REL-01..REL-13)

| Rule | Status | Notes |
|---|---|---|
| REL-01 annotated tag | ✅ | Publish gated on `event: tag`, `ref: refs/tags/v*`; tag-coherence asserts tag == pyproject == `__version__`. |
| REL-02 never reuse a version | ✅ | First publish; `dist/` git-ignored; CI builds fresh. |
| REL-03 HEAD == release surface | ✅ | `PUBLIC_API.json` carries `__version__`; the pin test asserts it matches the package. |
| REL-04 credentials from secrets | ✅ | `TWINE_PASSWORD` from the tag-scoped `devpi_password` secret; no plaintext. |
| REL-05 immutable index | ✅ | Publishes to the non-volatile `magogi/prod` stage. |
| REL-06 gate order | ✅ | build+`twine check` → tag-coherence → smoke → publish → verify-devpi via `depends_on`. |
| REL-07 no open feedback left by the release | ✅ | The only ledger entry was the mis-imported mgf-fastapi paper; removed this pass. No genuine paper is left open by 0.1.0. |
| REL-08 post-publish smoke | ✅ | Installs the freshly-built wheel into an ephemeral venv, imports the package, asserts `__version__` == tag. |
| REL-09 notify consumers | N/A | First release; no published consumer yet (`used_by` is honestly empty until step D). |
| REL-10 cohort-walk wave | N/A | Not an mgf-common release; a leaf library's first release breaks no sibling pin, so no wave is triggered. |
| REL-11 Phase A/Phase B split | N/A | No cohort wave (REL-10), so the split does not apply. |
| REL-12 Phase-A pytest-denial fallback | N/A | No cohort wave, so the fallback does not apply. |
| REL-13 registry consistency gate | N/A | The `gen_mgf_libraries.py --check` gate is the mgf-common supervisor's release duty, run from mgf-standard — not a per-repo artifact. This repo's mgf-* pins are all windowed with upper bounds. **Note:** that gate is currently RED fleet-wide for reasons unrelated to this library (`mgf-fed-web`/`mgf-test-web` pin `mgf-fedres >=0.1,<0.2` while fedres is 0.2.0) — raised separately. |

### §2.16 PKG — PACKAGE_DISTRIBUTION (PKG-01..PKG-12)

| Rule | Status | Notes |
|---|---|---|
| PKG-01 resolve + publish via devpi | ✅ | `[tool.uv] index-url` = `magogi/prod/+simple/`; publish to `magogi/prod`. No mgf-* on PyPI. |
| PKG-02 canonical endpoints | ✅ | `+simple` URL for resolve/verify; root for upload; no hand-typed variants. |
| PKG-03 auth: publish yes, read anonymous | ✅ | Tag-scoped org secret for upload; `--index-url` read is anonymous. |
| PKG-04 build once, upload that artifact | ✅ | `python -m build` + `twine check`; publish uploads the same `dist/`, no rebuild. |
| PKG-05 verify against devpi | ✅ | `verify-devpi` queries the `+simple` listing for the version. |
| PKG-06 single index resolution | ✅ | One `--index-url`; no `--extra-index-url`. |
| PKG-07 immutable published versions | ✅ | Non-volatile stage; first release. |
| PKG-08 host retention | N/A | devpi-host infra-ops hygiene, not a per-library artifact. |
| PKG-09 tag-driven publish | ✅ | `when: event: tag` + `ref: refs/tags/v*`; never on a plain push. |
| PKG-10 canonical names | ✅ | Hyphenated dist `mgf-uitest-web`; dotted import `mgf.uitest_web`; Codeberg project URLs. |
| PKG-11 no pypi.org version checks | N/A | No in-repo published-version check; `verify-devpi` targets devpi. |
| PKG-12 no PyPI surface | ✅ | The stray `pypi.org/project/mgf-common/` link in the (mis-copied) SECURITY.md is gone with the rewrite; publish + resolve are devpi-clean. |

### §2.17 SP — SCOPE (SP-01..SP-06)

| Rule | Status | Notes |
|---|---|---|
| SP-01 in-scope published | ✅ | `SCOPE.md` §1 — the launcher, the pillar checks, the `Console` + plugin; boundary stated as "driving a web console's rendered UI in a real browser". |
| SP-02 out-of-scope with reasons | ✅ | §2 — a 5-row table, each with a Why. |
| SP-03 the gate | ✅ | §3 — the in-scope test a PR justifies against; console-specific glue routed to the console's own `tests/ui/`. |
| SP-04 adjacent tier demand-gated | N/A | No formal Adjacent tier declared (IN/OUT + a gate). The deferrals stated *are* demand-gated (the Qt sibling; extract `mgf-uitest-core` only at the 2nd consumer). **Pre-1.0 follow-up:** add an explicit Adjacent section. |
| SP-05 alternatives cited | ✅ | "Where instead" names `mgf-uitest-qt`, the consoles, `mgf-test-supervisor`, `mgf-brand-web`. |
| SP-06 revisit at MAJOR | N/A | Keyed to MAJOR releases; this is 0.1.0, pre-1.0 — no boundary reached. **Pre-1.0 follow-up:** add the revisit clause before 1.0. |

### §2.18 AG — AGENTS (AG-01..AG-20)

| Rule | Status | Notes |
|---|---|---|
| AG-01 thin `AGENTS.md` pointer | ✅ | Byte-identical to the cookiecutter template; carries no briefing copy. |
| AG-02 single briefing source | ✅ | Points at `mgf-fed agents`; project lookup lives in CLAUDE.md, not duplicated. |
| AG-03 both commit trailers | ✅ | VERIFIED: every commit carries `Signed-off-by` + `Co-Authored-By`; now also auto-filled locally (AG-18) and gated server-side by the CI `commit-trailers` step. |
| AG-04 agent conduct on review | N/A | Behavioural (review conduct); `FEEDBACK.md` is the intake channel. No static artifact to certify. |
| AG-05 verify memory before acting | N/A | Self-enforced conduct — not a checkable library artifact. |
| AG-06 destructive-command guardrails | N/A | Harness-enforced; `.claude/settings.json`'s deny-list (`rm -rf`, force-push, hard reset) is consistent scaffolding. |
| AG-07 track multi-step work | N/A | Session conduct. |
| AG-08 memory scoping | N/A | Self-enforced; `docs/memory/MEMORY.md` seeded, unpolluted by session logs. |
| AG-09 verify siblings against the index | N/A | Review conduct; the uv index-url does target devpi. |
| AG-10 standards drift → paper, not silent fix | N/A | Review conduct. Honoured in practice this pass: the CLAUDE.md generator defect and the DOC-12 fleet divergence were routed to `pending-feedback/`, not patched locally. |
| AG-11 route feedback to the target repo | N/A | Review conduct; `FEEDBACK.md` present. |
| AG-12 project briefing content | ✅ | `docs/claude/CLAUDE.md` present (see DOC-07 for its generator-owned inaccuracies, routed as feedback). |
| AG-13 only the supervisor edits mgf-common | N/A | Governance; honoured — the generator defects go out as papers. |
| AG-14 propagate coupled surfaces in-change | N/A | Review conduct. The copy-paste drift this audit found is exactly its failure mode; the docs are now propagated (DOC-09/DOC-18). |
| AG-15 empowerment charter | N/A | Behavioural; no checkable artifact. |
| AG-16 corpus resolvable | ✅ | `mgf-common[standards]>=0.47,<1.0` + `mgf-standard>=0.1.6,<0.2`. |
| AG-17 `docs/memory/MEMORY.md` | ✅ | Present + seeded (app-doctor ✓). |
| AG-18 standardized git config | ✅ | **Closed this pass — the hook trap fired.** `.githooks/prepare-commit-msg` was committed but **inert** (no `core.hooksPath`, no shim), silently dropping the AG-03 signoff (PAPER-117). Now: `core.hooksPath=.githooks` wired, `.gitmessage` added + `commit.template` wired, `.gitignore` canonical (incl. `my_stuff/`, and `.gates/`/`.coverage` added), `check_commit_trailers.py` runs as the CI gate. app-doctor: "hook present + active" ✓. |
| AG-19 runtime auto-memory VCS | N/A | No machine-local runtime store for this project yet (app-doctor ✓). |
| AG-20 exhaust owned-infra recovery | N/A | Behavioural. |

### §2.19 WF — WORKFLOWS (WF-01..WF-13)

| Rule | Status | Notes |
|---|---|---|
| WF-01 CI triggers | ✅ | push→main, pull_request, tag. 🔍 Remote Woodpecker activation is unverifiable until the repo exists — checked at first publish. |
| WF-02 the four mandatory gates | ✅ | **Closed this pass.** ruff + format, mypy, pytest×3 + coverage were enforced; the **import-linter gate was not** — no contract existed and `lint-imports` never ran, while the lint step's comment claimed it. Contract added; the renderer now splices the line in. |
| WF-03 tag-only publish | ✅ | `event: tag` + `refs/tags/v*` → twine upload. |
| WF-04 secrets not in the file | ✅ | `from_secret: devpi_password`. |
| WF-05 tag coherence | ✅ | tag vs pyproject vs `__version__`, before smoke/publish. |
| WF-06 build in-run | ✅ | Fresh `python -m build`; publish uploads that run's artifact. |
| WF-07 post-build smoke | ✅ | Ephemeral-venv wheel install + import + version assert. |
| WF-08 verify after publish | ✅ | `verify-devpi` GETs the anonymous index. Single-shot rather than poll-until-listed — weaker against propagation lag; noted. |
| WF-09 pinned images/actions | ✅ | python 3.11/3.12/3.13-slim, plugin-git 2.9.2, gitleaks v8.30.1, cyclonedx `>=7,<8`. |
| WF-10 parallel gates, serial release | ✅ | Gates carry no `depends_on`; the publish flow is serial. |
| WF-11 reproducible runs | ✅ | Pinned images, declared `$DEVPI_URL`, `filterwarnings=["error"]`, per-test timeouts. |
| WF-12 no unjustified `\|\| true` | ✅ | None. Noted: `check_commit_trailers.py` fail-opens when `base..HEAD` can't be computed — a template-wide "green without checking" path, routed as feedback rather than patched locally. |
| WF-13 generated file is current | ✅ | Self-declares generated; canonical step set/order; the renderer omits `lint-imports` for contract-less repos, which is why it was absent — now spliced in because the contract exists. 🔍 Byte-currency re-verified at registration. |

### §2.20 TS — TESTING (TS-01..TS-28)

| Rule | Status | Notes |
|---|---|---|
| TS-01 tests mirror `src/` | ✅ | `tests/unit/` created this pass — `test_server.py`, `test_console.py`, `test_checks.py`, `test_public_api.py`, `test_security_pins.py`. Previously the only tests were browser/console-driven; the pure logic had no unit layer. |
| TS-02 unit suite: no I/O/creds/daemons | ✅ | Unit tests need only the interpreter; the console-free contract tests use `set_content` + routed fulfils. |
| TS-03 isolation | ✅ | Function-scoped context/page with close() teardown; session browser stateless; no HOME/XDG or module-global mutation. |
| TS-04 `filterwarnings = ["error"]` | ✅ | app-doctor ✓. It bites: it caught a real double-plugin-load this pass. |
| TS-05 `--strict-markers` + `--strict-config` | ✅ | Both in `addopts`. |
| TS-06 coverage gate ≥80% | ✅ | **Measured 95%** on the tier-0-2 gate (was 71% browser-free); `fail_under=90`. The mechanism: `[tool.mgf-fed] browser = true` splices `playwright install --with-deps chromium` into the test steps, so CI drives a real browser and the browser-driving code is genuinely covered — no `pragma` and no mock theatre. **Closed 2026-07-16:** the carve-out shipped — `mgf-standard 0.1.63` (`frag-playwright-install.yml` + the `<<INSERT:playwright-install>>` markers) and `mgf-fed 0.13.0` (the `browser` gate) are both released and on devpi, and this repo's `.woodpecker.yml` was re-rendered against them — the browser install is present in all three test jobs (3.11/3.12/3.13). Verified the carve-out is opt-in: the other 37 members render with no playwright step. |
| TS-07 every typed exception unit-tested | ✅ | `ServerStartError`'s message, both raise paths, and its `returncode`/`output` fields pinned (`tests/unit/test_server.py`, `tests/integration/test_live_server.py`). |
| TS-08 translation seams tested | N/A | No vendor-SDK→taxonomy seam; `_probe` returns a probe result, not a typed translation. |
| TS-09 observer tests | N/A | No best-effort observer loop owned by the library. |
| TS-10 security rules pinned mechanically | ✅ | `tests/unit/test_security_pins.py` — no `shell=True`, no `verify=False`/`CERT_NONE`, no `yaml.load`/`pickle`, and the one subprocess site stays an argv list. |
| TS-11 GUI worker tests | N/A | No Qt GUI (that is `mgf-uitest-qt`). |
| TS-12 async tests | N/A | Fully synchronous. |
| TS-13 property/round-trip tests | N/A | No round-trip/serialisation surface; the layout JS returns a one-way geometry dict. |
| TS-14 perf budgets benchmarked | N/A | Owns no latency/throughput budget (see PF-*). |
| TS-15 smoke opt-in / self-contained | ✅ | `smoke` marker registered; e2e specs are tier-gated, tmp_path-scoped, and skip when the console CLI is absent. |
| TS-16 self-explanatory failures | ✅ | `LayoutReport.describe()` / `HealthWatch.describe()` / `describe_a11y()` are passed as assert messages throughout — the library's whole point is a legible failure. |
| TS-17 conftest fixture hierarchy | ✅ | Plugin fixtures via the pytest11 entry point; `console_launch` is the one fixture a consumer overrides. This repo defines it once, directory-scoped at `tests/integration/` (the stdlib static server). The console-specific overrides moved out to the consoles that own them (`mgf-fed-web` / `mgf-test-web`, each at its own `tests/e2e/conftest.py`) — the same sanctioned override pattern, now across a repo boundary. |
| TS-18 slow tests marked | ✅ | **Drift removed**: pyproject still registered the legacy `slow` marker, which M2 Wave-2 deleted fleet-wide ("do not re-add it"). Tests are slow *because* of what they do — `e2e` carries it. |
| TS-19 layer markers registered | ✅ | The 12-marker taxonomy; the `integration` label's stale "tier-1" corrected to tier-2 (canonical `MARKER_TIER`). |
| TS-20 canonical directory partition | ✅ | Partitioned into the canonical directories (the suite was previously flat): `tests/unit/`, `tests/integration/`, `tests/smoke/`; markers match dirs. **`tests/e2e/` retired 2026-07-16** when the console-specific specs moved into the consoles that own them — this package now has no full-bootstrap-to-output chain of its own, because driving a real console IS the consumer's chain, not the library's. TS-20 partitions tests into the right directory; it does not require a directory for a tier this repo does not have. |
| TS-21 published-library smoke layer | ✅ | `tests/smoke/test_smoke.py` — import + every `__all__` name reachable + `__all__` sorted/unique. Was absent for a package about to ship a wheel. |
| TS-22 tiered runs via the supervisor | ✅ | CI drives `mgf.test_supervisor --tier 0-2`; verified locally — 38 selected, 25 correctly skipped as wrong-tier. |
| TS-23 supervisor + child-process coverage | ✅ | **The landmine.** CI ran `coverage run -m mgf.test_supervisor` while pyproject lacked `[tool.coverage.run] patch=["subprocess"]` — coverage would have seen **nothing** and the build would have redded *with every test passing*. Added (coverage 7.15.2 ≥ 7.10); verified: "Combined 3 files". app-doctor ✓. |
| TS-24 structured per-test records | ✅ | Supervisor writes `.gates/last-run/run.jsonl`; `.gates/` now git-ignored (it was not — run records could have been committed). |
| TS-25 auto-quarantine | ✅ | Ships with the adopted supervisor; state under the (now-ignored) `.gates/`. |
| TS-26 compiled-artifact tests | N/A | Pure Python; Playwright's Chromium is a dependency's binary, not this project's — the rule expressly permits N/A. |
| TS-27 per-failure bundles | ✅ | Supervisor writes `.gates/last-run/failures/<id>.txt`. |
| TS-28 perf capture | ✅ | L2 rule the supervisor satisfies; no `--perf` writer wired (that is mgf-common's plugin, not a runtime dep) — conformant deferral. |

### §2.21 DEP — DEPLOYMENT (DEP-01..DEP-11)

`DEPLOYMENT.md` scopes itself to stateful web-service consumers and **explicitly
excludes runtime-less federation libraries** (§ "Applies to"). This package
provisions nothing: it ships a wheel to devpi and is imported by a consumer's
pytest. The only thing it "starts" is an ephemeral console subprocess inside a test,
torn down deterministically in a `finally`. Every rule is therefore N/A by project
shape — accounted for, not omitted (CFM-03).

| Rule | Status | Notes |
|---|---|---|
| DEP-01 infrastructure as code | N/A | Provisions no VM/network/LB/bucket/DNS — it publishes a wheel. |
| DEP-02 production hosts configured as code | N/A | No production host; the library runs inside the consumer's pytest process. |
| DEP-03 immutable deploy artefact | N/A | No service deploy step. Wheel immutability is a PKG-07/devpi concern, met there. |
| DEP-04 deploy secrets management | N/A | No production secrets; the sole secret is the tag-scoped devpi publish password (a Woodpecker org secret, never in-repo). |
| DEP-05 deploy/backup/restore scripts | N/A | No `deploy/scripts` exist and none are required. |
| DEP-06 rollback procedure | N/A | No deploy to reverse; a bad release is remediated by consumers pinning a prior version. |
| DEP-07 canonical `deploy/` layout | N/A | No `deploy/` directory — verified absent; a federation library, not a web-service consumer. |
| DEP-08 production observability | N/A | No production runtime to observe (see OB-*). |
| DEP-09 DNS + TLS | N/A | No hosted endpoint. |
| DEP-10 first-production-cut runbook | N/A | No production environment to green-field provision. |
| DEP-11 environments | N/A | No deployable environments; the py3.11/3.12/3.13 CI matrix is version-compat, not prod/staging. |

---

## §3. Decline-with-rationale ledger (CFM-04)

**DP-02 — third-party I/O behind provider ABCs — declined.**
DP-02 targets *replaceable* third-party I/O placed behind a domain seam so a
mock can stand in. Here the third-party I/O **is the product**: the package exists
to drive a *real* Chromium via Playwright and to launch the *real* console as a
black box over HTTP. A mock browser verifies nothing — it would assert that our own
fake returns what we told it to, which is precisely the false confidence this
harness was built to replace (an in-process `TestClient` renders no CSS and runs no
JS; that gap is why the library exists). Wrapping Playwright in an ABC would also be
the premature abstraction the project deliberately defers: `mgf-uitest-core` gets
extracted **only once a second consumer exists** (the `mgf-uitest-qt` sibling), not
on speculation. The underlying need — *a swappable seam* — is met differently and
provably: `browser.py` isolates browser acquisition in one place, and the PR-01
import-linter contract mechanically guarantees the harness never couples to any
console's stack. Scoped out per DESIGN_PRINCIPLES §14.2 +
[non-adoption-is-valid](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/principles/non-adoption-is-valid.md).

**DP-05 — 1:1 `src/` test mirror with mocked I/O — declined (in part).**
The mirror half is now **met** (`tests/unit/` mirrors the modules — see TS-01); what
is declined is DP-05's *mocked-backend* premise. The unit of this library is a
driven console, so its specs are organised by consumer scenario, and its
check-logic is proven deterministically against real DOM built with `set_content`
rather than against a mocked page. Determinism — DP-05's actual goal — is achieved
by *pinning the browser* (bundled Chromium only, no system-browser fallback), which
this project learned the hard way: a fallback browser once invented a
`/global-tokens.css` 404 that did not reproduce. Same need, stronger mechanism.

**SC-10 — committed lockfile — declined.**
SC-10's pinning premise holds for applications, which own their deployed
dependency graph. A **library must not lock its consumers' transitive graph** — the
consumer's own lockfile governs resolution, and a lockfile here would either be
ignored or actively fight a console's resolver. The underlying need — *a bounded,
scanned dependency surface* — is met by a different mechanism, with proof: every
runtime dep carries an upper bound (`playwright>=1.50,<2`, `axe-playwright-python>=0.1.4,<1`,
`pytest>=8.0,<10`; upper bounds added this pass), every image/action in CI is pinned
by digest or tag, and `pip-audit` runs as a CI gate on every build. If a consumer
needs byte-exact reproduction it pins us — which the fleet's own `>=x,<y` windows
already express.

---

## §4. Audit log

| Date | Auditor | Trigger | Findings |
|---|---|---|---|
| 2026-07-16 | Claude (CTO/Court), 9 parallel fresh-eyes auditors + mechanical gates | Initial audit — pre-publication certification for v0.1.0 (corpus 0.1.62 / 265 MUSTs) | **117 ✅ · 143 N/A · 3 🚫 · 2 ⏳.** Found and closed real pre-publication debt: mgf-fastapi doc contamination (SC-12/OP-04/DOC-09), a CI coverage gate that would red with every test passing (TS-23), three instruments claiming checks they never ran (PR-01/WF-02 import-linter, DOC-08 API pin, AG-18 inert hook), missing `PUBLIC_API.md` + tiers (AP-10/11), no unit/smoke layers (TS-01/21), flat test tree (TS-20), marker drift (TS-18/19). Open: AP-02 (usage examples), TS-06 (95% measured; awaiting the cornerstone releases carrying the CI browser carve-out). |
| 2026-07-16 | Claude (CTO/Court) | **TS-06 closure** — the cornerstone releases the initial audit was waiting on | **118 ✅ · 143 N/A · 3 🚫 · 1 ⏳.** `mgf-standard 0.1.63` (`frag-playwright-install.yml` + the three `<<INSERT:playwright-install>>` markers) and `mgf-fed 0.13.0` (the `[tool.mgf-fed] browser` gate) are released and served from devpi; this repo's `.woodpecker.yml` was re-rendered against them and the browser install is present in all three test jobs. **TS-06 ⏳ → ✅.** Blast radius verified rather than asserted: the other 37 registry members render with no playwright step and no render error. `drift-check` reports `✓ mgf-uitest-web`. Remaining open: AP-02 only. |

---

## §5. Cross-references

- [mgf-standard/docs/standards/](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/) — the standards source of truth.
- [`docs/standards/README.md`](../standards/README.md) — this repo's pointer to that corpus.
- [PUBLIC_API.md](../../PUBLIC_API.md) — the AP-10 contract (tiers per AP-11).
- [SCOPE.md](../../SCOPE.md) — the SP boundary + gate.
- [LESSON_LEARNED.md](../../LESSON_LEARNED.md) — DOC-19 local lessons.
- [principles/non-adoption-is-valid.md](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/principles/non-adoption-is-valid.md) — the ASPIRE-04 / CFM-04 basis for §3.

## §6. When to update

- **Every standards bump** — re-audit anything whose rule text changed; append a §4 row.
- **Every PR** that touches a conformance rule (logging shape → LG-*, public surface → AP-*).
- **Every quarter** as a sanity sweep — drift over time is the signal.
