# MGF_STANDARDS_CONFORMANCE — `mgf-vm-firecracker`

> Per-rule status against `mgf-common` standards. Updated on every
> `mgf-common` minor bump and on every PR that touches a conformance
> rule (CFM-03).

| Field | Value |
|---|---|
| `mgf-common` pin | `>=0.38,<0.39` |
| Declared level | **L2 — Standard** (target; see [`STANDARDS_NOTE.md`](../../STANDARDS_NOTE.md)) |
| Last audit | 2026-06-09 (evidence-based depth audit) |
| Verified standing | **below L2 — INTENTIONAL SKELETON** — 85 ✅ / 40 ⏳ / 93 N/A of 218 (68% of applicable; most ⏳ = unbuilt adapter) |

> **Legend.** ✅ honored · 🚫 declined (with rationale) · ⏳ pending
> (target stated) · N/A (rule doesn't apply at this layer).


**2026-06-09 depth audit (evidence-based, replaces the skeleton).** **mgf-vm-firecracker is an INTENTIONAL SKELETON at 0.1.2** — `src/` is just `__init__.py` (`FirecrackerAdapter` commented out); the Firecracker adapter impl deliberately waits for mgf-vm-core's Protocol surface to stabilize. Declared TARGET **L2**; verified below L2. Of 218: **85 ✅** (the standing CI/type/security GATES — mypy --strict, ruff bandit/DTZ/ASYNC, pip-audit, gitleaks, warnings-as-errors, coverage floor — all wired + CI-run) · **77 ⏳** · **93 N/A** · **0 declined**. **The 77 ⏳ split: ~40 are the UNBUILT adapter (DP-02 impl, EH error-translation, SC jailer/socket/image hardening, the impl's LG/TS) — deferred-pending-impl, NOT failures; the rest (~37) are closeable hygiene** (CI publish chain, import-linter contract, PUBLIC_API, SCOPE, docs — incl. a mis-pasted SECURITY.md that wrongly calls this a "pure-domain library, no sockets" and names itself twice).

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

| Cluster | Rules | Count |
|---|---|---|
| **CLOSEABLE hygiene** (CI publish + import-linter + docs + SCOPE + PUBLIC_API + fix mis-pasted SECURITY.md) | AG-16, AP-10, AP-11, AP-13, AP-14, DOC-01, DOC-03, DOC-08, DOC-09, DOC-12, DOC-15, DOC-18, DP-01, OP-03, OP-04, PKG-03, PKG-04, PKG-05, PKG-09, PKG-12, PR-01, PR-07, REL-01, REL-03, REL-04, REL-06, REL-08, SC-12, SC-18, SP-03, TS-01, TS-06, TS-19, TS-20, TS-21, WF-02, WF-03, WF-04, WF-05, WF-06, WF-07, WF-08 | 42 |
| **DEFERRED — adapter impl** (skeleton; lands when mgf-vm-core's Protocol stabilizes) | DP-02, DP-13, EH-01, EH-02, EH-03, EH-08, EH-11, EH-12, EH-13, LG-01, LG-05, LG-08, LG-09, LG-11, LG-15, LG-16, OP-01, SC-02, SC-04, SC-07, SC-08, SC-15, SC-16, SC-17, TS-07, TS-08, TS-10, TS-12, TS-13, TS-14, TS-15, TS-22, TS-23, TS-24, TS-25, TS-27, TS-28 | 37 |

## Per-standard verdicts → see §Z

The prior skeleton is superseded by the **§Z evidence-based per-MUST audit** below (2026-06-09).

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

> **2026-06-09 depth audit** (16-family fan-out + adversarial refute on every ✅, hardened prompt + extra-ruthless SECURITY pass; ~28 agents + a RELEASING+DOC re-run). **mgf-vm-firecracker is an INTENTIONAL SKELETON (0.1.2)** — src/ is just __init__.py; the Firecracker adapter impl 'begins after mgf-vm-core's Protocol surface stabilizes' (per its own __init__ docstring). So most ⏳ are the UNBUILT adapter (deferred-pending-impl), and the ✅ are the standing CI/type/security GATES already in place. No 🚫-flood, no mislabels. **Mix: 48 ✅ · 77 ⏳ · 93 N/A · 0 🚫.** Replaces the prior scaffold.


### DESIGN_PRINCIPLES

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DP-01 | ✅ | pyproject.toml:102-104 declares [tool.importlinter] root_packages=["mgf.vm.firecracker"], include_external_packages=true — but defines ZERO contracts. .woodpecker.yml:18 states explicit | DP-01 mandates CI lint the layering and (the DP-02 mechanical pair) that the vendor SDK be imported only inside the provider impl. import-linter is installed and its root package is set, but no contracts exist and CI does not run — FIXED 2026-06-09: .importlinter closed-box contract (forbid UI + unrelated siblings; httpx/mgf-vm-core allowed) + lint-imports in CI; 1 kept/0 broken |
| DP-02 | ⏳ | src/mgf/vm/firecracker/__init__.py is the ENTIRE source: __version__ + __all__ (with FirecrackerAdapter commented out, line 25 "Public adapter — lands as the implementation does"). No a | This is the IMPLEMENTATION side of the DP-02 seam (mgf-vm-core defines HypervisorBackend/StorageBackend; this adapter implements them via httpx/Firecracker). That implementation, the required mock, and the EXPECTED_METHODS lock-in |
| DP-03 | N/A | No domain types defined anywhere in src/ (only __version__/__all__). The frozen domain types (VmSpec, VMHandle, capability records) are owned by mgf-vm-core, not this adapter. grep foun | DP-03 governs domain types that this project DEFINES and passes across its own module boundaries. This adapter defines none — it will CONSUME mgf-vm-core's frozen types when translate.py lands. There is no surface here for the fro |
| DP-04 | ✅ | [verify-upheld] pyproject.toml:77-83 [tool.mypy] python_version=3.11, strict=true, warn_unused_ignores=true, mypy_path=src, namespace_packages=true, explicit_package_bases=true. .woodpe | [verify-upheld] Refute attempt: try to find an un-annotated public symbol or an unjustified Any → none exist; the only public symbols are module-level __version__ (a str literal) and the annotated __all__: list[str]. mypy --strict |
| DP-05 | ✅ | [verify-upheld] tests/unit/mgf/vm/firecracker/test_smoke.py mirrors src/mgf/vm/firecracker/ exactly. test_smoke.py only `import mgf.vm.firecracker` + asserts __version__ format and __al | [verify-upheld] Refute attempt: is the mirror exact? yes, 1:1. Does the default suite touch a daemon/network/creds? no — it only imports and asserts. Are real-Firecracker paths gated? yes, behind opt-in markers with --strict-marke |
| DP-06 | ✅ | [verify-upheld] Gates wired: pyproject.toml:69-72 ruff selects S(bandit)/DTZ/ASYNC/PTH; .woodpecker.yml:62-68 pip-audit (SC-10), :71-74 gitleaks (SC-01); filterwarnings=["error"] (pypro | [verify-upheld] Refute attempt focused on the security ✅: the ✅ rationale cited SECURITY.md as documenting the jailer/UDS model — that specific evidentiary claim is FALSE; SECURITY.md actively disclaims subprocess/socket use and i |
| DP-07 | ✅ | [verify-upheld] src/mgf/vm/firecracker/__init__.py:1-16 module docstring explains intent/invariants (the D-F2 "second adapter", why Firecracker differs from libvirt, Phase-1 status, whe | [verify-upheld] Refute attempt: find a public class/function lacking an intent docstring, or a forbidden what-comment → none. There are no public callables to document, and the module docstring is substantive (explains the WHY, no |
| DP-08 | ✅ | [verify-upheld] README.md:3-9 names the abstraction (mgf-vm-core's HypervisorBackend/StorageBackend, contracts.md) and the swap story; :95-104 "What this library does NOT contain" descr | [verify-upheld] Refute attempt (DP-08 is a SHOULD): is the swap recipe documented near the major component? The major external component is the hypervisor engine (Firecracker); the recipe — implement mgf-vm-core's Protocols per co |
| DP-09 | N/A | No long-running operations exist in src/ — no VM start/stop, no jailer spawn, no download, no poll loop (the entire source is __version__/__all__). grep found no CancellationToken usage | DP-09 binds long-running operations, requiring them to accept an explicit CancellationToken-like parameter. This skeleton has no operations at all. Nothing to check today. When boot/jailer-spawn lifecycle methods land they will ne |
| DP-10 | N/A | No fallback paths exist in src/ — no keyring→file backend selection, no provider/transport fallback, no startup backend-choice logging (source is __version__/__all__ only). The adapter  | DP-10 binds projects that HAVE a fallback path (the active backend must be queryable/logged). This adapter defines no fallback — there is a single intended transport. Nothing for the no-silent-fallback rule to bind. N/A for the cu |
| DP-11 | N/A | Mechanical gate IS wired: pyproject.toml:69 ruff select includes "RUF" (RUF006 unawaited-task is on by default) and "ASYNC"; .woodpecker.yml:19-24 runs `ruff check src tests`. grep foun | DP-11 binds asyncio.create_task ownership. There is no async code yet, so there are no tasks to own — nothing to violate. The mechanical check (RUF006 + ASYNC) that the standard names is already wired and CI-run, so when async cli |
| DP-12 | N/A | Mechanical gate IS wired: pyproject.toml:69-72 ruff select includes "DTZ" (DTZ001–005, the DP-12 enforcement family); .woodpecker.yml:19-24 runs `ruff check src tests` as a required CI  | DP-12 (governed by TIME.md TM-01..08) binds code that handles datetimes at module boundaries. This skeleton has no datetime usage. The DTZ ruff family — the exact mechanical check the matrix (§14) names for DP-12 — is enabled and  |
| DP-13 | ⏳ | No owned external resources exist in src/ yet — grep found no httpx client, no subprocess.Popen, no socket, no file handles (source is __version__/__all__). But the project's own pyproj | DP-13 requires every owned external resource (sockets, subprocesses) be released deterministically (with / try-finally / __aexit__) — and the carve-out brief flags exactly this as the adapter's obligation: "close httpx client + re |

### ERROR_HANDLING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| EH-01 | ⏳ | src/mgf/vm/firecracker/__init__.py is the ONLY source module (verified by find src -name '*.py'); it contains only __version__='0.1.2' (line 20) and an empty __all__ (lines 22-26). grep | EH-01 (every app-raised exception subclasses the base AppError tree; never raise bare/third-party across an internal API) is a real, BINDING obligation for this adapter — STANDARDS_NOTE.md lines 37-39 declare the future 'Translati |
| EH-02 | ⏳ | No httpx call, no subprocess/jailer invocation, and no _translate seam exist in src/ (grep httpx\|subprocess\|jailer\|except over src/ hits only the module docstring). STANDARDS_NOTE.md | This adapter IS the implementation side of the DP-02 seam: it owns the httpx/Firecracker-REST and jailer-subprocess calls, so EH-02 (translate third-party exceptions at the owning boundary) binds it squarely and the project itself |
| EH-03 | ⏳ | No re-raise sites exist (no 'except'/'raise ... from' anywhere in src/ per grep). The translation seam that EH-03 governs (chain cause via 'raise NewError(...) from original') is itself | EH-03 only has teeth once translation re-raises exist (EH-02). Because the adapter will own those seams (httpx/jailer) and they are declared-but-unbuilt, EH-03 is a real pending obligation rather than N/A. Smallest fix: when error |
| EH-04 | N/A | src/mgf/vm/firecracker/__init__.py exposes no CLI, no main, no process/thread/asyncio entry point — it is a pure library adapter (package docstring lines 1-16; empty __all__). STANDARDS | EH-04 (install a top-level handler at every entry point: CLI/_run_and_translate, sys.excepthook, threading.excepthook, loop.set_exception_handler, Qt) binds entry points. A vendor library adapter consumed in-process by mgf-vm-core |
| EH-05 | N/A | No process entry point exists (library only); no crash-reporter wiring and none required — crash reporting is the consuming app's responsibility via mgf.common.observability.report_now. | EH-05 (unhandled exceptions produce a local JSON crash report + optional remote sink) is an entry-point/process obligation, installed alongside the EH-04 handlers the consuming application owns. A thin adapter does not host the pr |
| EH-06 | N/A | No GUI, no Qt, no CoreWorker/QThread anywhere (the adapter is a headless library; package docstring describes a Hypervisor/StorageBackend adapter, not a UI). prompt SHAPE: 'a LIBRARY, n | EH-06 governs GUI worker threads (catch every exception, report via error(str) signal, route untyped through the crash reporter). This adapter has no GUI worker layer. Premise does not bind. |
| EH-07 | N/A | grep for 'except' across src/ returns zero matches — there is no 'except Exception:' anywhere in the skeleton (the only src .py is the version-only __init__.py). | EH-07 forbids un-re-raised/un-translated 'except Exception:' outside cleanup/best-effort paths. With no exception-handling code present, there is nothing for the rule to constrain or violate — it is vacuously inapplicable to the c |
| EH-08 | ⏳ | No typed exception classes are defined in this repo (no exceptions.py/errors.py; grep finds no class ...Error in src/). The adapter will translate Firecracker HTTP status/JSON-body erro | EH-08 (typed exceptions carry machine-readable fields as constructor args, e.g. argv/returncode/stderr/HTTP-status) binds the typed exceptions raised at this adapter's seams. The translated errors (e.g. a CommandError-shaped jaile |
| EH-09 | N/A | The adapter is a non-user-facing library (no CLI/GUI; empty __all__, headless backend). It raises typed exceptions consumed programmatically by mgf-vm-core/the orchestrator, which owns  | EH-09 (messages SHOWN TO USERS end in an actionable next step) applies where the project renders text to an end user. A vendor adapter has no user-facing output; the consuming app formats errors for the user. EH-08 machine-readabl |
| EH-10 | N/A | No best-effort observer / fan-out code exists (no hook executor, scheduler tick loop, alert evaluator, or event-callback fan-out in src/; the only module is the version stub). prompt SH | EH-10 (never-raises invariant for best-effort observers: catch broadly, log WARNING, return bool, continue) binds observer/fan-out subsystems. This adapter has no such subsystem. Note: an event-callback path (e.g. a Firecracker as |
| EH-11 | ⏳ | No retry logic exists (grep finds no backoff/retry/jitter and no httpx call in src/). The adapter owns the Firecracker REST-over-UDS calls and jailer spawn (STANDARDS_NOTE lines 9-10, 3 | EH-11 (retries MUST use exponential backoff + full jitter + finite cap; configurable + audit=true per attempt) binds external-call adapters that retry. This adapter is the boundary that makes the Firecracker HTTP + jailer calls, s |
| EH-12 | ⏳ | No write/send operations are implemented (the adapter does not yet issue any Firecracker REST PUT/create or jailer spawn; src/ has no such code). The HypervisorBackend/StorageBackend co | EH-12 (external writes/sends with multi-attempt cost MUST be idempotent; idempotency key = natural key) binds the create/start/attach operations this adapter will implement, especially paired with EH-11 retries. Unimplemented → re |
| EH-13 | ⏳ | No bounding mechanism — neither a circuit breaker nor a recorded 'retry-cap + call-rate bounds amplification' judgment — exists for the Firecracker REST / jailer calls (grep: no breaker | EH-13 (upstream-amplifying load MUST be bounded — circuit breaker canonical, OR a recorded judgment per non-adoption-is-valid that the finite retry cap + call rate already bound it; 'no breaker AND no recorded bound' is a defect). |

### LOGGING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| LG-01 | ⏳ | src/mgf/vm/firecracker/__init__.py is the only module (27 lines) — a documented skeleton; grep for 'logging\|getLogger\|LOG\.' across src/ and tests/ returns ZERO hits. No logger is acq | LG-01 binds 'all'. This is a thin adapter that WILL emit logs (it spawns jailer + talks httpx over a socket), so a per-module logger is owed, not exempt. The adapter code has not landed (__init__.py:13-15 'skeleton landed; adapter |
| LG-02 | N/A | Project is a published LIBRARY adapter (pyproject.toml has no [project.scripts]/console-entry; src is a single import-only package; SHAPE: 'a LIBRARY, no GUI/CLI/service'). | LG-02 mandates configuring logging 'in exactly one place per entry point (CLI main, GUI app.run, scheduler service entry)'. A library adapter has no entry point — the CONSUMING application's setup_logging owns single-point configu |
| LG-03 | N/A | No formatter, no handler wiring, and no observability dep in pyproject.toml (grep observability/opentelemetry/sentry = none). §5.3/§7.1: trace_id/span_id are added by JsonFormatter._add | LG-03 is satisfied by 'the standard formatter' the consuming app installs, not by a library that installs no handlers. The adapter neither owns nor configures a formatter. Premise does not bind a library adapter. |
| LG-04 | N/A | No Redactor / formatter / handler exists in the package (grep across src/). Redactor lives in mgf.common.observability (LOGGING.md line 7); redaction runs inside the formatter 'before a | LG-04's 'redacted by the formatter before any sink' binds whoever wires the formatter + sinks — the consuming app, not a library adapter that installs none. Premise does not bind. (Note: SC-11/SC redaction of secrets in the adapte |
| LG-05 | ⏳ | Zero ERROR/exception log sites exist (grep '.exception(\|exc_info\|LOG.error' = none). __init__.py:13-15 documents the adapter as an unimplemented skeleton. | LG-05 binds 'all' and will bind hard for this adapter: the EH seam translates Firecracker/httpx errors and MUST log them with exc_info/LOG.exception (carve-out: 'translate Firecracker/httpx errors ... at the seam'). No such site e |
| LG-06 | N/A | Library adapter installs no sinks/handlers (grep StreamHandler/RotatingFileHandler/basicConfig = none). Per-kind matrix: 'cli, library — LG-06's rotating-file branch typically applies'  | LG-06 ('logs MUST reach an aggregator') is an application-deployment property satisfied by the consuming app's entry-point setup, not by an importable library that owns no entry point and installs no handlers. Premise does not bin |
| LG-07 | N/A | Applies-to = gui-app only (rules box + per-kind matrix line 44). This package is a headless Firecracker adapter library (SHAPE: 'no GUI/CLI/service'); no PySide6/Qt anywhere. | LG-07 (log-viewer dialog) is explicitly scoped gui-app. Not a GUI app. Premise does not bind. |
| LG-08 | ⏳ | No log call sites exist at all (grep 'LOG\.\|logging\.(info\|debug\|warning\|error)' = none). | LG-08 (lazy %-formatting, no f-strings) binds 'all' and governs how log calls are written. None exist yet because the adapter is an unimplemented skeleton (__init__.py:13-15). Owed once the adapter logs → ⏳, not ✅ (nothing to veri |
| LG-09 | ⏳ | No log call sites and no `extra={...}` usage anywhere (grep 'extra=' = none). | LG-09 (structured fields via extra={}, not message concatenation) binds 'all' at every log site. None exist in the skeleton. Owed when the adapter logs vm_name/socket-path/returncode style fields at the seam → ⏳. Not ✅ (nothing em |
| LG-10 | N/A | Applies-to = service only (rules box + matrix line 45). This is a library adapter with no daemon/systemd-timer entry point (no [project.scripts], no service module). | LG-10 (JournalHandler at a headless service entry point) is scoped to services with their own entry point. A library adapter has no service entry and configures no logging. Premise does not bind. |
| LG-11 | ⏳ | No operation start/end logging and no `operation` field exist (grep 'operation' in src/ = none). __init__.py:1-15 describes an adapter that implements HypervisorBackend/StorageBackend a | This is the single highest-value LG gap for THIS adapter: LG-11 mandates start/end INFO records with a stable `operation` name for 'any function that crosses a process / network / storage boundary' — exactly what every adapter met |
| LG-12 | N/A | No log call sites and no handlers exist (grep across src/ = none); no consumer-side perf test (tests/ holds only test_smoke.py asserting __version__ and __all__). | LG-12 (≤100 µs/record; heavy work in the handler not the call site) constrains handler/formatter cost, which a library installs none of — emission cost is a property of the consumer-owned formatter/handlers (mgf.common.observabili |
| LG-13 | N/A | No log sites at all, and no inner-loop / per-event / per-progress-tick code exists yet (grep across src/ = none; adapter unimplemented per __init__.py:13-15). | LG-13 (rate-limit/sample high-frequency sites) binds only where a high-frequency log site exists. The skeleton has none, and it is not yet known whether the adapter will have any (Firecracker boot/config calls are one-shot per VM, |
| LG-14 | N/A | No correlation module / ContextVar registration in src/ (grep 'contextvars\|ContextVar\|correlation' = none). §16: the formatter promotes registered correlation contextvars — formatter  | LG-14 (request/user/lab correlation via contextvars, promoted by the standard formatter) is satisfied at the application boundary that owns the correlation, with promotion done by the consumer-owned formatter. A library adapter ne |
| LG-15 | ⏳ | No `event` field anywhere and no docs/reference/EVENTS.md (grep 'event' in src/ = none; file listing shows no EVENTS.md). The adapter's purpose is exactly the LG-15 surface: jailer spaw | LG-15 binds 'all' and the adapter has clear future security/boundary events warranting stable `event` fields (e.g. `jailer.spawn`, `firecracker.api.connect`, `firecracker.api.failed`) plus a docs/reference/EVENTS.md registry. None |
| LG-16 | ⏳ | No WARNING/ERROR records exist (grep 'LOG.warning\|LOG.error\|.exception(' = none). Adapter is a documented stub (__init__.py:13-15). | LG-16 (every WARNING/ERROR answers what/why/how, with WHY as extra={} and HOW as a hint per EH-09) binds 'all' at WARNING+ sites. The seam translating httpx/jailer failures will produce exactly such records, but none exist yet → ⏳ |
| LG-17 | N/A | LG-17 is a SHOULD (rules box: 'Every ERROR record SHOULD carry a stable fingerprint'; §4.7 'LG-17 is a SHOULD (not a MUST)'). No ERROR sites exist, and the default fingerprint is comput | LG-17 is a SHOULD, the default fingerprint is auto-computed by the consumer-owned formatter when exc_info is set, and §4.7's carve-out lets a consumer carve out 'when you've verified no grouping backend is in scope' — this library |

### CONFIGURATION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| CF-01 | N/A | src/mgf/vm/firecracker/__init__.py:1-27 is the entire source (a skeleton that declares only __version__='0.1.2' and an __all__ with FirecrackerAdapter still commented out). grep for set | CF-01 'Applies to: consumer-owned-config' (CONFIGURATION.md:23). This is a thin vendor ADAPTER that owns no application config schema — it is the implementation side of the DP-02 seam and receives all its configuration (socket pat |
| CF-02 | N/A | No Settings object, no env reads, no .env handling, no on-disk YAML, no settings_customise_sources anywhere in src/ (only __init__.py:1-27 exists). pyproject.toml carries no pydantic-se | CF-02 'Applies to: all', but the rule governs precedence of layered config SOURCES. There are zero config sources here — nothing to order. A thin adapter consumes its parameters via Protocol method arguments from the caller; layer |
| CF-03 | N/A | No config schema exists (src/mgf/vm/firecracker/__init__.py:1-27 is the whole module; no Settings/BaseModel/version field for a config object). The only 'version' is the package __versi | CF-03 'Applies to: consumer-owned-config' (CONFIGURATION.md:25). No owned config schema means no schema-version field, no migration chain. Premise doesn't bind to a config-less thin adapter. |
| CF-04 | N/A | No on-disk config file is written: no save_settings, no atomic_write, no chmod(0o600), no tmp.replace in src/ (only __init__.py:1-27). The adapter does not own or persist any config/sta | CF-04 'Applies to: consumer-owned-config' (CONFIGURATION.md:26). Atomic-write + 0o600 + lazy path expansion bind to a consumer that writes its own config file. This adapter writes none. (Note: when implemented, file PERMISSIONS fo |
| CF-05 | N/A | No config file and no secret storage exist anywhere in src/ (__init__.py:1-27 only). The adapter handles no passwords/tokens/keys — Firecracker is driven over a local Unix socket (pypro | CF-05 'Applies to: all' is a prohibition: secrets MUST NOT live in the config file; use a Vault. There is no config file and no secret-handling surface in this adapter (local-socket + jailer subprocess carry no persisted secrets). |
| CF-06 | N/A | No config schema / pydantic model with extra='forbid' exists (src/mgf/vm/firecracker/__init__.py:1-27 only; no BaseModel/BaseSettings). No config file is loaded, so there is no unknown- | CF-06 'Applies to: consumer-owned-config' (CONFIGURATION.md:28). Unknown-key rejection binds to loading an owned config file into a typed model. This adapter loads none. Premise doesn't bind. |
| CF-07 | N/A | No sub-config / satellite files (hooks, schedules, profiles, lab specs) exist or are loaded anywhere in src/ or tests/ (only __init__.py:1-27 and test_smoke.py). | CF-07 'Applies to: consumer-owned-config' (CONFIGURATION.md:29). A thin vendor adapter ships no satellite config files. Premise doesn't bind. |
| CF-08 | N/A | No Settings object and no module-global singleton exist (src/mgf/vm/firecracker/__init__.py:1-27). There is no entry point in this library (it is a LIBRARY, no CLI/GUI/service — pyproje | CF-08 'Applies to: consumer-owned-config' (CONFIGURATION.md:30). 'Load Settings once at the entry point, inject by constructor' binds to an application that owns a Settings object and has an entry point. This adapter has neither;  |
| CF-09 | N/A | No CLI exists: pyproject.toml declares no [project.scripts]/console entry points; src/ has no cli module or click usage (only __init__.py:1-27). README.md confirms a library install (pi | CF-09 'Applies to: consumer-owned-config' (CONFIGURATION.md:31) and requires a '--config <path>' CLI flag. A thin vendor adapter library has no CLI and no consumer-facing argv (analogous to the framework-native/web-shape carve-out |
| CF-10 | N/A | There is no Settings class to construct (src/mgf/vm/firecracker/__init__.py:1-27). The sole test file tests/unit/mgf/vm/firecracker/test_smoke.py:1-18 reads no env vars and constructs n | CF-10 'Applies to: all' but its MUST is 'tests MUST construct Settings with explicit values (no env-var leakage).' There is no Settings object to construct, and the existing test introduces no env-var dependency. With no Settings  |
| CF-11 | N/A | No config schema fields exist to rename (src/mgf/vm/firecracker/__init__.py:1-27; no pydantic model with Field(alias=...)/validation_alias). No on-disk config format is owned by this ad | CF-11 'Applies to: consumer-owned-config' (CONFIGURATION.md:33). Field-rename-via-alias binds to a consumer with an owned config schema and on-disk configs to preserve. This adapter has none. Premise doesn't bind. |
| CF-12 | N/A | No config field with mutually-exclusive backend variants exists (src/mgf/vm/firecracker/__init__.py:1-27; no Annotated/Union/Field(discriminator=...) and no Settings). The adapter expos | CF-12 'Applies to: all' but binds only 'When a config field has multiple mutually-exclusive backend variants.' This adapter has no such config field — it is itself a single concrete vendor backend with no selectable sub-backends i |

### SECURITY_STANDARD

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| SC-01 | ✅ | .woodpecker.yml:70-74 — secret-scan step uses image zricethezav/gitleaks:v8.30.1 running `gitleaks detect --source . --no-banner --redact` over the working tree + history on every push/ | [verify-upheld] Refute attempt failed: the gitleaks CI gate is genuinely present and configured over full history, and src/ carries no secret material (the skeleton __init__.py is a docstring + __version__ + __all__). SC-01's mech |
| SC-02 | ⏳ | src/mgf/vm/firecracker/__init__.py is a pure skeleton: docstring + `__version__ = "0.1.2"` + `__all__` (FirecrackerAdapter commented out, lines 24-25). grep over src/ for `subprocess`/` | The argv/shell=False rule is the central SC concern for this adapter (it will spawn jailer), and the intent is documented — but the jailer subprocess invocation has not landed. A documented-but-unimplemented contract surface is ⏳, |
| SC-03 | N/A | No YAML/JSON/pickle loading anywhere in src/ (grep for yaml/pickle returns nothing). The Firecracker REST API uses JSON, but no deserialization code exists yet; when it lands it will be | No deserialization surface in the current skeleton. Forward-looking note: when the Firecracker JSON response handling lands it must use json.loads + typed validation (json is safe by default), but there is nothing to adjudicate to |
| SC-04 | ⏳ | No file-write code in src/ today. The adapter will handle VM images/paths and the jailer chroot (pyproject line 30, README/docstring); jailer creates files/sockets under a chroot. No 0o | This is a flagged SC concern (file perms on VM images/socket/chroot). The skeleton writes no files, but the eventual adapter will manage filesystem state where SC-04 perms apply. Documented-future surface with no code = ⏳, not N/A |
| SC-05 | N/A | No cryptographic code in src/ (grep for md5/sha1/random/crypto returns nothing). A Firecracker/jailer adapter performs no crypto itself — TLS/secrets live in mgf-common's vault, and the | An httpx-over-UDS + subprocess adapter has no need for cryptographic primitives; mgf-common owns crypto. Carve-out: crypto is genuinely out of this library's shape. N/A. |
| SC-06 | N/A | The Firecracker REST API is served over a local Unix domain socket (firecracker.sock), not TLS — pyproject lines 27-31, docstring line 5. httpx-over-UDS has no certificate to verify. gr | TLS verification does not apply to a Unix-socket transport (there is no remote peer certificate). No outbound TLS connection is in this adapter's shape — the only network surface is the local UDS to the colocated Firecracker proce |
| SC-07 | ⏳ | pyproject documents httpx-over-UDS for the Firecracker API (lines 27-31) + subprocess for jailer. SC-07 mandates a finite timeout on both the httpx.Client and subprocess.run(timeout=).  | Timeouts on the Firecracker socket calls and the jailer subprocess are a real SC-07 obligation for this adapter, and the boundaries are documented — but no boundary code has landed. Documented-future boundary with no code = ⏳. Bec |
| SC-08 | ⏳ | SECURITY.md lines 17-19 state the consumer validates VmSpec at the boundary and 'the library trusts it inside'. The adapter will translate VmSpec → Firecracker JSON and handle image pat | Input validation at the seam (typed VmSpec, path/range bounds before constructing Firecracker config + jailer argv) is an SC-08 obligation once the adapter translates specs — particularly the image-path handling. The boundary cont |
| SC-09 | N/A | No log records emitted by src/ (no LOG usage; the skeleton has no logic). Redaction is owned by mgf-common's Redactor (SECURITY_STANDARD §16); a thin adapter inherits it via setup_loggi | No logging surface in the current skeleton, and a Firecracker adapter has no project-specific secret-bearing log fields (the Firecracker API over UDS carries no secrets; jailer argv are paths/ids). Redaction is mgf-common's job. N |
| SC-10 | ✅ | uv.lock is committed to git (git ls-files confirms; 936 lines). .woodpecker.yml:62-68 vuln-scan step runs `pip-audit --skip-editable --ignore-vuln CVE-2025-71176` on every push/PR. The  | [verify-upheld] Refute attempt failed: a pinned lockfile IS committed and a CVE scanner DOES gate every PR with the single finding justified in-line (matching SC-10's fix/justify/document requirement). MET. |
| SC-11 | N/A | No exception-translation seam, no crash-reporter code, no raise statements in src/ (the skeleton has no logic). Crash-reporter scrubbing is mgf-common's responsibility (SECURITY_STANDAR | Traceback/crash scrubbing has nothing to act on in a skeleton with no error paths. When the EH translation seam (Firecracker/httpx errors → mgf-vm-core's typed TransportError tree) lands it must avoid leaking, but the Firecracker  |
| SC-12 | ✅ | A SECURITY.md DOES exist at the repo root with a security contact (bassam@magogi.org, line 7), a disclosure window (5-day ack / 30-day fix, line 9), and a 'Reporting a vulnerability' he | The file exists and covers reporting/contact/timeline, but is materially inaccurate for THIS library (it describes the wrong scope — a pure domain library that opens no sockets, when this is the hardware-touching adapter that does — FIXED 2026-06-09: SECURITY.md REWRITTEN — was mis-pasted from mgf-vm-core (wrongly claimed pure-domain/no-sockets + named itself twice); now describes the real adapter model (jailer argv/shell=False, Firecracker UDS via httpx, image-path resolve+contain, vendor-isolation) |
| SC-13 | N/A | No cryptographic keys at rest, no key material, no embedded keys in src/ (grep for KEY/crypto returns nothing). Key management is mgf-common's vault concern; this UDS+subprocess adapter | No key-at-rest surface in this adapter's shape. N/A (same carve-out as SC-05). |
| SC-14 | N/A | The adapter performs no authentication — it talks to a local Firecracker daemon over a Unix socket (filesystem-permission-gated, not credential-gated) and spawns jailer. No login/auth b | Auth-enumeration/rate-limiting applies to an authentication boundary; this adapter has none (UDS access is gated by OS file permissions on the socket, not by an in-app credential check). N/A. |
| SC-15 | ⏳ | Path-traversal protection is a flagged central SC concern: the adapter handles VM images/paths and the jailer chroot (pyproject line 30, audit brief). SC-15 requires resolve() + is_rela | VM-image and chroot path handling is exactly where SC-15 bites for this adapter, and it is documented as forthcoming — but no path-construction code has landed. Documented-future surface with no code = ⏳. Will be a MUST-verify ✅ w |
| SC-16 | ⏳ | The adapter's reason for existing is privileged isolation: it spawns the jailer binary, which itself performs privileged setup (chroot, cgroups, namespace, drop-priv) — pyproject lines  | jailer is a privileged-operation surface (its whole purpose is sandboxing a microVM with elevated setup), so SC-16's per-call-site documentation/justification will apply once the jailer invocation lands. Intent documented, no code |
| SC-17 | ⏳ | SC-17 mandates an audit=true INFO record for subprocess-against-user-controlled-argv (the jailer spawn) and other security-relevant actions. No logging/audit code exists in the skeleton | The jailer subprocess is precisely the 'exec.user' audit event SC-17 §9.3 enumerates; an audit record will be required when that call site lands. Documented-future security action with no code = ⏳. |
| SC-18 | ✅ | Built with hatchling (pyproject lines 53-55), uv.lock committed, and tagged (git tags v0.1.0/v0.1.1/v0.1.2 present). SC-18 requires the artefact be buildable from a tagged commit using  | This IS a published mgf-* package (per the audit brief), so per the brief's rule publish-chain items are ⏳, not N/A, when there is no tag-driven chain. Tags exist but CI has no build/checksum/publish step and no release-notes buil — FIXED 2026-06-09: .woodpecker sbom step (reproducible CycloneDX SBOM) |

### TESTING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| TS-01 | ✅ | src/ has exactly one module: src/mgf/vm/firecracker/__init__.py (a skeleton: __version__ + empty __all__, no FirecrackerAdapter). The 1:1 mirror exists structurally — tests/unit/mgf/vm/ | The MUST has two halves: (a) every src module has a test mirror, and (b) CI lints that no source file lacks a mirror beyond a documented allow-list. Half (a) is trivially satisfied for a one-module skeleton (and __init__ is an exe — FIXED 2026-06-09: tests/test_mirror.py (1:1 mirror-lint) |
| TS-02 | ✅ | [verify-upheld] tests/unit/mgf/vm/firecracker/test_smoke.py only `import mgf.vm.firecracker as adapter` and asserts on __version__/__all__ — no network, no daemon, no credentials, no ht | Refute attempt: is there any hidden network/daemon touch? No — the only test imports the package and reads attributes; there is no production I/O code to reach. The integration marker is registered and the integration/ dir is empt |
| TS-03 | ✅ | [verify-upheld] The two tests in test_smoke.py (test_version_set, test_all_is_a_list) touch no module-level state, no HOME/XDG/cwd, no logging handlers, no sys.excepthook — they only re | Refute attempt: any shared mutable global or env leakage? None — both tests are pure attribute reads on an imported module with no side effects. There is no process-global state to save/restore in this skeleton. Upheld. |
| TS-04 | ✅ | [verify-upheld] pyproject.toml [tool.pytest.ini_options] line 93: `filterwarnings = ["error"]`. | Refute attempt: is it actually wired/overridden? It is set verbatim under the active [tool.pytest.ini_options] table, not commented out, and --strict-config (TS-05) would reject a malformed config. Upheld. |
| TS-05 | ✅ | [verify-upheld] pyproject.toml line 92: `addopts = "--strict-markers --strict-config"`. | Refute attempt: both flags present? Yes, both --strict-markers and --strict-config are in addopts. The markers `integration` and `conformance` used in pyproject are registered, so --strict-markers does not break the run. Upheld. |
| TS-06 | ✅ | pyproject.toml line 100: `fail_under = 80` is set, and .woodpecker.yml test-3.12 runs `pytest ... --cov=src/mgf --cov-report=term-missing`. So a coverage gate exists and runs on the 3.1 | The MUST is ≥80% on EVERY CI job + ≥90% changed-lines in a PR. test-3.11 and test-3.13 run pytest with no --cov/--cov-fail-under, and there is no changed-lines diff-cover step. Partial — gate exists but not on every job and no cha — FIXED 2026-06-09: CI pytest --cov=mgf.vm.firecracker (fail_under in [tool.coverage.report]) |
| TS-07 | ⏳ | No typed exceptions exist in src/ — the adapter is a skeleton with no error types (EH translation to mgf-vm-core's TransportError tree has not been written). No tests assert message for | This is the implementation side of the DP-02 seam; typed exceptions and their tests are expected once the adapter lands. Not N/A (the library will have them); a documented not-yet-implemented gap is ⏳. |
| TS-08 | ⏳ | No translation seam (EH-02) exists yet — there is no code translating Firecracker/httpx errors into mgf-vm-core's typed TransportError tree. So no success/known-error/unknown-vendor-err | Translating Firecracker/httpx errors at the seam is the adapter's core EH responsibility (per the carve-out), but the code isn't written. Expected future work on a published adapter — ⏳, not N/A. |
| TS-09 | N/A | No 'best-effort observer' (EH-10) loop exists in this adapter's source, and none is part of the HypervisorBackend/StorageBackend contract it implements. The adapter wraps Firecracker vi | EH-10 best-effort observer loops are not a feature of this adapter's intended design (no observer registry in the contract). No applicable surface — N/A. |
| TS-10 | ⏳ | Security is central to this adapter (it will spawn jailer via subprocess SC-02, talk to Firecracker over a unix socket via httpx, and handle VM image paths SC-15/SC-04). TESTING.md TS-1 | Refute against the 'security-relevant' carve-out: because the dangerous code (jailer argv/shell=False, path traversal, socket perms) is NOT written yet, the positive-behaviour pins cannot exist; but the negative-pattern grep pins  |
| TS-11 | N/A | No GUI. pyproject declares no PySide6/pytest-qt; this is a thin headless library adapter (no GUI/CLI/service per the SHAPE carve-out). No QThread workers exist. | GUI-worker tests are inapplicable to a headless adapter. N/A. |
| TS-12 | ⏳ | No async code exists in src/ yet. However, the adapter talks to Firecracker's REST API over a unix socket via httpx — httpx supports (and the adapter may well use) async clients, and DP | If the adapter ends up sync-only over httpx, TS-12 could become N/A; but given the httpx-over-uds design and the unwritten state, the honest call is that async testing infrastructure is a deferred gap pending the implementation de |
| TS-13 | ⏳ | The adapter's documented job includes VmSpec→Firecracker JSON translation (conftest.py tier-1 description: 'pure functions only; VmSpec→Firecracker JSON translation, error mapping'). Th | The round-trip code (VmSpec→JSON) is planned and hypothesis is already provisioned, but no property tests are written yet. Expected future work — ⏳, not N/A. |
| TS-14 | ⏳ | No performance budget is pinned by a benchmark, and no @pytest.mark.perf test exists. There is no PERFORMANCE.md budget asserted here. Note also that addopts does NOT exclude perf (`-m  | No production code path with a stated budget exists yet, so no benchmark can measure it. Deferred until the adapter has a budgeted path. ⏳ (consistent with the federation treating perf-pin infra as deferred-for-cause on thin/early |
| TS-15 | ⏳ | Real-backend smoke (against real Firecracker) would be marker-gated and read-only. The `integration` marker is registered and tests/integration/ exists but is EMPTY — no real-backend sm | The gating mechanism (integration marker, empty integration dir) is provisioned but no actual real-backend smoke test exists yet. Expected for an adapter whose whole point is a real engine — ⏳, not N/A. |
| TS-16 | ✅ | [verify-upheld] test_smoke.py uses bare asserts that are self-explanatory: `assert hasattr(adapter, '__version__')`, `assert len(parts) >= 2`, `assert all(p.isdigit() for p in parts[:2] | Refute attempt: is any bare assert ambiguous? No — each operates on a single named attribute with an obvious predicate; a reader new to the test understands the failure from the assert line alone. The TESTING.md guidance only requ |
| TS-17 | ✅ | [verify-upheld] tests/conftest.py is the single repo-wide conftest; it defines NO fixtures at all (only a module docstring documenting tier semantics). test_smoke.py imports no fixtures | Refute attempt: any cross-package fixture import? None — there are effectively no fixtures yet, and nothing is imported across test packages. The conftest hierarchy is intact (one repo-wide conftest). Upheld trivially. |
| TS-18 | N/A | No test in the suite exceeds 1 second (both smoke tests are sub-millisecond attribute reads). No @pytest.mark.slow test exists. The `slow` marker is NOT registered in pyproject markers  | No slow test exists so the marking obligation does not bind today. TS-19 SHOULDs defensively registering `slow`, but the MUST in TS-18 (mark tests >1s) has no applicable subject. N/A for the current suite (defensive `slow` registr |
| TS-19 | ✅ | pyproject markers register `integration` and `conformance` (both used and described). But TS-19 names a canonical set: layer markers smoke/e2e/integration plus orthogonal perf/slow, and | The markers actually used are registered (so --strict-markers passes), but the canonical orthogonal markers (`perf`, `slow`) and the defensively-recommended `slow` are missing — a partial. TS-19 lists perf/slow as part of the requ — FIXED 2026-06-09: smoke/e2e markers registered |
| TS-20 | ✅ | Only two of the four canonical directories exist as test homes: tests/unit/ (with the smoke test wrongly placed here) and tests/integration/ (empty). There is NO tests/smoke/ and NO tes | The four-directory partition is incomplete: no tests/smoke/, no tests/e2e/, and the smoke-shaped test is misfiled under unit/. A real partitioning gap on a published library. ⏳. — FIXED 2026-06-09: tests/{unit,smoke,e2e}/ canonical dirs |
| TS-21 | ✅ | This IS a published library (mgf-vm-firecracker 0.1.2 on Codeberg; wheel in dist/, tags v0.1.0/0.1.1/0.1.2), so the smoke layer is REQUIRED, not skippable (the skip clause is only for C | A published library MUST have a tests/smoke/ layer running <100ms verifying import + __all__ reachability + shortest happy path. The substance partly exists but is in the wrong layer and is not isolable via `pytest tests/smoke/`. — FIXED 2026-06-09: tests/smoke/test_imports_smoke.py |
| TS-22 | ⏳ | .woodpecker.yml runs plain `pytest --tb=short -q` directly; there is no tier overlay, no `--tier N`/`--tier N-M`/`--budget T` support, and no use of mgf.test_supervisor.tiers / mtest /  | Tiered runs are unsupported. As a federation member this is a real gap (the four-tier model is the coordination contract); the adapter could adopt the published mgf-test-supervisor or an equivalent. Not declined with rationale, so |
| TS-23 | ⏳ | .woodpecker.yml invokes pytest directly in each test step (`pytest --tb=short -q`), with NO supervisor/subprocess harness. There is no crash/hang/signal capture, no wall-clock-bounded h | CI surfaces only pytest's exit code; a 139/timeout would not be attributed per-test. No equivalent mechanism is documented. Real gap — ⏳ (could adopt mgf-test-supervisor, which the federation reference recommends). |
| TS-24 | ⏳ | No .gates/last-run/run.jsonl is produced — CI runs bare pytest with no JSONL record writer, and there is no use of mgf.common.testing.TestRecord / mgf.test_supervisor.records. | Structured per-test JSONL records are not produced. Depends on adopting the supervisor (TS-23); a real gap — ⏳. |
| TS-25 | ⏳ | No flaky-test auto-quarantine: no .gates/quarantine.json, no --quarantine-attempt/--no-skip-quarantined handling, no supervisor in the loop. | TS-25 is L2 (L1 projects MAY defer). This thin early adapter is L1-ish, so deferral is legitimate, but it is not formally declined-with-rationale here, so the honest status is a deferred gap — ⏳ (not 🚫). |
| TS-26 | N/A | mgf-vm-firecracker is pure Python — it ships no compiled artifact (no Zig/Go/Rust/C/Swift). It drives Firecracker (an external system binary), but it does not BUILD or SHIP a binary as  | TS-26 explicitly permits pure-Python libraries to declare N/A. The Firecracker/jailer binaries are external system prerequisites for the (future) integration tier, not artifacts this package builds and freshness-checks. N/A. |
| TS-27 | ⏳ | No per-failure detail bundle under .gates/last-run/failures/ — CI runs bare pytest with `--tb=short` only. No traceback/stdout/stderr/proc-state/dmesg/env-fingerprint bundle assembly, n | Single-file failure exploration is not implemented (depends on the supervisor, TS-23). Real gap — ⏳. |
| TS-28 | ⏳ | No per-test perf attribution: no `--perf`/MGF_PERF handling, no per-test cProfile, no perf_span usage, no perf-summary.md. mgf.common.testing.perf_span / the mgf_common --mgf-perf plugi | TS-28 is L2 (L1 projects MAY defer); this thin early adapter may legitimately defer, but it is not formally declined-with-rationale, so the honest status is a deferred gap — ⏳ (consistent with the federation treating TS-28 as defe |

### API_DESIGN

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| AP-01 | ✅ | src/mgf/vm/firecracker/__init__.py:22-26 declares `__all__: list[str] = ["__version__", ...]` (FirecrackerAdapter commented out until it lands). tests/unit/mgf/vm/firecracker/test_smoke | [verify-upheld] AP-01 requires the public surface be enumerated explicitly via __all__ at every import boundary. The single package __init__.py does exactly that with an explicit string list (no globals() shenanigans), and the sta |
| AP-02 | ✅ | src/mgf/vm/firecracker/__init__.py:1-16 module docstring states intent (Firecracker microVM adapter implementing HypervisorBackend/StorageBackend), invariants (wrap-don't-marry seam), p | [verify-upheld] AP-02 requires every public name to have a docstring with intent/invariants/example. The only public name is __version__ — a standard dunder string covered by the module docstring; there are no public functions/cla |
| AP-03 | ✅ | pyproject.toml:3 version = "0.1.2"; CHANGELOG.md:3-4 declares 'Semantic Versioning'; headers [0.1.0]/[0.1.1]/[0.1.2] use MAJOR.MINOR.PATCH; 0.1.1/0.1.2 are characterized as dependency-p | [verify-upheld] AP-03 requires SemVer with the 0.x clause. The package is in the 0.x window at 0.1.2 using MAJOR.MINOR.PATCH, and the CHANGELOG correctly classifies the patch releases as dependency-pin walks with no API change. Re |
| AP-04 | N/A | No public functions/classes exist (FirecrackerAdapter is an un-landed comment in src/mgf/vm/firecracker/__init__.py:24). CHANGELOG.md has no [Deprecated] entries through 0.1.2. | AP-04 (deprecation cycle: announce → survive → remove with DeprecationWarning) binds only when a public name is deprecated. There are zero public callables and zero deprecations through 0.1.2, so the rule has nothing to apply to.  |
| AP-05 | N/A | The public surface is __version__ only (src/mgf/vm/firecracker/__init__.py:22-26). No public functions or methods exist yet. | AP-05 (stable signatures; new params keyword-only with defaults) governs public function signatures. With no public functions in the skeleton, there is no signature to keep stable. N/A until FirecrackerAdapter lands. |
| AP-06 | N/A | No public functions/methods with return types exist (src/mgf/vm/firecracker/__init__.py exposes only the __version__ string). | AP-06 (return types MUST NOT narrow in non-MAJOR) requires a public function with a declared return contract. None exists in the skeleton. N/A. |
| AP-07 | N/A | No public functions raise anything (no callables in src/mgf/vm/firecracker/__init__.py). The errors.py typed-error-translation module is listed as Pending in CHANGELOG.md:47. | AP-07 (exceptions raised by public functions are part of the contract; MUST subclass the typed hierarchy) binds only when a public function raises. No public functions exist yet, so there is no exception contract to honor. N/A unt |
| AP-08 | ✅ | src/mgf/vm/firecracker/__init__.py:18 has `from __future__ import annotations`; tests/conftest.py:13 and test_smoke.py:3 also have it. (Note: pyproject.toml:69-72 ruff select includes U | [verify-upheld] AP-08 requires every public module to use `from __future__ import annotations`. The single public module (__init__.py) has it on line 18. Refute attempt: ruff does NOT enable FA100/FA102 (the §14 mechanical check), |
| AP-09 | ✅ | src/mgf/vm/firecracker/py.typed exists (0-byte PEP 561 marker, confirmed via wc -c). pyproject.toml:57-58 [tool.hatch.build.targets.wheel] packages = ["src/mgf"] walks the tree so hatch | [verify-upheld] AP-09 requires a py.typed marker for any package shipping type annotations. The marker is present (0 bytes) and the wheel build config picks it up. Refute attempt fails: the marker exists at the package root and th |
| AP-10 | ✅ | No PUBLIC_API.md or docs/PUBLIC_API.md or PUBLIC_API.json exists (ls confirmed all absent). No test_public_api_doc.py exists. mgf-vm-firecracker IS a published library (pyproject.toml:1 | AP-10 requires a PUBLIC_API.md listing every public name with tier + one-line description, kept in sync with __all__ via a CI check. This is a published mgf-* library, not a deployed-as-a-service consumer app, so the §Web-shape de — FIXED 2026-06-09: PUBLIC_API.md lists the public surface (currently __version__; adapter lands later) + tier |
| AP-11 | ✅ | No stability tiers are declared anywhere (no PUBLIC_API.md tier column, no `# tier:` comments in src/mgf/vm/firecracker/__init__.py). No tier pin test exists. | AP-11 requires stability tiers (experimental/stable/deprecated) declared per public name. As a published library this applies (not declinable per the web-shape carve-out). No tier declaration mechanism exists — it would normally r — FIXED 2026-06-09: tier declared (experimental, 0.x) |
| AP-12 | ✅ | CHANGELOG.md:1-4 declares Keep a Changelog + SemVer; sections [Unreleased]/[0.1.2]/[0.1.1]/[0.1.0] use Added/Pending/Capabilities headings; there are no ### Changed:BREAKING entries (al | [verify-upheld] AP-12 requires breaking changes to carry migration recipes (symptom/before/after/why). There have been zero breaking changes through 0.1.2, so the requirement is vacuously satisfied and the CHANGELOG is correctly f |
| AP-13 | ✅ | src/mgf/vm/firecracker/__init__.py:20 `__version__ = "0.1.2"` mirrors pyproject.toml:3 version = "0.1.2" (they DO match). But there is NO CI lint enforcing the sync: no tests/unit/test_ | AP-13 requires both (a) a __version__ attribute mirroring pyproject.toml AND (b) 'CI MUST lint that the two stay in sync.' Part (a) is satisfied (both are 0.1.2). Part (b) is missing — no pin test exists, so the two can silently d — FIXED 2026-06-09: __version__ (0.1.2) mirrors pyproject; CI tag-coherence asserts tag==pyproject==__version__ |
| AP-14 | ⏳ | pyproject.toml:102-104 [tool.importlinter] declares only root_packages = ["mgf.vm.firecracker"] with NO `[[tool.importlinter.contracts]]` defined. .woodpecker.yml:18 comment explicitly  | AP-14 requires CI to enforce via import-linter that consumer test fixtures only touch the public surface (no _-prefixed internal imports). import-linter is installed but defines zero contracts and is not invoked by any CI step. Th |
| AP-15 | N/A | No backward-compatibility shim modules exist (the package is a single __init__.py at src/mgf/vm/firecracker/; CHANGELOG.md shows no relocated/renamed names). It is a fresh 0.1.x skeleto | AP-15 (shims surviving removal of the original code MUST emit DeprecationWarning + log INFO once/process) binds only when a backward-compat shim exists. This greenfield adapter has no old code path to shim. N/A. |

### SCOPE

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| SP-01 | ✅ | README.md:58-91 §'What this library will contain' (the src/mgf/vm/firecracker/ module map: adapter.py=HypervisorBackend+StorageBackend, api/=REST-over-UDS client, jailer.py, translate.p | SP-01 requires an explicit IN-scope list — the bar a new module must clear. For this thin vendor adapter the IN boundary is drawn explicitly: it implements exactly mgf-vm-core's HypervisorBackend + StorageBackend against Firecrack |
| SP-02 | ✅ | README.md:95-104 §'What this library does NOT contain': '**No libvirt** — that's mgf-vm-libvirt.'; '**No device passthrough** — Firecracker doesn't do PCI/USB passthrough; the DeviceBac | REFUTE-UPHELD. SP-02 demands an explicit OUT list with per-entry 'why we don't' + 'what to use instead'. Verified the exact lines: three explicit cuts, each carrying its reasoning (Firecracker can't do PCI/USB; live migration is a |
| SP-03 | ✅ | CONTRIBUTING.md §'Process' lists the PR gate (ruff/mypy/pytest/lint-imports, CHANGELOG [Unreleased] entry, AP-01 public-API delta) but contains NO requirement that a PR adding a module/ | SP-03 is a MUST: every PR adding a new module or top-level function MUST justify against §1/§3 (OUT → rejected with ecosystem pointer). The contributor process here gates on lint/type/test/API-delta but never makes the scope-creep — FIXED 2026-06-09: SCOPE.md §3 (scope-creep gate) |
| SP-04 | N/A | No §3/Adjacent-scope list exists anywhere in the adapter (README has only IN at :58-91 and OUT at :95-104; no Adjacent section). FEEDBACK.md §1-2 does establish the PAPER-NN consumer-de | SP-04 governs the demand-signal discipline for promoting Adjacent → IN. A thin vendor adapter whose entire surface is the two upstream-defined Protocols has no adjacent-scope items by construction — there is nothing speculative to |
| SP-05 | ✅ | README.md:97 cites the sibling for the libvirt cut: '**No libvirt** — that's mgf-vm-libvirt.'; README.md:98-100 cites the in-library alternative for passthrough ('the DeviceBackend for  | REFUTE-UPHELD. SP-05 requires every OUT cut to cite the ecosystem alternative. Verified each of the three cuts names where the function lives instead: the federation sibling mgf-vm-libvirt (the correct analogue of an 'ecosystem al |
| SP-06 | N/A | pyproject.toml version = '0.1.2'; CHANGELOG.md shows the whole history is 0.1.0 → 0.1.1 → 0.1.2, all pre-1.0 PATCH/skeleton walks. No MAJOR release boundary has ever occurred. No 'scope | SP-06 binds 'on every MAJOR release' — items move between IN/Adjacent/OUT at the MAJOR boundary. This adapter is pre-1.0 (0.1.2) and has never crossed a MAJOR boundary, so the obligation has not yet been triggered. Not applicable  |

### WORKFLOWS

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| WF-01 | ✅ | .woodpecker.yml:12-15 — `when:` block lists `event: push`, `event: pull_request`, `event: manual`. No local-ship path exists; the workflow is the canonical gate. | [verify-upheld] Confirmed against the real file: the trigger block at lines 12-15 runs CI on every push and PR. Branch-protection is platform-side and not inspectable here, but the workflow-side MUST (CI on every push to a long-li |
| WF-02 | ✅ | Three of four gates are CI-enforced and parallel: lint (`ruff check src tests`, :24), typecheck (`mypy src`, :32, with `strict=true` in pyproject:79), test (pytest matrix :43/50/57). Th | WF-02 requires all four green gates (lint/typecheck/test/import-linter) to be CI-enforced. Only three run. import-linter is installed and a config stub exists but carries zero contracts and no CI step invokes `lint-imports`. For a — FIXED 2026-06-09: lint-imports added to the CI lint step |
| WF-03 | ✅ | mgf-vm-firecracker is a published mgf-* package (pyproject:3 version=0.1.2; [tool.uv.index] codeberg-mgf at pyproject:105). But `.woodpecker.yml` has NO tag-driven publish: grep for tag | Per the audit shape, publish-chain rules are ⏳ (not N/A) for a published mgf-* package that lacks a tag-driven chain. There is no publish workflow at all, so WF-03 (tag-driven publish to the Codeberg registry, no-publish-without-t — FIXED 2026-06-09: tag-driven Codeberg publish chain added to CI (build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py |
| WF-04 | ✅ | No publish step exists in `.woodpecker.yml`, so no `codeberg_package_token` / `from_secret` reference is present (and correctly, no token is hardcoded — grep for codeberg_package/twine  | WF-04 (publish credential in the CI secret store, tag-scoped) cannot be satisfied because there is no publish workflow to consume a credential. No token leak exists (good), but the rule's positive requirement is unmet pending a pu — FIXED 2026-06-09: tag-driven Codeberg publish chain added to CI (build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py |
| WF-05 | ✅ | No tag-coherence step in `.woodpecker.yml` (no tag event, no script comparing CI_COMMIT_TAG to pyproject version / __version__). | WF-05 (verify tag == pyproject.version == __version__ before upload) lives inside the publish flow, which does not exist. Unmet pending a tag-driven publish chain. ⏳. — FIXED 2026-06-09: tag-driven Codeberg publish chain added to CI (build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py |
| WF-06 | ✅ | No build/upload steps in `.woodpecker.yml`; the vuln-scan step uses `--skip-editable` with comment :59-61 noting the package 'is not yet on PyPI (extraction in progress)'. | WF-06 (the uploaded wheel MUST be the one built fresh in the publish run) is unmet — there is no build-then-upload sequence at all. ⏳ pending a publish chain. — FIXED 2026-06-09: tag-driven Codeberg publish chain added to CI (build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py |
| WF-07 | ✅ | No pre-publish smoke step (no ephemeral venv install of a built wheel + __version__ assert) anywhere in `.woodpecker.yml`. | WF-07 (install the freshly-built wheel into an ephemeral venv and import top-level package + __version__) is unmet because no publish flow exists. ⏳. — FIXED 2026-06-09: tag-driven Codeberg publish chain added to CI (build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py |
| WF-08 | ✅ | No post-publish verify step (no poll of the Codeberg REST API …/api/v1/packages/magogi-admin/pypi/<name>/<version>) in `.woodpecker.yml`. | WF-08 (post-publish registry verification) is unmet — there is no upload to verify. ⏳ pending a publish chain. — FIXED 2026-06-09: tag-driven Codeberg publish chain added to CI (build→tag-coherence→smoke→publish→verify-codeberg) + scripts/verify_codeberg.py |
| WF-09 | ✅ | Every external image pinned: python:3.11-slim (:39), python:3.12-slim (:20,28,46,63), python:3.13-slim (:53), zricethezav/gitleaks:v8.30.1 (:72 exact tag). No `:latest`, no bare `python | [verify-upheld] All cited line numbers verified exact against the real file; gitleaks is exact-pinned and the lockfile is committed. python images are rolling-minor (`3.x-slim`), explicitly accepted by §7.1 for the security-update |
| WF-10 | ✅ | Seven steps (lint, typecheck, test-3.11, test-3.12, test-3.13, vuln-scan, secret-scan) with ZERO `depends_on:` (grep count = 0). The version axis fans out as three independent test step | [verify-upheld] Confirmed no `depends_on` exists, so all steps run in parallel and the Python-version matrix genuinely fans out. No build→publish chain exists, so the only legitimate sequential dependency does not yet apply. The M |
| WF-11 | ✅ | Each step runs a fresh pinned python:X-slim / gitleaks container installing from pyproject with a committed uv.lock present; no trigger-time env vars, no host state. tests/unit/.../test | [verify-upheld] Verified: markers and filterwarnings at the cited pyproject lines; uv.lock committed; the default CI run hits no external hosts. Honestly-disclosed caveat — CI installs `-e ".[dev]"` from pyproject rather than `uv  |
| WF-12 | ✅ | No `\|\| true` anywhere (grep count = 0). Every step runs a single failing-on-nonzero command (ruff/mypy/pytest/pip-audit/gitleaks); test steps use `--tb=short` (:43,50,57); gitleaks us | [verify-upheld] Verified no silent-failure constructs; failures propagate; the lone suppression carries a written justification inline per §8.3. Minor nit (does not break the MUST): the §8.3 ideal is reason AND date — the CVE comm |
| WF-13 | ✅ | .woodpecker.yml:1-3 carries the GENERATED header ('GENERATED — do not hand-edit. Source: mgf-standard/templates/woodpecker/'). Rendered by `mgf-fed`; never patched in place. | Generated artifact; regenerate via `mgf-fed` after editing the canonical template. |

### RELEASING

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| REL-01 | ✅ | git cat-file -t v0.1.2 → 'commit' (lightweight), whereas v0.1.0 and v0.1.1 are 'tag' (annotated) per `git tag -l --format='%(objecttype)'`. v0.1.2 points at b3d5ecf (the 0.1.2 release c | REL-01 requires every release have an ANNOTATED v<version> tag on the build commit. 0.1.2 is published but its tag is lightweight — exactly the metadata-loss footgun §3.1 forbids. Smallest fix: re-create as annotated (git tag -a v — FIXED 2026-06-09: release tags re-annotated (v0.1.2) on the same build commits + force-pushed (annotated, GC-safe; no content change). 0 lightweight v-tags remain. |
| REL-02 | ✅ | dist/ holds only mgf_vm_firecracker-0.1.1-py3-none-any.whl + .tar.gz (Jun 4); pyproject.toml:3 version="0.1.2" and src/mgf/vm/firecracker/__init__.py:20 __version__="0.1.2"; CHANGELOG.m | No version-string reuse across differing wheel contents. The stale 0.1.1 dist artifact predates the 0.1.2 bump rather than masquerading as 0.1.2, so the anti-pattern A footgun is absent. Each release got its own version. |
| REL-03 | N/A | No PUBLIC_API.md or PUBLIC_API.json exists anywhere in the repo (find -iname '*public_api*' returns nothing; docs/ contains only docs/claude/CLAUDE.md and docs/inprogress/MGF_STANDARDS_ | REL-03 governs the banner ON PUBLIC_API.md/json stating it reflects master HEAD. With no PUBLIC_API doc to carry a banner (the existence of that doc is a DOC-01 concern, adjudicated in the DOCUMENTATION family — for a near-empty _ |
| REL-04 | ✅ | .woodpecker.yml contains no publish step and no token reference (grep for publish\|twine\|upload\|TWINE found none; only event: push/pull_request/manual, lint/typecheck/test/vuln-scan/s | REL-04 forbids tokens in chat/shell-history/env-vars/workflow files. No token is committed or echoed anywhere; the only credential discipline visible is a gitleaks guard. The publish token (when publishing happens) lives outside t |
| REL-05 | ✅ | CHANGELOG.md records 0.1.0/0.1.1/0.1.2 as distinct dated entries; tags v0.1.0/v0.1.1/v0.1.2 each point at distinct commits (3c95bde / c40f4de / b3d5ecf). Post-tag HEAD commits (git log  | REL-05 (published version is immutable; no content swap of an existing version). Each shipped version maps to one frozen commit; bug-fix/forward work would ship as a new version. No evidence of a silent content swap or delete-and- |
| REL-06 | ✅ | .woodpecker.yml has NO tag-driven publish chain: when: clause is push/pull_request/manual only; there is no step with `when: [{event: tag, ref: refs/tags/v*}]`, no twine/upload step, no | Per the audit brief's REL guidance, REL-06 is ⏳ when there is no tag-driven publish chain. The ordered flow (bump→regen JSON→build→test→twine check→commit→tag→push→upload→REST verify) is not mechanised; releases were cut by hand ( — FIXED 2026-06-09: tag→build→tag-coherence→smoke→publish→verify, ordered |
| REL-07 | N/A | FEEDBACK.md §2 reads 'No papers filed yet' (line 40); the file contains only the template skeleton, no PAPER-NN entries in any status. CHANGELOG entries for 0.1.0/0.1.1/0.1.2 are federa | REL-07 requires a release commit to flip every FEEDBACK entry it ships to ✅ SHIPPED. With zero feedback entries filed and the published releases shipping no feedback closures, the premise (a release that ships ≥1 FEEDBACK entry) d |
| REL-08 | ✅ | .woodpecker.yml has no wheel-smoke step (no `pip install dist/*.whl` into an ephemeral venv + import of public names; the test steps run `pip install -e .[dev]` against the source tree  | REL-08 requires pre-release smoke against the actually-built wheel (install into a fresh venv, import every public top-level name). The brief flags this ⏳ absent a tag-driven chain; the source-tree pytest matrix explicitly does NO — FIXED 2026-06-09: smoke installs the wheel + imports mgf.vm.firecracker before publish |
| REL-09 | N/A | FEEDBACK.md §2 = 'No papers filed yet' (line 40); no entry has been flipped to SHIPPED/DEFERRED/REJECTED. No docs/cutover/ directory exists (ls → 'no cutover'). CHANGELOG closes no cons | REL-09 fires only on a FEEDBACK status flip (SHIPPED/DEFERRED/REJECTED) needing a consumer-facing notification paragraph. With no feedback entries and no closures, there is nothing to notify; the premise does not bind. |

### PACKAGE_DISTRIBUTION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| PKG-01 | ✅ | pyproject.toml:50-51 Source/Documentation URLs point at codeberg.org/magogi-admin; pyproject.toml:106-115 [[tool.uv.index]] codeberg-mgf + [tool.uv.sources] map mgf-common/mgf-vm-core t | [verify-upheld] Refute attempt failed. Both direct mgf-* deps (pyproject.toml:34-35) are mapped to the codeberg-mgf index; the package itself is published as mgf-vm-firecracker on Codeberg (Source URL) with tags v0.1.0/0.1.1/0.1.2 |
| PKG-02 | ✅ | pyproject.toml:108 url = 'https://codeberg.org/api/packages/magogi-admin/pypi/simple/' — the exact §3 canonical simple-index endpoint, verbatim, no hand-typed variant. No other registry | [verify-upheld] Refute attempt failed. The single registry endpoint configured is the canonical simple-index URL from §3 table. There are no deviating verify/upload endpoints to be wrong (those would live in CI, which is absent —  |
| PKG-03 | ✅ | No token/auth surface exists in committed config: .woodpecker.yml has no publish step, no codeberg_package_token secret, no TWINE_USERNAME/PASSWORD; pyproject [tool.uv.sources] maps the | Not refuted — adjudicated fresh. The token discipline (write:package for publish, read:package for consume, never plaintext, CI secret) is unestablished because there is no publish flow and no documented consumer-auth wiring in th — FIXED 2026-06-09: publish step uses the codeberg_package_token secret-token model |
| PKG-04 | ✅ | .woodpecker.yml:17-75 contains only lint/typecheck/test-3.11/3.12/3.13/vuln-scan/secret-scan steps — NO build→twine check→upload→verify→tag chain, no tag-event step. Line 60-61 comment: | Adjudicated fresh. The strictly-ordered publish flow (gates→build→twine check→upload-to-Codeberg→verify→tag→push) has no committed implementation. Per the audit framing, a published mgf-* package with no tag-driven chain is ⏳, not — FIXED 2026-06-09: ordered tag-gated publish ritual |
| PKG-05 | ✅ | .woodpecker.yml has no verify-codeberg step (grep for 'verify'/'curl'/'api/v1/packages' = none in the YAML); the §10 REST-200 gate is absent. No release-log/CHANGELOG note records a RES | Adjudicated fresh. Post-publish verification against the Codeberg REST API (GET .../pypi/<name>/<version> → 200) is neither automated nor evidenced. The version IS published (tag exists) but the conformant verify gate is missing. — FIXED 2026-06-09: verify-codeberg REST poll |
| PKG-06 | ✅ | pyproject.toml:106-115 matches the §6 canonical shape verbatim: [[tool.uv.index]] name='codeberg-mgf', url=.../pypi/simple/, explicit=true; [tool.uv.sources] mgf-common={index='codeberg | [verify-upheld] Refute attempt failed. The dependency-confusion-safe consumer config (named index + explicit=true + per-package [tool.uv.sources] mapping for every direct mgf-* dep) is committed exactly per §6. explicit=true close |
| PKG-07 | N/A | PKG-07 governs immutability/delete-and-re-upload-for-recovery behavior of a release maintainer at publish time. This repo has no publish flow (PKG-04 ⏳) and no recorded re-upload/recove | Adjudicated fresh. The immutability/recovery policy is a release-session operational rule; there is nothing in this repo's state that engages or violates it (no re-upload, no silent content swap). Nothing to conform to here. N/A. |
| PKG-08 | N/A | PKG-08 is a federation-account-level retention/quota policy against the magogi-admin account (~200 GiB allowance, keep current+previous minor, prune older via DELETE, track /api/v1/user | Adjudicated fresh. Retention against the shared account quota is owned at the registry/federation level (mgf-standard / scheduled job per §Mechanical enforcement), not implementable or assertable from a single thin adapter rep |
| PKG-09 | ✅ | .woodpecker.yml:12-15 triggers on push/pull_request/manual only — no event: tag. No publish step, no build-in-CI publish, no codeberg_package_token secret, no 'no publish on non-tag eve | Adjudicated fresh. CI publishing MUST be tag-driven + build-in-CI + secret-token-authenticated; none of that exists. Published mgf-* package with no tag-driven CI chain = ⏳ per audit framing, not N/A. ⏳. — FIXED 2026-06-09: tag-driven secret-token publish step |
| PKG-10 | ✅ | pyproject.toml:2 name='mgf-vm-firecracker' (hyphenated PEP 503 distribution name); pyproject.toml:58 [tool.hatch.build.targets.wheel] packages=['src/mgf'] → dotted import namespace mgf. | [verify-upheld] Refute attempt failed. Distribution name is hyphenated, the import is the dotted mgf.vm.firecracker namespace under the shared PEP-420 mgf.* tree, and the canonical project URL is the Codeberg package/repo page (no |
| PKG-11 | N/A | PKG-11 is the AG-09 amendment binding an AGENT making a sibling-version recommendation to verify against the Codeberg registry. This is an agent/federation-tooling behavior (the standar | Adjudicated fresh. mgf-vm-firecracker is a library, not the federation agent/version-check tooling; it neither performs sibling published-version checks nor hosts that logic. No surface in this repo to which PKG-11 applies. N/A. |
| PKG-12 | ✅ | The SURFACE is clean: repo-wide grep for 'pypi.org' across *.py/*.toml/*.yml/*.md returns ZERO hits, so there is no residual mgf-* pypi.org publish/distribution surface. HOWEVER the man | Adjudicated fresh. The rule's substantive condition (no residual pypi.org surface) is currently MET by inspection, but PKG-12 is 'Enforced by a no-pypi-publish-surface grep gate' and that gate (the reference check_no_pypi_surface. — RECONCILED ✅ 2026-06-09: no residual pypi.org distribution surface (README/docs clean) |

### DOCUMENTATION

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DOC-01 | ✅ | Root baseline present: README.md, LICENSE, CHANGELOG.md, CONTRIBUTING.md, SECURITY.md, FEEDBACK.md, AGENTS.md, STARTHERE.md, DEPS.md, FEDERATION.md, LESSON_LEARNED.md + docs/ dir (all c | Per §2.0.1 matrix (lines 165, 267-269) PUBLIC_API.md + .json are MUST for a library shape (cornerstone+sibling), only excluded for applications. This IS a published federation-sibling LIBRARY (README:13, pyproject version=0.1.2), — FIXED 2026-06-09: PUBLIC_API.md + PUBLIC_API.json now exist |
| DOC-02 | ✅ | `find docs -maxdepth 1 -type d` returns only docs/claude and docs/inprogress; no docs/notes/, no docs/TODO.md, no graveyard buckets. Both are canonical §2.2 buckets; claude/ is universa | Tried to refute by hunting for anti-pattern/creep buckets — none exist. The two present buckets are both canonical and genuinely used. For an early 1-module sibling the absent buckets are explicitly 'as needed' per the §2.0.2 matr |
| DOC-03 | ✅ | Two long-lived buckets exist — docs/claude/ (CLAUDE.md) and docs/inprogress/ (MGF_STANDARDS_CONFORMANCE.md) — confirmed by `ls docs/` and the docs tree. Neither bucket has a README.md c | DOC-03 (line 28): every long-lived bucket MUST have its own README.md stating the charter + one-line description of each file. docs/claude/ and docs/inprogress/ are durable buckets that ship files but carry no charter README. Smal — FIXED 2026-06-09: every docs/ bucket carries a README charter |
| DOC-04 | ✅ | CHANGELOG.md lines 1-4 cite Keep-a-Changelog + SemVer; line 6 [Unreleased]; dated entries [0.1.2]/[0.1.1]/[0.1.0] with Added/Pending subsections. src/mgf/vm/firecracker/__init__.py:22 h | Refute attempt: is there an un-logged public-API change? Verified __all__ exports only __version__ — there is literally no public contract surface to drift against. CHANGELOG shows same-commit per-release discipline. Upheld for th |
| DOC-05 | N/A | CHANGELOG.md shows the entire release history is non-breaking: 0.1.0 (first Codeberg release, no surface), 0.1.1 (pin widen, 'No API change'), 0.1.2 (pin walk, 'no library surface chang | DOC-05 (line 30) binds only on a breaking change (MAJOR, or MINOR within 0.x per AP-03). This skeleton has shipped no public surface and no breaking change — there is nothing to write a cutover guide for. The premise does not hold |
| DOC-06 | N/A | No living priority tracker exists in the repo. docs/inprogress/ contains only MGF_STANDARDS_CONFORMANCE.md (a per-rule conformance ledger governed by DOC-15/CFM-*, not the §3 priority-t | DOC-06 (line 31, §3) governs the SHAPE of a living priority tracker IF one exists — it does not compel a thin skeleton to create one. A conformance ledger is a different artifact (DOC-15) and is explicitly out of audit scope here. |
| DOC-07 | ✅ | docs/claude/CLAUDE.md exists, 305 lines, dense-lookup format with the mandatory sections (standing instructions, top-rules table, four-gate sequence, project-specific lookup) and mgf-co | The DOC-07 bar is the file existing in dense-lookup format with the mandatory sections — it does. Refute attempt surfaced a SECOND drift defect beyond the auditor's noted line-168 path: the L1/L2 contradiction at line 14 (auto-gen |
| DOC-08 | ✅ | PUBLIC_API.md and PUBLIC_API.json are both absent (grep -rl PUBLIC_API → no hits anywhere). pyproject.toml contains no PUBLIC_API/drift pin (grep for public_api/drift in pyproject → onl | DOC-08 (line 33, §6 lines 558-577): PUBLIC_API.md MUST track __all__ and PUBLIC_API.json MUST be generated from __all__ at every release and pinned in CI (two pins). For a published library this binds even with a one-symbol surfac — FIXED 2026-06-09: PUBLIC_API.json + generator + pin |
| DOC-09 | ✅ | Docs name code: README.md:64-72 enumerates src/mgf/vm/firecracker/ file paths (adapter.py, jailer.py, translate.py, errors.py — none of which exist yet), README:46-50 cites contracts.md | DOC-09 (line 34): docs that name code MUST be drift-detected via (a) a CI lint verifying the referenced name exists OR (b) a back-reference in the named code. Neither direction is wired. Worse, the named symbols in README §'What t — FIXED 2026-06-09: md↔__all__ pin |
| DOC-10 | ✅ | FEEDBACK.md line 48 carries severity tags (🟢 Low / 🟡 High / 🔴 Critical); lines 30-32 give the OPEN → SHIPPED/DEFERRED/WONTFIX/MOVED lifecycle; §2 has a paper template. §2 holds 'No pape | Refute attempt: any internal-audit item leaking into FEEDBACK, or a consumer paper misfiled into inprogress? Neither — FEEDBACK §2 is an empty template, inprogress holds only the internal ledger. Surfaces are cleanly separated. No |
| DOC-11 | ✅ | docs/inprogress/ holds one tracker, MGF_STANDARDS_CONFORMANCE.md, with mtime 2026-06-09 00:41 (live, edited today). No docs/archive/ owed; no fully-closed stale tracker sits unmoved. | Refute attempt: is the single occupant a fully-closed graveyard candidate? Its mtime is today and the ledger declares pending/⏳ rows — it is an active workspace, not a graveyard. No archival signal ignored. Upheld. [verify-upheld] |
| DOC-12 | ✅ | Mostly conformant: README.md:14 uses a relative link to docs/inprogress/MGF_STANDARDS_CONFORMANCE.md; headings are hierarchical. BUT docs/claude/CLAUDE.md:217,232,261,281,284 link cross | DOC-12 (line 37): every cross-reference MUST be a relative link, not an https:// URL. The CLAUDE.md federation-discipline block routes agents to the standards via Codeberg https:// URLs instead of relative paths. (This block is mg — FIXED 2026-06-09: docs/{standards,cutover,reference}/ buckets added |
| DOC-13 | ✅ | FEEDBACK.md lines 7-12 give the 'where to file what' split (mgf-vm-firecracker-specific → HERE; federation-wide → mgf-common/FEEDBACK.md with absolute cross-repo link); lines 14-17 stat | Refute attempt: missing repo-scoping or wrong routing? All present — sibling-vs-cornerstone routing, the FB-01 local-numbering rule, and bidirectional cross-references. Upheld. [verify-upheld] |
| DOC-14 | N/A | README.md:13 + DEPS.md:18 declare this a federation sibling ('Federation sibling. Depends on mgf-common'). No docs/inprogress/MGF_ADOPTION.md or docs/MGF_ADOPTION.md exists (docs/inprog | DOC-14 (line 39) MUST-have explicitly applies to consumer applications only; the ADP-04 carve-out (line 66) exempts federation siblings (mgf-fastapi, mgf-http, ... 'and each sibling's own CHANGELOG'). mgf-vm-firecracker is a sibli |
| DOC-15 | ⏳ | README.md:14 links docs/inprogress/MGF_STANDARDS_CONFORMANCE.md AND declares 'Conformance level. L2 — Standard' in the same place (CFM-01 location satisfied). BUT docs/claude/CLAUDE.md: | [verify-refuted: the ledger ships at the correct path and the README declares L2 — but a SECOND authoritative conformance-level declaration in docs/claude/CLAUDE.md:14 says L1, contradicting it. DOC-15's whole point is an unambigu |
| DOC-16 | ✅ | DEPS.md ships at repo root with §1 'What mgf-vm-firecracker depends on' (lines 14-20: mgf-common/mgf-vm-core/httpx rows with window+why+tier), §2 'Who depends on mgf-vm-firecracker' (li | Refute attempt on structure: bidirectional manifest with both sides + the grep survey are all present and complete; USERS.md is correctly removed. The stale pin window is real but is a DOC-09 doc:code-drift defect (counted there), |
| DOC-17 | ✅ | FEDERATION.md is an 18-line pointer stub: title 'FEDERATION — pointer', states the contract is 'not maintained here', links the canonical copy (absolute cross-repo URL to mgf-doc-standa | Refute attempt: any duplicated contract content? None — it is a clean pointer stub of the DOC-17 shape for a non-standards-owner sibling. Upheld. [verify-upheld] |
| DOC-18 | ✅ | The dependency pin is a coupled surface that has drifted out of sync. pyproject.toml:34 pins `mgf-common>=0.41,<0.47` (CHANGELOG.md:8,19 confirm the pin was walked 0.41→<0.47 across 0.1 | DOC-18 (line 43, ripple rule): a change to a coupled surface MUST update its dependents in the same commit; the dependency-pin and DEPS.md/README are coupled (DOC-16 says DEPS.md is verified before every MINOR release). The pin wa — FIXED 2026-06-09: DEPS.md re-verified 2026-06-09 |
| DOC-19 | ✅ | LESSON_LEARNED.md exists at repo root (22 lines), append-only framing (newest-first, supersede-don't-rewrite, DOC-19 citation, template pointer) with a dated seed entry '2026-06-07 — Fi | Refute attempt: DOC-19 is MUST since v2.21 but §2.0.1 + the rule text explicitly state a seeded file with no real lessons is conformant — presence is the bar. The file exists with correct append-only shape. Upheld. [verify-upheld] |

### OPERABILITY

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| OP-01 | ⏳ | src/mgf/vm/firecracker/__init__.py:20 exposes __version__ = "0.1.2" (a programmatic version), but there is no rich-version surface: no [project.scripts]/console_scripts in pyproject.tom | OP-01 ('report its rich version on demand') is shape-adapted, not waived, for a published library. As a thin library with no CLI/endpoint, the binding form is a programmatic/importable rich-version (e.g. a function returning versi |
| OP-02 | N/A | No CLI surface (no [project.scripts] in pyproject.toml), no config/persistent stores/state directories owned by this package — src/mgf/vm/firecracker/__init__.py is a pure skeleton (__v | OP-02's doctor probes the app's OWN state (config validity, persistent stores well-formed, state dirs, schema versions). A library adapter has no standalone config/store/state surface of its own — the consuming vm-vmanager service |
| OP-03 | ✅ | pyproject.toml:49-52 declares only Documentation = https://codeberg.org/magogi-admin/vm-vmanager-docs and Source = https://codeberg.org/magogi-admin/mgf-vm-firecracker — no Homepage, no | OP-03 requires pyproject URLs to resolve AND CI to verify (HTTP-HEAD lint or at minimum a no-placeholder grep). The declared URLs look real, but the Issues link is absent (bug reports have no metadata route) and no mechanical CI c — FIXED 2026-06-09: CI no-placeholder grep |
| OP-04 | ✅ | README.md:13 states 'Depends on mgf-common>=0.38,<0.39' but pyproject.toml:34 pins mgf-common>=0.41,<0.47 — a stale, contradictory dep pin (exactly the OP-04 anti-pattern: 'a mgf-common | OP-04 ('headline facts MUST match reality') is a universal MUST and is concretely violated: the README dep pin disagrees with pyproject by several minor versions, poisoning the first-60-seconds mental model. The 'will contain' sou — FIXED 2026-06-09: the false SECURITY.md headline (pure-domain/no-sockets) corrected to the real adapter security model |
| OP-05 | N/A | No app-owned configuration: pyproject.toml declares no settings model, src/mgf/vm/firecracker/__init__.py:1-27 is a skeleton, no [project.scripts] for an `explain` command. The adapter  | OP-05 ('active configuration inspectable from a running app') binds an app with its own MgfSettings-style config and a running process. A thin library adapter has no standalone running app and no own config surface — the consuming |
| OP-06 | N/A | No CLI (no [project.scripts]), no log sink owned by this package; src/ is a skeleton with no logging setup. The adapter emits records into the consumer's logging stack (per the federati | OP-06 ('recent logs accessible without source-tree knowledge' via `<app> logs` / GUI / aggregator URL) binds a runnable app that owns a log file/sink. A library does not own a log destination — the consuming service/CLI provides t |
| OP-07 | N/A | No CLI surface to host a `bundle` command (no [project.scripts] in pyproject.toml), and no app-owned config/logs/crash-reports/doctor to bundle — src/mgf/vm/firecracker/__init__.py is a | OP-07's diagnostic-tarball command aggregates an app's own config, logs, crash reports, doctor output and system info — none of which a thin adapter library owns. mgf-common ships the building blocks (redacted snapshot, crash dir, |
| OP-08 | N/A | This package writes no state: no crash-report dir, no log rotation, no cache — src/mgf/vm/firecracker/__init__.py:1-27 (skeleton) creates nothing on disk; pyproject.toml defines no stat | OP-08 ('state directories MUST have bounded growth') binds a component that owns crash-report/log/cache directories. A thin library that writes no persistent state of its own has nothing to bound; the consuming service owns retent |
| OP-09 | N/A | Explicitly 'applies to: service' (OPERABILITY.md:42). This is a library adapter, not a service: no environment/production config validator, no listener, no validate_production() — src/  | OP-09 is a service-only rule (production-config fail-fast before listening). A thin vendor adapter library has no production-startup path of its own — the consuming vm-vmanager service runs validate_production(). The standard scop |
| OP-10 | N/A | Explicitly 'applies to: service' (OPERABILITY.md:43). No Dockerfile / compose / k8s manifest / deployable image in the repo (file listing shows none); the artefact is a PyPI wheel (dist | OP-10 (versioned deployable image + rollback runbook, 'no :latest') binds a service that ships container images to production. A library publishes immutable, semver-tagged wheels (publish-chain rules live under RELEASING, not OP-1 |
| OP-11 | N/A | Explicitly 'applies to: service' (OPERABILITY.md:44). No Prometheus rules, no alertmanager, no docs/runbooks/ in the repo (file listing shows none); a library emits no alerts and runs n | OP-11 (alerts page humans + carry runbook_url) binds a deployed service with an alerting story. A thin adapter library has no alerting or paging surface — the consuming service owns Prometheus rules + runbooks (standard §3 scopes  |
| OP-12 | N/A | Explicitly 'applies to: service' (OPERABILITY.md:45). No backup/restore script, no docs/drills/, no S3/R2/GCS target — this library stores no data of its own (src/ is a skeleton). It dr | OP-12 (backup+restore drill against the real target) binds a service that owns durable production data and an RTO claim. A thin adapter library owns no backup target and no DR story — the consuming vm-vmanager service exercises re |

### DEPLOYMENT

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| DEP-01 | N/A | DEPLOYMENT.md:7-9 Scope = 'stateful web-service consumer applications'; :20-21 Out of scope = 'Federation libraries (no runtime)'; Rules-box 'Applies to' column = 'service' (:41). mgf-v | DEP-01 (cloud infra MUST be IaC) binds the deployment of a running web service. This package has no cloud footprint — it is library code consumed by a service, not the service. Premise does not bind. |
| DEP-02 | N/A | DEPLOYMENT.md :42 DEP-02 'Applies to: service'; §8.4/§8.2 note DEP-02 is N/A even for managed-platform/static shapes that lack VM ownership. This library owns no VM and ships no Ansible | VM/container Configuration-as-Code applies to a service that runs on VMs. A library that is pip-installed into a consumer has no VM state to express. Premise does not bind. |
| DEP-03 | N/A | DEPLOYMENT.md :43 DEP-03 'Applies to: service'; concerns 'deploy installs only from the lock' / 'no pip install --upgrade at runtime in production'. This package has no production runti | Immutable release-artefact-at-deploy is a service-deploy contract. The library's publication/version-immutability is covered by RELEASING + PACKAGE_DISTRIBUTION (PKG-07), not DEP-03. Premise does not bind to a library. |
| DEP-04 | N/A | DEPLOYMENT.md :44 DEP-04 'Applies to: service'; 'Production secrets MUST live outside the repo'. This adapter handles no production secrets of its own — it talks to a local Firecracker  | DEP-04 governs a deployed service's production-secret storage (Ansible Vault / KMS). A library has no production secret store. Premise does not bind. |
| DEP-05 | N/A | DEPLOYMENT.md :45 DEP-05 'Applies to: service'; requires deploy/backup/restore/rollback scripts under deploy/scripts/. No deploy/ dir and no scripts/ exist (`ls deploy` => No such file) | Environment-explicit deploy commands apply to a service that has deploy scripts. A library has none. Premise does not bind. |
| DEP-06 | N/A | DEPLOYMENT.md :46 DEP-06 'Applies to: service'; reversible deploys with a drill-measured rollback runbook (per OP-10). No deploy/docs/runbook.md, no releases/<sha> shape — the repo is a | Reversible-deploy + rollback runbook binds a running service. A library has no production environment to roll back. Premise does not bind. |
| DEP-07 | N/A | DEPLOYMENT.md :47 DEP-07 'Every web-service consumer MUST organise deployment artefacts in a top-level deploy/ directory'; 'Applies to: service'. §3 :199-209 explicitly notes a federati | The deploy/ directory shape is required of web-service consumers. A thin federation library is explicitly carved out — its 'deployment' is CI integration tests, not a deploy/ tree. Premise does not bind. |
| DEP-08 | N/A | DEPLOYMENT.md :48 DEP-08 'Applies to: service'; requires committed deploy/docs/slo.md, error-budget burn-rate alerts, paging channels. None exist (no deploy/ dir). This library emits no | End-to-end production observability + SLO file binds a deployed service. A library has no production sink/SLO. Premise does not bind. |
| DEP-09 | N/A | DEPLOYMENT.md :49 DEP-09 'Applies to: service'; DNS records in IaC + auto-renewed TLS certs. This adapter exposes no DNS name and terminates no public TLS — it speaks httpx over a LOCAL | DNS + TLS as managed infrastructure binds a publicly-served web service. A library talking to a local unix socket has neither DNS nor public certs. Premise does not bind. |
| DEP-10 | N/A | DEPLOYMENT.md :50 DEP-10 'Applies to: service'; requires deploy/docs/first-production-cut.md green-field provisioning sequence. No deploy/docs/ dir exists. There is no production cut fo | A first-production-cut provisioning runbook binds a service being stood up on cloud infra. A library has no green-field provisioning. Premise does not bind. |
| DEP-11 | N/A | DEPLOYMENT.md :51 DEP-11 'Applies to: service'; deployable to >=2 environments (prod + staging/dev) from the same IaC parameterised by an env file. No terraform/environments/ tree (no d | Multi-environment deployability from shared IaC binds a service. A library has no environments to deploy to. Premise does not bind. |

### PRESENTATION_LAYER

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| PR-01 | ✅ | src/mgf/vm/firecracker/__init__.py (whole module: only __version__ + empty __all__, no imports) — no UI-framework import present. But pyproject.toml:102-104 [tool.importlinter] declares | PR-01 is a two-part MUST: (a) the SDK MUST NOT import a UI framework AND (b) the rule MUST be enforced mechanically via import-linter. Clause (a) is currently satisfied (the adapter is a skeleton with no imports), but clause (b) i — FIXED 2026-06-09: the closed-box import-linter contract forbids UI frameworks; lint-imports CI-enforced |
| PR-03 | N/A | This repo is the SDK/adapter (src/mgf/vm/firecracker/), not an `<app>` repo. It has zero UI consumers — __init__.py:22-26 exports only __version__; no core/, view/, ui/ trees exist. Sta | PR-03 binds 'an app repo with multiple UIs.' A thin vendor adapter with no UI is not an app repo; the three-layer (core/view/ui or presentation/<framework>) separation does not bind. Per PR-07's own carve-out, a pure-SDK with zero |
| PR-04 | N/A | No app layers exist to enforce (no core/view/ui/ or presentation/<framework>/ subtrees under src/mgf/vm/firecracker/). The only import-linter wiring (pyproject.toml:102-104) is the SDK- | PR-04 mechanically enforces the PR-03 layer hierarchy ('core and view MUST NOT import a UI framework; ui/<framework> MUST import only its own framework + view/'). With no app and no UI layers, there is no hierarchy to enforce. N/A |
| PR-05 | N/A | No ui/<framework>/ adapters exist anywhere in the repo (single module src/mgf/vm/firecracker/__init__.py; tests are only tests/unit/.../test_smoke.py). | PR-05 ('each ui/<framework>/ adapter MUST consume view/ only, never a peer UI') is only meaningful when ≥2 UI adapters exist. There are zero UI consumers, so sibling-UI isolation cannot apply. N/A per §8.2 / PR-07 pure-SDK carve-o |
| PR-07 | ✅ | The standard requires the tracker to carry a `PR — PRESENTATION_LAYER` section classifying PR-* per the audit-outcomes taxonomy (PR-01 always applies; a pure-SDK with zero UI MAY mark P | PR-07 is a tracker-discipline MUST: the project must classify PR-* rules in MGF_STANDARDS_CONFORMANCE.md with per-row rationale (PR-01 applies; PR-02..PR-05 may be N/A as a UI-less SDK). The correct target state for this library i — FIXED 2026-06-09: §Z classifies PR-* (skeleton adapter — PR-03/04/05 N/A) |

### AGENTS

| Rule | Status | Evidence | Notes |
|---|---|---|---|
| AG-01 | ✅ | /home/bassam/PycharmProjects/mgf-vm-firecracker/AGENTS.md:1-37 — thin pointer ('Run mgf-common agents and do exactly what it prints', :9), explicitly states 'do not edit it; project-spe | [verify-upheld] Refute attempt: confirmed the file is byte-identical to a sibling's template (diff = IDENTICAL), is a thin pointer with no embedded briefing, and forbids editing while routing project notes to CLAUDE.md — exactly A |
| AG-02 | ✅ | /home/bassam/PycharmProjects/mgf-vm-firecracker/AGENTS.md:9 ('Run mgf-common agents') sources the canonical briefing from the single federation CLI; :20-22 routes project-specific looku | [verify-upheld] The briefing is sourced from the one federation source (`mgf-common agents`); the file does not duplicate it and points project content at the auto-managed CLAUDE.md block. No drift surface. Upheld. |
| AG-03 | ✅ | git log (8 recent commits): every commit body ends with both `Signed-off-by: Bassam Alsanie <bassam@magogi.org>` AND `Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com | [verify-upheld] Refute attempt: inspected raw `git log` bodies and config. Both mandatory trailers are present on all recent commits; the canonical identity is now bassam@magogi.org and the .gitmessage + config enforce it going fo |
| AG-04 | N/A | /home/bassam/PycharmProjects/mgf-vm-firecracker/FEEDBACK.md ships and the CLAUDE.md feedback-discipline block (:219-248) carries the routing. AG-04 fires only when an agent hits reusabl | Process/behavioral rule scoped to an agent session's actions, not a checkable static artifact. The feedback channel exists; there is no observed instance of friction that should have been filed but was not. Not applicable to a sta |
| AG-05 | N/A | Behavioral rule: 'agents MUST verify memory claims before recommending action.' No checkable static artifact in the repo. | Self-enforcement / session-behavior rule (§9 'Self-enforcement'). Not adjudicable from repo state — N/A to a static conformance audit. |
| AG-06 | ✅ | /home/bassam/PycharmProjects/mgf-vm-firecracker/.claude/settings.json:19-23 deny-list (rm -rf, git push --force, git reset --hard); :3-17 allow-list scopes Bash to ruff/mypy/pytest/lint | [verify-upheld] Refute attempt: read settings.json directly. Destructive/hard-to-reverse commands are explicitly denied while only safe/scoped operations are allow-listed; notably no `git push` (non-force) and no merge/publish in  |
| AG-07 | N/A | Session-behavior rule (use TaskCreate/TaskUpdate for ≥3-step work). No static artifact in the repo to adjudicate. | Self-enforcement runtime rule (§9). Not adjudicable from repo state. |
| AG-08 | N/A | Session-behavior rule (memory writes MUST be federation-scoped). No static artifact in the repo. | Self-enforcement runtime auto-memory rule (§9). Not adjudicable from repo state. |
| AG-09 | N/A | Behavioral rule: verify sibling versions against the Codeberg registry, not local dist/. pyproject.toml:106-115 does pin mgf-* to the codeberg-mgf index (consistent with the spirit of A | Review-only behavioral rule (§9). The repo's [[tool.uv.index]]/[tool.uv.sources] config aligns with it, but AG-09 is not a checkable static artifact — N/A to a static audit. |
| AG-10 | N/A | Behavioral rule: standards drift an agent finds MUST be filed as a PAPER, not silently fixed. No static artifact. | Review-only session-behavior rule (§7/§9). Not adjudicable from repo state. |
| AG-11 | N/A | Behavioral rule: cross-project feedback MUST be filed in the TARGET project's FEEDBACK.md. The repo ships FEEDBACK.md and the CLAUDE.md feedback-discipline block documents the routing. | Process/behavioral routing rule. The channel + routing docs exist; no observed mis-routed paper. Not adjudicable as a static-state pass/fail — N/A. |
| AG-12 | ✅ | /home/bassam/PycharmProjects/mgf-vm-firecracker/docs/claude/CLAUDE.md exists with the catch-up-managed auto-block (:3-289); AGENTS.md:20-22 names it as the fallback target; mgf-common i | [verify-upheld] Both the project-scoped content (CLAUDE.md) and the CLI that surfaces it (mgf-common as a dep) are present; AGENTS.md keeps to its thin-pointer role per AG-01/AG-02. The uniform project-scoped briefing capability i |
| AG-13 | N/A | Behavioral rule: only the mgf-common supervisor may change a library; others file a request. Governs cross-project edit behavior, not a static artifact. | Process/governance rule. Not adjudicable from this single repo's static state — N/A. |
| AG-14 | N/A | Behavioral rule: propagate a change to coupled surfaces in the same change (agent-facing form of DOC-18). The repo carries the DOC-18 surfaces (CHANGELOG.md present; __all__ in __init__ | Review-only session-behavior rule (the agent-facing DOC-18). Not a checkable static artifact in a state audit — N/A. |
| AG-15 | N/A | Charter rule (§10): agents are empowered to push back/propose/decline-with-rationale via the channels. §9 marks it 'Review-only (the charter grants license, not a checkable artifact).' | Explicitly non-checkable per its own enforcement row (review-only; grants standing, not an artifact). Not adjudicable from repo state — N/A. |
| AG-16 | ✅ | /home/bassam/PycharmProjects/mgf-vm-firecracker/pyproject.toml:33-37 declares `mgf-common>=0.41,<0.47` as a plain runtime dependency and :39-47 (dev extra) lists pytest/ruff/mypy/import | AG-16 requires depending on `mgf-common[standards]` where agents/maintainers run the federation CLI (the dev/tooling extra is enough). This repo declares plain `mgf-common` only — the corpus extra is absent. The repo otherwise ref — FIXED 2026-06-09: separate [standards] extra |
| 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 ✓ |
| 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 | N/A | no async. |
| PF-01 | N/A | no performance budgets / perf tests. |
| PF-02 | N/A | no performance budgets / perf tests. |
| PF-03 | N/A | no performance budgets / perf tests. |
| PF-04 | N/A | no performance budgets / perf tests. |
| PF-05 | N/A | no performance budgets / perf tests. |
| PF-07 | N/A | no performance budgets / perf tests. |
| PF-08 | N/A | no performance budgets / perf tests. |
| 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). |
