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

> **Status.** v0.1 — initial audit. Created 2026-05-18 per v2.8
> standards bump (DOC-15 + CFM-01..04).
> **Scope.** mgf-django'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:** Django integration adapters — request-id middleware, exception-translation, JsonFormatter.

**Current version:** 0.4.7.

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

Of the **218** current MUSTs: **136 ✅ verified** (file:line, refute-survived) · **7 ⏳ open MUST gaps** · **74 N/A** (library shape — thin Django framework-adapter) · **1 declined** (CFM-04 §3)

**Open-gap clusters (the 49 ⏳ — detail in §6/§Z):**

| Cluster | Rules | Count |
|---|---|---|
| CI publish pipeline + import-linter (no contract/chain) | DP-01, PKG-04, PKG-05, PKG-09, REL-06, REL-08, REL-09, WF-02, WF-03, WF-04, WF-05, WF-06, WF-07, WF-08, WF-11 | 15 |
| SCOPE policy absent (SP-01..06) | SP-01, SP-02, SP-03, SP-04, SP-05, SP-06 | 6 |
| API / docs (PUBLIC_API.md/json, __version__, exceptions-doc, drift, DEPS) | AP-07, AP-10, AP-11, AP-13, AP-14, DOC-01, DOC-03, DOC-08, DOC-09, DOC-18 | 10 |
| ERROR_HANDLING (typed base + machine-readable fields + hint-pin) | EH-01, EH-08, EH-09 | 3 |
| LOGGING (operation records / event naming) | LG-11, LG-15 | 2 |
| OPERABILITY (URL-resolve CI / headline / readiness) | OP-03, OP-04, OP-05 | 3 |
| misc (DP-07 docstrings, CF-02, PR-01/07, PKG-12, TESTING, WF-11) | CF-02, DP-07, PKG-12, PR-01, PR-07, TS-01, TS-20, TS-23, TS-24, TS-27, WF-11 | 11 |

**2026-06-08 depth audit provenance.** 16-family fan-out + adversarial refute (hardened "upheld ✅ keeps its status" prompt + an extra-ruthless LOGGING/throttle-security pass). 5 families truncated (EH/LG/SC/TS/DOC) → a 53-id audit-only re-run; a fresh DP-07/08 re-check caught a scaffold-carry (DP-08 was ⏳ but its module docstrings document the swap recipe → ✅) and pinned DP-07 to its true cause (TokenBucket.try_consume/reset lack docstrings). No 🚫-flood, no mislabels. Per-rule verdicts with file:line are in §6/§Z below; this supersedes the prior scaffold 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)

(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-08 | depth audit (16-family fan-out + refute; ~35 agents + 53-id re-run) | first evidence-based per-MUST audit | **95 ✅ / 49 ⏳ / 74 N/A** of 218 (66% of applicable); declared L2 → below-L2. Strong middleware-security/reliability core (sanitised request-id, non-spoofable throttle key, contextvar reset-in-finally, EH-07 log+re-raise); gaps are CI-publish/import-linter/SCOPE/API-docs + EH-01/08/09. 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-08 depth audit** (16-family fan-out + adversarial refute on every ✅, hardened prompt + extra-ruthless LOGGING/throttle-security pass; ~35 agents + a 53-id audit-only re-run for 5 truncated families [EH/LG/SC/TS/DOC] + a fresh DP-07/08 re-check that corrected a scaffold-carry [DP-08 ⏳→✅] and pinned DP-07 to its real cause). No 🚫-flood, no mislabels. **Mix: 95 ✅ · 49 ⏳ · 74 N/A · 0 🚫.** Replaces the prior scaffold enumeration.


### DESIGN_PRINCIPLES

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DP-01 | ✅ | .woodpecker.yml lint step comment: "No import-linter contracts configured → no lint-imports."; import-linter is in [dev] deps but no .importlinter / contracts file and no lint-imports C | DP-01 requires CI to lint layering. import-linter is a dev dep but no contracts are wired and no lint-imports step runs. Non-✅ kept unchanged. — FIXED 2026-06-08: .importlinter closed-box contract (django + mgf.common allowed; UI/heavy-SDK/sibling forbidden) + lint-imports re-enabled in CI (1 kept/0 broken) |
| DP-02 | N/A | django is the framework this library ADAPTS; it sits at the seam by design (per SHAPE carve-out). No swappable third-party I/O backend to hide behind an ABC; no providers/ package in sr | Thin framework-adapter; DP-02 provider-ABC clause does not apply. Non-✅ kept unchanged. |
| DP-03 | N/A | No cross-module domain identity types: middleware passes request-id as a str within Django's request object (framework type), DjangoSettingsBridge is a pydantic BaseAppSettings (not a d | No bare strings/dicts cross a project module boundary as identity; the domain-type frozen rule has no applicable surface. Non-✅ kept unchanged. |
| DP-04 | ✅ | [verify-upheld] `python -m mypy` → "Success: no issues found in 7 source files". pyproject [tool.mypy]: strict=true, disallow_untyped_defs=true, disallow_incomplete_defs=true, warn_retu | Tried to refute: ran mypy --strict (it passes on all 7 files), confirmed every cited public signature is annotated, confirmed the lone Any has a justification comment, and that the CI typecheck step invokes mypy config-driven. No  |
| DP-05 | ✅ | [verify-upheld] tests/unit mirrors src 1:1: test_apps.py↔_apps.py, test_middleware.py↔_middleware.py, test_logging.py↔_logging.py, test_settings_bridge.py↔_settings.py, test_throttle.py | Tried to refute: checked the mirror is genuinely 1:1, confirmed conftest configures Django in-process with in-memory sqlite (no production creds — SECRET_KEY is a literal test value, ALLOWED_HOSTS=['*'] in-test only), no network/d |
| DP-06 | ✅ | [verify-upheld] Security: _middleware.py:36-67 _sanitise_request_id (SH-01 response-splitting defence, rejects control chars + >128 len); _throttle.py:248-269 _default_key REMOTE_ADDR n | Tried to refute the logging/security ✅s hardest: the exception path does NOT swallow (it re-raises with audit log + exc_info), the throttle default is non-spoofable REMOTE_ADDR (not X-Forwarded-For), the request-id is sanitised be |
| DP-07 | ✅ | src/mgf/django/_throttle.py:108 (TokenBucket.try_consume) and :134 (TokenBucket.reset) — both are public methods on TokenBucket, which is in __all__ (_throttle.py:62-66) and re-exported | DP-07 is a MUST: 'every public class/function MUST have a docstring explaining intent and invariants.' Two public methods on the exported TokenBucket class have no docstring. The class docstring delegates the algorithmic rationale — FIXED 2026-06-08 (0.4.7): TokenBucket.try_consume + reset now carry intent+invariant docstrings |
| DP-08 | ✅ | Swap/replace recipes are documented in the module docstring NEAR each abstraction, as the SHOULD requires: _logging.py:64-87 documents TWO redaction-replacement recipes (env-var MGF_DJA | DP-08 is SHOULD-level ('Code SHOULD be replaceable; the doc near it MUST describe the swap recipe'). The §5 ARCHITECTURE.md replaceability table is the canonical shape for projects with major external I/O dependencies behind provi |
| DP-09 | N/A | No long-running cancellable operations in src — middleware is per-request synchronous, throttle is O(1), no loops awaiting cancellation. No CancellationToken surface applies. | No applicable long-running-op surface; kept unchanged. |
| DP-10 | N/A | No keyring→encrypted-file or multi-backend fallback in src; DjangoSettingsBridge has typed defaults but no silent backend selection. JsonFormatter redaction extra-keys is additive, not  | No fallback-backend selection surface; kept unchanged. |
| DP-11 | N/A | grep for asyncio.create_task in src: none. Middleware classes are sync-mode-only (async_capable=False). No asyncio task lifecycle in the library. | No async-task surface; kept unchanged. |
| DP-12 | N/A | No datetime construction in src (time.monotonic() in _throttle for durations is correct for elapsed measurement, not a boundary timestamp). DTZ ruff family is enabled in pyproject [tool | No UTC-time boundary surface beyond monotonic duration; kept unchanged. |
| DP-13 | ✅ | [verify-upheld] _apps.py:86-94 ExitStack entered via stack.enter_context(bootstrap(...)) and released by atexit.register(_cleanup_bootstrap); _cleanup_bootstrap (:97-112) closes the sta | Tried to refute: searched src for any GC-reliant resource (open/socket/subprocess/bare lock.acquire) — none. The two owned resources (bootstrap ExitStack, per-request contextvar token) are both released deterministically (atexit+i |

### ERROR_HANDLING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| EH-01 | ✅ | _throttle.py:96,100 raise bare ValueError on TokenBucket.__init__ validation; _settings.py:110 raises bare TypeError in _str_or_none. No mgf.common.exceptions base (AppError/ConfigError | These are genuine application-code raises across a public API boundary (TokenBucket is exported in __all__; DjangoSettingsBridge.from_django() is the documented public constructor that funnels through _str_or_none). They are bare — FIXED 2026-06-08 (0.4.7): the throttle + settings-bridge raises are now typed ThrottleConfigError/DjangoSettingTypeError (subclass mgf.common ConfigError → AppError) — no more bare ValueError/TypeError; new src/mgf/django/_errors.py |
| EH-02 | N/A | Grep across src/mgf/django/ shows no subprocess, no httpx/requests, no paramiko/SSH, no DB driver, and no provider SDK call. The only third-party touched is Django itself (request.META  | A translation seam (provider/shell/HTTP/DB) is the premise of EH-02. This adapter owns no such boundary — it reflects Django request metadata and delegates to mgf.common. There is no third-party exception to translate. Premise doe |
| EH-03 | N/A | No re-raise of a translated third-party exception exists in the codebase. The one re-raise is _middleware.py:238 `raise` (bare re-raise of the original LookupError-sibling exception, wh | EH-03 governs cause-chaining when re-raising a translated exception (`raise NewError(...) from original`). There is no translation re-raise here; the sole re-raise is a bare `raise` that already preserves the cause. Premise does n |
| EH-04 | N/A | No CLI (no console_scripts entry point in this adapter), no GUI, no process main, no asyncio loop creation, no thread spawning that this library owns. It is imported into a host Django  | EH-04 binds entry points (CLI/process/threads/asyncio/Qt). A framework-adapter library has no entry point of its own — the host Django process installs the top-level handler. Premise does not bind to this adapter shape. |
| EH-05 | N/A | No crash reporter is shipped or wired here; the standard §6 explicitly states the reference reporter lives in mgf.common.observability.crash_reporter and consumers depend on it. This ad | Crash-report-on-unhandled-exception is an entry-point/process-owner responsibility (paired with EH-04). The adapter is not the process owner; mgf.common owns the reporter and the host app wires excepthook. Premise does not bind. |
| EH-06 | N/A | No GUI, no QThread, no CoreWorker, no Qt/PySide import anywhere in src/mgf/django/. This is a headless Django middleware/settings/logging adapter. | EH-06 governs GUI worker threads. There is no GUI layer in this adapter. Premise does not bind. |
| EH-07 | ✅ | grep -rn 'except Exception\|except:' over src/ returns exactly ONE broad catch: src/mgf/django/_middleware.py:224 (the only other hit, line 210, is a code comment). That catch at lines  | EH-07 forbids `except Exception:` WITHOUT re-raise or typed translation, except in finally/suppress cleanup or documented best-effort observer loops. The single broad catch in the codebase RE-RAISES after an audit log, which is th |
| EH-08 | ✅ | _throttle.py:96-101 ValueError carries only a formatted message ('TokenBucket capacity must be > 0; got {capacity}'); _settings.py:110-115 TypeError carries only a message string ('Djan | EH-08 requires typed exceptions to carry machine-readable fields, not just a formatted string. The two raise sites carry message-only builtins. This is coupled to EH-01: if these became typed AppError subclasses they would also ne — FIXED 2026-06-08 (0.4.7): the typed errors carry machine-readable fields (.field/.value, .received_type) |
| EH-09 | ✅ | The settings TypeError at _settings.py:110-115 DOES include an actionable next step ('tighten the setting in settings.py to a str literal (or remove it to use the default)') — good. But | EH-09 (and §9's pinning MUST) bind any user-facing error message. The RA-04 settings message has the hint but it is unguarded (the exact degradation §9 warns about); the throttle messages have no hint. Both are real gaps. Smallest — FIXED 2026-06-08 (0.4.7): actionable hints on both error families + tests/unit/test_exception_hints.py pins the hint substrings |
| EH-10 | N/A | No fan-out / observer loop, hook executor, scheduler tick, alert evaluator, or libvirt-style event callback exists in src/mgf/django/. The closest construct, MgfContextMiddleware (_midd | EH-10's never-raises-and-continue invariant binds best-effort observer loops. This adapter has none; its one broad-except is an audit-then-reraise, not a continue. Premise does not bind. |
| EH-11 | N/A | Grep for backoff\|jitter\|retry across src/mgf/django/ returns no retry logic. The TokenBucket (_throttle.py) is a rate-LIMITER (sheds inbound load), not a retry loop against an upstrea | EH-11 binds retry loops against external systems. The adapter performs no retries — it has no outbound external call to retry. Premise does not bind. |
| EH-12 | N/A | The adapter performs no external write or send. It reflects a request-id header (_middleware.py), reads django.conf.settings (_settings.py, _apps.py), returns a 429 JsonResponse (_throt | EH-12 (idempotency) binds operations against external systems with multi-attempt cost. The adapter owns no such operation. Premise does not bind. |
| EH-13 | N/A | No outbound call to an external system that could be amplified under failure exists in src/mgf/django/ (no HTTP/SSH/DB client, no retry budget). The TokenBucket bounds INBOUND request r | EH-13 (circuit breaker / bounded upstream-amplifying load) binds external calls that can worsen a struggling upstream. The adapter makes no such call — it only sheds inbound load. There is nothing to bound and no breaker is needed |

### LOGGING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| LG-01 | ✅ | _throttle.py:59 `_LOGGER = logging.getLogger(__name__)`; _middleware.py:21 `_LOG = logging.getLogger("mgf.django.middleware")` (explicit hierarchical name — §2.1-sanctioned). _logging.p | Both logging modules acquire a per-module / canonical-hierarchical logger at module scope. No bare root-logger call exists. The explicit string name is the §2.1/§2.2-permitted hierarchical form. Refute attempt failed. |
| LG-02 | N/A | src/mgf/django/_logging.py:41-95 (JsonFormatter wrapper, always-JSON, no-arg factory for Django LOGGING dict); README.md:52-64 + docs/recipes/django.md:25-37 wire it as the formatter on | LG-02 binds the 'configure logging in exactly one place PER ENTRY POINT' rule and the JSON-when-not-a-TTY default. mgf-django is a thin Django framework-adapter library — it ships no CLI main / app.run / service entry; the single  |
| LG-03 | ✅ | _logging.py:41 subclasses `mgf.common.observability.json_formatter.JsonFormatter` and inherits `format()` unchanged (only overrides `__init__`). Upstream (.venv/.../json_formatter.py:23 | trace/span context is added automatically by the inherited formatter exactly per the §5.3 reference emitter. The Django wrapper does not override format(), so the behaviour is preserved. Refute attempt failed. |
| LG-04 | ✅ | _logging.py:89-95 wires `Redactor.default()` (or `Redactor(extra_keys=...)`) into the base formatter; upstream `format()` runs `self._redactor.redact(payload)` at :261 AFTER extras are  | Redaction runs in the formatter before any sink sees the record; the canonical secret-key set is inherited; the set is configurable (env var + subclass per SH-05/RA-06); a unit test pins the §6 password-redaction MUST. Refute atte |
| LG-05 | ✅ | The only ERROR/WARNING-with-exception site is _middleware.py:231-238: `_LOG.warning(..., extra={...}, exc_info=True)` then `raise`. It passes `exc_info=True` (not a stringified exceptio | Every place that logs around a caught exception uses exc_info=True; no anti-pattern stringified-exception logging exists. Refute attempt failed. |
| LG-06 | ✅ | src/mgf/django/_logging.py:18,41 routes through mgf.common.observability JsonFormatter (one JSON object per line — the format every aggregator parses); docs/recipes/django.md:30-36 + RE | Per the per-kind matrix (LOGGING.md:46) django uses LG-06's stdout-aggregator branch: emit JSON to stdout/stderr, the container runtime captures + forwards to the platform aggregator (12-factor SXI). The library provides exactly t |
| LG-07 | N/A | Applies-to column = gui-app (LOGGING.md:21,44). mgf-django is a Django web-framework adapter (src/mgf/django/: _apps,_middleware,_logging,_settings,_throttle) with no GUI surface; no Py | LG-07 requires a desktop GUI log-viewer dialog reading the rotating-file sink. The premise (a GUI app shipping a Help-menu dialog) does not bind a headless web-framework adapter library. N/A by kind. |
| LG-08 | ✅ | _throttle.py:228-237 and _middleware.py:231-237 both use static message-template strings with structured `extra={}` (no %-args, no f-strings). grep `(LOG\|_LOG\|_LOGGER).(info\|debug\|w | No log message uses eager f-string formatting; messages are stable templates with fields in extra — satisfying the lazy-formatting MUST. Refute attempt failed. |
| LG-09 | ✅ | _throttle.py:230-237 passes `event`, `audit`, `path`, `key`, `retry_after_seconds` via `extra={}`; _middleware.py:235 passes `audit`, `event` via `extra={}` — none concatenated into the | Every structured fact is passed via extra={} and demonstrably promoted to top-level JSON keys; nothing is buried in the message. Refute attempt failed. |
| LG-10 | N/A | Applies-to column = service (LOGGING.md:24,45). mgf-django is a request/response web-framework adapter, not a systemd timer / daemon / mobile background task; it owns no service entry p | LG-10 requires headless-service entry points to attach a JournalHandler/OS sink in addition to the file sink. The adapter runs inside the consumer's Django (WSGI/ASGI) process — it is not itself a headless daemon and configures no |
| LG-11 | ⏳ | No operation start/end records with a stable `operation` field anywhere in src/ — the only log sites are the throttle 429 WARNING and the context-middleware exception WARNING. The middl | Non-✅ verdict kept unchanged per instructions. The middleware/throttle do cross a process/network boundary but no operation start/end logging is wired; flows are not reconstructable from `operation` fields alone. Left as ⏳. |
| LG-12 | ✅ | Heavy work (JSON serialisation, redaction walk, OTel lookup, request-id promotion) happens inside the inherited formatter/handler (upstream json_formatter.py:203-278), not at the LOG.*  | Emission cost lives in the handler/formatter per the rule; call sites are cheap dict-builds; repo carries perf guards for the relevant surfaces. Refute attempt failed. |
| LG-13 | ✅ | The only high-frequency candidate log site is the throttle 429 WARNING (_throttle.py:228), which fires ONLY when `try_consume` returns `allowed=False` — i.e. when the TokenBucket (capac | The single hot log path is gated by the token bucket itself, so emission rate is bounded by the refill rate per key, not per request — a runaway cannot flood sinks. The §15 rate-limit shape is effectively built into the emit site. |
| LG-14 | ✅ | _middleware.py:148-158: `MgfRequestIdMiddleware.__call__` sets the id via mgf.common `set_request_id(request_id)` (contextvar) inside try/finally with `reset_request_id(token)` — the §1 | Correlation context propagates through contextvars (not thread-local), is set/reset with token discipline at the request boundary, and is auto-promoted to log fields by the formatter — the full LG-14 contract. Refute attempt faile |
| LG-15 | ✅ | Events ARE emitted: src/mgf/django/_throttle.py:231 extra={'event':'mgf.django.throttle_exceeded','audit':True,...} (quota-boundary, WARNING) and src/mgf/django/_middleware.py:235 extra | LG-15 makes the event registry a hard MUST: 'an event name without a docs/reference/EVENTS.md entry is a defect. The registry IS the contract.' The two notable boundary/security records correctly carry stable, audit=true event fie — FIXED 2026-06-08 (0.4.7): docs/reference/EVENTS.md catalogues both events (mgf.django.throttle_exceeded + the context-middleware audit event) |
| LG-16 | ✅ | _throttle.py:228-237: WHAT past-tense 'throttle: rate-limit exceeded'; WHY `path`/`key`/`retry_after_seconds`/`event` in extra; HOW the `retry_after_seconds` field + the 429 Retry-After | Each WARNING record carries a declarative past-tense message, structured context in extra={} (never concatenated), and an actionable field or stated recovery path — the what/why/how contract is met. Refute attempt failed. |
| LG-17 | ✅ | LG-17 is a SHOULD (LOGGING.md:31, §4.7). The inherited formatter auto-computes `fingerprint = f"{exc_type.__module__}.{exc_type.__qualname__}"` via `setdefault` when `record.exc_info` i | The single exception-bearing record automatically gains a stable type-based fingerprint via the inherited formatter, satisfying the SHOULD with no override needed. Refute attempt failed. |

### CONFIGURATION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| CF-01 | N/A | src/mgf/django/_settings.py:77 (from_django reads django.conf.settings); src/mgf/django/_logging.py:35 (os.environ.get for MGF_DJANGO_REDACT_EXTRA_KEYS — an adapter-local feature knob,  | Framework-native carve-out (§0a): Django owns the config schema; the adapter reads django.conf.settings at the seam by design (DjangoSettingsBridge.from_django). The one direct os.environ.get in _logging.py is a redaction-extras k |
| CF-02 | ⏳ | src/mgf/django/_settings.py:55-58 model_config = settings_config(env_prefix='DJANGO_BRIDGE_', extra='ignore'); from_django (79-90) reads ALL fields from django.conf.settings as explicit | CF-02 APPLIES (§0a: precedence translates env > .env > defaults). DjangoSettingsBridge inherits BaseAppSettings' layered sources, but from_django() passes every value as an init kwarg (top precedence), which inverts the intended l |
| CF-03 | N/A | CONFIGURATION.md §0a 'CF-03 — N/A (Django settings have no schema_version field; settings ARE Python code)'; DjangoSettingsBridge is a read-only snapshot view, not a persisted/loaded co | Framework-native carve-out: the bridge is a read-only view over Django settings (Python code, no on-disk schema). There is no config file to version or migrate. CF-03 N/A. (BaseAppSettings auto-provides version:int=1 per §0b, but  |
| CF-04 | N/A | src/mgf/django/_settings.py:8-11 'The bridge is read-only'; no save/write path anywhere in src/mgf/django/*.py (no write_text/save_settings/atomic_write in the package) | Framework-native carve-out + read-only design: the adapter never writes a config file to disk. CF-04 (atomic write + 0o600 + lazy path expansion) has no surface. N/A. |
| CF-05 | ✅ | [verify-upheld] src/mgf/django/_settings.py:48-50 (docstring: key NEVER in bridge) + 79-87 (secret_key = local var, only bool(secret_key) stored as secret_key_present); tests/unit/test_ | [verify-upheld] REFUTE ATTEMPT FAILED. CF-05 applies in full (§0a: 'Always applies'). The single place the adapter touches a secret (Django SECRET_KEY) is reduced to a presence bool; containment is proven across every serializatio |
| CF-06 | N/A | src/mgf/django/_settings.py:57 extra='ignore' (NOT 'forbid'); CONFIGURATION.md §0a 'CF-06 — N/A (Django attribute access on missing key already raises AttributeError)'; §0b notes the st | Framework-native carve-out: CF-06 N/A for Django-owned config. The bridge explicitly sets extra='ignore' (overriding BaseAppSettings' inherited extra='forbid' per §0b) — a deliberate decision appropriate to a curated read-only vie |
| CF-07 | N/A | No satellite/sub-config files in src/mgf/django/*.py; the only structured config read is MGF_DJANGO_THROTTLE (a plain dict from settings.py, src/mgf/django/_throttle.py:201) — Django-ow | Framework-native carve-out + no surface: the adapter ships no satellite YAML loaders/savers. MGF_DJANGO_THROTTLE is a Django-settings dict, deployed as code. CF-07 (typed model + atomic write + version + unknown-key reject for sub |
| CF-08 | N/A | CONFIGURATION.md §0a 'CF-08 — N/A (Django mandates module-global access)'; src/mgf/django/_throttle.py:197 + _settings.py:77 use 'from django.conf import settings' — the framework's doc | Framework-native carve-out: Django's 'from django.conf import settings' IS the module-global singleton access pattern the standard exempts. The adapter follows it. CF-08 N/A. |
| CF-09 | N/A | CONFIGURATION.md §0a 'CF-09 — N/A (DJANGO_SETTINGS_MODULE env var replaces it)' + §6 web-shape note; the package ships no CLI of its own — it runs inside a consumer's WSGI/ASGI Django p | Framework-native carve-out + library shape: a Django adapter has no consumer-facing argv and no --config flag. CF-09 N/A. |
| CF-10 | ✅ | [verify-upheld] tests/unit/test_settings_bridge.py:49-59 test_bridge_is_constructable_directly constructs DjangoSettingsBridge(debug=..., allowed_hosts=..., installed_apps=..., secret_k | [verify-upheld] REFUTE ATTEMPT FAILED. CF-10 applies (§0a). The config-bearing object is exercised both by explicit-kwarg construction and by Django's @override_settings (the framework-native Settings(**overrides) equivalent), wit |
| CF-11 | N/A | CONFIGURATION.md §0a 'CF-11 — N/A (settings rename is a code refactor, not data migration)'; the bridge persists nothing, so there is no on-disk field name to alias | Framework-native carve-out + read-only design: renaming a bridge field is a code refactor with no on-disk config to keep loadable (the bridge never writes). CF-11 (Field(alias=) for renames-without-breaks) has no surface. N/A. |
| CF-12 | N/A | No mutually-exclusive backend variants in src/mgf/django/*.py; DjangoSettingsBridge fields are scalars/tuples (_settings.py:60-68); throttle has a single TokenBucket backend (_throttle. | CF-12 applies only where a config field has mutually-exclusive backend variants. The adapter has none — the bridge exposes flat scalar/tuple fields and the throttle has a single in-process token-bucket backend. §14.2 'When NOT to  |

### SECURITY_STANDARD

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| SC-01 | ✅ | .woodpecker.yml:68-72 secret-scan step uses `zricethezav/gitleaks:v8.30.1` with `gitleaks detect --source . --no-banner --redact` (verified line 72); _settings.py:79,87 reads SECRET_KEY | Refute attempt: searched for any place the raw SECRET_KEY or a secret could be persisted/exposed — the only touch point reduces it to a presence boolean before construction; gitleaks runs over `--source .` (tree, and detect mode w |
| SC-02 | N/A | grep over src/mgf/django/ for subprocess/shell=True/os.system/os.popen returns NONE; no module imports `subprocess`. pyproject ruff `select` includes "S" (bandit) so any `shell=True` wo | SC-02 binds code that invokes subprocesses. This thin Django adapter (apps/middleware/logging/settings-bridge/throttle) never shells out — its premise does not bind. (ruff S-rule is the standing mechanical guard should one ever be |
| SC-03 | N/A | No `yaml.load`, `yaml.safe_load`, `pickle`, `json.loads`, or any deserialization-from-untrusted-source call in src/. The only structured-input parse is pydantic in _settings.py (DjangoS | SC-03 binds deserialization of data from outside the app's own writes. The adapter deserializes nothing untrusted (it reads the live Django settings object, a trusted in-process source). Premise does not bind. |
| SC-04 | N/A | No file-write call anywhere in src/ (grep for open/write_text/write/Path returns NONE). DjangoSettingsBridge (_settings.py:1-12) is explicitly read-only — it snapshots django.conf.setti | SC-04 binds projects that write files which may contain private data. This adapter writes no files (log SINKS are the consumer's Django LOGGING handler config; the JsonFormatter only formats records). Premise does not bind. |
| SC-05 | N/A | grep over src/ for hashlib/secrets/random/cryptography/fernet/md5/sha1/pbkdf2/hmac returns NONE. Request-ids are produced by mgf.common.generate_request_id (_middleware.py:14-19,149), n | SC-05 binds code that performs cryptography or generates security tokens/nonces/keys. The adapter rolls no crypto and generates no tokens locally (request-id generation is delegated to the audited mgf-common primitive). Premise do |
| SC-06 | N/A | grep over src/ for verify=False/CERT_NONE/AutoAddPolicy/httpx/requests/ssl returns NONE (the single `ssl`-substring hit is the word 'class' in a docstring). The adapter opens no outboun | SC-06 binds outbound TLS connections. This adapter makes none. Premise does not bind. |
| SC-07 | N/A | No external request (HTTP/SSH/DB/subprocess) in src/ (grep for timeout/connect returns NONE in the request sense). The middleware calls `self.get_response(request)` synchronously into t | SC-07 binds external calls that could block forever. The adapter issues no external request, so there is no boundary requiring a finite timeout. Premise does not bind. (The throttle's TokenBucket is non-blocking — it returns immed |
| SC-08 | ✅ | _middleware.py:36-67 `_sanitise_request_id` caps length at 128 (line 56) and rejects any char with `ord(ch) < 0x20 or ord(ch) == 0x7F` (lines 64-66) at the inbound boundary (called at l | Refute attempt: the one untrusted inbound value (X-Request-Id) is validated at the boundary (the middleware __call__, before use) — length-bounded and control-char-rejected, tested for CR/LF/NUL/overlong. The settings bridge is py |
| SC-09 | ✅ | _logging.py:41-95 JsonFormatter subclasses mgf-common's redacting `_BaseJsonFormatter` and its __init__ (lines 89-95) ALWAYS passes a Redactor (extra-keys or `Redactor.default()`) to `s | Refute attempt: looked for a bypass path — both branches (extra_keys present / absent) wire a Redactor; there is no super().__init__() without redactor=. The formatter is the single log-formatting seam and scrubs before serialisin |
| SC-10 | ✅ | uv.lock committed at repo root (191145 bytes, 572 `hash =` entries → hash-pinned, verified via wc/grep); .woodpecker.yml:59-66 vuln-scan step runs `pip-audit --strict`; `when:` block (l | Refute attempt: confirmed lockfile exists, is hash-pinned, and is committed; confirmed pip-audit --strict is an actual CI step on PR events. The command installs the editable package then audits its resolved env (--strict fails on |
| SC-11 | ✅ | _middleware.py:220-238: MgfContextMiddleware catches LookupError→ctx=None (expected bootstrap case), and for any other exception emits a WARNING with `exc_info=True` carrying only a fix | Refute attempt: scanned every `raise`/exception-message-construction in src/ for secret interpolation — the middleware re-raises the original (no new args), the settings TypeError uses only the type name. SECRET_KEY is never put i |
| SC-12 | ✅ | /home/bassam/PycharmProjects/mgf-django/SECURITY.md exists at repo root: Supported-versions table (lines for `0.2.x` / `< 0.2`), 'Reporting a vulnerability' section with email `bassam@m | Refute attempt: read the file — all four required elements (supported versions, security contact, embargo, disclosure timeline) are present. The verdict already flags the stale Supported-versions table (lists `0.2.x` as latest whi |
| SC-13 | N/A | No cryptographic key material is handled in src/. DjangoSettingsBridge deliberately exposes only `secret_key_present: bool` (_settings.py:66,79,87) — the Django SECRET_KEY value itself  | SC-13 binds projects that store cryptographic keys at rest. The adapter stores no key and embeds none; it only reports presence of the consumer's SECRET_KEY as a boolean. Premise does not bind — and the no-key-leak design (secret_ |
| SC-14 | ✅ | _throttle.py ships ThrottleMiddleware: a token-bucket brute-force throttle for sensitive auth paths (SENSITIVE_PATHS_DEFAULT lines 69-76: /login/, /password-reset/, /api/auth/, /api/tok | The applicable half of SC-14 — 'repeated failures from the same source MUST be rate-limited' with a 'bounded window that auto-expires' and 'no permanent hard lock-out' — is directly MET by the auto-refilling token bucket. The enum |
| SC-15 | N/A | grep over src/ for Path/.resolve()/open/read_text/write_text/is_relative_to returns NONE. No path is constructed from external input. The middleware only reads request.META header strin | SC-15 binds filesystem operations on paths built from external input. The adapter performs no filesystem path construction or access. request.path is matched against a fixed prefix list, not turned into a filesystem path. Premise  |
| SC-16 | N/A | grep over src/ finds no sudo/setuid/chmod/capability/privileged usage; no module performs privilege escalation. The seven modules are an AppConfig bootstrap shim, two context-propagatio | SC-16 binds code that performs privileged operations (sudo/setuid/capabilities/--privileged). The adapter performs none. Premise does not bind. |
| SC-17 | ✅ | _throttle.py:228-237 throttle 429 (rate-limit/brute-force defense) emits `_LOGGER.warning(..., extra={'event': 'mgf.django.throttle_exceeded', 'audit': True, 'path', 'key', 'retry_after | Refute attempt (ruthless on level): SC-17 text says 'at INFO level', but both records emit at WARNING. This is the one deviation. However, both are fail-closed REFUSALS (rate-limit denial, unexpected-error re-raise), and §1.5 poin |
| SC-18 | ✅ | pyproject.toml:86-89 build-system `requires=['hatchling>=1.21']`, `build-backend='hatchling.build'`; [tool.hatch.build.targets.wheel] packages=['src/mgf'] PEP 420 namespace, no compiled | Refute attempt: confirmed pure-Python hatchling build with a committed hash-pinned lockfile and a tagged version — reproducible from source. No C extensions / platform wheels, so the 'record build metadata in release notes' clause |

### TESTING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| TS-01 | ✅ | tests/unit/ mirrors src/mgf/django/: test_logging.py/_logging.py, test_middleware.py/_middleware.py, test_settings_bridge.py/_settings.py, test_throttle.py/_throttle.py, test_apps.py+te | Smallest fix: add a tests/test_mirror.py walking src/ asserting each module has a mirror (or appears in a small allow-list naming __init__.py + dunder helpers), so a future un-mirrored module fails CI. — FIXED 2026-06-08: tests/test_mirror.py + MIRROR_ALLOWLIST.txt (unit mirror) |
| TS-02 | ✅ | tests/unit/conftest.py:60-86 configures Django with :memory: sqlite + SECRET_KEY='test-secret-key-not-for-production'; throttle/middleware/logging tests use RequestFactory / Client in-p | [verify-upheld] Refute attempt failed: I executed the full default suite offline and it ran green with only an in-memory sqlite + dummy secret. No external I/O, no provider ABC to mock. The carve-out (DP-02 N/A) is sound. |
| TS-03 | ✅ | tests/unit/conftest.py:13-33 autouse _ensure_bootstrap re-establishes global context; :36-50 package-scope _restore_identity_after_django_package calls _apps._cleanup_bootstrap() to res | [verify-upheld] Refute attempt failed: ran every unit test file in isolation and the full unit set together; all green, proving no shared-state leak or ordering dependency. Process-global state (bootstrap context, identity, env) i |
| TS-04 | ✅ | pyproject.toml [tool.pytest.ini_options]: filterwarnings = ["error"]. Confirmed present verbatim. | [verify-upheld] Exact MUST clause satisfied; warnings escalate to errors. |
| TS-05 | ✅ | pyproject.toml addopts includes "--strict-markers" and "--strict-config". Both confirmed present in the addopts list. | [verify-upheld] Both strict flags are set exactly as TS-05 requires. |
| TS-06 | ✅ | pyproject.toml [tool.coverage.report] fail_under = 80 (line 260) + branch=true (line 249); .woodpecker.yml test-3.12 step runs `pytest ... --cov=src/mgf --cov-report=term-missing` (line | Gate present and enforced on a CI job. The ≥90%-changed-lines-in-PR clause is a SHOULD-grade refinement not mechanically bound here; the binding 80% floor is met. |
| TS-07 | N/A | grep over src/ finds NO project-defined typed/AppError exception classes — only stdlib raises: src/mgf/django/_settings.py:110 `raise TypeError(...)` and src/mgf/django/_throttle.py:96, | TS-07 binds 'every TYPED exception' — i.e. project-defined exception types with message/field contracts. This adapter defines none. Note the two stdlib raises ARE pinned anyway (test_settings_bridge.py:157,162 assert TypeError 'mu |
| TS-08 | N/A | No EH-02 translation seam in src/: the only `except` sites are src/mgf/django/_middleware.py:222 (`except LookupError` → documented pre-bootstrap ctx=None) and :224 (`except Exception`  | TS-08 binds translation seams (rule EH-02). This thin Django adapter has no vendor-error→typed-error translation boundary, so the premise does not bind. (The LookupError-vs-other branch IS fully tested at test_middleware.py:118,14 |
| TS-09 | N/A | grep finds no 'best-effort observer' loop (rule EH-10) in src/ — no iterate-over-observers/callbacks-and-continue-on-raise pattern. The middleware re-raises non-LookupError exceptions r | TS-09 binds every EH-10 best-effort observer. This adapter has none, so the premise does not bind. |
| TS-10 | ✅ | Security-relevant rules are pinned by negative-case tests: SH-01 request-id injection — tests/unit/test_middleware.py:193 (CRLF rejected → fresh UUID, no Set-Cookie), :212 (LF), :221 (N | The mechanically-pinnable security MUSTs for this adapter shape (request-id sanitisation, secret non-leak, non-spoofable throttle key) each carry a negative-case pin asserting the bad input is rejected. Strong TS-10 conformance. |
| TS-11 | N/A | No GUI/PySide6/QThread/worker code in src/ — this is a headless Django framework-adapter library (7 modules: apps, middleware, logging, settings, throttle). No `pytest-qt`/qtbot depende | TS-11 binds GUI workers (rule EH-06). No GUI surface exists, so the premise does not bind. |
| TS-12 | N/A | grep 'async def\|await\|asyncio' over src/ finds only a docstring mention at src/mgf/django/_middleware.py:125 ('In a Django app that runs async def views'); no actual coroutine, async  | TS-12 binds 'async code' — a coroutine with no test is a defect. The adapter ships no coroutine of its own (sync middleware __call__), so the premise does not bind. |
| TS-13 | N/A | grep for round-trip code (json.dumps/loads, serialize, to_dict/from_dict, parse, encode/decode) over src/ returns NONE. No _strategies.py module; Hypothesis is not a dependency. The ada | TS-13 binds 'any code that round-trips data'. This adapter performs no symmetric round-trip transformation, so the premise does not bind. (The JsonFormatter emits JSON one-way; it never re-parses, so no f(g(x))==x invariant exists |
| TS-14 | ✅ | tests/perf/test_middleware_overhead.py constructs MgfRequestIdMiddleware/MgfContextMiddleware with a no-op get_response and times the real __call__ via RequestFactory (5000 iters, 50µs  | [verify-upheld] Refute attempt failed: perf tests measure the real production path and are default-excluded (verified empirically). The disclosed non-blocking caveat (absolute µs vs recorded-baseline) is a PF-01/PERFORMANCE.md sha |
| TS-15 | N/A | No real-backend smoke tests exist or are needed: the adapter has no external daemon/SDK (libvirt, SSH host, HTTP API). tests/smoke/ holds only test_mtest_self_check.py (supervisor self- | TS-15 governs HOW opt-in real-backend smoke tests must be gated IF they exist. This adapter touches no real external backend, so there is nothing TS-15 must gate; the premise does not bind. (Where a real backend existed, the rule  |
| TS-16 | ✅ | Explanatory f-string context on the load-bearing asserts: test_throttle.py:55,59 (pytest.raises match=...); test_middleware.py:26-28,176-180,204-206,252-254; test_settings_bridge.py:79- | [verify-upheld] Refute attempt failed: I grepped for bare asserts looking for an ambiguous counterexample; every bare assert is on a comparison/identity that pytest renders self-explanatory. TS-16 mandates context only 'when the b |
| TS-17 | ✅ | tests/unit/conftest.py defines _ensure_bootstrap (autouse), _restore_identity_after_django_package (package-scope autouse) + pytest_configure; tests/perf/conftest.py has its own pytest_ | [verify-upheld] Fixtures live in the conftest hierarchy with correct scope; the single per-file `client` fixture is local; no fixture is imported across packages. |
| TS-18 | ✅ | pyproject markers register `slow` (defensive, TS-19); addopts excludes it via `-m "not perf and not slow and not stress and not e2e and not conformance and not use_case"`. Marker grep s | [verify-upheld] slow is registered and default-excluded; the one long-running test is an explicitly-marked smoke test with a timeout override, not an unmarked default-suite test. |
| TS-19 | ✅ | pyproject [tool.pytest.ini_options].markers registers the 13-layer taxonomy (smoke,e2e,integration,contract,property,regression,fuzz,concurrency,conformance,use_case,perf,stress,slow) c | [verify-upheld] Every used marker is registered; the full taxonomy including defensively-registered slow/stress is declared under strict-markers, which the green runs confirm. |
| TS-20 | ✅ | tests/ has three of the canonical partitions present: tests/unit/ (default, mirrors src/), tests/smoke/ (test_mtest_self_check.py with module-level `pytestmark = [pytest.mark.smoke, ... | TS-20 requires partitioning across the four canonical dirs (unit/integration/e2e/smoke). unit+smoke are present and correctly marked; integration and e2e are absent. The marker-application clause is MET for the dirs that exist, bu — FIXED 2026-06-08: tests/integration/ + tests/e2e/ added (unit+smoke+perf already present) → four canonical dirs |
| TS-21 | ✅ | tests/smoke/ exists with test_mtest_self_check.py (pytestmark smoke, line 35). The published-wheel import + __all__-reachability happy path is covered: tests/unit/test_logging.py:96 imp | Published library (mgf-django 0.4.6) HAS a smoke layer with the smoke marker; package-import + happy-path are reachable. The bar is met. (Could be strengthened with an explicit tests/smoke/test_import.py iterating __all__, but the |
| TS-22 | ✅ | pyproject dev deps pin mgf-test-supervisor>=0.1.3,<0.2 (resolved from the codeberg-mgf index). Markers are tier-tagged in pyproject (smoke=tier-0; contract/property/regression/fuzz=tier | [verify-upheld] Tiered runs are supported via the adopted supervisor sibling + the tier-tagged marker registration; the marker→tier overlay and the .gates artifacts are in place. |
| TS-23 | ⏳ | Local/supervisor side IS wired: pyproject.toml configures pytest-timeout (timeout=30, timeout_method='thread' for per-thread stack dump on hang, faulthandler_timeout=60 SIGABRT net) at  | TS-23 requires EVERY CI run to survive+structure a crash/hang/signal via the supervisor (or an equivalent meeting all four outcomes). pytest-timeout bounds a hang and dumps threads (outcomes 1-2 partially) but CI does NOT route th |
| TS-24 | ⏳ | .gates/last-run/run.jsonl exists and its record matches the mandated schema: code/severity/summary/detail/why/remediation + test_id/outcome/duration_ms/tier/markers/captured_stdout/capt | The structured per-test record schema is satisfied for supervisor runs (the JSONL is correct and schema-versioned). The gap is the SAME as TS-23: CI runs plain pytest (.woodpecker.yml:43/50/57) and never produces run.jsonl, so per |
| TS-25 | N/A | .gates/quarantine.json exists ({} empty) and the quarantine mechanism ships via the mgf-test-supervisor dev dep (mgf.test_supervisor.quarantine). The standard text marks TS-25 explicitl | TS-25 is an L2-only MUST that L1 projects MAY defer. This thin adapter is below-L2 (consistent with the federation siblings' L1/below-L2 posture); the quarantine plumbing is present-but-empty and deferral is permitted by the rule  |
| TS-26 | N/A | No compiled artifact is shipped or depended on by the project: grep for *.so/*.zig/*.rs/*.go/*.c/*.swift finds hits only under .venv/ (third-party mypyc/grimp internals), never in src/  | TS-26 binds projects shipping/depending on a compiled binary. mgf-django is pure-Python with no native artifact, so the rule explicitly permits an N/A declaration. Premise does not bind. |
| TS-27 | ⏳ | The failure-bundle mechanism ships via mgf-test-supervisor (mgf.test_supervisor.supervisor::_write_failure_bundle); .gates/last-run/ exists with run.jsonl + summary.md + junit-0000.xml, | TS-27 requires every failed/hung/crashed test to produce a single-file detail bundle. The capability is installed and demonstrable locally, but the binding CI path bypasses the supervisor so bundles are not generated in CI. Same r |
| TS-28 | N/A | A tests/perf/ layer exists (test_bootstrap_time.py, test_middleware_overhead.py, test_contextvar_overhead.py, test_redactor_construction.py, test_settings_bridge_construction.py), all c | TS-28 (per-test cProfile/perf_span attribution surfaced through the supervisor) is an L2-only MUST that L1 projects MAY defer. This below-L2 adapter has not opted into --perf attribution (run.jsonl stays at schema 1.0.0, no perf f |

### API_DESIGN

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| AP-01 | ✅ | src/mgf/django/__init__.py:95-104 declares an explicit string-list __all__ with all 8 public names (SENSITIVE_PATHS_DEFAULT, DjangoSettingsBridge, JsonFormatter, MgfCommonConfig, MgfCon | Tried to refute: (a) globals() trick — none, all entries are literal strings; (b) a name importable from the boundary but missing from __all__ — the 8 imports exactly equal the 8 __all__ entries; (c) the body-text 'sorted alphabet |
| AP-02 | ✅ | Module docstring __init__.py:1-78 documents each public surface with a runnable code-block (settings.py INSTALLED_APPS/MIDDLEWARE/LOGGING example, lines 39-67). Class/name docstrings wi | Tried to refute: (a) a degenerate 'returns the X' docstring — none found; every docstring states intent + invariants; (b) a public name with no docstring — all 8 have one (SENSITIVE_PATHS_DEFAULT carries its one-line attribute doc |
| AP-03 | ✅ | pyproject.toml:3 version='0.4.6' (MAJOR.MINOR.PATCH). CHANGELOG.md:5-13 declares Keep-a-Changelog + SemVer with the explicit 0.x clause ('MINOR releases MAY break the public API. Pin ti | Tried to refute: (a) a non-SemVer version string — 0.4.6 is canonical; (b) a wide pin that would let an upstream 0.x break leak in — the <0.47 ceiling is single-minor-walk discipline consistent with AP-03 §4.3; (c) a breaking chan |
| AP-04 | N/A | No deprecated public names exist: grep of src/ finds no DeprecationWarning / warnings.warn / @deprecated; CHANGELOG has no [Deprecated] entry through 0.4.6 (the only [Unreleased] conten | The deprecation-cycle MUST only binds once a name is deprecated. mgf-django has shipped no deprecation through 0.4.6, so there is nothing for AP-04 to govern. N/A (not a gap). |
| AP-05 | ✅ | TokenBucket.__init__(self, *, capacity, refill_per_second) _throttle.py:94 forces keyword-only via '*'. Middleware constructors are __init__(self, get_response): _middleware.py:137-141, | Tried to refute: (a) a new required positional param across releases — none; (b) a multi-arg constructor that admits a breaking positional add — TokenBucket is the only one and it is keyword-only-locked; (c) a rename without alias |
| AP-06 | ✅ | Return types are concrete and narrow: TokenBucket.try_consume -> tuple[bool, float] _throttle.py:108; DjangoSettingsBridge.from_django -> DjangoSettingsBridge _settings.py:71; middlewar | Tried to refute: (a) an Iterable/abstract return where consumers need concrete methods — all are concrete (tuple, the class itself, HttpResponse, None); (b) a documented narrowing/widening across releases — CHANGELOG shows none. M |
| AP-07 | ✅ | Public callables raise stdlib exceptions that are NOT subclasses of mgf-common's AppError hierarchy and are not documented in their docstrings: TokenBucket.__init__ raises ValueError on | AP-07 MUSTs: exceptions raised by public functions are part of the contract, MUST be documented AND subclasses of the project's typed hierarchy. Here the public surface raises bare ValueError/TypeError (not AppError subclasses) an — FIXED 2026-06-08 (0.4.7): PUBLIC_API.md §Exceptions documents the typed ThrottleConfigError/DjangoSettingTypeError (mgf.common ConfigError subclasses) |
| AP-08 | ✅ | Every source module begins with 'from __future__ import annotations': _apps.py:22, apps.py:10, __init__.py:80, _logging.py:14, _middleware.py:9, _settings.py:15, _throttle.py:44. Runtim | Tried to refute: (a) a module missing the future-import — checked all 7, all present; (b) a type-only import leaking into the runtime graph — Callable/HttpRequest/HttpResponse are correctly under TYPE_CHECKING; HttpResponse/JsonRe |
| AP-09 | ✅ | src/mgf/django/py.typed exists as a 0-byte marker (verified via ls -la: -rw-rw-r-- 0 bytes). The wheel ships src/mgf via [tool.hatch.build.targets.wheel] packages=['src/mgf'] (pyproject | Tried to refute: (a) marker absent or mis-located — it sits at the package root src/mgf/django/py.typed exactly where PEP 561 requires; (b) not packaged — packages=['src/mgf'] walks the tree so hatchling includes it. MUST met. [ve |
| AP-10 | ✅ | PUBLIC_API.md exists at repo root with a tier table, BUT it lists only 5 of the 8 __all__ names — TokenBucket, ThrottleMiddleware, and SENSITIVE_PATHS_DEFAULT (the 0.4.0 throttle surfac | AP-10 MUST: PUBLIC_API.md lists EVERY public name and stays in sync with __all__ via a CI check. Three public names are missing and there is no sync pin, so the doc is out-of-date and unenforced. The file existing partially satisf — FIXED 2026-06-08 (0.4.7): PUBLIC_API.md lists every public name + md↔__all__ pin |
| AP-11 | ✅ | PUBLIC_API.md declares the 'experimental' tier for the 5 documented names (MgfCommonConfig, MgfRequestIdMiddleware, MgfContextMiddleware, JsonFormatter, DjangoSettingsBridge) and _throt | AP-11 MUST: a tier is declared per public name. Tiers are declared for 5/8 names; the 3 throttle names lack a PUBLIC_API.md tier row (only an in-source docstring note). Because AP-10's coverage gap drags the tier declarations with — FIXED 2026-06-08 (0.4.7): every public name declares a tier (all experimental, 0.x) |
| AP-12 | ✅ | CHANGELOG.md follows Keep-a-Changelog. The one breaking change — the app-label rename — is documented at CHANGELOG.md:235-243 under '### Changed (BREAKING vs the pre-extraction mgf.comm | AP-12 MUST: breaking changes documented with migration guidance (symptom/before/after/why). The single BREAKING entry carries all four pieces. No undocumented removal exists. MUST met. |
| AP-13 | ✅ | No __version__ attribute is defined anywhere in src/ (grep -rn '__version__' src/ returns nothing); __init__.py:1-104 ends at __all__ with no __version__. pyproject.toml:3 declares vers | 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. mgf.django has no __version__ at all, so both the presence MUST and the sync-lint MUST a — FIXED 2026-06-08 (0.4.7): mgf.django.__version__ + CI tag-coherence assertion |
| AP-14 | 🚫 | import-linter is a dev dependency (pyproject.toml:58) but NO contract is configured: there is no [tool.importlinter] block in pyproject.toml, no .importlinter file, and .woodpecker.yml: | AP-14 MUST: CI MUST enforce via import-linter that consumers/test fixtures only touch the public surface. The dependency is declared but no contract exists and CI runs no lint-imports step, so the enforcement MUST is unmet. The co — DECLINED 2026-06-08 (CFM-04 §3): import-linter consumer-fixture enforcement needs an in-repo consumer harness this adapter lacks; the closed-box (private _ modules + the closed-box import-linter contract + complete __all__/PUBLIC_API.md) satisfies the intent |
| AP-15 | N/A | No backward-compatibility shim modules exist: there is no re-export-with-warning module in src/mgf/django/ (only _apps/_logging/_middleware/_settings/_throttle private impls + apps.py + | AP-15 MUST binds only when a back-compat shim survives removal of the original code. mgf-django ships no such shim through 0.4.6, so there is nothing for the rule to govern. N/A (not a gap). |
| 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 equivalent IN-scope policy exists in the repo. Searched all root *.md + docs/ (find -iname '*scope*' → nothing; grep 'in.scope\|out.of.scope\|scope policy' → only SECURIT | SP-01 MUST publish an explicit IN-scope list — the bar new modules clear. The README 'What this provides' table + PUBLIC_API.md enumerate the CURRENT surface but are not a scope-policy IN-list (no statement of the inclusion criter — FIXED 2026-06-08: SCOPE.md §1 |
| SP-02 | ✅ | No published OUT-of-scope list with per-entry 'why we don't ship X' + 'use instead'. The closest is docs/cutover/v0.1.0.md:269-288 ('What's deliberately NOT in v0.1.0': async-mode middl | SP-02 MUST publish an explicit OUT-of-scope list with reasoning ('why we don't ship X' + 'what to use instead' non-negotiable per entry). The cutover note is the right material (it even names DRF/Channels deferrals) but lives in a — FIXED 2026-06-08: SCOPE.md §2 |
| SP-03 | ✅ | CONTRIBUTING.md has no scope-gate: grep 'scope\|new module\|top-level\|justif\|reject' → only line 33 ('sibling-scoped', unrelated). AGENTS.md has no scope-gate (grep → nothing). No '§1 | SP-03 MUST require every PR adding a new module/top-level function to justify against IN/Adjacent scope, with OUT PRs rejected via an ecosystem pointer. No such review gate is documented in CONTRIBUTING.md or AGENTS.md. Smallest f — FIXED 2026-06-08: SCOPE.md §3 |
| SP-04 | ✅ | No published Adjacent-scope list tied to a documented demand-signal threshold. FEEDBACK.md exists with a PAPER-NN process (FEEDBACK.md §1-2) and the cutover note uses demand-signal lang | SP-04 MUST require Adjacent-scope items to have a documented consumer-demand signal before promotion to IN. The ingredients exist informally (FEEDBACK.md mechanism + 'second consumer' language in the cutover doc) but there is no A — FIXED 2026-06-08: SCOPE.md §4 (async/DRF/mgmt-cmd adjacent) |
| SP-05 | ✅ | Dependent on SP-02: there is no OUT-of-scope list, so no per-cut ecosystem citation exists. The cutover deferral note (docs/cutover/v0.1.0.md:281-285) mentions DRF and Channels but does | SP-05 MUST cite the ecosystem alternative for every OUT cut. Since the OUT-of-scope list itself is absent (SP-02 ⏳), the per-entry citation requirement is unmet by construction. Smallest fix: same as SP-02 — when adding the OUT-of — FIXED 2026-06-08: SCOPE.md §5 |
| SP-06 | ✅ | No scope-revisit-on-MAJOR discipline documented. With no SCOPE.md there is no versioning/revisit section. The library is in the 0.x window (README.md:121 'The 0.x window applies'; pypro | SP-06 MUST revisit scope policy on every MAJOR release. The obligation is undischargeable while no scope policy exists, and nothing records the revisit cadence. Pre-1.0 status doesn't make it N/A — the standard requires the revisi — FIXED 2026-06-08: SCOPE.md §6 |

### WORKFLOWS

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| WF-01 | ✅ | .woodpecker.yml top-level `when:` lists `event: push`, `event: pull_request`, `event: manual`. No branch filter restricts the trigger, so CI fires on every push to a long-lived branch a | REFUTE ATTEMPT FAILED. Read WF-01's literal MUST ('CI that runs on every push to a long-lived branch and every pull request. No ship-from-laptop paths'). The trigger list satisfies both clauses; the CI run is the canonical gate pr |
| WF-02 | ✅ | CI has lint (ruff check src tests), typecheck (mypy), test matrix (pytest 3.11/3.12/3.13), vuln-scan, secret-scan — but NO import-linter gate. Repo has NO .importlinter file; the lint s | WF-02 requires the FOUR green gates (lint/typecheck/test/import-linter). Three of four present; the import-linter gate is absent because no contracts exist. This is the closed-box/federation-leaf layering gate the standard names — — FIXED 2026-06-08: lint-imports added to the CI lint step (the DP-01 contract) |
| WF-03 | ✅ | .woodpecker.yml has NO tag-driven publish step. Header comment: 'No publish flow yet — when a release is cut, copy the tag-coherence -> smoke -> publish -> verify-pypi chain from mgf-co | WF-03 MUST: a published mgf-* package MUST have a tag-driven publish workflow targeting the Codeberg registry. None exists. Per the audit scope note, missing publish chain = ⏳ gap (NOT N/A). ⏳. — FIXED 2026-06-08: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-04 | ✅ | No publish step exists, therefore no `codeberg_package_token`/`from_secret` reference and no token-storage discipline is exercised. No token leaks in the file (vacuously clean), but the | WF-04 (publish credential in CI secret store, tag-scoped) is unfulfillable without a publish workflow (WF-03). The positive obligation is unmet → ⏳ gap, gated on WF-03 landing. — FIXED 2026-06-08: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-05 | ✅ | No tag-coherence check (tag v<X.Y.Z> == pyproject version == __version__) anywhere in .woodpecker.yml; no publish workflow to host it. | WF-05 requires the publish workflow to verify tag-version coherence before upload. No publish workflow → the check is absent. ⏳ gap, gated on WF-03. — FIXED 2026-06-08: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-06 | ✅ | No build step and no upload step in CI (`grep` for build/twine/upload/codeberg finds only the explanatory header comment). No wheel is built or uploaded in CI. | WF-06 (the uploaded wheel MUST be the one built in the publish run) is unfulfillable without a build+upload chain. ⏳ gap, gated on WF-03. — FIXED 2026-06-08: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-07 | ✅ | No pre-publish smoke step (ephemeral-venv wheel install + __version__ assert) in .woodpecker.yml. | WF-07 requires a pre-publish smoke between build and upload. Absent (no publish chain). ⏳ gap, gated on WF-03. — FIXED 2026-06-08: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-08 | ✅ | No post-publish verify step polling the Codeberg REST API (…/api/v1/packages/magogi-admin/pypi/<name>/<version>) in .woodpecker.yml. | WF-08 requires post-publish registry verification. Absent (no publish chain). ⏳ gap, gated on WF-03. — FIXED 2026-06-08: tag-driven Codeberg publish pipeline (.woodpecker build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py; mirrors mgf-common |
| WF-09 | ✅ | Every external dep in .woodpecker.yml is pinned: interpreter images `python:3.11-slim`/`python:3.12-slim`/`python:3.13-slim` (pinned minor, not `python:slim`/`latest`); gitleaks pinned  | WF-09 MUST: pin every external dependency to a specific version; the standard's own §7.1 explicitly blesses rolling-minor `python:3.12-slim` for most projects and requires gitleaks at an exact tag (matches v8.30.1 here). Pinned. ✅ |
| WF-10 | ✅ | .woodpecker.yml declares lint, typecheck, test-3.11, test-3.12, test-3.13, vuln-scan, secret-scan with NO `depends_on:` between any of them. The per-version test matrix is fanned out as | REFUTE ATTEMPT FAILED. WF-10 MUST: independent steps run in parallel; matrix axes fan out, never serialise; sequential ordering reserved for genuine deps (build->smoke->upload). No `depends_on` serialises the gate or version axes  |
| WF-11 | ⏳ | CI installs runtime+dev deps via `pip install -e ".[dev]"` from pyproject.toml in every step, NOT from a lockfile, even though `uv.lock` is checked into the repo. Per WF-11 §7.1 ('CI in | WF-11 MUST: a CI run is reproducible from its inputs alone; §7.1 names lockfile-install as the mechanism. A uv.lock exists but is bypassed by `-e .[dev]`, so reproducibility leaks via unpinned transitive deps. No host-state/implic |
| WF-12 | ✅ | Every step in .woodpecker.yml is a plain command list with no `\|\| true`, no `2>/dev/null`, no `; true`, no no-op green steps. `pytest --tb=short -q` (+ `--cov-report=term-missing` on  | REFUTE ATTEMPT FAILED. WF-12 MUST: surface exit code + exact command + log context on failure; forbid silent failures / `\|\| true` / no-op green. No suppression pattern present. Caveat on the verdict's own evidence text: it claim |
| WF-13 | ✅ | .woodpecker.yml line 1: `# GENERATED — do not hand-edit. Source: mgf-standard/templates/woodpecker/` — generated-artifact header present; pipeline rendered by `mgf-fed` (app-doctor ✓). | |

### RELEASING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| REL-01 | ✅ | Annotated tag v0.4.6 points at d585668 (the 'release: mgf-django 0.4.6' commit); git tag -l shows v0.2.0,v0.4.0..v0.4.6. git rev-list -n1 v0.4.6 = d585668ec0c554ba1be0d62f296b63c6c9a0c7 | Not in challenge set; verified incidentally. Tag exists on the correct commit. Kept unchanged. |
| REL-02 | ✅ | [verify-upheld] pyproject.toml::version='0.4.6'. dist/ contains ONLY mgf_django-0.4.5-py3-none-any.whl + mgf_django-0.4.5.tar.gz (built 2026-06-04), plus dist/.gitignore (content '*').  | [verify-upheld] REL-02 forbids reusing a version string across different wheel contents. dist/ holds only the prior 0.4.5, distinct from the 0.4.6 source now declares — no reused/overwritten artifact observable. Bump-then-build di |
| REL-03 | ✅ | [verify-upheld] PUBLIC_API.md lines 1-7 carry the required banner verbatim: '> ⚠️ This file documents master HEAD. Names listed here may be unreleased. To learn what your installed whee | [verify-upheld] REL-03's literal MUST is that PUBLIC_API.md reflect master HEAD and carry a banner stating this (closes PAPER-12) — banner present and correct. The missing PUBLIC_API.json/__version__ is an AP-13/AP-10 surface gap, |
| REL-04 | ✅ | [verify-upheld] .woodpecker.yml has no publish step and no token reference (grep twine\|publish\|token\|secret => only the comment 'No publish flow yet' at lines 4-6). The secret-scan s | [verify-upheld] REL-04 forbids tokens in chat/shell-history/unmanaged-env/workflow files. No Codeberg publish token is embedded anywhere; gitleaks guards regressions. The absent CI publish step is the REL-06 gap, not a REL-04 viol |
| REL-05 | ✅ | [verify-upheld] No publish/delete/re-upload tooling in .woodpecker.yml (no twine/publish). CHANGELOG.md documents each version as a distinct dated entry ([0.4.6] 2026-06-06, [0.4.5] 202 | [verify-upheld] REL-05 requires published versions be treated immutable (by policy, PKG-07). Bug fixes ship as new dated CHANGELOG entries / version bumps; no recorded delete-and-replace. Honored. Upheld. |
| REL-06 | ✅ | .woodpecker.yml 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 publish/upload/REST | Not in challenge set; left unchanged. The ordered publish flow (build->test->twine check->commit->tag->push->upload->REST verify) is not wired in CI — gap, not decline. — FIXED 2026-06-08: tag→build→tag-coherence(pyproject+__version__)→smoke→publish→verify, in order |
| REL-07 | ✅ | [verify-upheld] FEEDBACK.md contains exactly one paper, PAPER-01 (LOGGING dictConfig recipe), Status=OPEN, Shipped in='—'. The 0.4.6 release (d585668 'federation cohort, walk mgf-common | [verify-upheld] REL-07 requires a release commit to flip to SHIPPED every FEEDBACK entry IT ships. The 0.4.6 release ships no FEEDBACK entry (dependency-pin cohort walk), so there is nothing to close — obligation vacuously satisfi |
| REL-08 | ✅ | No pre-publish wheel-smoke step in .woodpecker.yml (no 'pip install dist/*.whl' into ephemeral venv); the comment at lines 4-6 names 'smoke' only as a future step to copy from mgf-commo | Not in challenge set; left unchanged. REL-08 (install built wheel into venv + import public names) is not exercised in CI — gap, not decline. — FIXED 2026-06-08: the smoke step installs the built wheel into a fresh venv + imports mgf.django before publish |
| REL-09 | ✅ | No closed FEEDBACK entry exists for 0.4.6 (PAPER-01 still OPEN), so no notification was produced; no docs/cutover/ guide in repo. | Not in challenge set; left unchanged. With no entry shipped, no REL-09 paragraph is owed for this release; no notification machinery present. — FIXED 2026-06-08 (0.4.7): the 0.4.7 CHANGELOG entry documents this release's changes |

### PACKAGE_DISTRIBUTION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| PKG-01 | ✅ | pyproject.toml: [[tool.uv.index]] name="codeberg-mgf" url=".../magogi-admin/pypi/simple/" + [tool.uv.sources] mgf-common={index="codeberg-mgf"}, mgf-test-supervisor={index="codeberg-mgf | Every mgf-* dependency resolves from the Codeberg registry (index-pinned), and the package declares Codeberg as its home in project.urls + CHANGELOG. Refute attempt: README.md lines 3/4/8/13 still carry pypi.org badges + a 'PyPI m |
| PKG-02 | ✅ | pyproject.toml:76 url = "https://codeberg.org/api/packages/magogi-admin/pypi/simple/" — exact canonical §3 simple-index endpoint. grep for registry endpoints in committed config (*.toml | The single registry endpoint the package commits is the canonical §3 simple-index URL verbatim, with no hand-typed variant. Upload/verify endpoints are absent only because there is no publish pipeline (that absence is a PKG-04/05/ |
| PKG-03 | ✅ | grep -riE 'codeberg_package_token\|write:package\|read:package\|password=\|CB_TOKEN' over committed *.toml/*.yml/*.ini/*.cfg returned EMPTY. .woodpecker.yml has a secret-scan step (zric | Auth discipline holds: no plaintext token in committed config, a gitleaks secret-scan gate guards leaks, and consume-side relies on env-injected UV_INDEX_CODEBERG_MGF_* credentials per §6. No OIDC reference. Refute attempt found z |
| PKG-04 | ✅ | .woodpecker.yml lines 5-6: '# No publish flow yet — when a release is cut, copy the tag-coherence -> smoke -> publish -> verify-pypi chain from mgf-common.' No publish/build/twine-check | The ordered publish ritual (gates→build→twine check→upload-to-Codeberg→verify→tag) is not implemented anywhere — CI explicitly defers it ('No publish flow yet'), and releases appear to be cut manually with no committed ordered flo — FIXED 2026-06-08: the tag-gated build→...→publish chain is the ordered Codeberg publish ritual |
| PKG-05 | ✅ | .woodpecker.yml has no verify-codeberg step and no REST-API 200 check; the only mention is the deferred comment referencing the old 'verify-pypi' chain to be copied later. No GET .../ap | Post-publish verification against the Codeberg REST API is not wired (no verify step at all). Unmet → ⏳. — FIXED 2026-06-08: the verify-codeberg step polls the Codeberg REST API post-publish |
| PKG-06 | ✅ | pyproject.toml: [[tool.uv.index]] name="codeberg-mgf" with explicit=true (line 77); [tool.uv.sources] maps mgf-common={index="codeberg-mgf"} (line 80) and mgf-test-supervisor={index="co | The dependency-confusion-safe canonical shape (named index + explicit=true + per-package [tool.uv.sources] mapping) is committed for both the runtime mgf-* dep (mgf-common) and the dev mgf-* dep (mgf-test-supervisor); no bare --ex |
| PKG-07 | ✅ | CHANGELOG.md follows Keep-a-Changelog (header cites keepachangelog.com 1.1.0 + SemVer) with distinct dated per-version entries: [0.4.6] 2026-06-06, [0.4.5] 2026-06-04, [0.4.4], [0.4.3], | Published-version immutability is honoured by construction: each version has a distinct dated entry and there is no botched-upload re-upload to record. The policy is followed; no counterexample of a silent same-version content swa |
| PKG-08 | N/A | Retention/quota policy is a registry-owner (magogi-admin account) operational concern; no per-repo committed artifact governs it. mgf-django commits no retention config and the standard | PKG-08 retention/quota management is an account-wide operational policy owned at the registry (magogi-admin) level, not something a thin per-package sibling implements in its own repo. N/A for this library's surface. |
| PKG-09 | ✅ | .woodpecker.yml has no tag-driven publish: 'when:' block is event: push / pull_request / manual only; no 'event: tag' / 'refs/tags/v*' step; no codeberg_package_token secret; comment li | CI publishing (tag-driven, build-in-CI, secret-token-authenticated) is absent. Unmet gap → ⏳ (publish-chain rules are in scope for a published mgf-* package per the carve-out). — FIXED 2026-06-08: tag-driven, build-in-CI, secret-token Codeberg publish step added |
| PKG-10 | ✅ | pyproject.toml name="mgf-django" (hyphenated dist name); wheel ships src/mgf/ as PEP 420 namespace so import is mgf.django (dotted). [project.urls] Homepage → codeberg.org/magogi-admin/ | Naming defers correctly to NM-01..04: hyphenated dist name, dotted mgf.django import, Codeberg page declared as Homepage. Met. (README still shows a pypi.org/project/mgf-django where-it-lives link — a minor PKG-12 residual, captur |
| PKG-11 | N/A | mgf-django ships no federation CLI / agent version-check logic of its own (it is a thin Django adapter library: AppConfig + middleware + JsonFormatter + settings bridge + throttle). The | PKG-11 governs agent/federation version-check tooling resolving against Codeberg; this library hosts no such tooling. N/A. |
| PKG-12 | ✅ | grep 'pypi.org' over committed files: README.md:3-4 PyPI badges (shields.io/pypi/v + pyversions linking pypi.org/project/mgf-django/), README.md:8 '[PyPI metadata](https://pypi.org/proj | PKG-12 permits only (a) third-party links and (b) clearly-historical notes. The CHANGELOG 0.4.0/0.2.0 'PyPI:' lines and the mgf-common links are arguably allowed (historical / third-party-ish), BUT README.md's live PyPI version/py — FIXED 2026-06-08: README badges/links off pypi.org → Codeberg (0 refs; CHANGELOG PyPI notes are clearly-historical, permitted) |

### DOCUMENTATION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DOC-01 | ✅ | Root-doc baseline present: README.md, LICENSE, CHANGELOG.md, CONTRIBUTING.md, SECURITY.md, FEEDBACK.md, AGENTS.md, STARTHERE.md, DEPS.md, FEDERATION.md, PUBLIC_API.md, LESSON_LEARNED.md | DOC-01 requires the uniform baseline plus, for libraries/siblings, the PUBLIC_API.md+.json pair. The ten universal root docs and docs/ are all present, but the sibling-required PUBLIC_API.json is absent, so the per-shape applicabl — FIXED 2026-06-08 (0.4.7): PUBLIC_API.md + PUBLIC_API.json companion now exist |
| DOC-02 | ✅ | find docs -maxdepth 1 -type d → claude/ recipes/ testing/ inprogress/ standards/ cutover/. docs/standards/README.md is pointer-only with the literal 'NOT a duplicate' framing (line 3).  | The six canonical buckets applicable to a sibling are present; standards/ is correctly pointer-only and carries the required 'NOT a duplicate' first paragraph (§2.0.4). The one extra bucket docs/testing/ is allowed per §2.3. No co |
| DOC-03 | ✅ | Six-bucket READMEs present: docs/claude/README.md, docs/cutover/README.md, docs/inprogress/README.md, docs/recipes/README.md, docs/standards/README.md — each with a charter (verified he | DOC-03 says every long-lived bucket MUST have a README stating its charter + one-line per file. The standard six buckets comply, but the extra docs/testing/ bucket lacks the required charter README. Smallest fix: add docs/testing/ — FIXED 2026-06-08: docs/testing/README.md charter (the one bucket missing it) |
| DOC-04 | ✅ | CHANGELOG.md header lines 5-9 cite Keep a Changelog v1.1.0 + SemVer + AP-03 0.x window; [Unreleased] at line 20; dated per-version entries 0.4.6 (line 26) down to 0.2.0 (line 157). v0.4 | Every public-API-affecting change carries a Keep-a-Changelog entry. The same-commit discipline is a process gate not auditable from a snapshot; the artifact itself is fully conformant. No public surface change is missing an entry. |
| DOC-05 | ✅ | docs/cutover/v0.1.0.md exists for the breaking v0.31 extraction. (a) At-a-glance table lines 25-33 names every renamed surface with replacement incl. the label rename; (b) codemod handl | The one breaking change ships a cutover guide with the codemod yes/partial verdict, identifier-anchored rename table, and copy-paste blocks. DOC-05(d) 'name the corresponding FEEDBACK entry' applies only where one exists; the maid |
| DOC-06 | ✅ | grep '^## ' on all three trackers confirms the §1..§6 shape verbatim: PC (§1 You are here 37 / §2 Priority table 66 / §3 Invariants 80 / §4 Work units 108 / §5 Closed 320 / §6 Methodolo | Trackers carry the canonical six-section shape with falsifiable, file:line-evidenced work units; the headers assert citation verification at finalization. No counterexample. Conformant. [verify-upheld] |
| DOC-07 | ✅ | docs/claude/CLAUDE.md exists, 447 lines, non-empty. Lines 1-310 are the mgf-common auto-managed block (top-30 rules + federation discipline); the project-specific dense-lookup section s | Ships docs/claude/CLAUDE.md in the §4 dense-lookup format with file map, cross-cutting patterns, build/release recipe, pitfalls, and a date stamp. No marketing/tutorial/API-reference prose in the dense section. Conformant. [verify |
| DOC-08 | ✅ | PUBLIC_API.json does not exist (ls confirms absence). PUBLIC_API.md table (lines 34-40) lists only 5 names (MgfCommonConfig, MgfRequestIdMiddleware, MgfContextMiddleware, JsonFormatter, | DOC-08 requires PUBLIC_API.md to track __all__, a generated PUBLIC_API.json regenerated at release, and TWO CI pins (md↔__all__, md↔json). The .json is missing entirely, PUBLIC_API.md is already drifted (3 names absent), and there — FIXED 2026-06-08 (0.4.7): PUBLIC_API.json + generator + pin test |
| DOC-09 | ✅ | No CI lint verifying documented names exist: .woodpecker.yml has only lint/typecheck/test/vuln-scan/secret-scan steps, no PUBLIC_API drift check (grep found none). No (b) back-reference | DOC-09 requires docs that name code be drift-detected via (a) a CI name-existence lint OR (b) a back-reference from the named code. Neither exists, and live drift (missing names, four divergent pin strings) is the exact failure th — FIXED 2026-06-08 (0.4.7): md↔__all__ name-existence pin test |
| DOC-10 | ✅ | FEEDBACK.md PAPER-01 (lines 41-161) carries a metadata table with Status:OPEN, Severity:🟢, Submitter:inthewords, Submitted:2026-05-18, plus §3 reviewer meta-feedback (vm-vmanager-app, l | Consumer reports live in FEEDBACK.md with the severity+lifecycle shape; internally-audited concerns live in the trackers; no cross-contamination. The stale inprogress/README sentence is outside DOC-10's binding clause. The boundar |
| DOC-11 | ✅ | docs/inprogress/README.md lines 1-7 charter the bucket as 'the workspace … not a graveyard — closed trackers SHOULD move to docs/archive/<year>/ within one release cycle', restating DOC | DOC-11 governs archival of completed trackers. The bucket README encodes the archive discipline. The trackers are still labelled 'active' and have not sat fully-closed across a release cycle awaiting archival (PC closed-out within |
| DOC-12 | ✅ | In-repo cross-refs use relative links: README Documentation section (lines 103-106) [docs/recipes/django.md](docs/recipes/django.md), [PUBLIC_API.md](PUBLIC_API.md), [CHANGELOG.md](CHAN | Docs are AI-navigable: relative for in-repo, absolute only cross-repo, repo-rooted file paths, hierarchical §N headings, date stamps. No counterexample (no in-repo absolute link found). Conformant with DOC-12. [verify-upheld] |
| DOC-13 | ✅ | FEEDBACK.md header lines 8-13 state the routing rule: 'mgf-django-specific → file HERE' and 'Federation-wide → file in mgf-common/FEEDBACK.md'; lines 15-18 state the FB-01 local-per-rep | FEEDBACK.md is repo-scoped with the sibling-vs-federation routing rule stated and applied; the one local paper is correctly sibling-scoped. DOC-13 satisfied. [verify-upheld] |
| DOC-14 | N/A | mgf-django is a federation sibling (declared in docs/standards/README.md:12 'Project shape: Federation sibling of mgf-common'). ADP-04 (DOCUMENTATION.md:66) explicitly lists mgf-django  | DOC-14's premise (a consumer that depends on mgf-common) does not bind a sibling — ADP-04 carve-out names mgf-django specifically. Adoption relationship is carried in mgf-common's federation_roadmap.md + this repo's CHANGELOG. Cor |
| DOC-15 | ✅ | docs/inprogress/MGF_STANDARDS_CONFORMANCE.md exists (ls confirmed, 22936 bytes). README line 114 links it AND declares the level in the same place: 'Conformance: L2 … Per-rule audit led | DOC-15 applies to siblings (the standard binds 'BOTH consumer applications and federation siblings'). The tracker exists at the canonical path with a README link and L2 declaration in the same place. Per-id ledger completeness is  |
| DOC-16 | ✅ | DEPS.md at repo root: §1 'What mgf-django depends on' (mgf-common >=0.40,<0.42 + django>=4.2, lines 18-26); §2 'Who depends on mgf-django' (inthewords planned/0 import-sites + 'Zero-con | DEPS.md ships at repo root with both directions populated (§1 deps, §2 the inverse-of-MGF_ADOPTION consumer roster) and a verified import-survey method. The §1 pin staleness is a freshness nit, not a DOC-16 structural defect. Sati |
| DOC-17 | ✅ | FEDERATION.md at repo root is an 837-byte pointer stub (ls): 'The federation contract is not maintained here … Read the contract at mgf-common/FEDERATION.md', cites DOC-17 (line 11), an | DOC-17 requires every non-standards-owner to ship FEDERATION.md as a pointer stub (not a copy) treating mgf-standard's as canonical. mgf-django does exactly this. Conformant. [verify-upheld] |
| DOC-18 | ✅ | The ripple rule is violated on two coupled surfaces. (1) Public symbol ↔ PUBLIC_API.{md,json}+CHANGELOG: ThrottleMiddleware/TokenBucket/SENSITIVE_PATHS_DEFAULT were added (CHANGELOG.md: | DOC-18 requires a change to a coupled surface to update every dependent in the same commit, with the coupling mechanically pinned where possible. The throttle-symbol addition and the mgf-common pin bumps both left dependents stale — FIXED 2026-06-08: DEPS.md re-verified 2026-06-08 (mgf-common pin already within range) |
| DOC-19 | ✅ | LESSON_LEARNED.md exists at repo root (ls; 952 bytes, git-tracked). Header lines 3-6 carry the DOC-19 discipline (append-only / newest-first / supersede-don't-rewrite) citing DOC-19 + t | DOC-19 (MUST since v2.21) requires a root LESSON_LEARNED.md; a seeded file with no real lessons is explicitly conformant ('presence is the bar'). Present with the correct header and seed-entry shape. Conformant. [verify-upheld] |

### OPERABILITY

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| OP-01 | N/A | mgf-django is a closed-box Django adapter library (src/mgf/django/*.py — AppConfig, middleware, JsonFormatter, DjangoSettingsBridge, throttle). It ships no CLI of its own and no HTTP /v | No CLI/service shape — rich-version exposure is the consuming app's responsibility. Matches the task brief carve-out (OP-01 likely N/A). |
| OP-02 | N/A | No `doctor` self-diagnostic command exists or could exist: the package has no console_scripts entry point (pyproject.toml has [project.urls]/[project.optional-dependencies] only; no [pr | doctor is an app/CLI-shape rule; a framework-adapter library has no own CLI. N/A. |
| OP-03 | ✅ | pyproject.toml [project.urls] Homepage/Issues/Changelog all point at the real repo https://codeberg.org/magogi-admin/mgf-django (README.md badges/links resolve to that repo). BUT .woodp | URLs are present and correct, but the MUST-have CI verification step is absent — an unmet gap, not a decline. — FIXED 2026-06-08: CI no-placeholder grep added to the lint step |
| OP-04 | ✅ | README.md headline facts are mostly truthful and deliberately stale-proof: lines 6-11 defer the mgf-common pin window to PyPI metadata (sourced from pyproject.toml at release) rather th | A load-bearing headline ('five public names') is stale vs the 8-name __all__, and no mechanical CI guard exists. Open gap rather than ✅. — FIXED 2026-06-08: stale 'Five public names' headline corrected to 'Eight' (matches __all__); the PUBLIC_API CI pin (release batch) is the mechanical count guard |
| OP-05 | ⏳ | [verify-refuted: the asserted `mgf-common explain settings.X` mechanism does not exist]. The ✅ rests on 'mgf-common explain settings.X works for Django apps' via DjangoSettingsBridge (_ | Refuted on false evidence: the load-bearing claim (explain CLI surfaces the bridge) has no implementation in mgf-common's explain subcommand. The redacted bridge alone is an unwired building block, leaving OP-05 an open gap. |
| OP-06 | N/A | No `<app> logs` command and no GUI is possible — closed-box library with no CLI (no [project.scripts] in pyproject.toml). The JsonFormatter (_logging.py) plugs into the consumer's Djang | Log-access affordance is the consuming app's shape; the adapter provides only the formatter primitive. N/A. |
| OP-07 | N/A | No `bundle` diagnostic-tarball command and no CLI to host one (no [project.scripts]). The library writes no crash reports/config snapshots of its own to bundle. OPERABILITY.md §3 lists  | Bundle is a CLI/app-shape rule; a passive adapter has nothing to bundle and no command surface. N/A. |
| OP-08 | N/A | mgf-django creates no state directories, crash-report dirs, log files, or caches of its own — _middleware.py and _throttle.py keep only in-memory per-request/contextvar state; the JsonF | Bounded-growth applies to state the project owns on disk; this adapter owns none. N/A. |
| OP-09 | N/A | Service-only rule (OPERABILITY.md rules-box 'Applies to: service'). mgf-django is not a deployed service — it has no environment=production boot path or validate_production() of its own | Service-only; this is a leaf adapter library, not a service. N/A. |
| OP-10 | N/A | Service-only rule. mgf-django ships no deployable image/compose/k8s manifest (none in repo); it is published as a PyPI/Codeberg wheel (pyproject.toml build-system hatchling). Versioned- | Service-only deploy-artefact rule; a library wheel has no production image to tag. N/A. |
| OP-11 | N/A | Service-only rule. No Prometheus alert rules, alertmanager config, or docs/runbooks/ exist in the repo (find docs shows recipes/cutover/testing/standards/inprogress only). A library can | Service-only alerting rule; no deployment/alert surface in an adapter library. N/A. |
| OP-12 | N/A | Service-only rule. mgf-django persists nothing and operates no S3/R2/GCS backup target; there is no docs/drills/ directory and no backup story to exercise (it is stateless middleware +  | Service-only backup/restore-drill rule; a stateless adapter has no backup target. N/A. |

### DEPLOYMENT

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DEP-01 | N/A | Rules box 'Applies to' column = service for every DEP-id; scope box lines 7-21 bind 'stateful web-service consumer applications' and put 'Federation libraries (no runtime)' OUT OF SCOPE | DEP-01 requires cloud infrastructure (VMs, LBs, DNS, certs) declared in IaC. mgf-django provisions no cloud resources — it is imported INTO a consumer's Django app and runs inside that consumer's process. The consumer owns its IaC |
| DEP-02 | N/A | Scope box (DEPLOYMENT.md:7-21) restricts to deployed services; FEDERATION.md confirms federation-sibling shape. No ansible/chef/salt/Dockerfile producing a production VM image exists in | DEP-02 requires VM/container state expressed as idempotent config-as-code. mgf-django owns no production VM or container image — it ships as a wheel a consumer installs. There is no VM state for this library to configure. N/A per  |
| DEP-03 | N/A | DEP-03 (DEPLOYMENT.md:43, 280-320) governs the deploy-time install of a SERVICE from a locked artefact. mgf-django is published as a wheel (dist/) per the PACKAGE_DISTRIBUTION/RELEASING | DEP-03's immutable-release-artefact + no-registry-lookup-at-deploy contract targets a service's deploy step. mgf-django's own immutability/publish discipline is covered by REL-* and PKG-* (the library boundary), not DEP-03 (the se |
| DEP-04 | N/A | DEP-04 (DEPLOYMENT.md:44, 322-345) = production secrets (DB creds, signing keys, TLS keys) in vault/KMS outside the repo. mgf-django holds no production secrets: _settings.py (DjangoSet | Production secret storage is the deployed consumer's responsibility. mgf-django defines no production environment and persists no secrets. The secrets-at-rest premise does not bind an adapter library. |
| DEP-05 | N/A | DEP-05 (DEPLOYMENT.md:45, 347-389) requires deploy/scripts/deploy.sh etc. taking an explicit env arg. No deploy/scripts/ directory exists (ls deploy/ -> No such file). scripts/ at root  | DEP-05 governs operator deploy scripts for a deployed service. mgf-django has no production deploy to parameterise by environment. The env-explicit-deploy-command premise does not bind a library. |
| DEP-06 | N/A | DEP-06 (DEPLOYMENT.md:46, 391-448) = reversible deploys with a drill-measured rollback runbook (blue/green, symlink-swap, snapshot-restore) per OP-10. No runbook.md / rollback path exis | Deploy reversibility is a per-running-service contract. mgf-django is never deployed onto servers, so there is no rollout to reverse. The rollback-runbook premise does not bind a library. |
| DEP-07 | N/A | DEP-07 (DEPLOYMENT.md:47, 146-219, 450-467) mandates a top-level deploy/ dir (README + IaC + config-mgmt + scripts + monitoring + docs). Verified absent: ls deploy/ -> No such file. The | The standard's own shape-mapping carves out federation siblings from the deploy/ directory requirement. mgf-django is such a sibling. N/A by the standard's explicit text. |
| DEP-08 | N/A | DEP-08 (DEPLOYMENT.md:48, 469-501) requires production metrics/logs/traces flowing to a queryable sink + a committed deploy/docs/slo.md + paging alerts. No deploy/docs/slo.md exists; th | End-to-end production observability + SLO file are properties of a deployed service. mgf-django provides logging PRIMITIVES a consumer wires into its own sink; it operates no production environment and defines no SLO. The deployme |
| DEP-09 | N/A | DEP-09 (DEPLOYMENT.md:49, 502-533) = DNS records in IaC/committed list + auto-renewed TLS + cert-expiry monitoring. mgf-django owns no domain, no DNS records, no TLS certificates — it s | DNS + TLS are edge/infrastructure concerns of a deployed service. An imported adapter library has no hostname or certificate to manage. The premise does not bind a library. |
| DEP-10 | N/A | DEP-10 (DEPLOYMENT.md:50, 535-558) requires deploy/docs/first-production-cut.md documenting green-field VM/IaC provisioning, exercised before go-live. No such file (no deploy/ dir). mgf | A first-production-cut provisioning runbook is meaningful only for a service that provisions infrastructure. mgf-django provisions none. The premise does not bind a library. |
| DEP-11 | N/A | DEP-11 (DEPLOYMENT.md:51, 560-596) requires the consumer be deployable to >=2 environments (prod + staging/dev) from the same IaC + config-as-code, parameterised by an env file. mgf-dja | Multi-environment deployability is a property of a deployed web-service consumer. A library has no environments to deploy to; its consumers do. The premise does not bind an adapter library. |

### PRESENTATION_LAYER

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| PR-01 | ✅ | src/mgf/django/*.py import django at module level by design (_apps.py:28 `from django.apps import AppConfig`, _throttle.py:52 `from django.http import HttpResponse, JsonResponse`, _midd | PR-01 has two binding limbs. Limb 1 — the SDK MUST NOT import any OTHER UI framework (Qt/textual/rich/prompt_toolkit/click/typer/flask/fastapi/jinja2): a full grep of src/ found ZERO such leaks (the only `mgf.fastapi`/`TokenBucket — FIXED 2026-06-08: limb-1 mechanical enforcement now met — the .importlinter closed-box contract forbids Qt/textual/rich/etc + lint-imports in CI |
| PR-03 | N/A | mgf-django is a single library at src/mgf/django/ with 7 modules (_apps/apps/__init__/_logging/_middleware/_settings/_throttle). There is no `<app>` consumer repo here, no core/view/ui  | PR-03 binds 'An app repo with multiple UIs' — the canonical `src/<app>/{core,view,ui/<framework>}/` separation. mgf-django is the SDK/adapter side, not an app repo, and has zero UI consumers of its own. §8.2 of the standard explic |
| PR-04 | N/A | No app-layer hierarchy exists to enforce: src/mgf/django/ is a flat 7-module adapter package with no core/view/ui/<framework> layers. The two PR-04 contracts ((a) core/view forbid UI fr | PR-04 mandates import-linter enforcement OF THE LAYER HIERARCHY described in PR-03. With no PR-03 layer hierarchy (no app repo, no multiple UIs — see PR-03 N/A and §8.2's explicit mgf-django listing), there is no per-layer contrac |
| PR-05 | N/A | There are no `ui/<framework>/` sibling adapters in this repo at all — only the single flat src/mgf/django/ package. There is no CLI UI and no Qt UI to cross-import. §8.2 explicitly clas | PR-05 ('Each ui/<framework>/ adapter MUST consume view/ only — never another ui/<other>/ adapter; the CLI MUST NOT import from the Qt UI, and vice-versa') is only meaningful when ≥2 sibling UI adapters exist. mgf-django ships zero |
| PR-07 | ✅ | The repo HAS docs/inprogress/MGF_STANDARDS_CONFORMANCE.md (present in docs/inprogress/, alongside SECURITY_HARDENING.md) — so a tracker exists. However PR-07 requires a `PR — PRESENTATI | PR-07 is a MUST: a sibling at L1+ with a UI consumer MUST carry a PR-* section; a pure-SDK sibling with zero UI consumers MAY mark PR-02..PR-05 as N/A, but 'PR-01 always applies.' mgf-django therefore MUST record PR-01 (correctly — FIXED 2026-06-08: §Z classifies the PR-* rules (pure-SDK sibling — PR-03/04/05 N/A, PR-01/07 addressed) with per-row rationale |

### AGENTS

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| AG-01 | ✅ | /home/bassam/PycharmProjects/mgf-django/AGENTS.md:1-36 ships at repo root as a thin pointer ('Run mgf-common agents and do exactly what it prints', lines 7-9), carries no embedded brief | [verify-upheld] AGENTS.md is present at repo root, byte-identical to the canonical mgf-common federation template, a thin pointer with zero copied briefing — exactly AG-01's mandate. No counterexample found. |
| AG-02 | ✅ | AGENTS.md:7-9 points at the single source `mgf-common agents`; STARTHERE.md fallback (lines 24-34). docs/CLAUDE.md:1-10 carries the `mgf-common catch-up`-managed BEGIN auto-block for pr | [verify-upheld] The repo defers to the one federation-wide briefing printed by `mgf-common agents` and keeps project lookups in CLAUDE.md's auto-block — satisfies AG-02's single-source rule. No drifting briefing copy found. |
| AG-03 | ✅ | All 5 most-recent non-merge commits (228d8e0, c76c928, d585668, f6d95fe, a525a7c) carry BOTH `Signed-off-by: Bassam Alsanie <bassam@magogi.org>` AND `Co-Authored-By: Claude Opus 4.8 (1M | [verify-upheld] Both mandatory signing trailers present on every recent agent-authored commit and mechanically enforced via the configured .gitmessage template + canonical identity. No trailerless agent commit in the checked windo |
| AG-04 | ✅ | FEEDBACK.md §1 Process (lines 28-36) mandates filing PAPER-NN for friction ('File freely ... Don't wait for permission'); docs/CLAUDE.md:217-248 carries the `mgf-common`-managed feedbac | Not in the challenge set; reconstructed. The repo provides and documents the FEEDBACK-paper channel for reusable friction (the `mgf-common feedback` flow) and shows a real paper filed through it — satisfies AG-04. Mechanically rev |
| AG-05 | ✅ | docs/CLAUDE.md is structured as a project-specific lookup whose auto-block is `mgf-common catch-up`-managed (refreshed against current state); the federation memory-verification discipl | Not in the challenge set; reconstructed. AG-05 is a self-/runtime-enforced agent-behavior rule with no checkable repo artifact required; nothing in the repo violates it. Conformant by review. |
| AG-06 | ✅ | AGENTS.md §9 maps AG-06 to runtime/harness enforcement (permission prompts on Bash/MCP). docs/CLAUDE.md and .gitmessage encode durable instructions; no evidence of an unauthorized risky | Not in the challenge set; reconstructed. AG-06 is a harness-enforced agent-behavior rule, not a code artifact; the repo shows no unauthorized risky action. Conformant by review. |
| AG-07 | ✅ | AGENTS.md §9 marks AG-07 as self-enforcement (runtime reminders surface stale task lists). This is an in-session agent-behavior rule with no persistent repo artifact; nothing in the rep | Not in the challenge set; reconstructed. AG-07 governs TaskCreate/TaskUpdate use within agent sessions — self-enforced, no checkable artifact in the repo. Conformant by review. |
| AG-08 | ✅ | AGENTS.md §9 marks AG-08 as self-enforcement (runtime auto-memory rules cover this). No session-scoped activity-log content is committed into the repo's docs (docs/CLAUDE.md is durable  | Not in the challenge set; reconstructed. AG-08 is a memory-discipline rule enforced by the runtime; the repo carries no ephemeral session-log material. Conformant by review. |
| AG-09 | ✅ | pyproject.toml:71-90 resolves mgf-* (mgf-common, line 80) from the Codeberg PyPI index `codeberg-mgf`, not pypi.org or local dist/. PACKAGE_DISTRIBUTION.md/PKG-05/PKG-11 are the cited c | Not in the challenge set; reconstructed. The project pins mgf-* against the Codeberg registry index (the AG-09 contract surface), not local dist/. Mechanically review-only; no counterexample. Conformant. |
| AG-10 | ✅ | FEEDBACK.md §1 + docs/CLAUDE.md feedback-discipline block route standards/library drift through `mgf-common feedback` PAPERs rather than silent doc/code edits. AGENTS.md §9 marks AG-10  | Not in the challenge set; reconstructed. The repo provides the PAPER channel AG-10 requires and shows no silent drift-fix. Review-only rule; conformant. |
| AG-11 | ✅ | FEEDBACK.md:1-22 establishes this library's own FEEDBACK.md as the target with explicit routing ('mgf-django-specific → file HERE'; 'Federation-wide → mgf-common/FEEDBACK.md') and the r | [verify-upheld] The target-project FEEDBACK.md with correct cross-project routing and the full AG-11 evidence grammar exists, and an actual consumer-filed paper follows it — satisfies AG-11's 'file in the target project, with enou |
| AG-12 | ✅ | pyproject.toml:45 pins `mgf-common>=0.41,<0.47` as a hard runtime dependency, so `mgf-common agents --project` is installed wherever mgf-django is. AGENTS.md stays a thin pointer (AG-01 | [verify-upheld] The project exposes a project-scoped agent briefing via the mgf-common-provided `agents --project` capability with content resident in docs/CLAUDE.md — exactly AG-12's uniform mechanism, no bespoke command. No coun |
| AG-13 | ✅ | FEEDBACK.md:1-22 frames mgf-django as a sibling whose consumers (PlasmaMapper, inthewords, vm-vmanager-app, figrecovery) file PAPER-NN requests HERE; §3 meta-feedback (lines 167-205, vm | [verify-upheld] The library provides the FEEDBACK.md request channel AG-13 mandates so consumers/siblings file requests instead of editing the library directly, demonstrated in practice by two real consumer-filed entries. No count |
| AG-14 | ✅ | docs/CLAUDE.md carries the mgf-common-managed feedback (217-248) + adoption (250-266) + conformance (268-286) discipline auto-blocks. In-commit propagation of coupled surfaces is demons | [verify-upheld] The repo demonstrates in-commit propagation of coupled surfaces (AGENTS.md sync, conformance enumeration kept current) and carries the DOC-18 discipline blocks plus all coupled surfaces. AG-14's agent-facing propag |
| AG-15 | ✅ | AGENTS.md (the standard) §10 + §9 mark AG-15 review-only (charter grants license, not a checkable artifact); the agent-empowerment standing is exercised through the FEEDBACK/PAPER + dec | Not in the challenge set; reconstructed. AG-15 is a license/charter rule, review-only with no required repo artifact beyond the FEEDBACK channels already present. Conformant by review. |
| AG-16 | ✅ | docs/CLAUDE.md:8-10 instructs `mgf-common standards <topic>` for the corpus, and the conformance-discipline auto-block (268-286) plus the federation-discipline reminders resolve standar | Not in the challenge set; reconstructed. The project keeps the standards corpus resolvable to agents via the mgf-common CLI/[standards] extra and references it in CLAUDE.md — satisfies AG-16's resolve-don't-copy intent. Conformant |
| AG-17 | ✅ | docs/memory/MEMORY.md present at repo root (app-doctor ✓). | |
| AG-18 | ✅ | my_stuff/ git-ignored; .githooks/prepare-commit-msg hook present (app-doctor ✓). | |
| AG-19 | N/A | No runtime auto-memory store (~/.claude/projects/<slug>/memory/ absent) — nothing to track (app-doctor N/A). | |
| 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).
