# Deliver two MGF operator web tools — `mgf-fed-web` + `mgf-test-web` (ProofWarden), on a shared `mgf-fedres` spine

> **Status:** refined & pressure-tested (round 2). Every "reuse, don't reinvent" claim below was
> verified against the real sibling repos under `~/PycharmProjects/mgf-*`; where the original plan
> overstated a reuse, this revision corrects it and re-scopes the work honestly. Corrections are
> tagged **⚠︎ corrected** inline and collected in the **Verified reuse ledger**.

## Context

Bassam has two design-closed internal web tools to deliver, each with an authoritative spec + brief + a working reference wireframe under **`docs/planning/`** (`mgf-fed-web/`, `mgf-test-web/`):

- **`mgf-fed-web`** — a read-mostly **federation dashboard**: per project, it renders real status, the end-to-end roadmap, what's in progress / stalled / next-best / awaiting-decision, plus a rounds-based human↔AI feedback loop and a live activity view. The rule that makes it trustworthy: **the web is never a second source of truth** — each project *generates* a schema-governed `fed-resources/generated/` set from its own artifacts; the web only composes + displays, tags anything it computes `derived`, and a **freshness gate** (`regenerate → byte-identical`) makes "in sync" real.
- **`mgf-test-web` / ProofWarden** — a **testing & CI authority console**. Its heart: **a given test can never run twice at once**, no matter the launcher (CLI / web / AI agent / CI). A per-project resident **warden** daemon is the *sole executor*; everyone submits run *requests*; single-flight is enforced **by construction** via an atomic **lease registry** (heartbeat + TTL + audited reclaim), with **coalesce** (same test+config) / **queue** (different work), **fail-closed** when the warden is down.

Both must be first-class MGF federation citizens (PEP420 `mgf.*` packages, scaffolded, conformance-ledgered, CI-gated, registry-listed, branch-protected) and carry the MGF spirit throughout: **honest-absence**, **refuse-don't-guess**, **generated-not-asserted**, **read-mostly**, everything **printable**, and *never reduce a tool's power for branding* (the brand layer is additive only).

**Two forks resolved with the user (locked):**
1. **Packaging → shared `mgf-fedres` core.** The two tools share a real spine (the `fed-resources/` convention, the manifest+sync engine, the `SourceProvider` seam, the `live/` NDJSON streams, run-records, and *all* the schemas — the test spec literally "reuses mgf-fed-web's DNA"). We factor that into one core library both webs consume, rather than vendoring it twice.
2. **First targets → the mgf-* Python fleet (pytest).** The **sooth family (soothfast/soothsmith, Zig) is deferred to a later phase** — for *both* tools. So the **pytest-via-`mtest` runner adapter is primary**; the Zig `zig build test --list` adapter ships with the sooth phase. **⚠︎ correction the specs predate:** every "dogfood on soothfast" line in the specs is redirected to a **Python** target (see **D-DOGFOOD**).

### What the four investigations + this round's code-verification established
- **The warden is new; `mgf-test-supervisor` (mtest) stays as-is and is driven as a library.** mtest is stdlib-only (TS-23, `dependencies = []` confirmed), stateless-per-invocation, and orchestrates pytest in chunks. **Verified integration shape:** the warden imports `Supervisor(RunConfig(test_ids=[node_id], chunk_size=1, …)).run()` — the **CLI cannot target a single test id**, only the Python API can — and reads structured per-test results back from `.gates/last-run/run.jsonl` via `read_jsonl()` (the call returns only an exit code). **mtest installs process-global SIGINT/SIGTERM handlers that `sys.exit()`**, so the warden MUST run mtest in a **child process**, never inside the daemon's own process. mtest's `.gates/.lock` is `fcntl` + `LOCK_NB` + **fail-fast**, released the instant a run ends — it guards one `.gates/` writer and is **not** a coordination primitive; daemon/lease/heartbeat/coalesce/queue are confirmed absent (the warden adds them above mtest). See **D-MTEST-API**.
- **The federation's `regenerate→byte-identical` discipline exists to learn from — but not to lift wholesale. ⚠︎ corrected.** `mgf-standard/scripts/gen_mgf_libraries.py --check` *is* a true byte-identical render-currency gate (good conceptual model). `gen_rules_index.py --check` is a *set-reconciliation* gate (different shape — do **not** model fedres on it). `mgf-fed/_drift.py` is **in-memory full-text string equality + render-currency keyed off a 3-entry hand-authored allow-list** in `mgf-standard/templates/policy.toml [exact]` — it has **no sha256, no manifest, no regenerate-into-tmp**. fedres reuses its *structure* (the `DriftItem`/`RepoDrift` dataclasses and the check→report flow) but **writes the per-file-sha256 manifest + regenerate-into-tmp + digest-diff engine itself**. That engine is the net-new heart of A3.
- **The wireframes are one design language built on `mgf-brand-web`'s dialect**, but the operator-instrument layer is **net-new ⚠︎ corrected**. brand-web (0.1.0, clean bump to 0.2) already ships `tokens.css`/`base.css`/`components.css` with `nav/card/table/badge/empty/ledger/forms`, a `static_dir()`, the gold-accent rule (`--color-accent: var(--mgf-gold)`), and ready functional state colors (`--color-success/-warning/-info/-error` + tints, dark-mode remapped). It has **none** of the ~14 instrument families (only adjacent `.badge`/`.ledger`/`.empty`). A1 is a real build, not a veneer.
- **No `fed-resources/` exists anywhere yet** — M0/M1 instantiates the very first one. **The richest Python targets and what they can actually feed (verified):** `test_catalog` projects cleanly from `pytest --collect-only` (mgf-standard 118, **mgf-common ~1635** (not "700+"), mgf-fed 642); the federation **architecture graph** and **coupling** project cleanly from `mgf-standard/MGF_LIBRARIES.json` (machine-readable, but it lives **only** in mgf-standard); **`status`, `roadmap`, `focus`, `suggestions` have NO machine-readable source anywhere — they exist only as prose markdown**, and **no SVG/UML/mermaid/dot diagram exists in any repo** (so `architecture.embed_svg` is a dead path today). This is the central D-GEN problem (see **The generation model**).

---

## Locked decisions

| Topic | Decision |
|---|---|
| **Naming family** | `mgf-<domain>-web`: **`mgf-fed-web`**, **`mgf-test-web`** (product/tagline **ProofWarden**; daemon **warden**; CLI **testctl**). `fedres` CLI ships from the core. |
| **Shared core** | **`mgf-fedres`** — schemas + sync engine + `SourceProvider` + live NDJSON + run-records + the `fedres` CLI + validator. Single schema authority (resolves spec **D3**). Headless (no web framework) so it's testable and reusable by the warden. |
| **Layering** | `mgf-brand-web 0.2` → `mgf-fedres` → {`mgf-fed-web`, `mgf-test-web`}. `mgf-test-web` base = warden+testctl (CI-installable, **FastAPI-free**); `[web]` extra = the console. The extras split follows **mgf-fed's zero-dep-core + `[cli]`-with-lazy-imports** model — **⚠︎ not cloud-app's** (where FastAPI is a *core* dep, so it has no such split to copy). |
| **First targets** | mgf-* fleet (Python). Primary runner adapter = **pytest via `mtest`** (library API). Sooth/Zig deferred. |
| **Cloud rename** | `mgf-cloud-app` → `mgf-cloud-web` (repo + package `mgf.cloud_app`→`mgf.cloud_web` + registry + brand-mount + protection). Contained (not on devpi). Verified low blast-radius: leaf app, **no external importers**, ~124 string sites in 38 files; follow-ups = the mgf-standard registry row + a deprecation help-string in `mgf-cloud`. The old `mgf_cloud_app` wheel stays orphaned on devpi. |
| **Infra** | Self-hosted Woodpecker (`195.15.241.48.sslip.io`) + devpi (`195.15.203.250.sslip.io/magogi/prod`) per `mgf-standard/MGF_INFRA.md` + **AG-20**; on-host JWT token-mint recipe (psql → HS256 signed with the user `hash` → `GET /api/user`; activate CI via `POST /api/repos`). |

### Spec confirm-lines — adopted values (all spec-default unless noted)
`fedres`/`testctl` = real binaries (D-SYNC-1, D-NAME) · Force-sync = regenerate-only on governed repos, you commit project-side (D-SYNC-2) · web reads the **working tree** in local mode (D-SYNC-3) · per-project packages later (D2) · schemas in **`mgf-fedres`** (D3) · `effort` = T-shirt `{XS,S,M,L,XL}`, `eta` separate (D-COST-1) · live = **follow-only** for v1, no `watch` daemon (D-LIVE-1) · run-records integrity-hashed but **exempt** from the reproduce-gate (D-LIVE-2 / D-RUN-4) · serialize-by-default, parallel opt-in (D-RUN-1) · resident daemon, fail-closed (D-RUN-2) · warden reachable from self-hosted Woodpecker → real cross-env single-flight (D-CI-1) · Woodpecker trigger = **API token + poll** reusing the AG-20 mint recipe (D-CI-2) · lease TTL 30s / heartbeat 10s, long tests send progress heartbeats (D-TTL) · queue = FIFO (D-RUN-3) · config types int/enum/bool/string, per-run only (no saved presets) (D-CFG) · runner adapters: **pytest-via-mtest** + shell now; **zig** with the sooth phase (D-RUNNERS).

### New confirm-lines this round (raised, not assumed — defaults chosen, settle during the phase named)
- **D-GEN-1 (Phase A/A3) — authored structured source.** `status`/`roadmap`/`focus`/`suggestions` have no machine source. **Default:** each project carries an authored, structured **single** source under `fed-resources/source/` (e.g. `roadmap.toml`, `tasks.toml`), and the generator *projects* `source/ → generated/` canonical JSON under the freshness gate. The authored source IS the source of truth (not a "second" one); the JSON is its projection. Confirm the source format + that this satisfies "no second source of truth."
- **D-GEN-2 (A3) — architecture mode.** `embed_svg` is unusable today (no diagrams exist). **Default:** v1 ships **graph** mode, projected from `MGF_LIBRARIES.json` (federation edges) + `.importlinter` (intra-repo layer edges) + `PUBLIC_API.json` (surface nodes); `embed_svg` stays in the schema for projects that later add a diagram.
- **D-COALESCE (A3/A4) — coalesce identity.** **Default:** coalesce iff *same `key` AND same `test_id` AND same `config_digest`*; a same-test request with a *different* effective config is different work → it **queues** (it must not silently receive another config's result). Closes a correctness hole in spec §1.3.
- **D-WARDEN-TRANSPORT (A4/C-M1) — IPC + singleton.** **Default:** Unix domain socket at a well-known per-project path; loopback HTTP only as a cross-container CI fallback; exactly one warden per project enforced by an `fcntl` pidfile/socket lock (the *one* place mtest's fcntl pattern is reused — for warden singleton, not test single-flight). Stdlib-only so base stays FastAPI-free.
- **D-CI-3 (C-M5) — the advisory escape hatch.** Fail-closed blocks *all* CI if the warden is unreachable from a remote runner. **Default:** `testctl run --from-ci` is the **single sanctioned** path that may run outside the warden — and only when (a) the warden is unreachable AND (b) a `--remote-advisory` policy is set; it runs via mtest, writes a run-record flagged `lease:{joined:false, advisory:true}`, and the web surfaces any local↔CI same-key overlap as a **loud flagged collision**, never as "prevented." Everywhere else, warden-down = refuse.
- **D-MTEST-API (A4/C-M1) — library coupling.** The warden couples to mtest's **library API** (`RunConfig`, `Supervisor.run`, `collect_tests`, `read_jsonl`, `TestRecord`), not its CLI. **Default:** pin `mgf-test-supervisor` with a tight bound and add a **contract test** so an mtest change can't silently break the warden; run mtest in a child process (signal-handler hazard).
- **D-CATALOG-CANON (C-M2) — deterministic catalog.** `pytest --collect-only` order/markers can vary. **Default:** `testctl catalog` canonicalizes (sort node-ids; derive category→group→test deterministically from path + markers) so the catalog satisfies `regenerate → byte-identical`.
- **D-BRAND-ACCENT (A1) — gold vs functional blue.** The wireframes use **blue** (`#2E86C8`) for primary buttons *and* the busy state; the brand rule is "one gold accent per view." **Default:** affirmative/primary actions adopt the brand **gold** accent (preserving one-gold-per-view); **blue** is reserved strictly as the functional `--state-busy/running` color and **violet** as `--state-derived/authority` — both functional, neither brand-identity. Re-skin the wireframes' blue primaries to gold. (Power is untouched; only the accent hue moves — consistent with "branding is additive.")
- **D-DOGFOOD (all phases) — Python dogfood targets.** Replace the specs' "soothfast" with: `mgf-fedres` itself → `mgf-standard` → `mgf-common` / `mgf-test-supervisor`.

Raise any concern or counter-proposal through the same `agent_raised` loop and commit to it.

---

## Verified reuse ledger (what's real vs. what's net-new)

| Asset (claim) | Verdict | What we actually reuse / build |
|---|---|---|
| `mgf-fed/_drift.py` byte-compare engine | **skeleton only ⚠︎** | Reuse the `DriftItem`/`RepoDrift` dataclasses + check→report flow. **Build new:** sha256 manifest, regenerate-into-tmp, canonical-JSON, digest-diff, sync-state enums. |
| `gen_mgf_libraries.py --check` discipline | **model (concept)** | The byte-identical render-currency *pattern* is the right mental model for fedres' deep check. (`gen_rules_index.py` is set-reconciliation — don't model on it.) |
| `mgf-test-supervisor` (mtest) as runner | **as-is, library API** | Import `Supervisor`/`RunConfig`(`chunk_size=1`)/`collect_tests`/`read_jsonl`/`TestRecord`. Run in a child process. CLI can't do single-test. Pin + contract-test (**D-MTEST-API**). |
| `mgf-cloud-app` FastAPI+Jinja+brand-mount shape | **clone shape; deps differ ⚠︎** | `web/_app.py` mounting `mgf.brand_web.static_dir()` at `/static/brand` is real and clone-worthy. **But** no `[cli]`/`[web]` extras pattern exists there (FastAPI is core) and **htmx is only a vendored asset, not load-bearing** — don't assume an htmx interaction model. |
| `[web]` extra / lean base split | **model = mgf-fed ⚠︎** | Follow mgf-fed's zero-dep-core + `[cli]` lazy-import pattern (verified), not cloud-app. |
| "app-shaped" `.woodpecker.yml` (hand-authored) | **does not exist ⚠︎** | The webs publish as **wheels with a `serve()` console entry**; CI is the **generic library pipeline regenerated by `mgf-fed._woodpecker` (base.yml)** + an `app-doctor` step. No deploy pipeline. Regenerate, don't copy. |
| `mgf-fed scaffold` "delivers the conformance bundle" | **partly ⚠︎** | scaffold applies **3 byte-exact files** (`verify_codeberg.py`, `check_commit_trailers.py`, `.gitleaks.toml`) + a generated `.woodpecker.yml`, and only *reports* the rest as drift. New-repo bootstrap = `mgf-standard/templates/cookiecutter-mgf-project` (ships LICENSE/AGENTS/README only). The **DOC-01** doc baseline is **authored** — no tool emits it; `catch-up` only audits it. |
| DOC-17 "contract files (CHANGELOG, SECURITY…)" | **mislabeled ⚠︎** | Those ten docs are **DOC-01**. **DOC-17** = the `FEDERATION.md` pointer-stub rule specifically. |
| AG-03 commit trailers | **as-is** | Reuse `.githooks/prepare-commit-msg` + the byte-exact `check_commit_trailers.py` + the `commit-trailers` CI fragment (requires `Signed-off-by` **and** `Co-Authored-By`). |
| Conformance ledger + `_status.py` parser | **as-is** | The `docs/inprogress/MGF_STANDARDS_CONFORMANCE.md` table format + `_VERDICT_RE`/`_conformance` scorer are directly reusable. |
| `app-doctor --standards` per-repo gate | **as-is (via dep)** | Lives in **`mgf-fed[cli]`** (depends on mgf-common). Pin it; it's the per-repo conformance CI step (DOC-15, py.typed, version-sync, DTZ…). Exit 2 on fail. |
| REL-13 registry / `MGF_LIBRARIES.json` | **as-is, auto-discovery ⚠︎** | Registration = create the sibling repo + regenerate the registry **in mgf-standard** + DEPS/NAMING ripple (DOC-18). It is a **release-time gate run from the mgf-common supervisor**, keyed on on-disk siblings — **not** a per-repo CI step. `mgf-fedres` is not yet registered. |
| AG-20 token-mint for CI trigger | **as-is** | The `MGF_INFRA.md §2` JWT recipe is exactly D-CI-2's "API token + poll." |
| `mgf-livepush` for live channel | **deferred reuse (new ref)** | SSE broker→client fan-out — **wrong layer for v1's file-NDJSON `live/`** (follow-only tail), but the **designated building block for the future SSE/push-relay + mobile** direction. Cited here so that surface isn't reinvented later. |

---

## Package architecture

```
mgf-brand-web 0.2     tokens/base/components + NEW static/instruments.css (operator layer)
        |               net-new: ~14 instrument families; reuses existing functional state tokens
        |
mgf-fedres            THE SHARED SPINE — headless (PEP420 src/mgf/fedres; NO web framework)
        |               schemas (ALL, incl. test_* + the live wire formats) + version-aware reader + `fedres-validate`
        |               manifest + sha256 + canonical-JSON  (net-new engine; _drift.py is a skeleton ref)
        |               sync engine: shallow (manifest) + deep (regenerate-into-tmp, diff, non-mutating)
        |               SourceProvider seam: DiskProvider (now) / PackageProvider (stub→later)
        |               D-GEN framework: source/→generated/ projection contract + reference projectors
        |               live/ NDJSON reader+writer + run-record writer (gate-exempt, integrity-hashed)
        |               `fedres` CLI: status / check / generate / run --trace / tail  + the freshness gate
        |
        |---------------------------------> mgf-fed-web   (src/mgf/fed_web; FastAPI+Jinja, htmx optional)
        |                                      FastAPI may be a CORE dep (pure web). Logic lives in fedres.
        |                                      8 lenses · sync matrix · feedback rounds · Follow-live
        |
        +--> mgf-test-web   (src/mgf/test_web)
               base : warden (resident broker + atomic lease registry + coalesce/queue/heartbeat/
               |       TTL/audited-reclaim) + WardenClient (UDS, stdlib) + `testctl` CLI
               |       + runner adapters (pytest-via-mtest library API, shell)
               |       deps: mgf-fedres, mgf-test-supervisor   <-- CI installs THIS, FastAPI-FREE
               [web]: ProofWarden console (Catalog/Running/History/CI)  deps add FastAPI + mgf-brand-web
                        ^                                                 (lazy-imported, mgf-fed [cli] model)
mgf-test-supervisor (unchanged)  =  mtest, driven as a LIBRARY in a child process
```

**Headless-core rule (tightening):** all logic that doesn't need a browser — `SourceProvider`, the version-aware reader, the sync engine, the live reader/writer, the run-record writer, the D-GEN projectors — lives in **`mgf-fedres`** with no web dependency, so it is unit-testable headless and the **warden reuses it without pulling FastAPI**. The webs are thin presentation layers over the core. The webs are wheels with a `serve()` entry (like cloud-app); CI builds/publishes a wheel — there is no deploy step.

---

## Schema set & governance classes (single authority in `mgf-fedres`, `schema_version: "0.1"`)

The schemas split into **four governance classes** — the original plan listed the files but blurred these, which matters because the gate, the manifest, and the validator treat them differently. **All four are versioned and validated; the validator (`fedres-validate`) covers wire formats too**, because they are the stability contract the future mobile push relay subscribes to.

**Class 1 — Gated state** (`generated/`, covered by the manifest, **`regenerate → byte-identical` reproduce-gate**):
`manifest.json` (the anchor: `schema_version`, `source_commit`, generator name+version, `generated_at`, per-file `sha256` over `generated/**`), `status.json`, `roadmap.json`, `architecture.json`, `focus.json`, `suggestions.json`, `federation.json`, **`test_catalog.json`**.

**Class 2 — Gated, reproduce-exempt** (`generated/runs/`, **integrity-hashed in the manifest but outside the reproduce assertion** — history can't be regenerated; D-LIVE-2 / D-RUN-4): `run_record.json` (fed), **`test_run_record.json`** (test, carries `effective_config` + `config_digest` + full `lease` audit).

**Class 3 — Authored, ungated** (`feedback/`, the generator never writes here): `feedback.json`, `response.json`.

**Class 4 — Live/ephemeral wire contracts** (`live/`, **gitignored, NEVER gated**, compact `"v":"0.1"` on NDJSON lines — *not* `schema_version`):
- **fed live-session event grammar** — `kind ∈ {session_start, step, progress, log, artifact, gate, error, session_end}`.
- **test run-log event grammar** — `kind ∈ {run_request, lease_acquired, test_start, step, log, progress, assert, artifact, test_end, lease_released, coalesced, queued, lease_reclaimed, cancelled, error}`.
- **`test_status`** — the lease-registry wire format returned by `testctl status` (the warden's in-memory authority serialized; `broker ∈ {up,down}`). **Not a `generated/` file** — it's live authority state.
- **pointers** — `live/CURRENT` (text: active session/run id or absent), `live/leases.json` (the registry journal/mirror for read-visibility + crash recovery).

**Cross-cutting sub-schemas (defined once):** `applies_to {view, ref}`, `links [{label, ref}]`, `evidence` (string), `config_schema [{name, type, default, …}]`, and the closed **state enums** — including the full sync set `{IN_SYNC, STALE, TAMPERED, UNKNOWN, UNREADABLE, CHECKING, SYNCING, ERROR}` (**⚠︎ the original A1 list dropped `UNREADABLE`**) and the test set `{pass, fail, error, skipped, unknown}`. **Version-aware reader:** any unrecognized `schema_version`/`v` → render `UNREADABLE`, never a guess.

---

## The generation model — **D-GEN** (the load-bearing risk, settled in A3)

`fedres` provides the **framework**; each project provides the **projection** of its own artifacts → `generated/`. The verified-source audit forces an honest split into two projection classes:

**Class P — projected from existing machine-readable artifacts (no new authoring):**
- `test_catalog` ← `pytest --collect-only` (via mtest `collect_tests`), canonicalized (**D-CATALOG-CANON**).
- `architecture` (graph) ← `MGF_LIBRARIES.json` (federation edges) + `.importlinter` (layer edges) + `PUBLIC_API.json` (surface nodes) (**D-GEN-2**). *Note: `MGF_LIBRARIES.json` lives only in mgf-standard, so the federation graph is sourced centrally; per-repo internal graphs are coarse.*
- `federation` (coupling) ← `MGF_LIBRARIES.json` `deps`/`used_by` — makes the Coupling lens real, not inferred.
- partial `suggestions`/`status` evidence ← the conformance-ledger gaps (rule-id + verdict + `file:line`) via the `_status.py` `_VERDICT_RE` parser — *fragile prose-parsing; treat as enrichment, not the spine.*

**Class A — authored structured single-source (genuinely prose today):** `status` (tasks), `roadmap` (stages), `focus`, the bulk of `suggestions`. **Resolution (D-GEN-1):** these are authored once, as *structured* data under `fed-resources/source/` (the single source of truth); the generator projects `source/ → generated/` canonical JSON, freshness-gated like everything else. This **preserves "no second source of truth"** — there is one source (the structured `source/`), and `generated/` is strictly its projection; the existing prose roadmaps (`federation_roadmap.md`, etc.) are migrated into `source/` once per project (and may thereafter be *generated from* it). **Honest-absence at projection granularity:** a project that hasn't authored a roadmap source simply has no `roadmap.json` → the web shows `UNKNOWN`/empty, never a fabricated stage.

**A3 deliverables for D-GEN:** (1) the generic framework (manifest, sha256, canonical-JSON, the gate, `SourceProvider`); (2) a **declared per-project generator contract** — a `[tool.fedres]` mapping / `fed-resources/generator.py` hook that names each schema's source (Class P projector or Class A `source/` file); (3) **reference projectors** for the Class-P sources and a **schema + loader** for the Class-A `source/` files. **Scope honesty:** authoring the Class-A `source/` for each fleet project is real per-project work, scheduled in **D2 (fleet rollout)** — not free projection. This is the single biggest scope correction in this revision.

---

## Warden & lease — single-flight design (the heart of mgf-test-web, tightened)

**Authority model.** One resident **warden** per project is the sole executor. It is the only writer of the lease registry, which is **authoritative in memory** and mirrored to `live/leases.json` (read-visibility + crash recovery). Web/CLI/agent/CI submit **requests**; none execute. Because the warden is a single process, the acquire decision is an **in-process critical section** — single-flight is correct **by construction**, with no file-lock TOCTOU. This is precisely why the daemon model beats the no-daemon lockfile fallback (D-RUN-2), which is documented but not default.

**Warden singleton (new — required for correctness).** Exactly one warden per project, enforced by an `fcntl` lock on a pidfile/socket path (mtest's fcntl pattern, reused here for the *warden*, not for tests). `testctl serve` acquires it; if held, it exits ("a warden is already running"). This prevents two wardens racing the same registry. The warden is explicitly started/supervised (systemd `--user` or a process manager); `testctl` never silently executes a test. An opt-in `testctl run --autostart` local convenience may spawn a warden if absent — safe because the singleton lock lets only one win.

**Transport (D-WARDEN-TRANSPORT).** Unix domain socket at a well-known per-project path; `WardenClient` abstracts it. Filesystem-permissioned, no port allocation, no localhost exposure; stdlib-only so **base needs no FastAPI**. Loopback HTTP is a fallback only where a UDS can't be shared (some CI containers).

**The acquire decision (enforcement).** On a request for `key`:
- **free** → grant lease, spawn the test (mtest in a child process), stream NDJSON.
- **held, same `key` + same `test_id` + same `config_digest`** → **coalesce** (D-COALESCE): attach the requester as a watcher, return the in-flight `run_id`, start no second run.
- **held, same `key`, different `test_id` *or* different `config_digest`** → **queue** (FIFO, bounded `max_depth`; the request carries its own config). A same-test/different-config request is *different work* and must not receive another config's result.
- `independent: true` tests use `key = test_id` (their own lease) and so run alongside the project-key run — they bypass the project queue.
- Every outcome — acquire / coalesce / queue / release / **reclaim** / **refused** — is an NDJSON event **and** an entry in the run-record audit: the **visible proof** the lock held.

**Heartbeat / TTL — what they actually guard (new clarification).** In daemon mode the warden **owns** the child, so child exit is observed directly via `wait()`/SIGCHLD → immediate `lease_released` + `test_run_record`; **TTL is not in the normal path**. TTL/heartbeat is the **warden-crash recovery** mechanism:
- The warden refreshes each held lease's `heartbeat_at` in `live/leases.json` every `heartbeat_s` (10s) — a liveness beacon for *the warden itself*.
- If the warden dies, its children die/orphan and the lease's `heartbeat_at` freezes. The next warden to acquire the singleton reads `leases.json`, finds leases aged past `ttl_s` (30s), **reclaims** them with an audited `lease_reclaimed` event, and **kills any orphaned child** (an orphan running outside authority would break single-flight) — recorded.
- "Long tests send progress heartbeats" (D-TTL): the running test's `progress`/`step` events refresh a *last-progress* timestamp shown in the UI and feed an optional hung-test detector (child alive but silent > N×ttl → surface `STALLED`, offer cancel). They are a UI/diagnostic signal; the reclaim trigger remains warden-liveness.
- The wireframe's "Sim holder crash" models the **lockfile-CLI fallback** (holder = test process), where holder death *is* the reclaim trigger — call out the distinction so the daemon model isn't mis-implemented from the sim.

**CI & the fail-closed/advisory tension (D-CI-3).** Local CLI/web/agent: warden unreachable → **refuse** (nonzero), never spawn. CI `testctl run --from-ci` joins the **same lease** when the warden is reachable (self-hosted, UDS mounted → real cross-env single-flight, D-CI-1). When unreachable from a remote runner, hard fail-closed would block *all* CI; so `--from-ci --remote-advisory` is the **one sanctioned out-of-warden path**: it runs via mtest, writes `lease:{joined:false, advisory:true}`, and the web flags any local↔CI same-key overlap as a **loud collision** (never "prevented"). This is the only exception to "warden = sole executor," gated and always recorded.

**mtest integration (D-MTEST-API).** Per accepted request, the warden (in a **child process**) builds `RunConfig(test_ids=[node_id], chunk_size=1, test_markers=…)`, calls `Supervisor.run()`, streams the child's output as NDJSON, and on completion reads `.gates/last-run/run.jsonl` via `read_jsonl()` → structured `TestRecord` → `test_run_record.json`. Pin `mgf-test-supervisor` tightly; ship a **contract test** against `RunConfig`/`Supervisor.run`/`read_jsonl`/`TestRecord` so an upstream change surfaces loudly.

---

## Phase plan (end-to-end, both tools, in build order)

Each repo, when created, gets the **federation-conformance bundle** (see checklist). **Critical-path note:** A1 (brand-web 0.2) blocks only the **web UIs** (B/M2+, C/M2+), *not* the cores — so **A1 ∥ A2/A3** (run A1 in parallel; it must not gate the spine). The spine critical path is **A2 → A3**, then the warden, then the UIs.

### Phase A — Foundation (shared) `[blocks everything downstream]`
- **A1 · `mgf-brand-web` 0.2 — the instrument layer (net-new, parallelizable).** Add `static/instruments.css` (+ minimal token additions) with the ~14 component families distilled from the wireframes: **state chips** (sync `IN_SYNC/STALE/TAMPERED/UNKNOWN/UNREADABLE/CHECKING/SYNCING/ERROR`; test `pass/fail/error/skipped/running`), animated **live indicator dots**, **progress** bars, **tabs/lens-tabs**, the dark streaming **console**, **authority/broker** markers, **ribbons**, the **live-pane** (run/session card), **config-panel**, **level** badges, **telemetry** marker, reference **pills**, **detail/evidence** blocks, **empty-state** variants. **Reuse** brand-web's existing functional state colors; **add** only `--state-busy` (blue) + `--state-derived/authority` (violet) as *functional* tokens, keep the gold accent for affirmative actions (**D-BRAND-ACCENT**). Reconcile the wireframes' ad-hoc hex to named tokens. Additive only. Bump 0.1.0→0.2; publish to devpi; update README + register the change. *Done when:* `instruments.css` renders the wireframe components on brand tokens, and `mgf-cloud-app` still renders unchanged after the bump.
- **A2 · `mgf-fedres` M0 — the contract.** **Complete** the repo (it's a skeleton: only `pyproject`/`README`/`LICENSE`/`src`/`docs/planning` exist — author the DOC-01 baseline, apply the 3 byte-exact files, generate `.woodpecker.yml`, stand up the ledger, then **register in mgf-standard**). Publish the **`0.1` schemas for all four classes** (see Schema set) + the version-aware reader + `fedres-validate`. *Done when:* the validator passes every spec example payload (incl. the NDJSON wire grammars + `test_status`) and **fails closed (nonzero)** on a hand-corrupted one and on an unknown `schema_version`.
- **A3 · `mgf-fedres` M1 — engine + CLI + gate + D-GEN.** Build the net-new engine: per-file-sha256 manifest, canonical-JSON, shallow check (manifest only) + deep check (regenerate-into-tmp, diff, **non-mutating**); `DiskProvider` (+ `PackageProvider` stub behind the seam); live NDJSON reader/writer; run-record writer (gate-exempt, integrity-hashed); the `fedres` CLI (`status/check/generate/run --trace/tail`); the freshness gate; and the **D-GEN framework + reference projectors + `source/` loader** (D-GEN-1/2). Dogfood: instantiate the **first `fed-resources/`** on `mgf-fedres` itself, then `mgf-standard` (**D-DOGFOOD**). *Done when:* `fedres check` → `IN_SYNC` right after `generate`, `STALE` after a source change, `TAMPERED` after a hand-edit, gate exits nonzero on drift; shallow `status` agrees with deep `check`. Release to devpi.
- **A4 · Warden spike — `mgf-test-web` C/M1 pulled forward `[strongly recommended]`.** The warden is the highest-novelty, highest-risk component; the locked order otherwise lands it *after an entire other tool*. De-risk it now with a thin vertical slice on a Python target (`mgf-common` / `mgf-test-supervisor`'s suite): resident broker + atomic lease registry + warden singleton + `testctl run/status/cancel` + serialize-by-default + coalesce (config-digest) + FIFO queue + heartbeat/TTL/audited reclaim + the pytest-via-mtest child-process adapter + `WardenClient` (UDS) + fail-closed. *Acceptance = the C/M1 bar (below), met before B's UI is built.* If the user prefers the strict B-then-C order, this collapses back into C/M1 — but the late-warden risk is then accepted explicitly.

### Phase B — `mgf-fed-web` (the spine tool, first)
Scaffold `mgf-fed-web` (clone the cloud-app FastAPI+Jinja+brand-mount *shape*; FastAPI may be core; logic stays in `mgf-fedres`). Then, per spec §6:
- **B/M2** shell + legend + federation overview + one project's lenses (read-only via `DiskProvider`).
- **B/M3** sync UI: shallow-on-load, deep **Check sync**, **Force-sync**, per-project + global, full state language (incl. `UNREADABLE`), the sync matrix.
- **B/M4** feedback loop: compose → produce + deliver `feedback.json` into the target inbox; ingest `response.json`; the round thread (`open`/`answered`, `agent_raised`).
- **B/M5** polish: print/export + project review pack; architecture **graph** mode (embed_svg path stubbed until a project ships a diagram, D-GEN-2); `derived` cross-project overview; multi-project.
- **B/M6** live activity: Follow-live mode on the In-progress lens (discovery marker, current step / live progress / last-event age / latest log, session timeline, Play/Pause, idle/ended states), telemetry-tagged + gate-excluded; run-record → Changed. *(M7 package mode: `PackageProvider` left stubbed behind the seam.)*
- Activate CI, branch-protect after first green, register (cross-repo, in mgf-standard), release.

### Phase C — `mgf-test-web` / ProofWarden (second, reuses the spine)
Scaffold `mgf-test-web` (base = warden+testctl, deps `mgf-fedres` + `mgf-test-supervisor`, **FastAPI-free**; `[web]` extra = console + FastAPI + `mgf-brand-web`, lazy-imported per the mgf-fed model). Schemas already shipped in A2. Then, per spec §6:
- **C/M1 — the warden + single-flight (the CORE).** As designed in **Warden & lease** above. *(If A4 was taken, this is already proven — C/M1 becomes hardening + the catalog handoff.)* **Acceptance bar (exact):** two concurrent `testctl run <T>` from different origins → **one** execution + one `coalesced` record; a *different test* (or same test, different config) **queues**; killing the warden mid-run → `lease_reclaimed` + orphan killed + queue advances on restart; with the warden stopped, `testctl run` **refuses** (nonzero) and never spawns a test.
- **C/M2** catalog (`testctl catalog`, canonicalized + gated, **D-CATALOG-CANON**) + the **Catalog** view (tree, status chips, expandable configs) + the **Running** view (reads `testctl status`, honest-absence when down).
- **C/M3** run + live logs from the web (`WardenClient`; NDJSON **console**; run-record on completion; a CLI relaunch shown **coalescing**).
- **C/M4** History (run-records: result/duration/origin/effective-config/lease-audit, filters) + per-run **config overlay** (effective config recorded, committed defaults never mutated).
- **C/M5** CI: `testctl ci start` → Woodpecker pipeline + the **Watch** deep-link (AG-20 mint: JWT + poll, D-CI-2); `--from-ci` lease-join (real on self-hosted; **advisory + loud surfacing if remote**, D-CI-3). *(M6 package mode stubbed.)*
- Activate CI, branch-protect, register, release.

### Phase D — Rename, fleet rollout, deferred adapters
- **D1** `mgf-cloud-app` → `mgf-cloud-web` (repo + `mgf.cloud_app`→`mgf.cloud_web` + brand-mount + registry row + branch protection); adopt brand-web 0.2. Mechanical (no external importers); follow-ups: regenerate `.woodpecker.yml`, update mgf-standard registry + the `mgf-cloud` deprecation help-string; old wheel stays orphaned on devpi.
- **D2** Fleet rollout: instantiate `fed-resources/` + per-project projections **+ author each project's Class-A `source/`** (the real D-GEN work) + the test catalog across the mgf-* fleet in waves (`mgf-standard` → `mgf-common` → `mgf-fed` (meta) → the rest); wire each project's `fedres check` / `testctl catalog --check` freshness gate into its Woodpecker pipeline.
- **D3 (optional, surfaced not assumed)** a standards entry formalizing the `fed-resources/` convention (generated-not-asserted + honest-absence + read-mostly + the `source/`-vs-`generated/` split) so fleet adoption is uniform — proposed as a follow-up, not v1-blocking.
- **Deferred:** the **sooth family** (soothfast/soothsmith) + the **Zig `zig build test --list` adapter** + the hybrid Zig+Python forge-GUI target; and the **live push direction** (SSE/`watch` + the mobile push relay watching `generated/` + `live/`) built on **`mgf-livepush`** — all a later phase, per your steer.

---

## Federation-conformance bundle (applied to each new repo: `mgf-fedres`, `mgf-fed-web`, `mgf-test-web`)
> **⚠︎ Honesty correction:** no single tool *delivers* this bundle. Bootstrap with `cookiecutter-mgf-project` (LICENSE/AGENTS/README/pyproject/structure), **author** the rest of the DOC-01 baseline, run `mgf-fed scaffold` for the byte-exact files + generated CI, then `app-doctor`/`catch-up` to *audit*.

- **PEP420 namespace** `src/mgf/<name>` (no top-level `__init__.py`; hatchling `packages=["src/mgf"]`); `__version__` + `PUBLIC_API.json`.
- **DOC-01 doc baseline** (*not* DOC-17): `README, LICENSE, CHANGELOG, CONTRIBUTING, SECURITY, FEEDBACK, AGENTS, STARTHERE, DEPS, FEDERATION` + a `docs/` dir. (**DOC-17** specifically = the `FEDERATION.md` pointer-stub rule.) Authored, since no generator emits them.
- **`mgf-fed scaffold`** applies the **3 byte-exact** template files (`verify_codeberg.py`, `check_commit_trailers.py`, `.gitleaks.toml`) + the **generated** `.woodpecker.yml`. The webs use the **generic library pipeline** (`mgf-fed._woodpecker` base.yml) — lint, mypy, test-3.11/12/13, build, sbom, publish-on-tag, verify-devpi — plus fragments: **commit-trailers**, **gitleaks**, **`app-doctor --standards`**, and a **new freshness fragment** (`fedres check` / `testctl catalog --check`) contributed to `mgf-standard/templates/woodpecker/`. **No deploy step** (the webs are wheels with a `serve()` entry).
- **Conformance ledger** `docs/inprogress/MGF_STANDARDS_CONFORMANCE.md` in the `_status.py`-parseable table format; **AG-03 trailers** on every commit (`Signed-off-by` + `Co-Authored-By`, via the reused hook + byte-exact checker + CI step).
- **REL-13 registry**: register via **auto-discovery** — the new repo exists as an on-disk `mgf-*` sibling with a `pyproject.toml`; regenerate `MGF_LIBRARIES.{md,json}` (`gen_mgf_libraries.py` / `mgf-fed registry`) **and commit it in mgf-standard**, with the DOC-18 ripple (`DEPS.md` + NAMING). Grows the roster 33 → ~36.
- **Woodpecker activation** (mint JWT per `MGF_INFRA.md §2`; `POST /api/repos`) + **branch protection** after first green (full gate; relax-push-restore for any doc sweeps).
- **devpi release** for `mgf-fedres`, `mgf-fed-web`, `mgf-test-web` (push `v*` tag → tag pipeline → org `devpi_password`); `mgf-cloud-web` stays off devpi.

---

## Verification (per phase, end-to-end)
- **A1:** load `instruments.css` in a scratch HTML against the wireframes — components render on brand tokens; the gold/blue/violet split reads as **D-BRAND-ACCENT**; `mgf-cloud-app` still renders unchanged after the bump.
- **A2:** `fedres-validate` passes all spec example payloads **including the NDJSON wire grammars + `test_status`**; fails closed (nonzero) on a hand-corrupted payload and on an unknown `schema_version`.
- **A3:** on `mgf-fedres` then `mgf-standard`: `generate` → `check` = `IN_SYNC`; edit a source artifact → `check` = `STALE`; hand-edit a generated file → `check` = `TAMPERED`; the gate exits nonzero on drift; shallow `status` matches deep `check`; a Class-A `source/` edit reprojects deterministically (byte-identical on regenerate).
- **A4 / C/M1 (the single-flight proof — the gate):** the exact C/M1 acceptance bar above, demonstrated on a Python target, *before* B's UI if A4 is taken.
- **B:** run `mgf-fed-web` against the live working tree — the 8 lenses render from real `generated/`; a missing project shows `UNKNOWN` and a malformed-schema project `UNREADABLE` (honest-absence, not blank); **Check sync** is provably non-mutating (tree unchanged); **Force-sync** settles to `IN_SYNC`; a delivered feedback item appears in the project inbox and its response renders; print is clean.
- **C:** from the web — a run streams live in the console; a CLI relaunch of the same test+config shows `coalesced`; a same-test/different-config relaunch **queues**; the finished run lands in History with `effective_config` + `config_digest` + lease audit; warden stopped → "test authority unreachable — no runs can start (fail-closed)"; a remote CI run of a live key shows the **advisory collision** flag (D-CI-3).
- **Contract tests:** the mtest library-API contract test (D-MTEST-API); the catalog canonicalization test (D-CATALOG-CANON).
- **CI (per repo, in `.woodpecker.yml`):** pipeline green incl. `app-doctor --standards` + commit-trailers + gitleaks + the new freshness gate.
- **Release-time (separate, ⚠︎ not per-repo CI):** REL-13 currency/consistency GREEN — run from the **mgf-common supervisor** checkout with the new repos present as on-disk siblings (don't bake this into fedres CI).

---

## Risks & open decisions (prioritized)

1. **D-GEN-1 — authored structured source (highest).** `status`/`roadmap`/`focus`/`suggestions` have no machine source; v1 cannot "seed from existing artifacts" as the original plan implied. Mitigation: the `source/` single-source projection model + per-project authoring scheduled in D2. Confirm the model preserves "no second source of truth" to your satisfaction.
2. **Late-warden sequencing.** The riskiest component lands after a full tool in the locked order. Mitigation: **A4 warden spike** (recommended). Decide: take the spike, or accept the risk and keep strict B-then-C.
3. **D-GEN-2 / D-ARCH-SRC — architecture is coarse in v1.** No diagrams (embed_svg dead); per-repo internal graph is weak; the good federation graph is centralized in mgf-standard. Confirm graph-first + accept coarseness.
4. **D-COALESCE — config-aware coalescing.** Confirm same-test/different-config queues (not coalesces).
5. **D-CI-3 — the advisory escape hatch.** The one sanctioned out-of-warden path; confirm the policy gate + loud surfacing.
6. **D-MTEST-API — library coupling to mtest.** Confirm the pin + contract test; accept that the warden tracks mtest's library surface, not just its CLI.
7. **D-WARDEN-TRANSPORT / singleton.** Confirm UDS + the fcntl singleton.
8. **D-BRAND-ACCENT.** Confirm gold-for-actions vs the wireframes' blue.
9. **Smaller, carried from the specs:** D-NAME, D-TTL (30s/10s), D-RUN-3 (FIFO + max_depth + run-or-attach/run-or-queue), D-CFG (per-run only), D-RUNNERS (pytest-via-mtest + shell now), D-CI-2 (JWT + poll). Defaults chosen; settle in round 1.
10. **Cross-repo coupling.** Registration and the REL-13 gate require committing into **mgf-standard** and the new repo present on-disk — coordinate those commits; `mgf-fedres` is not yet registered.

---

## Scope & cadence
This is a multi-increment program; the plan is end-to-end but I'll **implement in phase order and checkpoint with you** after each high-risk gate: **after A3** (the spine), **after A4 / C-M1** (the single-flight proof — the new, strongly-recommended early checkpoint), **after B/M3**, and **after C/M5**. First shippable increment = **Phase A** (brand-web 0.2 + `mgf-fedres` M0–M1), the spine everything else builds on; A4 (the warden spike) is the recommended immediate follow-on to retire the program's biggest technical risk early. I'll hold mgf-standard + the MGF spirit at every step, keep `generated/` and `source/` honestly separated, and raise any new fork through the same `agent_raised` loop rather than guessing.
