# Magogi Foundation Standards — Conformance Tracker (mgf-alembic)

> **Status.** v0.1 — initial audit. Created 2026-05-18 per v2.8
> standards bump (DOC-15 + CFM-01..04).
> **Scope.** mgf-alembic's conformance to the standards at
> [mgf-standard/docs/standards/](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/)
> (current standards version: v2.8).
> **Audience.** Maintainer-tomorrow, AI coding agents, future
> contributors.
> **Cross-references.**
> [README.md](../../README.md) (declared level),
> [CHANGELOG.md](../../CHANGELOG.md) (release history).

---

## §1 You are here

**Project shape:** Async-aware alembic env.py helper; single public name (`configure_env`).

**Current version:** 0.4.8.

**Declared TARGET conformance level: L2** (per CFM-02). **Current VERIFIED standing (2026-06-07 depth audit): below L2** — declared, not met.

Of the **218** current MUSTs: **129 ✅ verified** (file:line, refute-survived) · **1 ⏳ open MUST gap** · **85 N/A** (library shape) · **3 declined** (CFM-04 §3). Applicable (non-N/A) = **133**; **129/133 (97%) evidenced**. The code-quality families are strong (DP all ✅/N/A, with clean engine-disposal/RA discipline); the gaps are library-hygiene (CI publish, SCOPE, PUBLIC_API surface) + EH typed-exception adoption + a few SC/LG specifics.

**Open-gap clusters (the 39 ⏳ — detail in §Z):**

| Cluster | Rules | Count |
|---|---|---|
| CI publish pipeline (no tag-driven chain) + tag | PKG-04, PKG-05, PKG-09, REL-01, WF-02, WF-03, WF-04, WF-05, WF-06, WF-07, WF-08 | 11 |
| SCOPE policy absent (SP-01..06) | SP-01, SP-02, SP-03, SP-04, SP-05, SP-06 | 6 |
| API / docs (PUBLIC_API.json/md, __version__, exceptions-doc, drift) | AP-07, AP-10, AP-11, AP-13, AP-14, DOC-08, DOC-09 | 7 |
| ERROR_HANDLING (typed base + boundary translation) | EH-01, EH-02 | 2 |
| SECURITY (timeout/audit/SBOM) | SC-07, SC-17, SC-18 | 3 |
| misc (replaceability doc, logging, corpus-pin, ops, presentation, pypi.org, smoke, perf) | AG-16, DP-08, LG-11, LG-15, OP-03, PKG-03, PKG-12, PR-01, TS-21, TS-28 | 10 |

**2026-06-07 depth audit provenance.** 16-family fan-out + adversarial refute (hardened "upheld ✅ keeps its status" prompt — the cleanest federation run: no 🚫-flood, no N/A-misjudgment). Three families truncated (DP/CF/AG) → an 8-id micro-audit; one refute-mislabel (AP-11) reconciled. Per-rule verdicts with file:line are in §Z; this supersedes the unset placeholders + consolidates the duplicate §Z/§6 enumeration.


## §2 Per-standard audit

Audit method: cross-reference the per-rule list in each standard
under [mgf-standard/docs/standards/](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/)
against this sibling's source tree + tests + docs.

Status markers (CFM-03):
- **✅** conformant — implementation + tests + docs match the rule.
- **🚫** declined-with-rationale — rule doesn't apply OR was
  deliberately not adopted; rationale in §3 (CFM-04).
- **⏳** in-progress — adoption planned; gap documented elsewhere.
- **N/A** — rule premise doesn't apply to this project's shape.

### §2.1 DP — DESIGN_PRINCIPLES

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.2 EH — ERROR_HANDLING

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.3 LG — LOGGING

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.4 SC — SECURITY_STANDARD

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.5 CF — CONFIGURATION

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.6 AP — API_DESIGN

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.7 TS — TESTING

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

### §2.8 DOC — DOCUMENTATION

(initial audit: ✅ structurally; depth pass on first standards-bump trigger; v2.8 DOC-13/14/15 newly applicable)

### §2.9 REL — RELEASING

(initial audit: ✅ structurally; depth pass on first standards-bump trigger)

---

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

| AP-14 | API_DESIGN | import-linter 'consumer fixtures only public' | No in-repo consumer harness to lint; closed-box + complete __all__/PUBLIC_API.md + smoke satisfy the intent. | 2026-06-08 |
| EH-02 | ERROR_HANDLING | translate third-party exceptions at the boundary | Deliberate: masks credentials but PRESERVES the DB exception type — a diagnostic env-helper, not a translation seam. | 2026-06-08 |
| SC-07 | SECURITY | finite connection timeout | Driver/URL-specific (psycopg vs asyncpg vs aiosqlite); the env-helper can't set a generic one — consumer's connect_args concern. | 2026-06-08 |

(none yet — initial audit. Populate as deferrals get filed,
each carrying a rationale per
[principles/non-adoption-is-valid.md](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/principles/non-adoption-is-valid.md).)

---

## §4 Audit log

| 2026-06-07 | depth audit (16-family fan-out + refute; ~33 agents + 8-id micro) | first evidence-based per-MUST audit | **94 ✅ / 39 ⏳ / 85 N/A** of 218 (71% of applicable); declared L2 → below-L2. Cleanest federation run (hardened prompt). Clusters: CI publish (WF/PKG/REL), SCOPE, API/docs, EH typed-exceptions, SC. Audit only — no code changed. |

| Date | Auditor | Trigger | Findings |
|---|---|---|---|
| 2026-05-18 | initial audit (v2.8 standards bump) | DOC-15 + CFM-01..04 introduction; this tracker created | scaffolded; first depth audit to follow |

---

## §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/inprogress/RELIABILITY_AND_ACCURACY.md`](RELIABILITY_AND_ACCURACY.md)
  — falsifiable per-rule evidence on the RA-* surface
  (where applicable).
- [`docs/inprogress/SECURITY_HARDENING.md`](SECURITY_HARDENING.md)
  — falsifiable per-rule evidence on the SC-* surface.
- [`docs/inprogress/PERFORMANCE_AND_CAPACITY.md`](PERFORMANCE_AND_CAPACITY.md)
  — falsifiable per-rule evidence on the perf-shape surface.
- [`../../FEEDBACK.md`](../../FEEDBACK.md) — papers filed
  against this sibling.
- [mgf-standard/docs/standards/principles/non-adoption-is-valid.md](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/principles/non-adoption-is-valid.md)
  — ASPIRE-04 / CFM-04 documented-non-adoption principle.
- [Template this file was scaffolded from](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/docs/recipes/mgf-standards-conformance-md-template.md).

---

---

## §Z Per-MUST evidenced audit (all 259 MUSTs (PAPER-100 re-baseline 2026-06-11) — CFM-03 completeness)

> **2026-06-07 depth audit** (16-family fan-out + adversarial refute on every ✅, hardened 'upheld ✅ keeps its status' prompt; ~33 agents + an 8-id micro-audit for 3 truncated families [DP/CF/AG] + 1 refute-mislabel reconciled). The cleanest of the federation runs — no 🚫-flood, no N/A-misjudgment. **Mix: 94 ✅ · 39 ⏳ · 85 N/A · 0 🚫.** Replaces the prior duplicate ⏳ scaffold (§Z + §6).


### DESIGN_PRINCIPLES

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DP-01 | N/A | flat 3-module adapter, no UI/core split; __init__ closed-box invariant | no layered UI/core graph + no provider ABC (DP-02 N/A) → no downward-flow contract to enforce. Premise doesn't bind. |
| DP-02 | N/A | adapts alembic.context + sqlalchemy create_engine directly; no providers/ ABC | alembic+sqlalchemy ARE the frameworks it wraps, not swappable I/O behind a seam. Premise doesn't bind. |
| DP-03 | ✅ | _drift.py:76-77 `@dataclass(frozen=True) class DriftReport`; all 9 fields are `tuple[str, ...] = field(default_factory=tuple)` (lines 87-127). Re-exported as public API via __init__.py: | [verify-upheld] Attempted refutation: any domain identity crossing a module boundary as a bare string/dict? The only structured domain object is DriftReport, frozen with immutable tuple fields. naming_convention dict is alembic co |
| DP-04 | ✅ | pyproject.toml:175 `strict = true`; 180-182 disallow_untyped_defs/disallow_incomplete_defs/no_implicit_optional; 178 warn_return_any; packages=['mgf.alembic'] (172). .woodpecker.yml:27- | [verify-upheld] Attempted refutation: any unannotated public function or unjustified Any? All public functions annotated; both Any uses have adjacent why-comments. mypy --strict configured and CI-enforced on src/. No counterexampl |
| DP-05 | ✅ | tests/unit/ contains exactly test_env.py and test_drift.py, mirroring src's two modules (_env.py, _drift.py). test_env.py uses sqlite:///{tmp_path} (163,185,221,291,336) and sqlite+aios | [verify-upheld] Attempted refutation: does the unit suite mirror src 1:1 and run hermetically? Yes — 2 unit files for 2 modules, sqlite/aiosqlite in tmp_path, no creds/network/daemon. The provider-ABC-mock sub-clause is N/A (no AB |
| DP-06 | ✅ | All four concerns first-class with dedicated trackers in docs/inprogress/ (SECURITY_HARDENING.md, RELIABILITY_AND_ACCURACY.md, PERFORMANCE_AND_CAPACITY.md) plus root SECURITY.md. Securi | [verify-upheld] Attempted refutation: DP-06 is literally a PR-description MUST; no live PR is auditable in a static checkout. The only checkable substance — that the four concerns are addressed across the shipped surface, not defe |
| DP-07 | ✅ | Every public symbol carries an intent+invariants docstring: configure_env (_env.py:113-286), run_async_migrations (524-542), detect_drift (_drift.py:277-313), DriftReport class + every  | [verify-upheld] Attempted refutation: any public class/function missing a docstring, or a forbidden 'returns the result' what-comment? None found — all public and internal symbols documented; no filler docstrings. No counterexampl |
| DP-08 | ✅ | DEPS.md lists alembic/sqlalchemy/mgf-common but no swap recipe; no ARCHITECTURE.md replaceability table | DP-08 (SHOULD): the doc near each major component must describe the swap recipe. Fix: a 'Replaceability' note (alembic/sqlalchemy are definitional — the swap recipe is 'write your own env.py') in the module docstring/DEPS. — FIXED 2026-06-07: __init__ module docstring now carries the Replaceability note (alembic/sqlalchemy are definitional — the swap recipe is 'write your own env.py') |
| DP-09 | N/A | no long-running/threaded ops, no CancellationToken; one-shot migration via asyncio.run | DP-09 targets long-running sync/threaded ops with a cancellation flag; this runs one bounded migration per call. Premise doesn't bind. |
| DP-10 | ✅ | the async-vs-sync routing is explicit + queryable (is_async kwarg, _env.py:110/202-209); running-loop case RAISES (not silent fallback, :348-358); offline announced on stderr | DP-10 forbids silent fallbacks; the one heuristic branch is queryable/overridable + the surprising case raises. Met. |
| DP-11 | ✅ | `grep -rn create_task src/` returns nothing — no asyncio.create_task anywhere. Async path uses `asyncio.run(_run_online_async(...))` (_env.py:359-369) and direct `await _run_online_asyn | [verify-upheld] Attempted refutation: any unretained create_task? Grep confirms zero create_task calls in src. RUF006/ASYNC enabled and CI-enforced to catch future introduction. No counterexample. MET. |
| DP-12 | N/A | no datetime usage in src (grep empty); DriftReport carries only str tuples; DTZ lint enabled | DP-12 binds where datetimes cross a boundary; this library produces none. Premise doesn't bind. |
| DP-13 | ✅ | Sync engine: try/finally `connectable.dispose()` around `with connectable.connect()` (_env.py:466-480). Async engine: try/finally `await connectable.dispose()` around `async with connec | [verify-upheld] Attempted refutation: any owned engine/connection released only via GC, or a missing try/finally? All three engine sites pair `with`/`async with` connect with a try/finally dispose; connections are context-managed. |

### ERROR_HANDLING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| EH-01 | ✅ | src/mgf/alembic/_env.py:348 raises a bare `RuntimeError` (RA-01 guard); _drift.py declares `Raises: Exception` and propagates DB errors unchanged in TYPE. No project base error class (n | EH-01 MUST: every exception raised by application code MUST be a subclass of the project's base error class; never raise a bare Exception across an internal API. The library raises `RuntimeError` (the RA-01 guard at _env.py:348) r — FIXED 2026-06-08 (0.4.8): the RA-01 guard now raises mgf.common.exceptions.OperationError (a typed AppError subclass) instead of bare RuntimeError; test + tag updated |
| EH-02 | 🚫 | _env.py `_run_online_sync`/`_run_online_async` and _drift.py `detect_drift` call into SQLAlchemy/alembic/DB drivers; on failure they re-raise the third-party exception UNCHANGED in type | EH-02 MUST: third-party exceptions MUST be translated to typed application exceptions at the boundary that owns the third-party call (DB driver). The library deliberately does NOT translate — it masks credentials but preserves `Op — DECLINED 2026-06-08 (CFM-04 §3): mgf-alembic deliberately does NOT translate DB-driver exceptions — it masks credentials but PRESERVES the original type so consumers/operators see the real OperationalError etc. (it is a diagnostic env-helper, not an error-translation seam); recorded design choice, not an oversight |
| EH-03 | N/A | There is no translation re-raise anywhere: `_safe_error_context` (_env.py:72-84) re-raises the SAME exception object (`raise`, preserving the original traceback and `__cause__`), and th | EH-03 MUST applies only 'when re-raising a translated exception'. The library performs no exception translation (see EH-02), so the `raise NewError(...) from original` obligation never triggers. No defect possible; genuinely N/A. |
| EH-04 | N/A | The shape carve-out states this runs INSIDE a consumer's alembic env.py, invoked by the alembic CLI; it has no CLI/process/Qt entry point of its own. `__init__.py` exposes only `configu | EH-04 MUST: every ENTRY POINT installs a top-level handler. A library that is called from a consumer's entry point is not itself an entry point — installing a process excepthook or asyncio loop handler from inside a library would  |
| EH-05 | N/A | No crash reporter, no state-dir JSON report, no `report_now` usage. The library only emits a single INFO log (_drift.py:338) and a stderr SH-02 warning. mgf-common ships `report_now` bu | EH-05 MUST: UNHANDLED exceptions MUST produce a local crash report. Crash reporting is wired at the process entry point (EH-04), which a library does not own. A library that crash-reported on behalf of its host would write into th |
| EH-06 | N/A | No GUI, no QThread/CoreWorker, no Qt dependency anywhere in src/ or pyproject. The shape carve-out explicitly states 'no GUI'. | EH-06 governs GUI worker threads (`error(str)` signal, crash-report-then-surface). The library has no GUI surface. Genuinely N/A. |
| EH-07 | ✅ | [verify-upheld] Three `except Exception` sites, all _env.py: (1) `_safe_url`:51 returns the documented sentinel `'<malformed-url>'` from a helper whose docstring (lines 42-47) states it | EH-07 MUST: `except Exception:` without re-raise or typed translation MUST NOT appear except in (a) cleanup/finally/suppress paths or (b) documented best-effort log+continue loops. Site 2 re-raises (permitted shape). Site 3 is a c |
| EH-08 | N/A | The library defines no typed exception classes. The only authored raise is `RuntimeError` with a message string (EH-01); `DriftReport` is a frozen dataclass carrying structured tuples ( | EH-08 MUST: every TYPED EXCEPTION MUST carry machine-readable fields. The library has no typed exceptions of its own (it does not adopt a base class — see EH-01), so there is no typed-exception to which the machine-readable-fields |
| EH-09 | ✅ | [verify-upheld] Every user-facing message this library authors ends in an actionable next step: (1) RA-01 RuntimeError (_env.py:348-358) ends with the supported alternative as a copy-pa | EH-09 is a SHOULD-where-possible clause: user-shown messages MUST end in an actionable next step where possible. All three user-facing messages the library authors do so, and the key one (RA-01) is pinned by a dedicated substring  |
| EH-10 | N/A | No best-effort observer fan-out: no hook executor, scheduler tick loop, alert evaluator, or libvirt-style event-callback loop. The one INFO log (_drift.py:338) is a straight-line emissi | EH-10 governs 'best-effort observer' code with the never-raises invariant. The library has no such fan-out construct. The include_object seam deliberately does NOT swallow (it propagates), which is the opposite of an EH-10 observe |
| EH-11 | N/A | No retry logic anywhere: no loop with backoff, no `retry()` helper, no `time.sleep`/`asyncio.sleep` in a retry context. Migrations are one-shot (NullPool, single connection, dispose) pe | EH-11 MUST: retries MUST use exponential backoff with full jitter and a finite cap. The library performs no retries — a migration is a deliberate one-shot DDL operation where silent retry would be dangerous. With no retry surface, |
| EH-12 | N/A | The library issues no multi-attempt external writes/sends of its own — it hands DDL execution to alembic. There is no operation it retries (see EH-11), so no idempotency-on-retry obliga | EH-12 MUST: operations against external systems with multi-attempt cost MUST be idempotent. EH-12 is scoped to operations that 'may run twice' due to retry/at-least-once delivery; this wrapper neither retries nor delivers at-least |
| EH-13 | N/A | No external call that can amplify upstream load: a migration opens one connection (NullPool), runs DDL once, disposes (_env.py:467-480, 498-511). No retry budget, no call-rate loop, no  | EH-13 MUST: upstream-amplifying load MUST be bounded (circuit breaker the canonical mechanism). Amplification requires repeated/looping calls against a struggling upstream; a one-shot migration with no retry cannot amplify. There  |

### LOGGING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| LG-01 | ✅ | [verify-upheld] src/mgf/alembic/_drift.py:67 `_LOGGER = logging.getLogger(__name__)` at module scope. grep over src/ returns this as the ONLY getLogger call; no `logging.info\|debug\|wa | Refute attempt failed. The sole logger is acquired hierarchically via __name__ at module scope; the stderr.write path is outside the logging subsystem entirely and is independently warranted (an offline-mode operator notice, SH-02 |
| LG-02 | N/A | The package is a library that runs INSIDE a consumer's alembic env.py (invoked by the alembic CLI); it has no entry point of its own (no __main__, no CLI, no app.run, no service entry — | LG-02 binds 'the application MUST configure logging in exactly one place per entry point.' A library with no entry point has no entry point to configure; configuring root logging from a library would be a defect. The consumer's CL |
| LG-03 | N/A | LG-03's mechanism is 'the standard formatter adds trace_id/span_id automatically.' This package installs no formatter and no handler — it only emits one record (_drift.py:338) into what | The record-emitting site does the right thing (it does not, and cannot usefully, hand-attach trace context). Whether trace_id appears is determined by the consumer's formatter, which is out of this library's surface. No formatter  |
| LG-04 | N/A | Redaction (LG-04) is a formatter/sink responsibility — 'redacted by the formatter before any sink sees them.' This library installs no formatter and no redactor. Separately, the DB-URL  | The library owns no formatter to redact in, so the LG-04 formatter mandate has no in-scope implementation site. Its actual secret-bearing surface (the DB URL) is covered by the SECURITY (SH-01/SH-02) controls, and its one log emis |
| LG-05 | N/A | grep over src/ shows the package emits exactly one log record and it is INFO (_drift.py:338 `_LOGGER.info(...)`). There is no ERROR/exception log site anywhere. detect_drift and configu | LG-05 governs the shape of ERROR-level log records (must carry exc_info). The library logs no ERROR records, so the rule has nothing to bind. The chosen error strategy (propagate the typed exception to the consumer's handler) is c |
| LG-06 | N/A | LG-06 ('logs MUST reach a searchable aggregator; console-only is non-compliant in production') is a deploy-time property of an application/service. This is a library with no process of  | An adapter cannot own where logs land — it runs inside the alembic CLI process, whose owner picks the aggregator. There is no in-scope sink to fault. Per the matrix, library kind takes LG-06's rotating-file branch, but the respons |
| LG-07 | N/A | No GUI. The package is a headless alembic adapter (no PySide6/Qt, no dialogs, no app.run). The per-kind matrix scopes LG-07 to 'gui-app' only. | LG-07 (log-viewer dialog) is explicitly gui-app-only. This library has no GUI surface. Not applicable. |
| LG-08 | ✅ | [verify-upheld] The sole emission, _drift.py:338-340, is `_LOGGER.info("drift detection complete: %s", "clean" if report.is_clean else f"{len(report.all_differences)} diff(s)", extra={. | Refute attempt: I checked whether the f-string makes this an eager-format violation. LG-08 forbids passing an f-string AS THE MESSAGE ('LOG.info(f"processing {x}")'); here the message template is a literal %-template and lazy. The |
| LG-09 | ✅ | [verify-upheld] _drift.py:341-345 passes `extra={"event": "mgf.alembic.drift_detected", "is_clean": report.is_clean, "diff_count": len(report.all_differences)}`. The structured facts (i | Refute attempt failed: the only structured log site follows the extra={} contract exactly, and the keys avoid the reserved-name KeyError trap. No field is buried in the message string. Upheld. |
| LG-10 | N/A | No service / daemon / systemd-timer entry point. The package runs synchronously inside the alembic CLI invocation; it has no long-running headless process and installs no JournalHandler | LG-10 (journald/headless sink at a service entry point) applies to service-kind projects with their own headless entry point. This adapter has none. Not applicable. |
| LG-11 | ✅ | LG-11 requires a start AND end record with a stable `operation` field for any function ≥100 ms OR crossing a process/network/storage boundary. detect_drift (_drift.py:271) crosses a DB  | detect_drift and configure_env open real DB connections and run alembic reflection/migration — a storage/network boundary squarely in LG-11's MUST surface — yet there is no start/end pair with a stable `operation` field (the one r — FIXED 2026-06-08 (0.4.8): the DB-boundary-crossing migration run now logs start+complete with a stable operation=alembic.migrate field (_env.py, both sync+async paths) |
| LG-12 | ✅ | [verify-upheld] The single call site (_drift.py:338) passes a short %-template, a len()-based ternary, and three primitive extra values (str, bool, int). No JSON serialisation, no IO, n | Refute attempt failed: the emission is trivially under the 100 µs budget; there is no per-call serialisation or IO in the library's call site. Upheld. |
| LG-13 | ✅ | [verify-upheld] grep confirms exactly one emission site (_drift.py:338). It fires once per detect_drift() call — a once-per-CI-run operation — not inside a loop, per-object callback, or | Refute attempt failed: there is no high-frequency log site to rate-limit. The lone record is structurally once-per-run and therefore inherently bounded. No counterexample. Upheld. |
| LG-14 | N/A | Correlation-context promotion (request_id/user_id/lab) via contextvars + a promoting formatter is an application-boundary concern. This library sets no correlation ContextVar, owns no f | LG-14 binds entry points that own a correlation (CLI command, HTTP handler, scheduler tick) and the formatter that promotes the contextvars. An adapter with no such boundary and no formatter has no LG-14 surface; if a consumer set |
| LG-15 | ✅ | The only INFO+ record (_drift.py:341-345) DOES carry a stable `event` field in <subject>.<action> form: `event="mgf.alembic.drift_detected"`. But LG-15 also mandates: 'Event names MUST  | The record satisfies the field-presence half of LG-15 (it has a stable, well-formed event name for a plausible alert-target lifecycle event). But the rule is explicit: 'an event name without a docs/reference/EVENTS.md entry is a d — FIXED 2026-06-07: docs/reference/EVENTS.md catalogues mgf.alembic.drift_detected + bucket README |
| LG-16 | N/A | LG-16 binds 'every WARNING and ERROR record.' grep shows the package emits exactly one log record and it is INFO (_drift.py:338); there are zero WARNING/ERROR log records in src/. The o | LG-16's what/why/how contract is scoped specifically to WARNING+ log records (the doc: 'why LG-16 is a MUST at WARNING+ specifically — informational INFO records get a lighter contract'). The library has no WARNING/ERROR record to |
| LG-17 | N/A | LG-17 (stable `fingerprint` on ERROR records) is a SHOULD that binds ERROR records carrying exc_info. The package emits no ERROR records at all (only the one INFO at _drift.py:338) and  | With zero ERROR log sites in the library, there is no record to fingerprint; LG-17 has nothing to bind. Consistent with the rule's own coverage carve-out (no ERROR egress in scope). N/A. |

### CONFIGURATION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| CF-01 | N/A | grep over src/ and tests/ for BaseSettings / pydantic_settings / class Settings / BaseAppSettings returns nothing. The library owns no config schema; configure_env(database_url=..., tar | CF-01 is scoped 'consumer-owned-config'. mgf-alembic is a thin alembic/SQLAlchemy adapter with no config schema of its own — it consumes config the caller passes in. The 'single typed pydantic BaseSettings' rule has no surface her |
| CF-02 | N/A | No layered config sources exist. database_url / url arrive as direct function arguments (_env.py:103, _drift.py:274); there is no CLI, no .env reader, no on-disk config file, no env_set | CF-02 is scoped 'all', but the precedence chain (CLI → env → .env → file → defaults) presupposes the library resolves config from layered sources. mgf-alembic resolves nothing: the one config value (the DB URL) is a required expli |
| CF-03 | N/A | No config schema, hence no version field and no migration chain (grep for BaseSettings/config version field returns nothing in src/). The only on-disk schema this library touches is ale | CF-03 is scoped 'consumer-owned-config'. With no owned config schema there is nothing to stamp with a version or migrate. N/A. |
| CF-04 | N/A | The library writes no config/state file. configure_env runs alembic migrations (DDL against the DB) and offline mode emits SQL to stdout (_env.py:303-319); detect_drift only reads (_dri | CF-04 is scoped 'consumer-owned-config'. Atomic config writes presuppose an owned config file; this library owns none. N/A. |
| CF-05 | ✅ | [verify-upheld] _env.py:37-52 _safe_url masks password via make_url(url).render_as_string(hide_password=True); _env.py:55-84 _safe_error_context substitutes the masked URL in every str  | [verify-upheld] Refute attempt failed. CF-05 (scope 'all') requires secrets not live in the config file / not leak to logs or VCS. The library persists no secret anywhere and actively strips the transient DB password (the only sec |
| CF-06 | N/A | No config file is parsed, so there is no unknown-key surface. configure_env/detect_drift accept a fixed keyword signature; passing an unknown kwarg is a Python TypeError at the call sit | CF-06 is scoped 'consumer-owned-config'. Unknown-key rejection presupposes loading keys from a config file into a typed model; the library does neither. N/A. |
| CF-07 | N/A | No sub-config / satellite files (hooks, schedules, profiles, lab specs) exist or are written by the library. src/mgf/alembic/ contains only _env.py, _drift.py, __init__.py, py.typed; no | CF-07 is scoped 'consumer-owned-config'. There are no satellite config files to apply the typed-model/atomic-write/version shape to. N/A. |
| CF-08 | N/A | No Settings object exists to load-once-and-inject; there is no module-global config singleton in src/ (grep for Settings/singleton returns nothing). Config (the DB URL) is passed as a f | CF-08 is scoped 'consumer-owned-config'. The load-once-at-entry-point / constructor-injection rule presupposes an owned Settings object and an entry point; this adapter runs inside the consumer's alembic env.py and owns no Setting |
| CF-09 | N/A | The library has no CLI of its own — it runs inside the consumer's alembic env.py, invoked by the alembic CLI. No click/argparse entry point or --config flag exists in src/ (grep for cli | CF-09 is scoped 'consumer-owned-config' and presupposes a CLI that takes a --config path. mgf-alembic exposes a Python API, not a CLI, so there is no place for a --config flag. N/A (matches the stated carve-out: no CLI of its own) |
| CF-10 | ✅ | [verify-upheld] Every test drives the library through explicit url=/database_url= values built under tmp_path: tests/unit/test_env.py:118 _build_project(tmp_path, *, url) writes the URL | [verify-upheld] Refute attempt failed. CF-10 (scope 'all') requires tests construct config with explicit values and no env-var leakage. The suite supplies the DB URL entirely via explicit url=/database_url= arguments and tmp_path- |
| CF-11 | N/A | no [project.scripts], no BaseSettings subclass, no config schema; the only os.environ is in a docstring example the consumer writes | CF-11 is scoped 'consumer-owned-config' (CONFIGURATION.md:33); this library owns no config schema/fields to rename. Config enters via configure_env() call args (function params). Premise doesn't bind. |
| CF-12 | N/A | No config field with mutually-exclusive backend variants exists. The sync-vs-async routing in configure_env is selected by URL-prefix heuristic / is_async override (_env.py:329-379), no | CF-12 is scoped 'all' but applies 'wherever the consumer has mutually-exclusive backend variants in their config'. mgf-alembic models no backend-variant config field — the only variance is runtime path dispatch, not a config schem |

### SECURITY_STANDARD

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| SC-01 | ✅ | [verify-upheld] .woodpecker.yml:70-73 secret-scan step runs gitleaks v8.30.1 (`gitleaks detect --source . --no-banner --redact`) on push/pull_request/manual (when: 13-17). grep over src | Refute attempt failed: no committed secrets, gitleaks gates every PR over working tree + history, and the only secret-bearing value (the DB URL) is consumer-supplied and masked at the boundary. MUST met. UPHELD. |
| SC-02 | N/A | grep -rn 'shell=True\|subprocess\|os.system' src/ returns nothing — the library imports no subprocess module and shells out to nothing. | No subprocess invocation surface exists in this alembic adapter, so the argv-only rule has nothing to bind to. |
| SC-03 | N/A | grep -rniE 'yaml\.\|pickle' src/ returns nothing — no YAML/JSON/pickle deserialization of external input. The library passes a consumer-supplied URL + MetaData object to alembic/sqlalch | No deserialization of untrusted data; rule has no binding surface. |
| SC-04 | N/A | The library opens DB connections and hands off to alembic; it writes no config/vault/crash/state/log file of its own (offline mode writes SQL to stdout via the consumer's redirection, n | No private file is written by this library, so the 0o600 + atomic-write MUST has nothing to apply to. |
| SC-05 | N/A | grep -rniE 'md5\|sha1\|random\.\|hashlib\|cryptography\|fernet' src/ returns nothing — the library performs no cryptographic operations. | No crypto primitives are used, so the vetted-crypto MUST is not engaged. |
| SC-06 | N/A | grep -rniE 'verify=False\|CERT_NONE\|AutoAddPolicy' src/ returns nothing. The library makes no outbound HTTP/SSH calls; TLS to the database is negotiated by the DB driver from the consu | No outbound connection the library controls beyond the DB driver it adapts; TLS posture is the driver's + consumer URL's concern. No counterexample (no verify=False) exists. |
| SC-07 | 🚫 | _env.py:467 create_engine(url, poolclass=pool.NullPool) and :469 connectable.connect(), :498 create_async_engine, _drift.py:318 create_engine(url) — none pass a connect/statement timeou | The library owns the engine/connect boundary to the DB but sets no finite connection timeout, so a hung DB host yields an unbounded block through a boundary it constructs. Driver connect defaults are typically infinite. Unmet gap — DECLINED 2026-06-08 (CFM-04 §3): a finite connection timeout is driver- AND URL-specific (psycopg connect_timeout vs asyncpg command_timeout vs aiosqlite); the env-helper cannot set a generic one without owning the driver — it is the consumer's DB-URL/connect_args concern |
| SC-08 | ✅ | [verify-upheld] configure_env (_env.py:101-112) is fully keyword-only (`*`) and type-annotated (database_url:str, target_metadata:MetaData, bool/callable kwargs); pyproject.toml:175 myp | Refute attempt failed: inputs are typed at the public boundary, the one security-relevant decision is allow-list-driven, and the consumer's own env.py is the trust anchor for the URL. MUST met for this shape. UPHELD. |
| SC-09 | ✅ | [verify-upheld] _env.py:50 make_url(url).render_as_string(hide_password=True) redacts the DB password at the source boundary; _safe_error_context (:56-84) rewrites exc.args before re-ra | Refute attempt failed: the one secret that could reach a sink (the URL password) is redacted before any sink sees it, and no raw secret is logged. The library owns no Redactor (that lives in mgf-common) but performs the equivalent |
| SC-10 | ✅ | [verify-upheld] uv.lock committed at repo root (263062 bytes, tracked). .woodpecker.yml:61-67 vuln-scan step runs `pip-audit --strict` on every push/pull_request/manual (when: 13-17). | Refute attempt failed: lockfile present + committed and pip-audit --strict gates every PR. MUST met. UPHELD. |
| SC-11 | ✅ | [verify-upheld] _env.py:56-84 _safe_error_context walks exc.args, replaces the raw URL with the password-masked form, and re-raises preserving the exception TYPE (:64-67 docstring; test | Refute attempt failed: the only secret that could ride exc.args (the URL password from SQLAlchemy/driver errors) is scrubbed at the translation seam before re-raise. MUST met. UPHELD. |
| SC-12 | ✅ | [verify-upheld] SECURITY.md present at repo root: supported-versions table (lines 17-21), security contact bassam@magogi.org + Codeberg private advisory (27-31), disclosure timeline tab | Refute attempt failed: root SECURITY.md present with supported versions, contact, embargo, and disclosure timeline — every required section. MUST met. UPHELD. |
| SC-13 | N/A | No cryptographic keys exist in the library (SC-05 grep clean); nothing is stored at rest by this adapter. | No keys at rest, so the KDF/keyring MUST has no binding surface. |
| SC-14 | N/A | The library performs no authentication of its own — DB authentication is handled by the driver against the consumer-supplied URL. No auth boundary, no failure-message surface, no rate-l | No authentication surface owned by this adapter; the enumeration/backoff MUST does not apply. |
| SC-15 | N/A | No filesystem path is constructed from external input. The only path-shaped values are inside consumer-supplied SQLite URLs (sqlite:///...), parsed by sqlalchemy/the driver, not joined  | No external-input-derived path the library resolves; the traversal MUST has no binding surface. |
| SC-16 | N/A | grep for sudo/setuid/privileged/capability over src/ returns nothing; the library runs entirely in-process inside the consumer's alembic env.py with no privilege escalation. | No privileged operation surface, so the narrow-audited-surface MUST does not apply. |
| SC-17 | ✅ | _env.py:276-285 explicitly documents that migration runs go through standard alembic stdout and the wrapper does NOT emit structured INFO records with audit=true (SH-03, tracked follow- | Security-relevant DB-connection/migration actions emit no audit=true structured record; the library itself states this is a deferred follow-up, not a deliberate decline. Unmet gap (⏳). — FIXED 2026-06-08 (0.4.8): online migration runs now emit an audit=true structured record (event mgf.alembic.migration_run, _env.py) — the schema-changing action is on the audit trail |
| SC-18 | ✅ | .woodpecker.yml header (lines 5-6) states 'No publish flow yet'; the pipeline has lint/typecheck/test-matrix/vuln-scan/secret-scan steps only — no build, no twine check, no SBOM (cyclon | No reproducible-build verification or SBOM is produced in CI for a published package; unmet publish-chain gap (⏳), consistent with the project-shape note that absent publish-chain machinery is ⏳ not N/A. — FIXED 2026-06-07: .woodpecker sbom step generates a reproducible CycloneDX SBOM (dist/mgf-alembic.cdx.json) for the published wheel |

### TESTING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| TS-01 | ✅ | src/mgf/alembic/ has 3 modules: _env.py, _drift.py, __init__.py (leading-underscore-private, re-exported via __init__). tests/unit/ has test_env.py (mirrors _env.py) + test_drift.py (mi | tests/ mirrors src/ 1:1 within the two non-trivial private modules; the re-export __init__ falls under the documented shim exemption. No CI mirror-lint step exists, but with only 2 source modules each mirrored, the mirror itself h |
| TS-02 | ✅ | Unit suite (test_env.py, test_drift.py) uses only sqlite:///{tmp_path} and sqlite+aiosqlite:///{tmp_path}; aiosqlite is in [test]/[dev]. Real-Postgres tests live in tests/integration/te | [verify-upheld] Tried to refute: searched for any prod cred/network/daemon reachable by default. The Postgres _PG_URL is only touched inside _pg_available() under skipif and the integration module skips entirely when unreachable.  |
| TS-03 | ✅ | All DB files via tmp_path (test_env.py/test_drift.py passim). context.configure spies via monkeypatch.setattr (test_env.py:436,469); create_engine swap via monkeypatch.setattr (test_dri | [verify-upheld] Tried to refute: searched for sys.excepthook/logging-handler/global mutation without save-restore, and for order dependencies. All env/global mutation goes through monkeypatch (auto-restored) or tmp_path. The proce |
| TS-04 | ✅ | pyproject.toml [tool.pytest.ini_options]: filterwarnings = ["error"]. Per-test relaxation done correctly via @pytest.mark.filterwarnings('ignore::pytest.PytestUnraisableExceptionWarning | [verify-upheld] Tried to refute: verified the literal string is present and is a list with exactly 'error'. The two relaxations use the sanctioned @pytest.mark.filterwarnings escape hatch named in the MUST, narrowly scoped to the  |
| TS-05 | ✅ | pyproject.toml addopts list includes '--strict-markers' and '--strict-config' verbatim. | [verify-upheld] Tried to refute: confirmed both flags are present in the addopts array (not commented, not typo'd). Both flags present verbatim. Met. Upheld. |
| TS-06 | ✅ | [tool.coverage.run] source=['src/mgf/alembic'], branch=true. [tool.coverage.report] exclude_lines + fail_under=80. .woodpecker.yml test-3.12 step runs pytest with --cov=src/mgf --cov-re | The ≥80% project floor is wired (fail_under=80 + --cov on the 3.12 CI job). The ≥90%-changed-lines PR clause is not separately enforced (no per-PR diff-coverage step), but the binding TS-06 gate (≥80% every CI job) is met and beha |
| TS-07 | N/A | grep of src shows mgf-alembic defines no typed exception subclasses of its own — it raises stdlib RuntimeError/ValueError (the RA-01 running-loop guard at _env.py:348, and re-raises in  | TS-07 binds 'every typed exception MUST have a unit test'. This adapter authors no typed exceptions, so there is nothing to pin. The messages it DOES raise (RA-01 RuntimeError) are nonetheless tested (test_env.py:644-651). N/A by  |
| TS-08 | N/A | No EH-02 translation seam exists in src. _safe_error_context (_env.py:57-84) re-raises the SAME exception type with the URL masked — it is a redaction wrapper, not a vendor-error→typed- | TS-08 binds translation seams (EH-02). This library does not translate third-party errors into typed exceptions; it lets alembic/sqlalchemy errors propagate (only masking credentials). No seam → nothing to test. N/A by shape. |
| TS-09 | N/A | No EH-10 'best-effort observer' loop in src — no iteration over registered observers/callbacks that must continue past a raising member. The closest is the include_object filter pass-th | TS-09 binds best-effort observer loops (EH-10). This adapter has no such loop of its own. N/A by shape. |
| TS-10 | ✅ | SECURITY surface = DB-connection + drift-introspection credential handling. The security-relevant behaviour (password must never leak in an exception message — SH-01) is pinned with neg | The mechanically-pinnable security rule for this adapter (credential masking on the connect/introspect path) has negative-case pin tests; CI adds gitleaks/pip-audit. The generic SC-01..SC-18 grep-pin shapes mostly don't apply to t |
| TS-11 | N/A | No GUI/PySide6 surface; no QThread/QObject workers in src. The library runs inside alembic's CLI process. | Carve-out: no GUI. TS-11 GUI-worker tests are N/A by shape. |
| TS-12 | ✅ | pytest-asyncio>=0.23 in [dev]; asyncio_mode='strict' + asyncio_default_fixture_loop_scope='function' (pyproject.toml). Coroutines in src: run_async_migrations and the inner async run pa | [verify-upheld] Tried to refute: enumerated coroutines in src and looked for an untested one. run_async_migrations is tested directly (awaited from a running loop), the async dispatch is tested both through the public awaitable an |
| TS-13 | N/A | No Hypothesis dependency; no round-trip parse/serialise/encode/decode data path in src. _safe_url masks a URL (one-way redaction, not a reversible round-trip). No _strategies.py module  | TS-13 binds code that round-trips data. This adapter has no such surface — its 'round-trips' are alembic migration upgrade/downgrade DDL, exercised by example-based unit tests (TestSyncDriver/TestAsyncDriver), which is the appropr |
| TS-14 | ✅ | tests/perf/test_configure_env_overhead.py marks TestConfigureEnvOverhead @pytest.mark.perf (registered in pyproject.toml markers) and is default-excluded via addopts -m 'not perf ...'.  | The perf budget is pinned by a benchmark on the real production code path, marked perf, and excluded from the per-PR default — matching TS-14/PF-02. The budget is a generous regression cushion, not a tight absolute wall-clock valu |
| TS-15 | N/A | No real-backend smoke tests against live external systems. The Postgres tests in tests/integration/ are skipif-gated (not the §12 read-only-against-live pattern with a dedicated live/re | TS-15's §12 'smoke against real external backend' pattern (separate live/realbackend marker, read-only) has no instance here. The Postgres integration tests that touch a real DB are skip-gated and self-cleaning, which honors the s |
| TS-16 | ✅ | Context-carrying asserts throughout: test_env.py:495-497 (_safe_url did not mask the password: {safe!r}), :547-549 (left the password in the message: {msg!r}), :644-651 (RA-01 message n | [verify-upheld] Tried to refute: scanned for bare ambiguous asserts. The bare asserts that exist (e.g. test_drift.py:32-33 'No drift detected' in summary, async-prefix membership checks) are self-evident from the literal expected  |
| TS-17 | ✅ | find returned NO conftest.py anywhere in the repo. Every fixture used is a pytest builtin (tmp_path, monkeypatch, capsys) or a local in-file fixture (e.g. unique_table in test_postgres_ | [verify-upheld] Tried to refute: searched for conftest files and for fixture imports across test modules. None found. The MUST forbids importing fixtures across test packages and requires conftest-hierarchy discovery; with only bu |
| TS-18 | ✅ | 'slow' marker registered (pyproject.toml markers) and default-excluded via addopts -m 'not perf and not slow and not stress and not e2e and not conformance and not use_case'. The genuin | [verify-upheld] Tried to refute: looked for an unmarked >1s unit test polluting the fast default. The unit tests are sub-second sqlite round-trips; the one slow default-suite test is the smoke self-check (smoke layer, packaging pr |
| TS-19 | ✅ | pyproject.toml registers the full federation taxonomy under [tool.pytest.ini_options].markers: smoke, e2e, integration, contract, property, regression, fuzz, concurrency, conformance, u | [verify-upheld] Tried to refute: cross-checked every @pytest.mark.* used in the test tree against the registered set. All used markers (smoke, integration, perf, plus asyncio from pytest-asyncio) are declared. Exact MUST met under |
| TS-20 | ✅ | tests/ partitioned into unit/, integration/, smoke/ (plus perf/). tests/integration/test_postgres_migrations.py applies module-level pytestmark=[integration,...]; tests/smoke/test_mtest | Tests are partitioned across the canonical directories with the matching top-level pytestmark per layer (TS-20 SHOULD). The e2e/ directory is absent but TS-20 requires the partition only for the layers that have tests; an extra pe |
| TS-21 | ✅ | tests/smoke/ contains only test_mtest_self_check.py, which verifies the test SUPERVISOR self-check (a ~31s subprocess run), NOT the TS-21 smoke contract: (a) the package imports, (b) ea | mgf-alembic is a published library (0.4.7), so TS-21 applies (not the CLI/desktop skip). The existing smoke test is a supervisor self-check (~31s), the opposite of the <100ms post-install import/__all__/happy-path pre-flight TS-21 — FIXED 2026-06-08 (0.4.8): tests/smoke/test_imports_smoke.py (fast canonical smoke — import + __all__ reachability) |
| TS-22 | ✅ | mgf-test-supervisor>=0.1.3 in [dev] provides --tier/--budget tiered runs. Markers carry tier annotations in pyproject.toml (smoke '...; tier-0', perf '...; tier-3', contract/property/re | [verify-upheld] Tried to refute: checked whether the four-tier marker→tier mapping is actually declared and whether tier classification is evidenced. The mapping is in every marker's description and run.jsonl shows a real tier:0 c |
| TS-23 | ✅ | mgf-test-supervisor (pyproject.toml [dev]) runs pytest as an out-of-process subprocess; the smoke test itself shells out via subprocess.run([sys.executable,'-m','mgf.test_supervisor','- | [verify-upheld] Tried to refute: TS-23's four outcomes — (1) crash recorded as structured outcome (subprocess survives), (2) hang bounded with thread dump (pytest-timeout thread + faulthandler), (3) per-failure single-file assembl |
| TS-24 | ✅ | .gates/last-run/run.jsonl is one JSON object per line with exactly: test_id, outcome, severity, duration_ms, tier, markers, code, summary, detail, why, remediation, captured_stdout, cap | [verify-upheld] Tried to refute: read the actual run.jsonl line and checked every mandated field including the mandatory schema_version. All present, one-object-per-line, schema mirrors DoctorFinding + testing fields. The importab |
| TS-25 | ✅ | .gates/quarantine.json exists with valid JSON ({} — empty, no flakes yet). mgf-test-supervisor (pyproject.toml [dev]) provides the sliding-window quarantine + --quarantine-attempt/--no- | [verify-upheld] Tried to refute: checked the quarantine state file exists and is valid, and that the mechanism (not just the file) is present via the adopted supervisor. TS-25 is L2 (L1 MAY defer); the mechanism is fully wired wit |
| TS-26 | N/A | mgf-alembic is pure Python (src/mgf/alembic/*.py only; no Zig/Go/Rust/C/Swift compiled artifact, no build extension). pyproject build-system is hatchling, wheel ships src/mgf/ Python on | TS-26 explicitly allows pure-Python libraries to declare it N/A (no compiled artifacts → no freshness check). N/A by shape. |
| TS-27 | ✅ | .gates/last-run/failures/ directory exists (empty — last run had no failures; run.jsonl shows the smoke test passed). The per-failure bundle is written by mgf.test_supervisor.supervisor | [verify-upheld] Tried to refute: checked the failures/ sink exists and the DIAGNOSING_HANGS.md playbook exists. Both present; the directory is empty only because the recorded run had zero failures. The single-file-per-failure mech |
| TS-28 | ⏳ | No evidence of --perf / MGF_PERF=1 perf-attribution capture wired in this repo: run.jsonl is schema_version='1.0.0' (TS-28 requires TestRecord.perf at schema ≥1.1.0), there is no perf-s | TS-28 is L2 (L1 MAY defer). The capability is not evidenced: the run record is schema 1.0.0 (not the ≥1.1.0 that carries the perf field), no perf-summary.md, no perf_span instrumentation. As an unmet capability (not a deliberate d |

### API_DESIGN

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| AP-01 | ✅ | src/mgf/alembic/__init__.py:61 __all__ = ["DriftReport", "configure_env", "detect_drift", "run_async_migrations"] (alphabetically sorted, string literals); _env.py:554 __all__ = ["confi | Refute attempt FAILED. Read the literal AP-01 MUST: enumerate via __all__ at every package/module boundary, sorted, strings only, verified in tests. Verified each __all__ is a string-literal list, the package list is alphabeticall |
| AP-02 | ✅ | configure_env docstring _env.py:113-286 (full NumPy Parameters block, code-block example, Notes); run_async_migrations _env.py:524-542 (intent + when-to-use + pairing); detect_drift _dr | Refute attempt FAILED. AP-02 MUST: every public name has a docstring stating intent, invariants, and at least one usage example; no 'returns the X' stubs. All four public names (configure_env, run_async_migrations, detect_drift, D |
| AP-03 | ✅ | pyproject.toml:3 version = "0.4.7" (MAJOR.MINOR.PATCH). CHANGELOG.md:6-13 invokes SemVer + the 0.x clause ('MINOR releases MAY break the public API. Pin tightly'). CHANGELOG history: 0. | Refute attempt FAILED. AP-03 MUST: follow SemVer; in 0.x window MINOR may break. Verified version string is MAJOR.MINOR.PATCH, the CHANGELOG explicitly cites the SemVer 0.x clause, and the release lineage maps additions to MINOR a |
| AP-04 | N/A | grep for DeprecationWarning/deprecated across src/ returns no matches. CHANGELOG has no [Deprecated] entries; no public name has ever been renamed or removed (lineage is additions + pin | AP-04 governs the deprecation cycle. No deprecations exist in the library to date — nothing has been announced, survived, or removed — so the rule has no surface to apply against. N/A (not a gap: there is nothing to deprecate). |
| AP-05 | ✅ | configure_env _env.py:101-112 opens with bare * (line 102) making every param keyword-only; is_async/transaction_per_migration appended kw-only with defaults (lines 110-111). run_async_ | Refute attempt FAILED. AP-05 MUST: new optional params keyword-only with defaults; no new required params. Every public function begins with bare * so all params are keyword-only; the two params added post-initial-shape (is_async, |
| AP-06 | ✅ | configure_env/run_async_migrations -> None (_env.py:112, :523); detect_drift -> DriftReport (_drift.py:276), a frozen dataclass (_drift.py:76). DriftReport fields are concretely typed t | Refute attempt FAILED. AP-06 MUST: return types MUST NOT narrow in non-MAJOR (and widening is subtly breaking); pin contracts narrowly. Contracts are pinned narrowly: None, concrete DriftReport (frozen dataclass), tuple[str, ...]  |
| AP-07 | ✅ | Public functions raise bare stdlib RuntimeError: _env.py:348 raise RuntimeError(...) (running-loop guard in configure_env). detect_drift _drift.py:307-312 documents 'Raises: Exception'  | AP-07 MUST: exceptions raised by public functions MUST be documented AND be subclasses of the project's typed hierarchy. The running-loop failure raises a bare RuntimeError, not a subclass of mgf-common's AppError, even though mgf — FIXED 2026-06-08 (0.4.8): PUBLIC_API.md §Exceptions documents the typed OperationError raised by configure_env/run_async_migrations |
| AP-08 | ✅ | from __future__ import annotations at __init__.py:56, _env.py:19, _drift.py:52. Type-only imports fenced under if TYPE_CHECKING: (_env.py:29-34 Callable/Iterator/Connection/MetaData; _d | Refute attempt FAILED. AP-08 MUST (substantive requirement): public modules use from __future__ import annotations; runtime-unused imports in TYPE_CHECKING. Verified the future-annotations import is present in all three modules an |
| AP-09 | ✅ | src/mgf/alembic/py.typed exists as a 0-byte marker at the package root (ls -la confirms size 0). pyproject.toml:33 declares 'Typing :: Typed' classifier. Wheel target pyproject.toml:106 | Refute attempt FAILED. AP-09 MUST: a PEP 561 py.typed marker MUST exist for any package shipping type annotations. Verified the marker file is physically present at the package root and the hatchling wheel target packages src/mgf, |
| AP-10 | ✅ | PUBLIC_API.md exists at repo root (3341 bytes) with a tier column and contract prose. BUT it lists only one name in its table: configure_env. The other three public names in __all__ — d | AP-10 MUST: PUBLIC_API.md MUST list EVERY public name with tier + one-line description AND stay in sync with __all__ via a CI check. The doc exists and is well-formed but is out of sync — 3 of 4 __all__ names are missing rows, and — FIXED 2026-06-08 (0.4.8): PUBLIC_API.md now lists every public name (DriftReport/detect_drift/run_async_migrations added) + md↔__all__ CI pin |
| AP-11 | ✅ | PUBLIC_API.md declares a Tier column and marks configure_env 'experimental'; _drift.py:6 docstring states 'Stability tier: experimental (AP-11)'. BUT detect_drift, DriftReport, run_asyn | AP-11 MUST: stability tiers MUST be declared per public name. A tier vocabulary and column exist and configure_env + the drift module carry tier markers, so the mechanism is present — but tiers are not declared for every public na — FIXED 2026-06-08 (0.4.8): every public name now carries a stability tier in PUBLIC_API.md |
| AP-12 | N/A | CHANGELOG.md follows Keep a Changelog (line 5) with [Unreleased] + per-release sections. No release in the lineage is a breaking change requiring a migration recipe (all entries are add | AP-12 MUST: breaking changes MUST carry migration recipes (symptom/before/after/why). The format scaffolding is present and correct, but there has been no breaking change to date that triggers the recipe requirement. Nothing to mi |
| AP-13 | ✅ | grep -rn '__version__' across src/ and tests/ returns NO matches. src/mgf/alembic/__init__.py has no __version__ attribute. pyproject.toml:3 has version='0.4.7' but it is not mirrored o | AP-13 MUST: a __version__ attribute MUST be present on the top-level package and mirror pyproject.toml::project.version, with a CI sync lint. The package exposes NO __version__ at all, and there is no in-sync pin test. This is a c — FIXED 2026-06-08 (0.4.8): mgf.alembic.__version__ + CI tag-coherence assertion |
| AP-14 | 🚫 | All implementation lives in single-underscore-prefixed modules (_env.py, _drift.py) re-exported through __init__.py — the closed-box layout the rule wants. import-linter>=2.0 is a decla | AP-14 MUST: internal _-modules MUST NOT be consumer-imported, AND CI MUST enforce via import-linter that tests/consumers only touch the public surface. The source layout honours the convention and the tool is installed, but no imp — DECLINED 2026-06-08 (CFM-04 §3): import-linter consumer-fixture enforcement needs an in-repo consumer harness this env-helper lacks; closed-box (_ modules + complete __all__/PUBLIC_API.md + public-surface smoke) satisfies the intent |
| AP-15 | N/A | No backward-compatibility shim modules exist (grep for DeprecationWarning/deprecated in src/ returns nothing; no re-export-from-old-location modules; the only modules are __init__.py, _ | AP-15 governs back-compat shims that survive removal of original code (must emit DeprecationWarning + INFO audit log once/process). This library ships no shims — nothing has been moved or renamed yet. The rule has no surface to ap |
| AP-16 | ✅ | pyproject.toml pins the cornerstone with the federation window `mgf-common>=0.41,<1.0` (floor kept, ceiling <1.0 per API_DESIGN §4.4); the mandatory compatibility matrix runs in CI as the `mgf-common-matrix` step (.woodpecker.yml:201), exercising the suite against the declared floor (devpi-clamped to `mgf-common==0.44.*`, the oldest series the index serves). | Adopted in the AP-16 cohort wave (item1b runbook, 2026-07-01); ledger row added when the rule entered the released MUST index (mgf.standard 0.1.61 reconciled the count 264→265). |

### SCOPE

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| SP-01 | ✅ | No SCOPE.md or explicit IN-scope list anywhere in the repo (find -iname '*scope*' returns nothing; grep for 'in-scope/adjacent' over all non-standards .md finds only SECURITY.md vuln-di | SP-01 MUST: publish an explicit IN-scope list (the bar new modules clear). The premise binds: mgf-alembic is a published mgf-* package at L2 conformance (README.md:111), so every federation MUST applies; SCOPE rules are documentat — FIXED 2026-06-07: SCOPE.md §1 |
| SP-02 | ✅ | No OUT-of-scope module list with reasoning exists. SECURITY.md:68-79 has an 'Out of scope' block but it is vulnerability-disclosure scope (which deps to report where), not a scope-polic | SP-02 MUST: publish an explicit OUT-of-scope list with per-entry reasoning ('why we don't ship X' + 'what to use instead'). No such list exists. Smallest fix: add an OUT-of-scope table to SCOPE.md/README naming the natural adjacen — FIXED 2026-06-07: SCOPE.md §2 |
| SP-03 | ✅ | CONTRIBUTING.md:31-47 ('Process') and the PR checklist (CHANGELOG entry, PUBLIC_API delta) contain NO scope-creep review question. No mention of 'justify against IN scope / Adjacent' in | SP-03 MUST: every PR adding a new module/top-level function MUST justify against the IN-scope or Adjacent list. The contributor process imposes no such gate, and the lists it would reference do not exist. Smallest fix: add a line — FIXED 2026-06-07: SCOPE.md §3 |
| SP-04 | ✅ | No Adjacent-scope list exists, hence no documented promotion criterion / consumer-demand signal anywhere. FEEDBACK.md:39-44 records 'No papers filed against this sibling yet' and FEEDBA | SP-04 MUST: Adjacent-scope items require a documented consumer-demand signal before promotion to IN. Absent any published Adjacent list or demand-signal rule, the MUST is unmet. Smallest fix: add an Adjacent section to SCOPE.md wi — FIXED 2026-06-07: SCOPE.md §4 |
| SP-05 | ✅ | Because no OUT-of-scope module list exists (SP-02), no ecosystem-alternative citations are present for scope cuts. The only 'use X instead' pointers in the repo are SECURITY.md:70-79 (r | SP-05 MUST: every OUT-of-scope cut MUST cite the ecosystem alternative. This is contingent on SP-02's list existing; since it does not, the citation requirement is also unmet. Smallest fix: when adding the OUT list (SP-02), attach — FIXED 2026-06-07: SCOPE.md §5 |
| SP-06 | ✅ | No scope policy exists to revisit, and nothing in CHANGELOG.md, CONTRIBUTING.md release flow (CONTRIBUTING.md:50-53), or a 'Versioning of this document' table records a scope-revisit ob | SP-06 MUST: scope policy MUST be revisited on every MAJOR release (the only place a previously-IN item may be removed, per AP-04 deprecation). With no SCOPE.md there is no policy and no revisit discipline recorded. Smallest fix: i — FIXED 2026-06-07: SCOPE.md §6 |

### WORKFLOWS

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| WF-01 | ✅ | [verify-upheld] .woodpecker.yml:13-16 `when: - event: push - event: pull_request - event: manual`. Verified by re-reading the file: the trigger block triggers on every push and every pu | [verify-upheld] UPHELD. The workflow-file half of WF-01 (trigger on push + PR) is concretely met at lines 13-16. The platform-side branch-protection half is not verifiable from the repo, as the original verdict already conceded. N |
| WF-02 | ✅ | Three of four gates are CI-enforced: lint (.woodpecker.yml:25 `ruff check src tests`), typecheck (line 33 `mypy`), test (lines 44/51/58 `pytest`). The fourth gate, import-linter (`lint- | Partial. WF-02 names four gates (lint/typecheck/test/import-linter) as the contract. Three run in CI; the import-linter gate is not wired even though the tool is a declared dev dep — a 3-module leaf-private library could legitimat — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-03 | ✅ | No tag-driven publish workflow exists. .woodpecker.yml has only `when: [push, pull_request, manual]` (lines 13-16) and seven non-publishing steps. No `event: tag` trigger, no upload ste | Gap, not N/A. The package is published (0.4.7) so the tag-driven publish MUST applies; its absence is an unmet requirement → ⏳ per the publish-chain rule. The maintainer self-documents the gap, confirming a pending TODO rather tha — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-04 | ✅ | No publish step, hence no `codeberg_package_token` / `from_secret` / TWINE_* reference in .woodpecker.yml (grep of file shows none). No token is hard-coded anywhere — but the rule's sub | Gap, not N/A. As a published mgf-* package the token-in-secret-store requirement applies once a publish chain exists; since the chain is absent (WF-03), this is an unmet gap, not a deliberate decline → ⏳. — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-05 | ✅ | No tag-coherence check in .woodpecker.yml — no publish workflow at all (header comment lines 4-6: 'No publish flow yet'). The mechanical TAG_VERSION vs pyproject.toml::version vs __vers | Gap, not N/A. WF-05 is a property of the publish workflow; with no publish workflow the coherence gate cannot run, so the requirement is unmet for a package that does publish → ⏳. — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-06 | ✅ | No build/upload steps in .woodpecker.yml; nothing builds or uploads a wheel in CI. No `uv build`, no `twine upload`, no `dist/` reference. The 'wheel uploaded MUST be the one built in t | Gap, not N/A. Published mgf-* package → the CI-built-wheel-only rule applies once a publish run exists. Its absence is an unmet requirement → ⏳. — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-07 | ✅ | No pre-publish smoke step in .woodpecker.yml — no ephemeral-venv install of a freshly-built wheel, no `import mgf.alembic; assert __version__` smoke. Tests run against the source tree o | Gap, not N/A. The wheel-smoke requirement applies to this published package; absent because there is no publish workflow → ⏳. — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-08 | ✅ | No post-publish verify step in .woodpecker.yml — no poll of the Codeberg REST API `…/api/v1/packages/magogi-admin/pypi/mgf-alembic/<version>` for 200. No publish flow exists to verify ( | Gap, not N/A. Post-publish verification applies to a published mgf-* package; absent → ⏳. — FIXED 2026-06-07: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + .importlinter closed-box + lint-imports in CI + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-09 | ✅ | [verify-upheld] Re-read + grep confirm every external image is pinned: .woodpecker.yml:21,29,47,62 `python:3.12-slim`; line 40 `python:3.11-slim`; line 54 `python:3.13-slim`; line 71 `z | [verify-upheld] UPHELD. WORKFLOWS §7.1 explicitly accepts rolling-minor `python:3.X-slim` ('Most projects accept rolling-minor for the security-update benefits'), and the plugin image (gitleaks) is pinned to exact patch v8.30.1 as |
| WF-10 | ✅ | [verify-upheld] Re-read + grep confirm zero `depends_on:` in .woodpecker.yml (`grep depends_on` → NONE found). All seven steps (lint, typecheck, test-3.11, test-3.12, test-3.13, vuln-sc | [verify-upheld] UPHELD. WF-10 requires independent steps to fan out in parallel and reserves serial ordering for genuine dependencies (build→publish, smoke→upload) — none of which exist here yet (no publish chain). The Python-vers |
| WF-11 | ✅ | uv.lock is checked into the repo (`ls uv.lock` → 263 KB present, dated Jun 4). Each step runs in a pinned `python:X-slim` container (WF-09) and does an isolated `pip install` (.woodpeck | Met for a non-publishing CI. A run is reproducible from its inputs: pinned images + checked-in lockfile + hermetic in-process DB tests. Minor weakness (not disqualifying): CI installs from `pyproject.toml` via `pip install -e ".[d |
| WF-12 | ✅ | [verify-upheld] Re-read + grep confirm zero `\|\| true` in .woodpecker.yml (`grep '\|\| true'` → NONE found). Each gate runs its exact command bare so a non-zero exit fails the step lou | [verify-upheld] UPHELD. No error-swallowing and no no-op green ticks: every step's exact command is visible in the workflow file, exit codes propagate to the platform UI, and per-step containers surface failures individually. No ` |
| WF-13 | ✅ | .woodpecker.yml opens with "GENERATED — do not hand-edit. Source: mgf-standard/templates/woodpecker/" header; generated artifact managed by mgf-fed, never patched in place. | |

### RELEASING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| REL-01 | ✅ | git for-each-ref / git cat-file -t: v0.2.0..v0.4.6 are annotated tags (objecttype=tag); v0.4.7 is a LIGHTWEIGHT tag (objecttype=commit, points directly at cf29527 'release: mgf-alembic  | Not among the 4 challenged ✅ verdicts; carried unchanged. The latest release (0.4.7) violates REL-01's annotated-tag requirement — it is a lightweight tag — so REL-01 is a gap. (This does NOT refute REL-02, whose annotated-tag cla — FIXED 2026-06-07: lightweight v0.4.7 re-annotated on commit cf29527 + force-pushed (authorized); type=tag |
| REL-02 | ✅ | [verify-upheld] CHANGELOG.md headers are all distinct versions (0.4.7→0.4.6→0.4.5→0.4.4→0.4.3→...→0.1.0); no duplicate version string (grep of '^## \[' shows each once). No dist/ direct | [verify-upheld] Attempted refutation found the v0.4.7 lightweight-tag defect, but that is a REL-01 concern (annotated-tag requirement), NOT a REL-02 violation — REL-02 forbids reusing a version string across different wheel conten |
| REL-03 | N/A | Not among the 4 challenged ✅ verdicts; out of scope for this refute pass. | Refute pass covered only REL-02/04/05/07; REL-03 carried as not-evaluated in this pass. |
| REL-04 | ✅ | [verify-upheld] .woodpecker.yml has NO publish step: header lines 5-6 say 'No publish flow yet — when a release is cut, copy the ... publish ... chain from mgf-common.' grep for token/t | [verify-upheld] Tried to find a token committed to the workflow, env vars, or a token file — none exist. REL-04 forbids tokens in chat/shell-history/unmanaged env vars and in the workflow file; the publish step that would carry th |
| REL-05 | ✅ | [verify-upheld] CHANGELOG.md shows a strictly version-monotone history (0.1.0→...→0.4.7), each a NEW version: e.g. 0.4.4 'carrying the previously-unpublished 0.4.3 work', 0.4.6 'PATCH:  | [verify-upheld] Attempted to find a same-version content swap or a rewritten prior release — none in the checkout. Every fix advanced the version number rather than rewriting a published one, which is exactly REL-05's prescribed b |
| REL-06 | N/A | Not among the 4 challenged ✅ verdicts; out of scope for this refute pass. | Refute pass covered only REL-02/04/05/07; REL-06 carried as not-evaluated in this pass. |
| REL-07 | ✅ | [verify-upheld] FEEDBACK.md §2: 'No papers filed against this sibling yet.' (lines 41-44). The only other content is §3 reviewer meta-feedback from vm-vmanager-app dated 2026-05-18, whi | [verify-upheld] Tried to find an OPEN/ACCEPTED/SCHEDULED FEEDBACK entry the 0.4.7 release shipped but failed to flip to ✅ SHIPPED — none exists. With zero shippable FEEDBACK entries, REL-07's 'close every FEEDBACK entry it ships'  |
| REL-08 | N/A | Not among the 4 challenged ✅ verdicts; out of scope for this refute pass. | Refute pass covered only REL-02/04/05/07; REL-08 carried as not-evaluated in this pass. |
| REL-09 | N/A | Not among the 4 challenged ✅ verdicts; out of scope for this refute pass. | Refute pass covered only REL-02/04/05/07; REL-09 carried as not-evaluated in this pass. |

### PACKAGE_DISTRIBUTION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| PKG-01 | ✅ | [verify-upheld] pyproject.toml:42-46 [project.dependencies] (mgf-common, mgf-sqlalchemy) + 87-95 ([[tool.uv.index]] codeberg-mgf url=.../magogi-admin/pypi/simple/ explicit=true; [tool.u | RESOLVE side is conformant: every direct mgf-* dependency is mapped to the Codeberg index via [tool.uv.sources], so mgf-* resolve from Codeberg, not pypi.org; third-party deps (alembic, aiosqlite, psycopg2) correctly stay on publi |
| PKG-02 | ✅ | [verify-upheld] pyproject.toml:89 url = "https://codeberg.org/api/packages/magogi-admin/pypi/simple/" — exact §3 canonical simple-index endpoint. No other registry endpoint string appea | The single registry endpoint the project commits is the canonical simple-index URL from §3, character-for-character (no hand-typed variant, correct trailing slash, correct magogi-admin path). Refute attempt: searched for upload (. |
| PKG-03 | ✅ | .woodpecker.yml has no publish step and no codeberg_package_token / write:package / read:package secret reference (steps: lint, typecheck, test-3.11/3.12/3.13, vuln-scan, secret-scan on | No token discipline surface exists to evaluate because there is no publish flow. The PKG-03 Codeberg-token model (write:package release/CI token, read:package consumer token, REL-04 storage) is neither configured nor documented; t — FIXED 2026-06-07: the publish step uses the codeberg_package_token (write:package) secret-token model via from_secret, tag-event-scoped — no pypi.org, no OIDC |
| PKG-04 | ✅ | .woodpecker.yml header comment (lines 4-6): "No publish flow yet — when a release is cut, copy the tag-coherence -> smoke -> publish -> verify-pypi chain from mgf-common." No build/twin | The strictly-ordered Codeberg publish ritual (gates->build->twine check->upload-to-Codeberg->REST verify->tag->push) is not implemented in CI, and the documented manual flow targets generic twine (the comment even still says 'veri — FIXED 2026-06-07: the tag-gated build→...→publish chain is the ordered Codeberg publish ritual |
| PKG-05 | ✅ | .woodpecker.yml:4-6 references a yet-to-be-copied "verify-pypi" chain; no verify-codeberg step exists. No REST verification (GET .../api/v1/packages/magogi-admin/pypi/<name>/<version>)  | Post-publish verification against the Codeberg REST API is absent; the only verification the repo references is the not-yet-implemented 'verify-pypi' step inherited from the old shape. No Codeberg 200-check gate exists. Unmet -> ⏳ — FIXED 2026-06-07: the verify-codeberg step polls the Codeberg REST API post-publish |
| PKG-06 | ✅ | [verify-upheld] pyproject.toml:87-90 [[tool.uv.index]] name='codeberg-mgf', url=canonical simple index, explicit=true; 92-95 [tool.uv.sources] mgf-common / mgf-sqlalchemy / mgf-test-sup | This is the canonical §6 dependency-confusion-safe shape: named explicit index + per-package [tool.uv.sources] mapping. Refute attempt — 'map AND declare direct': mgf-common and mgf-sqlalchemy are direct deps (pyproject.toml:43-44 |
| PKG-07 | N/A | No publish/re-upload tooling, release session script, or delete-and-re-upload procedure in the repo (.woodpecker.yml has no publish step; scripts/ holds only an empty __init__.py). | PKG-07 governs the conduct of a delete+re-upload recovery during a release session against the Codeberg registry. With no publish flow present, there is no recovery surface to conform or violate, and nothing in the repo asserts ve |
| PKG-08 | N/A | No retention/prune script, no quota-tracking job, no DELETE-based pruning anywhere in the repo. scripts/ contains only scripts/__init__.py (empty). | Retention against the magogi-admin account quota is a registry-owner / federation-level operational policy (a scheduled storage-vs-quota report + prune), not something a single thin leaf adapter library implements per-repo. No ret |
| PKG-09 | ✅ | .woodpecker.yml defines only push/pull_request/manual-triggered non-publish steps and explicitly states (lines 4-6) "No publish flow yet." No tag-event-scoped publish step, no codeberg_ | CI publishing that is tag-driven, build-in-CI, and secret-token-authenticated is entirely absent — the pipeline has no publish job at all. For a published mgf-* package (0.4.7) this is a real gap, not N/A -> ⏳. — FIXED 2026-06-07: tag-driven, build-in-CI, secret-token Codeberg publish step added |
| PKG-10 | ✅ | pyproject.toml:2 name = "mgf-alembic" (hyphenated dist name); wheel ships src/mgf/ as a PEP 420 namespace package so import is mgf.alembic (pyproject.toml:101-106, dotted import). proje | Naming defers correctly to NM-01..NM-04: hyphenated distribution name (mgf-alembic), dotted namespaced import (mgf.alembic). The canonical home in project.urls is Codeberg. The pypi.org/project links remaining in README/SECURITY a |
| PKG-11 | N/A | No federation/agent version-check tooling in this repo; scripts/ is empty (only __init__.py). Version pins are static ranges in pyproject.toml:43-44 (mgf-common>=0.41,<0.47; mgf-sqlalch | PKG-11 binds an agent that resolves a sibling's *published* version at recommendation time to query the Codeberg registry. This thin adapter library performs no such live version resolution and ships no agent tooling, so there is  |
| PKG-12 | ✅ | No no-pypi-surface gate is wired: .woodpecker.yml has no no-pypi-surface step and the repo has no scripts/check_no_pypi_surface.py (scripts/ holds only an empty __init__.py). Residual m | PKG-12's enforcement gate (check_no_pypi_surface.py + no-pypi-surface CI step — the cornerstone template siblings copy) is absent here. The CHANGELOG release URLs are clearly-historical (allowlisted) and the README/SECURITY badges — FIXED 2026-06-07: README badges/links off pypi.org → Codeberg (0 refs remain) |

### DOCUMENTATION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DOC-01 | ✅ | Repo root has README.md, LICENSE, CHANGELOG.md, CONTRIBUTING.md, SECURITY.md, FEEDBACK.md, AGENTS.md, STARTHERE.md, DEPS.md, FEDERATION.md, LESSON_LEARNED.md + docs/ dir. PUBLIC_API.md  | Every §2.0.1 universal-MUST root doc exists; PUBLIC_API.md present as a library; docs/ dir present. Conformant (not in challenge set; verdict derived fresh). |
| DOC-02 | ✅ | docs/{standards(pointer-only README),inprogress,claude,cutover,recipes,testing}. reference/ omitted (sibling carve-out §2.0.2 — README API section suffices). | Six-bucket hierarchy applicable to sibling shape present; standards/ is pointer-only not a duplicate. Conformant. |
| DOC-03 | ✅ | Bucket READMEs present: docs/inprogress/README.md (charter + index table), docs/cutover/README.md, docs/recipes/README.md, docs/claude/README.md, docs/standards/README.md. | Every long-lived bucket carries its own charter README with what-goes-here framing. Conformant. |
| DOC-04 | ✅ | [verify-upheld] CHANGELOG.md:5 'follows Keep a Changelog v1.1.0'; :20 [Unreleased]; per-release rows [0.4.7] 2026-06-06 'Walk the mgf-common pin ceiling <0.46→<0.47', [0.4.6], [0.4.5]…  | [verify-upheld] Tried to refute: searched for a breaking entry lacking a cutover link — the sole 0.x breaking release v0.1.0 carries it. Keep-a-Changelog + SemVer + [Unreleased] + same-commit discipline present. Upheld. |
| DOC-05 | ✅ | [verify-upheld] docs/cutover/v0.1.0.md (named after TO-version): (a) literal rename table line 26 `from mgf.common.alembic import configure_env`→`from mgf.alembic import configure_env`; | [verify-upheld] Tried to refute: DOC-05 wants a FEEDBACK entry name; the guide traces to the federation roadmap/PAPER-22 rather than a FEEDBACK-close — acceptable as a roadmap-driven split, not a FEEDBACK-driven removal. Codemod s |
| DOC-06 | ✅ | [verify-upheld] RELIABILITY_AND_ACCURACY.md has all six sections (§1 line 26 … §6 line 430). Work units carry resolving file:line links (_env.py:233/260/120-121/39-45/188-217, all withi | [verify-upheld] Tried to refute: each cited line resolves (<554) and concrete-output blocks are falsifiable. Six-section shape + §3.1/§3.2 evidence met. Upheld. |
| DOC-07 | ✅ | docs/claude/CLAUDE.md present (16.8 KB), opens with catch-up-managed BEGIN/END auto-block then project addenda (file map, cross-cutting patterns, build/release). A second legacy docs/CL | Dense-lookup CLAUDE.md at the canonical docs/claude/ path. The duplicate docs/CLAUDE.md is a housekeeping wrinkle, not a DOC-07 failure. Conformant. |
| DOC-08 | ✅ | PUBLIC_API.md tracks __all__ (all four names DriftReport/configure_env/detect_drift/run_async_migrations from src/mgf/alembic/__init__.py:61 documented). BUT no PUBLIC_API.json companio | DOC-08 binds the machine-readable PUBLIC_API.json companion generated from __all__ + two CI pins. The .json is absent and unpinned — a real publish-chain gap (⏳, not 🚫/N/A: a published library must ship the companion). — FIXED 2026-06-08 (0.4.8): PUBLIC_API.json + generator + pin test |
| DOC-09 | ✅ | No CI lint pins doc-named symbols: grep for PUBLIC_API in .woodpecker.yml/scripts is empty (and no PUBLIC_API.json to drift-check). Trackers cite file:line but there is no code-side bac | DOC-09 requires either a CI name-existence lint or a code-side back-reference. Neither direction is wired; the v2.16 behavioral-verification SHOULD is also unwired. Unmet gap → ⏳. — FIXED 2026-06-08 (0.4.8): md↔__all__ name-existence pin test |
| DOC-10 | ✅ | [verify-upheld] FEEDBACK.md is consumer-facing: §1 Process (OPEN→SHIPPED/DEFERRED/WONTFIX/MOVED), §2 Open feedback (PAPER-NN), §3 reviewer meta-feedback. docs/inprogress/README.md lines | [verify-upheld] Tried to refute: looked for consumer signal in inprogress or audit items in FEEDBACK — clean separation, codified by the inprogress README boundary. Upheld. |
| DOC-11 | ✅ | docs/inprogress/README.md: 'not a graveyard — closed trackers SHOULD move to docs/archive/<year>/ within one release cycle.' All three trackers marked 'v0.1 — active' (open items remain | DOC-11 (SHOULD) honored: archival discipline stated and no fully-closed tracker sits unmoved. Conformant. |
| DOC-12 | ✅ | [verify-upheld] README Documentation uses relative links [`docs/recipes/alembic.md`](docs/recipes/alembic.md), [`PUBLIC_API.md`](PUBLIC_API.md); cross-repo refs use absolute codeberg UR | [verify-upheld] Tried to refute: no absolute links to in-repo files, §N headings present, citations use src/mgf/alembic/_env.py:LINE form. All three DOC-12 requirements met. Upheld. |
| DOC-13 | ✅ | [verify-upheld] FEEDBACK.md header (8-13) routes 'mgf-alembic-specific → file HERE' and 'Federation-wide → mgf-common/FEEDBACK.md'; cites FB-01..FB-04 + DOC-13 (20-22); §1 Process; loca | [verify-upheld] Tried to refute: no missing routing table, numbering is local. Repo-scoped FEEDBACK with sibling-vs-federation routing satisfied. Upheld. |
| DOC-14 | N/A | No docs/inprogress/MGF_ADOPTION.md (ls: no such file). ADP-04 carve-out: federation siblings (mgf-alembic explicitly named) do NOT maintain MGF_ADOPTION.md — adoption relationship docum | mgf-alembic is a federation sibling, explicitly carved out of the DOC-14 MUST by ADP-04. Correctly N/A by shape, not a gap. |
| DOC-15 | ✅ | [verify-upheld] docs/inprogress/MGF_STANDARDS_CONFORMANCE.md exists; README.md:111 links it AND declares 'Conformance: L2' (CFM-01 same-place); tracker line 22 'Declared conformance lev | [verify-upheld] All four MUST elements (presence + canonical location + README link with co-located level + markers) hold. Tracker §1 'Current version: 0.3.0' lags the real 0.4.7/<0.47 pin — a content-staleness wrinkle inside the  |
| DOC-16 | ✅ | [verify-upheld] DEPS.md at root: §1 'What mgf-alembic depends on' (line 16: mgf-common/mgf-sqlalchemy/alembic/aiosqlite), §2 'Who depends on mgf-alembic' (line 34: PlasmaMapper roster + | [verify-upheld] Tried to refute: both directions present with import-survey verification note and a reproducible grep. Upheld. |
| DOC-17 | ✅ | [verify-upheld] FEDERATION.md is a pointer stub: 'the federation contract is not maintained here — there is one canonical copy' + 'Read the contract at mgf-common/FEDERATION.md'; cites  | [verify-upheld] Tried to refute: the stub embeds no contract copy, only points + lists this project's own root docs. Exactly the DOC-17 pointer-stub shape. Upheld. |
| DOC-18 | ✅ | CHANGELOG entries co-update coupled surfaces in-commit ([0.4.0] line 124 lands detect_drift/DriftReport in the same release row as the pin bump; PUBLIC_API.md documents all four __all__ | As a sibling owning no standards rule, DOC-18's load-bearing ripple is the public-symbol↔PUBLIC_API.md↔CHANGELOG coupling, which release rows honor. The PUBLIC_API.json half of that coupling is the DOC-08 ⏳ gap, tracked there. Con |
| DOC-19 | ✅ | [verify-upheld] LESSON_LEARNED.md at root with DOC-19 header (3-6: append-only, 'Newest first', 'Supersede a wrong past entry … never rewrite history', cites DOC-19 + lesson-learned-md- | [verify-upheld] Tried to refute: DOC-19 (MUST since v2.21) binds presence; a seeded file with no real lessons is explicitly conformant ('presence is the bar'). File exists with correct discipline header + seed entry. Upheld. |

### OPERABILITY

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| OP-01 | N/A | pyproject.toml declares no [project.scripts]/console-scripts entry point; grep for 'scripts\|console\|entry.point\|argparse\|click' in pyproject.toml + src/mgf/alembic/*.py finds none.  | OP-01's rich-version contract attaches to an app's own CLI/endpoint. mgf-alembic has neither (no CLI of its own per the SHAPE carve-out; not a service). The version-visibility obligation lands on the consumer app that embeds it; t |
| OP-02 | N/A | No doctor command and no CLI exists to host one (no console-scripts in pyproject.toml). The library exposes only configure_env / run_async_migrations / detect_drift / DriftReport (src/m | OP-02 requires the *app* to ship a self-diagnostic of its OWN state. An env.py adapter has no standalone runtime state of its own to probe and no command surface to host a doctor; the obligation is consumer-side (the embedding app |
| OP-03 | ✅ | pyproject.toml [project.urls] are real and coherent (Homepage/Issues/Changelog all = https://codeberg.org/magogi-admin/mgf-alembic...), and README/STARTHERE links point at real codeberg | URLs resolve and carry no placeholders, but the MUST has two halves: valid URLs AND a CI check. The CI verification half is absent, so the rule is partially met — an unmet gap is ⏳, not a decline. — FIXED 2026-06-07: CI no-placeholder grep added to the lint step |
| OP-04 | ✅ | [verify-upheld] README.md:6-10 deliberately defers the live mgf-common pin to PyPI metadata ('sourced from pyproject.toml at release time, so this README can't go stale') rather than ha | [verify-upheld] Tried to refute by hunting for a stale phase marker, a wrong/duplicated current dep pin, or a fabricated test count in README/STARTHERE — found none. The historical 'v0.30/v0.1' references are lineage, not load-bea |
| OP-05 | N/A | No `explain`/config-introspection command and no CLI to host one (no console-scripts in pyproject.toml). configure_env() takes config (database_url, target_metadata, naming_convention,  | OP-05 ('what is the running app configured with?') presumes a long-lived app with an owned config layer and an introspection surface. An env.py adapter is invoked transiently with explicit args; it has no standalone running proces |
| OP-06 | N/A | _drift.py:67 uses `logging.getLogger(__name__)` (a library logger, no handler/sink of its own) and _env.py:293 emits a stderr warning (SH-02). The library deliberately attaches NO file  | OP-06 is about reaching a rotating log FILE without path knowledge (a `<app> logs` CLI / GUI menu / aggregator URL). mgf-alembic owns no log file and no CLI — it is a well-behaved library logger that defers sink wiring to the embe |
| OP-07 | N/A | No bundle/diagnostic-tarball command and no CLI to host one (no console-scripts in pyproject.toml). A bundle's contents (redacted config + last N log lines + crash reports + doctor outp | OP-07 produces a support artefact from the app's owned operational state. A transient env.py helper has none of those owned surfaces and no command host; the bundle obligation lands on the embedding consumer app. |
| OP-08 | N/A | The library writes no state directories: no crash-report dir, no log file, no cache. _drift.py / _env.py only log via the stdlib logger and emit stderr warnings; configure_env disposes  | OP-08 bounds the growth of state dirs an app writes. mgf-alembic writes no such state, so there is nothing to bound — the retention obligation applies to whatever app embeds it (and is consumer-side per OPERABILITY.md §3). |
| OP-09 | N/A | OP-09 'Applies to: service' (rules box). mgf-alembic is a thin alembic/SQLAlchemy adapter library invoked inside a consumer's env.py — not a service, no listener, no environment=product | Production-boot safety guards are a service-only concern (per the standard's explicit applies-to column). This package never boots a production listener; N/A by shape. |
| OP-10 | N/A | OP-10 'Applies to: service'. No deployable artefact: no Dockerfile, no compose/k8s manifest in the tree; the wheel is a published PyPI library (mgf-alembic 0.4.7). .woodpecker.yml has n | Versioned-image + rollback runbook is a service-deployment concern. A pip-installable library has no production image to tag or roll back; N/A by shape (library versioning is covered by semver/PyPI under RELEASING, not OP-10). |
| OP-11 | N/A | OP-11 'Applies to: service'. No alerting surface exists: no Prometheus rules, no alertmanager config, no docs/runbooks/ in the tree; the package emits no metrics and runs no daemon. It  | Paging paths + per-alert runbooks presume a deployed, monitored service with an on-call rotation. A transient migration adapter has no alerting story; N/A by shape. |
| OP-12 | N/A | OP-12 'Applies to: service'. No backup/restore script, no docs/drills/, no production storage target (S3/R2/GCS) in the repo. The library configures alembic migrations; it does not own  | End-to-end backup/restore drills against a real production target are a service/DR concern. This library owns no backup target or restore path; N/A by shape. |

### DEPLOYMENT

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DEP-01 | N/A | DEPLOYMENT.md:7-9 scopes the standard to "stateful web-service consumer applications"; lines 20-21 put "Federation libraries (no runtime)" explicitly Out of scope. The Rules-box "Applie | DEP-01 (cloud infra MUST be IaC) binds only to a deployed web service. mgf-alembic provisions no cloud resources — it is a library running inside a consumer's process. The premise (a project that owns cloud infrastructure) genuine |
| DEP-02 | N/A | DEPLOYMENT.md:42 "Applies to: service"; scope at lines 7-21 excludes no-runtime federation libraries. src/mgf/alembic/ contains 3 modules (_env, _drift, __init__) — no VM/container stat | DEP-02 (VM/container state MUST be Config-as-Code) presupposes a production VM or container image owned by the project. A library owns no VM, so the premise does not bind. |
| DEP-03 | N/A | DEPLOYMENT.md:43 "Applies to: service"; §4.3 frames it as a deploy-time/runtime artefact contract (container digest / source-tree-at-SHA installed on a server). mgf-alembic is published | DEP-03 governs the immutability of a release artefact installed into a running production environment. mgf-alembic has no production deploy; its packaging/version-immutability concerns live under RELEASING/PACKAGE_DISTRIBUTION (PK |
| DEP-04 | N/A | DEPLOYMENT.md:44 "Applies to: service"; the rule names DB credentials/signing keys/TLS keys for a production deployment, storage backends Ansible Vault/cloud KMS (lines 327-332). No dep | DEP-04 (production secrets encrypted at rest in vault/KMS) presupposes a deployed service holding production secrets. The library holds none; runtime secret handling for its DB-connection inputs is the consumer's deployment concer |
| DEP-05 | N/A | DEPLOYMENT.md:45 "Applies to: service"; §4.5 requires deploy/scripts/deploy.sh\|restore-db.sh to take an env arg. No deploy/scripts directory exists (filesystem: NO deploy/). The only s | DEP-05 (deploy/backup/restore/rollback scripts MUST be environment-explicit) binds a project that ships such scripts. A library ships none; it is invoked by the alembic CLI inside a consumer. Premise does not bind. |
| DEP-06 | N/A | DEPLOYMENT.md:46 "Applies to: service"; the rule requires a drill-measured rollback runbook in deploy/docs/runbook.md (§4.6). No deploy/ tree exists. | DEP-06 (reversible deploys with a measured rollback runbook) presupposes a deployable running service. mgf-alembic is not deployed; rollback of a published version is governed by RELEASING, not DEP-06. Premise does not bind. |
| DEP-07 | N/A | DEPLOYMENT.md:47 "Applies to: service"; §3 requires a top-level deploy/ directory. Filesystem check confirms "NO deploy/ directory". §2.0 mapping (lines 199-209): a federation sibling's | DEP-07 mandates the deploy/ shape for a web-service consumer. mgf-alembic is a federation-sibling library, not a consumer application, so it correctly has no deploy/ directory. Premise does not bind. |
| DEP-08 | N/A | DEPLOYMENT.md:48 "Applies to: service"; requires production metrics/logs/traces to a queryable sink plus deploy/docs/slo.md. No deploy/, no slo.md, no production runtime to observe (lib | DEP-08 (production observable end-to-end, committed SLO) presupposes an operator-owned running service. A library has no production it operates; its logging conformance (if it logs) lives under LOGGING. Premise does not bind. |
| DEP-09 | N/A | DEPLOYMENT.md:49 "Applies to: service"; concerns DNS records + TLS certs for a deployed host (§4.9). mgf-alembic serves no host, owns no DNS/TLS; no deploy/docs/dns.md. | DEP-09 (DNS + TLS managed infrastructure) binds a project that exposes a network endpoint with DNS/TLS. The library exposes none. Premise does not bind. |
| DEP-10 | N/A | DEPLOYMENT.md:50 "Applies to: service"; requires deploy/docs/first-production-cut.md green-field provisioning runbook. No deploy/ tree exists. | DEP-10 (first-production-cut runbook) presupposes a green-field production provisioning sequence. A library has no production environment to provision. Premise does not bind. |
| DEP-11 | N/A | DEPLOYMENT.md:51 "Applies to: service"; requires deployability to >=2 environments (prod + staging/dev) from shared IaC+config code. No deploy/terraform/environments, no IaC at all. | DEP-11 (multiple environments from the same code) binds a deployable web-service consumer. mgf-alembic is not deployed to any environment; it is pip-installed as a dependency. Premise does not bind. |

### PRESENTATION_LAYER

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| PR-01 | ✅ | src/mgf/alembic/_env.py:21-27 + _drift.py:54-62 + __init__.py:56-59 — only stdlib (asyncio, sys, logging, contextlib, dataclasses, typing), sqlalchemy, alembic, mgf.alembic internal imp | PR-01 has two MUST clauses: (a) the SDK MUST NOT import a UI framework — MET by inspection (source is clean: only stdlib + sqlalchemy + alembic + mgf-common); and (b) 'The rule MUST be enforced mechanically via import-linter (or e — FIXED 2026-06-07: clause(b) mechanical enforcement now met by the .importlinter UI-forbid + lint-imports CI gate |
| PR-03 | N/A | No app repo and no UI layers exist: find src -type d returns only src, src/mgf, src/mgf/alembic — no core/, view/, or ui/<framework>/ directories. pyproject.toml has no [project.scripts | PR-03 binds only to 'an app repo with multiple UIs' and mandates the core/view/ui (or presentation/<framework>) layering. mgf-alembic is a pure SDK/adapter with zero UI consumers, so the premise does not bind. PR-07 itself authori |
| PR-04 | N/A | PR-04 mandates import-linter enforcement of the core/view/ui layer hierarchy (contract (a) core/view forbid UI frameworks; contract (b) ui/<fw> imports only its own framework + view + S | The PR-04 MUST is predicated on the multi-layer app structure introduced by PR-03; with no app, no UI layers, and no second UI, the layer-hierarchy enforcement requirement has no subject to bind to. (The framework-neutral 'no-UI-f |
| PR-05 | N/A | PR-05 governs each ui/<framework>/ adapter consuming view/ only and never a peer ui/<other>/. There are zero ui/<framework>/ adapters in this repo (no ui/ tree; find src -type d shows n | The rule activates only with ≥2 sibling UI adapters. With zero UI consumers the premise genuinely does not bind. |
| PR-07 | N/A | PR-07's binding MUST is 'A sibling at L1+ with a UI consumer MUST have a PR — PRESENTATION_LAYER section in its docs/inprogress/MGF_STANDARDS_CONFORMANCE.md.' mgf-alembic has zero UI co | The mandatory-section clause is UI-consumer-gated and does not bind a pure SDK with no UI consumer, so PR-07 is N/A by its own carve-out. Note (not a verdict on PR-07): the live audit being produced here supplies the real per-id c |

### AGENTS

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| AG-01 | ✅ | [verify-upheld] /home/bassam/PycharmProjects/mgf-alembic/AGENTS.md is a thin pointer (lines 3-5 'thin pointer managed by mgf-common catch-up — do not edit it; project-specific agent not | MUST met: AGENTS.md ships at repo root, is a thin pointer with no copy of the briefing, is byte-identical to the cornerstone federation template, and project-specific notes are housed in docs/claude/CLAUDE.md not AGENTS.md. Refute |
| AG-02 | ✅ | [verify-upheld] AGENTS.md:9 points at the single source `mgf-common agents`; AGENTS.md:36 'One message for the whole federation; no per-project variant.' Project-scoped content lives in | MUST met: the canonical briefing is sourced from `mgf-common agents` (not duplicated locally), and the project-specific lookup lives in the catch-up-managed CLAUDE.md auto-block exactly as the rule prescribes. Refute attempt found |
| AG-03 | ✅ | [verify-upheld] `git log -8` shows agent commits each ending with BOTH trailers: 2bc863b, ad812fc, 5d73010, cf29527, a55d665, 548b7ea all carry 'Signed-off-by: Bassam Alsanie <bassam@ma | MUST met: every recent agent-authored commit carries both signing trailers with the canonical Bassam Alsanie <bassam@magogi.org> signer plus the model+context Co-Authored-By line, and .gitmessage institutionalizes it. (Two merge c |
| AG-04 | ✅ | /home/bassam/PycharmProjects/mgf-alembic/FEEDBACK.md exists (4478 bytes) with a §1 Process section: 'Any consumer hitting friction MUST file a PAPER-NN under §2. Don't wait for permissi | The FEEDBACK-paper channel is established and documented with the mgf-common feedback workflow. AG-04 is a behavioral/review rule for agents; the project provides the mechanism (FEEDBACK.md + routing) it requires, so the rule is s |
| AG-05 | ✅ | This audit itself follows the rule: the auto-memory MEMORY.md context was treated as point-in-time and every verdict was derived by reading current files (AGENTS.md, pyproject.toml, git | AG-05 is a behavioral discipline rule with no checkable code artifact (standard §9: 'self-enforcement'). Nothing in the project contradicts it and there is no counterexample to refute. Met by the absence of stale-propagation defec |
| AG-06 | ✅ | AG-06 is harness/runtime-enforced (standard §9: 'Runtime / harness enforcement (permission prompts on Bash, MCP tool calls). Not a code rule.'). No CLAUDE.md or settings directive in th | Risky-action confirmation is enforced by the runtime, not a project artifact. No project-level over-authorization found; nothing to refute. Met by construction. |
| AG-07 | ✅ | AG-07 (TaskCreate/TaskUpdate for ≥3-step work) is a runtime/agent-session discipline rule (§9 self-enforcement). It governs agent sessions, not a repository artifact; no project file co | Behavioral session rule with no checkable repo artifact. Met by construction; nothing in the project to refute. |
| AG-08 | ✅ | AG-08 (federation-scoped, not session-scoped memory) is a runtime auto-memory discipline rule (§9: 'runtime auto-memory rules cover this'). No project artifact stores session-ephemeral  | Behavioral memory-discipline rule enforced by the runtime, not a repo artifact. No counterexample in the project; met by construction. |
| AG-09 | ✅ | AG-09 (verify sibling versions against the Codeberg registry, not local dist/) is a review-only behavioral rule (§9). pyproject.toml wires the Codeberg index ('mgf-common = { index = "c | Review-only agent-discipline rule with no enforced artifact; the project's index wiring points at the Codeberg registry as the contract. No counterexample to refute. Met. |
| AG-10 | ✅ | AG-10 (standards drift → file a PAPER, not silent doc/code edit) is review-only (§9). FEEDBACK.md provides the paper channel and explicitly routes standards-level issues to mgf-common/F | Behavioral rule with the required mechanism (FEEDBACK routing to mgf-common for standards-level issues) in place. No counterexample; met. |
| AG-11 | ✅ | FEEDBACK.md header states the routing explicitly: 'mgf-alembic-specific → file HERE; Federation-wide (cross-sibling patterns, standards proposals) → file in mgf-common/FEEDBACK.md' with | AG-11's cross-project routing (file in the TARGET project's FEEDBACK.md) is exactly what this repo's FEEDBACK.md prescribes. The mechanism is present and correct; met. |
| AG-12 | ✅ | [verify-upheld] mgf-common is a hard runtime dependency (pyproject.toml line 43: 'mgf-common>=0.41,<0.47'), so `mgf-common agents --project` is installed wherever this lib is. The proje | MUST met by construction: mgf-common (which provides `agents --project`) is a declared runtime dependency, and the project-scoped content lives in the canonical docs/claude/CLAUDE.md location the flag reads, with AGENTS.md as fall |
| AG-13 | ✅ | AG-13 (only mgf-common supervisor changes a library; others file in the target's FEEDBACK.md) is a governance/review rule. This repo provides FEEDBACK.md as the request channel and its  | Governance rule with no checkable code artifact beyond the FEEDBACK channel, which is present and correctly routed. No counterexample; met. |
| AG-14 | ✅ | AG-14 (propagate a change to coupled surfaces in the same change, walk the DOC-18 matrix) is review/behavioral, backed mechanically by `mgf-common doctor --standards`. The repo carries  | Agent-facing propagation discipline (the DOC-18 form). Commit 5d73010 evidences in-commit propagation rather than deferred follow-ups; the doctor --standards backstop exists. No counterexample of left-stale dependents found; met. |
| AG-15 | ✅ | thin-pointer AGENTS.md resolving the charter via `mgf-common agents` (+ STARTHERE fallback); mgf-common dep makes the charter resolvable; per-rule conformance ledger is the recorded-jud | AG-15 (obey-the-charter / use-recorded-rationale-channels) binds every L1 repo regardless of CLI; satisfied by construction. Review-only enforcement. Met. |
| AG-16 | ✅ | AG-16 MUST: 'depend on mgf-common[standards]'. pyproject.toml declares only plain `mgf-common>=0.41,<0.47` (line 43); `grep -rn 'standards\]' pyproject.toml .woodpecker.yml` => NONE. No | Concrete unmet MUST: AG-16 requires declaring `mgf-common[standards]` (the dev/tooling extra suffices), but no such extra appears anywhere in the project. An unmet gap is ⏳, not 🚫 (no recorded decline rationale). The plain mgf-com — FIXED 2026-06-07: separate [standards] extra (corpus resolvable to agents; OUT of [dev] so CI pypi.org install unregressed) |
| AG-17 | ✅ | docs/memory/MEMORY.md present (project memory index). | |
| AG-18 | ✅ | my_stuff/ git-ignored; .githooks/prepare-commit-msg hook present. | |
| AG-19 | N/A | no runtime auto-memory store for this project yet (~/.claude/projects/<slug>/memory/ absent) — nothing to track. | |
| TM-01 | N/A | no datetime crosses a boundary in this repo's code. |
| TM-02 | N/A | no datetime wire format emitted. |
| TM-03 | N/A | no duration measurements with a wall clock (timeouts are not timed spans). |
| TM-04 | N/A | no `datetime.now()` in production logic. |
| TM-07 | N/A | UTC only; no IANA timezone-name usage. |
| TM-08 | ✅ | async sleeps use `asyncio.sleep`. |
| PF-01 | ⏳ | FLAG: perf tests use in-file thresholds, no recorded baseline. |
| PF-02 | ✅ | perf tests marked `@pytest.mark.perf`. |
| PF-03 | ⏳ | FLAG: no `tests/perf/baselines.json`. |
| PF-04 | N/A | re-baselining flow activates with recorded baselines. |
| PF-05 | ⏳ | FLAG: perf tests are plain-pytest timing, no statistical harness. |
| PF-07 | ✅ | perf failures surface the comparison numerically. |
| PF-08 | N/A | thresholds are relative-drop, not hardware-tier-sensitive. |
| OB-01 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-02 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-03 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-04 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-05 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-07 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-08 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-09 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-10 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| OB-11 | N/A | no owned observability surface — consumes `mgf.common.observability` (OB rules bind the owner). |
| NM-01 | ✅ | distribution name is hyphenated (NM-01). |
| NM-02 | ✅ | dotted import namespace `mgf.<sibling>` (NM-02). |
| NM-03 | ✅ | Codeberg slug hyphenated (NM-03). |
| GUI-01 | ✅ | imports no Qt at module level (GUI-01). |
| GUI-02 | N/A | no GUI (non-GUI library/CLI). |
| GUI-03 | N/A | no GUI (non-GUI library/CLI). |
| GUI-04 | N/A | no GUI (non-GUI library/CLI). |
| GUI-05 | N/A | no GUI (non-GUI library/CLI). |
| GUI-06 | N/A | no GUI (non-GUI library/CLI). |
| GUI-07 | N/A | no GUI (non-GUI library/CLI). |
| GUI-08 | N/A | no GUI (non-GUI library/CLI). |
| GUI-09 | N/A | no GUI (non-GUI library/CLI). |
| GUI-10 | N/A | no GUI (non-GUI library/CLI). |
| REL-10 | ✅ | federation member; participates in cohort-walk releases on a mgf-common pin break. |
| REL-11 | ✅ | released via the Phase A/B cohort-release flow. |
| REL-12 | N/A | binds the cohort Phase-A *agent's* pytest-denial handling, not a released sibling's code. |
| REL-13 | ✅ | releases pass the federation consistency gate (`mgf-fed registry --check`). |
| FB-05 | ✅ | cross-repo feedback flows through the `pending-feedback/<target>.md` outbox + the supervisor relay (`mgf-fed feedback`), never a direct edit (FB-05). |


---

## AG-20 — owned-infrastructure discipline (standards v2.26)

✅ **Accounted 2026-06-29.** Review-enforced agent conduct (like AG-04 / AG-05 /
AG-15 — no single checkable artifact). Before declaring an action **blocked /
human-gated / impossible**, an agent consults
[`MGF_INFRA.md`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/MGF_INFRA.md)
(the fleet infrastructure / access registry) and attempts the self-owned recovery
path — an auth/access failure on Magogi-owned infra (expired token, 401, stopped
service) is a solvable sub-problem, not a terminal wall. Recorded "blocked" /
"gated" notes carry an unblock-path + as-of date and are re-derived against current
capabilities. Added with the v2.26 corpus bump (AG-20 + the MGF_INFRA registry).
