"""Cross-layer audit — the gates that compare one layer of the federation to another.

WHY THIS MODULE EXISTS
----------------------
The federation has five layers, and almost every recurring defect is an answer
obtained from one of them and believed about another:

    declared  → committed → published → installed → live
    (registry,  (main)      (devpi)     (uv tool)   (Woodpecker,
     SECRETS.toml,                                   hosts, forge)
     pyproject)

Examples, each of which cost real time:

* ``rotate`` reported six green stages having written the **store**, while the
  **live** surface still served the old value — and then revoked the old one.
* ``sync`` announced "declared == deployed" having compared **declared** against
  **live metadata**, never the live value.
* ``mgf-alembic``'s **committed** main was 28 commits past the tag whose number it
  **published**; 6 of 7 wheels shipped ``License: MIT`` against Apache-2.0 source,
  so a completed relicense had reached no consumer at all.
* A fix merged to **committed** main is not shipped until **installed** has it.

Each incident produced a bespoke verifier in the court workspace's ``tools/``.
On 2026-07-30 there were **five of them, referenced by zero pipelines**. The
knowledge was captured; the enforcement was not, so the same classes recurred and
were re-diagnosed from scratch. This module is those verifiers folded into the
gate path, where an exit code makes them real.

THE TWO PROPERTIES THAT MAKE THIS DIFFERENT FROM A PILE OF CHECKS
-----------------------------------------------------------------
1. **Every check names the boundary it crossed.** A finding says *declared ↔
   published*, not just "problem". A check that cannot state its layers is a check
   whose scope will be misread — the exact class this module exists to end.

2. **A check that could not run is a FAILURE, not a pass.** Without ``--offline``,
   a missing token or an unreachable index exits non-zero. "I could not verify" and
   "I verified" must never produce the same exit code; that equivalence is what let
   a dead webhook look like a healthy repo for three weeks.

``--offline`` is the explicit opt-in that makes the network-free subset a legitimate
run — and even then, the skipped checks are named in the output. Silence is never
success.
"""

from __future__ import annotations

import hashlib
import json
import os
import re
import subprocess
import sys
import tomllib
import urllib.error
from dataclasses import dataclass, field
from pathlib import Path
from typing import TYPE_CHECKING, Any

from mgf.fed._http import request_json
from mgf.fed._roster import federation_root, is_git_repo

if TYPE_CHECKING:
    from collections.abc import Callable, Iterable, Sequence

# --------------------------------------------------------------------------- #
# Layers.
# --------------------------------------------------------------------------- #

DECLARED = "declared"  # the registries: MGF_LIBRARIES.json, SECRETS.toml, pyproject
COMMITTED = "committed"  # what origin/main actually holds
PUBLISHED = "published"  # what the index serves (devpi, and public PyPI)
INSTALLED = "installed"  # what the operator's environment actually runs
LIVE = "live"  # Woodpecker, the forge, the hosts

#: The devpi index the fleet publishes to and installs from.
DEVPI = "https://195.15.203.250.sslip.io/magogi/prod/+simple/"
_GIT_TIMEOUT_S = 30


def _wp_base() -> str:
    """The Woodpecker base URL, from the ONE place that already defines it.

    An earlier draft of this module hardcoded a plausible-looking hostname. It was
    wrong, and three checks reported SKIPPED — Woodpecker unreachable on the first
    live run. The honest-skip design caught it (a guess did not become a pass), but
    the guess should never have existed: a second definition of a shared fact is a
    second thing to drift.
    """
    import os

    from mgf.fed.cli._ping import _DEFAULT_WP_URL

    return os.environ.get("WOODPECKER_URL", _DEFAULT_WP_URL)


# --------------------------------------------------------------------------- #
# Results.
# --------------------------------------------------------------------------- #


@dataclass(frozen=True)
class Finding:
    """One cross-layer discrepancy. ``target`` is a repo/secret/name; ``detail``
    explains the gap in the terms of the two layers it sits between."""

    target: str
    detail: str


@dataclass
class CheckResult:
    """The outcome of one check, INCLUDING whether it actually ran.

    ``skipped`` is not a soft pass — :func:`run_audit` turns an unrequested skip
    into a non-zero exit. A check that reports zero findings because it never
    executed is the failure mode this whole module is built against.
    """

    name: str
    layers: tuple[str, str]
    examined: int = 0
    findings: list[Finding] = field(default_factory=list)
    skipped: str = ""  # non-empty = the reason it could not run

    @property
    def ok(self) -> bool:
        return not self.findings and not self.skipped

    def to_json(self) -> dict[str, Any]:
        return {
            "check": self.name,
            "layers": list(self.layers),
            "examined": self.examined,
            "skipped": self.skipped,
            "findings": [{"target": f.target, "detail": f.detail} for f in self.findings],
        }


# --------------------------------------------------------------------------- #
# Shared helpers.
# --------------------------------------------------------------------------- #


def _git(repo: Path, *args: str) -> str:
    try:
        return subprocess.run(  # noqa: S603 — fixed argv, repo path from the roster
            ["git", *args],  # noqa: S607 — `git` from PATH is the house convention
            capture_output=True,
            text=True,
            cwd=repo,
            timeout=_GIT_TIMEOUT_S,
            check=False,
        ).stdout.strip()
    except (OSError, subprocess.SubprocessError):
        return ""


def _repos_on_disk(root: Path) -> list[Path]:
    return sorted(p for p in root.glob("mgf-*") if is_git_repo(p))


def _wp_token(explicit: str | None = None) -> str | None:
    """Same resolution chain as ``mgf-fed ping``/``ci-stats`` — one token story."""
    if explicit:
        return explicit
    if os.environ.get("WOODPECKER_TOKEN"):
        return os.environ["WOODPECKER_TOKEN"]
    stored = federation_root() / "mgf-standard" / "my_stuff" / "woodpecker_token.txt"
    if stored.is_file():
        return stored.read_text(encoding="utf-8").strip()
    return None


def _wp(path: str, token: str, base: str | None = None) -> Any:
    return request_json(f"{base or _wp_base()}/api{path}", token=token, timeout=60)


def _wp_mgf_repos(token: str, base: str | None = None) -> dict[str, dict[str, Any]]:
    """``{repo-slug: woodpecker repo object}`` for the mgf-* repos it serves."""
    listing = _wp("/repos?limit=100", token, base)
    if not isinstance(listing, list):
        return {}
    return {
        str(r["full_name"]).split("/")[-1]: r
        for r in listing
        if isinstance(r, dict) and "/mgf-" in str(r.get("full_name", ""))
    }


# --------------------------------------------------------------------------- #
# CHECK: fleet — declared ↔ committed/disk
# --------------------------------------------------------------------------- #


def check_fleet(root: Path, **_: Any) -> CheckResult:
    """Every repo in the family registries exists on disk and is named in FLEET.md.

    ``FLEET.md`` lives in the private court workspace (``mgf/``), which is not a
    federation member — so an absent workspace is a legitimate SKIP rather than a
    failure of the fleet. Ported from ``mgf/tools/verify_fleet.py``.
    """
    res = CheckResult("fleet", (DECLARED, COMMITTED))
    fleet_md = root / "mgf" / "FLEET.md"
    if not fleet_md.is_file():
        res.skipped = f"no {fleet_md} (the court workspace is not checked out here)"
        return res
    fleet_text = fleet_md.read_text(encoding="utf-8")
    registries = [
        root / "mgf-standard" / "MGF_LIBRARIES.json",
        root / "sooth-standard" / "SOOTH_LIBRARIES.json",
    ]
    seen_any = False
    for reg in registries:
        if not reg.is_file():
            continue  # the sibling family may not be checked out — not this fleet's fault
        seen_any = True
        for name in sorted(_registry_names(reg)):
            res.examined += 1
            if not (root / name).is_dir():
                res.findings.append(
                    Finding(name, f"in {reg.name} but not on disk at {root / name}")
                )
            if name not in fleet_text:
                res.findings.append(Finding(name, f"in {reg.name} but not named in FLEET.md"))
    if not seen_any:
        res.skipped = "no family registry on disk"
    return res


def _registry_names(path: Path) -> set[str]:
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError):
        return set()
    items = (
        data
        if isinstance(data, list)
        else next((v for v in data.values() if isinstance(v, list)), [])
    )
    out = set()
    for item in items:
        if isinstance(item, dict):
            name = item.get("repo") or item.get("name") or item.get("slug")
            if name:
                out.add(str(name))
    return out


# --------------------------------------------------------------------------- #
# CHECK: agent-context — declared ↔ committed
# --------------------------------------------------------------------------- #

#: The pre-DOC-07 deep-context path. PAPER-54 left it valid on repos that never
#: migrated, and ``catch-up`` deliberately does not move them, so the pointer on
#: those repos legitimately names this file instead of the canonical one.
LEGACY_DEEP_CONTEXT = "docs/CLAUDE.md"

#: Benches that deliberately do NOT carry the agent-context surface. Every entry
#: MUST carry a reason, for the same purpose as ``GOVERNANCE_EXEMPT``: an
#: exemption is explicit and reviewable, never silent absence.
AGENT_CONTEXT_EXEMPT: dict[str, str] = {
    "mgf-secrets-store": (
        "the age-encrypted credential vault — ciphertext plus a manifest, not an "
        "engineering bench. Its HEAD commit is a stored secret, not code; an agent "
        "has nothing to be briefed about here."
    ),
    "PlasmaAI": (
        "never a bench: no git remote is configured at all, so it has no default "
        "branch to audit and nothing to distribute a pointer to."
    ),
}


def agent_context_roster(root: Path, registry: Path) -> list[str]:
    """Every repo that MUST carry the agent context — declared members AND the
    rest of the estate's benches.

    Scoping this to ``MGF_LIBRARIES.json``'s members was the Phase 2 court's
    **P2-F2**, and the finding is exact: the wave's universe was 57 repos, the
    registry declares 44, and the 13 excluded included ``mgf`` itself — the
    subject of the acceptance criterion four lines further down the same list —
    plus every repo §2.3 names. Worse, the two repos already known to lack the
    mechanism were both outside it, so ``exit 0 fleet-wide`` was a statement
    about **scope**, not about state. A roster that cannot see the failures is
    not a roster.

    Sooth-family repos are excluded by family: they keep hand-written AGENTS.md
    and were never in this programme's scope. **Family is READ from
    ``sooth-standard/SOOTH_LIBRARIES.json``, never inferred from a name prefix**
    (F-44) — ``first-light`` is a Sooth repo the prefix cannot see, and it was in
    this roster by accident rather than by the policy stated above.

    It STAYS in, for the reason the prefix could not express: it carries the MGF
    managed block in its root ``CLAUDE.md``, i.e. it has opted into the very
    mechanism this check judges. Keyed on the artifact, the roster is unchanged
    on today's estate — first-light is the only Sooth repo carrying the block —
    and now it is unchanged *for a reason* instead of by coincidence.
    """
    sooth = _sooth_family(root)
    names = set(_registry_names(registry))
    names |= {
        p.name
        for p in root.iterdir()
        if is_git_repo(p) and (p.name not in sooth or _carries_managed_block(p / "CLAUDE.md"))
    }
    return sorted(names - set(AGENT_CONTEXT_EXEMPT))


def _carries_managed_block(claude_md: Path) -> bool:
    """Has this repo opted into the MGF-managed root ``CLAUDE.md`` block?

    Read from the working tree rather than the committed one on purpose: this
    answers "is this repo in scope", not "does this repo pass". Getting scope
    wrong in the permissive direction costs a finding to triage; getting it wrong
    in the restrictive direction costs a repo nobody ever looks at again.
    """
    from mgf.fed.cli._catch_up import CLAUDE_MD_LEGACY_BEGIN_MARKER
    from mgf.fed.cli._init_project import CLAUDE_MD_BEGIN_MARKER

    try:
        text = claude_md.read_text(encoding="utf-8")
    except OSError:
        return False
    return CLAUDE_MD_BEGIN_MARKER in text or CLAUDE_MD_LEGACY_BEGIN_MARKER in text


def check_agent_context(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """Every declared member's default branch actually carries the agent context.

    ONE-ESTATE's diagnosis in one line: the estate distributed its knowledge to a
    path its own tooling never opens. Claude Code auto-loads the **root**
    ``CLAUDE.md`` and nothing else, so deep context at ``docs/claude/CLAUDE.md``
    reaches an agent only if a root pointer sends it there — and for 45 repos
    nothing did.

    Phase 2 of that program installed the pointer across the fleet and named this
    check as its acceptance criterion. **The check did not exist.** The mechanism
    was distributed to 54 repos with nothing in any exit code able to notice it
    leaving again — which is the program's own thesis committed by its author.

    Four properties, each one a defect the wave actually found:

    1. **The root file exists and carries the managed block.** Without it the
       repo's knowledge is unreachable to the agent it was written for.
    2. **The block is the current canonical rendering.** A drifted block is
       knowledge the fleet has not received.
    3. **The path the pointer names EXISTS in the same tree.** The wave shipped,
       and caught, a pointer to ``docs/claude/CLAUDE.md`` on five repos that only
       have ``docs/CLAUDE.md`` — green by every check, useless to the agent,
       because writer and checker compared against the same constant and neither
       consulted the repo.
    4. **The deep-context file's managed block is well-formed** — exactly one
       BEGIN, one END, and balanced HTML comments. Eighteen repos carried an
       unterminated END marker; ``mgf-common``'s 696 lines of authored deep
       context sat *inside* an HTML comment, invisible to any reader.

    Read from the **committed** tree, never the working tree. Trees across this
    estate are routinely parked on other branches, and a filesystem read scores a
    merged repo as missing — it undercounted by three the one time it was tried.
    That is also why staleness of the local ``origin/*`` view is a finding rather
    than a silent assumption: a check that reports on a week-old ref is answering
    a question nobody asked.
    """
    from mgf.fed.cli._catch_up import _extract_auto_block, _find_begin_marker
    from mgf.fed.cli._init_project import CANONICAL_DEEP_CONTEXT, root_claude_md_block

    res = CheckResult("agent-context", (DECLARED, COMMITTED))
    registry = root / "mgf-standard" / "MGF_LIBRARIES.json"
    if not registry.is_file():
        res.skipped = f"no {registry} — the declared roster is what this check audits"
        return res

    for name in agent_context_roster(root, registry):
        repo = root / name
        if not is_git_repo(repo):
            res.findings.append(
                Finding(name, "declared in MGF_LIBRARIES.json but not on disk — cannot be audited")
            )
            continue
        res.examined += 1
        ref = _default_ref(repo)
        if not ref:
            res.findings.append(Finding(name, "no origin/* default-branch ref — nothing to audit"))
            continue
        if not offline and (why := _origin_ref_unverified(repo, ref)):
            res.findings.append(Finding(name, why))
            continue

        tree = _tree_paths(repo, ref)
        short = ref.rsplit("/", 1)[-1]
        # P2-F4: AGENTS.md was a managed surface nothing checked. PLAN §2.2.3
        # named it alongside the root pointer and the docs block; the checking
        # half was never built, so deleting it from any repo left every gate
        # green — including in `mgf`, the subject of criterion 4 itself.
        if "AGENTS.md" not in tree:
            res.findings.append(
                Finding(
                    name,
                    f"no AGENTS.md on origin/{short} — the canonical entry point other "
                    "agent harnesses read (PLAN §2.2.3 lists it as a managed surface)",
                )
            )
        if "CLAUDE.md" not in tree:
            res.findings.append(
                Finding(
                    name,
                    f"no root CLAUDE.md on origin/{short} — Claude Code auto-loads the root "
                    "file only, so an agent starts this repo knowing none of its deep context",
                )
            )
            continue

        content = _git(repo, "show", f"{ref}:CLAUDE.md")
        if _find_begin_marker(content) == -1:
            res.findings.append(
                Finding(
                    name,
                    f"root CLAUDE.md on origin/{short} carries no managed block, so the "
                    "federation pointer cannot be kept current there",
                )
            )
            continue
        # P2-F7: block integrity was applied to the deep-context file only, so a
        # root CLAUDE.md carrying TWO managed blocks passed clean — the exact
        # `mgf-hrb` duplicate-block defect criterion 3 tests for by hand, one file
        # up, in the file Claude Code actually auto-loads. Runs only once the BEGIN
        # marker is known present, so it never duplicates the finding above.
        res.findings.extend(_managed_block_findings(name, content, "CLAUDE.md", short))

        deep = _committed_deep_context(tree)
        if deep is None:
            res.findings.append(
                Finding(
                    name,
                    f"root pointer names {CANONICAL_DEEP_CONTEXT}, which does NOT exist on "
                    f"origin/{short} — the pointer's one job is to name the detail file",
                )
            )
        elif _extract_auto_block(content).strip() != root_claude_md_block(deep).strip():
            res.findings.append(
                Finding(
                    name,
                    f"root CLAUDE.md's managed block on origin/{short} has drifted from the "
                    "canonical pointer — this repo has not received the current briefing",
                )
            )

        if deep is not None:
            res.findings.extend(
                _managed_block_findings(name, _git(repo, "show", f"{ref}:{deep}"), deep, short)
            )
    return res


def _default_ref(repo: Path) -> str:
    """The remote-tracking ref for the repo's default branch, or ``""``.

    **The remote is resolved, not assumed.** ``origin`` is a convention every
    clone happens to follow until one does not: ``soothrede``'s only remote on the
    bench is named ``codeberg``, and a hardcoded name answered ``""`` for a repo
    with a perfectly ordinary default branch — "nothing to audit" reported about a
    repo there was everything to audit. That is this module's own equivalence
    (*"I could not look"* reading as *"there is nothing there"*) committed in the
    helper the checks all read through. So: ``origin`` when it exists, else the
    sole configured remote. Several remotes and no ``origin`` is a *guess*, and a
    guess is what stays unaudited — the caller's ``""`` finding is then true.

    ``<remote>/HEAD`` is asked first because it is the forge's own answer; the
    named fallbacks exist only for clones where nobody ever set it.
    """
    remotes = _git(repo, "remote").splitlines()
    if "origin" in remotes:
        remote = "origin"
    elif len(remotes) == 1:
        remote = remotes[0]
    else:
        return ""
    head = _git(repo, "symbolic-ref", "--quiet", f"refs/remotes/{remote}/HEAD")
    if head.startswith(f"refs/remotes/{remote}/"):
        return head
    for cand in (f"refs/remotes/{remote}/main", f"refs/remotes/{remote}/master"):
        if _git(repo, "rev-parse", "--verify", "--quiet", cand):
            return cand
    return ""


def _origin_ref_unverified(repo: Path, ref: str) -> str:
    """``""`` when the local view of the default branch provably matches the forge.

    Every committed-layer check in this module reads its evidence from a
    remote-tracking ref that is only as fresh as the last fetch. Auditing a stale
    ref and printing PASS is the same equivalence — *"I could not verify"* reading
    as *"I verified"* — that the whole module exists to break, so this asks the
    forge rather than assuming, and says so when it cannot.

    **Which forge to ask is READ from the ref, never assumed.** ``_default_ref``
    resolves whatever remote the repo actually configures, and the name it settled
    on is carried in what it returns — ``refs/remotes/<remote>/<branch>``. Asking
    ``origin`` here anyway would re-file that same defect one function down, and
    worse than harmlessly: the resolver would hand over a good ``codeberg`` ref and
    the probe would answer *"could not reach the forge"*, converting a repo that
    was merely unresolvable into one that is unverifiable. Same name, same law,
    same lesson — a hardcoded remote is a guess about somebody else's clone.
    """
    remote, _, branch = ref.removeprefix("refs/remotes/").partition("/")
    local = _git(repo, "rev-parse", ref)
    forge = _git(repo, "ls-remote", remote, f"refs/heads/{branch}").split("\t")[0].strip()
    if not forge:
        return f"could not reach the forge to confirm {remote}/{branch} is current — not a pass"
    if not local:
        return f"could not read the local {ref}"
    if local != forge:
        return (
            f"the local view of {remote}/{branch} is STALE ({local[:8]} vs the forge's "
            f"{forge[:8]}) — fetch before trusting any committed-layer result here"
        )
    return ""


def _tree_paths(repo: Path, ref: str) -> set[str]:
    return {line for line in _git(repo, "ls-tree", "-r", "--name-only", ref).splitlines() if line}


def _committed_deep_context(tree: set[str]) -> str | None:
    """Which deep-context file this tree actually has — canonical wins, legacy counts.

    Mirrors ``catch-up``'s ``_resolve_claude_md_path`` against a committed tree
    instead of the filesystem. The two must agree: the writer renders the pointer
    from its answer, and a checker that answered differently would flag every
    legacy repo the tool deliberately left alone.
    """
    from mgf.fed.cli._init_project import CANONICAL_DEEP_CONTEXT

    if CANONICAL_DEEP_CONTEXT in tree:
        return CANONICAL_DEEP_CONTEXT
    if LEGACY_DEEP_CONTEXT in tree:
        return LEGACY_DEEP_CONTEXT
    return None


def _managed_block_findings(name: str, text: str, deep: str, branch: str) -> list[Finding]:
    """Is the deep-context file's managed block well-formed?

    The BEGIN marker is the opening LINE of an HTML comment that the block's own
    first line closes. Truncate the block and the ``<!--`` never closes, so the
    rest of the document — every line of authored deep context — is swallowed into
    a comment. It renders as an empty file and greps as present, which is why this
    survived on eighteen repos.
    """
    from mgf.fed.cli._catch_up import _find_begin_marker
    from mgf.fed.cli._init_project import CLAUDE_MD_END_MARKER

    out: list[Finding] = []
    where = f"{deep} on origin/{branch}"
    if _find_begin_marker(text) == -1:
        return [Finding(name, f"{where} carries no managed block")]
    ends = text.count(CLAUDE_MD_END_MARKER)
    if ends != 1:
        out.append(
            Finding(
                name,
                f"{where} has {ends} END marker(s) against its BEGIN — an unterminated "
                "block swallows the authored document below it into an HTML comment",
            )
        )
    opens, closes = text.count("<!--"), text.count("-->")
    if opens != closes:
        out.append(
            Finding(name, f"{where} has unbalanced HTML comments ({opens} open, {closes} close)")
        )
    return out


# --------------------------------------------------------------------------- #
# CHECK: conformance-ledgers — declared ↔ committed
# --------------------------------------------------------------------------- #


def check_conformance_ledgers(root: Path, **_: Any) -> CheckResult:
    """Every MUST the corpus declares is accounted for in every member's ledger.

    DOC-15 requires each repo's ``MGF_STANDARDS_CONFORMANCE.md`` to carry a row
    for every current MUST. ``app-doctor`` enforces that **per repo, in that
    repo's CI, against the corpus version that repo happens to have installed** —
    so a MUST added to ``mgf-standard``'s main is invisible to the whole fleet
    until someone publishes, and then it is red everywhere at once.

    That is not hypothetical. On 2026-08-03 a release of `mgf-standard` 0.1.75 —
    cut to clear an unrelated version drift — published five releases' worth of
    accumulated corpus in one act. **33 new MUSTs went live and no repo's ledger
    had a row for any of them**, so `app-doctor` went red fleet-wide minutes
    later. The corpus footer had recorded the required follow-up wave each time
    ("every member's ``MGF_STANDARDS_CONFORMANCE.md`` gains three rows … tracked
    separately") and each time it was deferred. The debt was *written down* and
    nothing was watching it.

    This is the watcher: it compares the corpus's **declared** Index of MUSTs
    against every member's **committed** ledger, before a publish rather than
    after. A release that would redden the fleet is visible while it is still a
    decision.

    Both sides are read from the **committed** tree, and that is load-bearing on
    the declared side too. The first draft sourced the MUST index from the
    INSTALLED corpus, the way ``app-doctor`` legitimately does — and on the bench
    that wrote it, the installed corpus was ``0.1.66``, nine releases stale. It
    confidently reported 268 declared MUSTs while ``mgf-standard``'s main
    declared 306. A check meant to answer *"would publishing redden the fleet?"*
    cannot take its idea of the corpus from whatever wheel this laptop happens to
    have; it must read what is about to BE published. Same wrong-layer class this
    module exists for, found in this module.
    """
    from mgf.fed.cli._doctor_standards import _RULE_ID_RE

    res = CheckResult("conformance-ledgers", (DECLARED, COMMITTED))
    std = root / "mgf-standard"
    std_ref = _default_ref(std) if is_git_repo(std) else ""
    if not std_ref:
        res.skipped = f"no mgf-standard checkout at {std} — the corpus is what this check declares"
        return res
    must_ids = _index_of_musts(_git(std, "show", f"{std_ref}:docs/standards/README.md"))
    if not must_ids:
        res.skipped = "mgf-standard's 'Index of MUSTs' resolved empty — cannot verify any ledger"
        return res

    registry = root / "mgf-standard" / "MGF_LIBRARIES.json"
    if not registry.is_file():
        res.skipped = f"no {registry} — the declared roster is what this check audits"
        return res

    for name in sorted(_registry_names(registry)):
        repo = root / name
        if not is_git_repo(repo):
            continue  # `fleet` owns the on-disk boundary; do not double-report it
        ref = _default_ref(repo)
        if not ref:
            continue
        res.examined += 1
        tree = _tree_paths(repo, ref)
        ledger = next((p for p in _LEDGER_PATHS if p in tree), None)
        if ledger is None:
            res.findings.append(
                Finding(name, f"no MGF_STANDARDS_CONFORMANCE.md on {ref.rsplit('/', 1)[-1]}")
            )
            continue
        accounted = set(_RULE_ID_RE.findall(_git(repo, "show", f"{ref}:{ledger}")))
        missing = sorted(must_ids - accounted)
        if missing:
            preview = ", ".join(missing[:8])
            more = f" (+{len(missing) - 8} more)" if len(missing) > 8 else ""
            res.findings.append(
                Finding(
                    name,
                    f"ledger accounts for {len(must_ids) - len(missing)} of {len(must_ids)} "
                    f"declared MUSTs — {len(missing)} unaccounted: {preview}{more}",
                )
            )
    return res


#: DOC-15 accepts either location; catch-up writes the first.
_LEDGER_PATHS = (
    "docs/inprogress/MGF_STANDARDS_CONFORMANCE.md",
    "docs/MGF_STANDARDS_CONFORMANCE.md",
)


def index_of_musts(readme: str) -> set[str]:
    """The rule ids in the corpus README's ``## Index of MUSTs`` table.

    Mirrors ``_doctor_standards._corpus_must_ids``' parsing, but over text the
    caller supplies rather than the installed package — so the same question can
    be asked of a *committed* corpus. The two must agree on what counts as a
    MUST, or this check and ``app-doctor`` would disagree about the same repo.
    """
    from mgf.fed.cli._doctor_standards import _RULE_ID_RE

    ids: set[str] = set()
    in_index = False
    for line in readme.splitlines():
        if line.startswith("## "):
            in_index = line.strip() == "## Index of MUSTs"
            continue
        if in_index and line.startswith("|"):
            first = line.split("|")[1].strip()
            if _RULE_ID_RE.fullmatch(first):
                ids.add(first)
    return ids


_index_of_musts = index_of_musts


# --------------------------------------------------------------------------- #
# CHECK: ci-workspace-truth — committed(pipeline + checker) ↔ declared(canon)
# --------------------------------------------------------------------------- #

#: Repos with no pipeline for this check to audit. Every entry carries its
#: reason, exactly as ``AGENT_CONTEXT_EXEMPT`` does: an exemption is explicit and
#: reviewable, never a silent absence. A repo missing from this map and missing a
#: pipeline is a FINDING, because "no CI at all" and "CI that checks nothing"
#: fail the same way — quietly.
CI_WORKSPACE_TRUTH_EXEMPT: dict[str, str] = {
    "mgf-secrets-store": (
        "the age-encrypted credential vault — ciphertext plus a manifest, not an "
        "engineering bench. It runs no pipeline and has no commits to gate."
    ),
    "PlasmaAI": (
        "never a bench: no git remote is configured at all, so it has no default "
        "branch and no forge-side pipeline."
    ),
    "mgf": (
        "the founder/CTO court workspace — review artifacts and memory, private and "
        "self-contained. It runs no forge pipeline and gates no shipped code."
    ),
    "_info_store": (
        "the founder's personal store, not an engineering bench and not federation code."
    ),
}


def ci_workspace_truth_roster(root: Path) -> list[str]:
    """Every repo whose CI could be lied to about its default branch.

    **This started as ``_repos_on_disk``, which globs ``mgf-*`` — and that was the
    Phase 2 court's P2-F2 defect committed again, in the check written to end this
    class.** The glob cannot see ``figrecovery`` (the repo Phase 3's live proof was
    built on, and the reason the step is branch-agnostic at all), ``TelePlasma``
    (named explicitly in PLAN §3.4), ``vm-vmanager-app``, ``magogi-proof`` or
    ``first-light`` — five real pipelines, including the two most likely to fail,
    because a `master` default is exactly what a `main`-shaped roster overlooks.

    The check's docstring argued about `master`-default repos while its roster
    excluded every one of them. A roster that cannot see the failures is not a
    roster; it is a statement about where the author chose to look.

    **And then it said "Sooth-family repos stay out by family" while filtering on
    ``not name.startswith("sooth")`` — F-44.** A name pattern standing in for a
    registry lookup, in the roster of the check that exists to end name patterns,
    one fix after the last one. Family membership is READ from
    ``sooth-standard/SOOTH_LIBRARIES.json``: ``first-light`` is a Sooth repo whose
    name the prefix cannot see, so it was being audited by accident, and
    ``soothrede`` was excluded by accident while carrying a DRIFTED copy of MGF's
    own trailers checker.

    Both accidents pointed the same way, which is why the fix is not simply "read
    the registry and drop the family". A Sooth repo that carries **MGF scaffold
    artifacts** has opted into MGF canon, and MGF canon is then the right thing to
    judge it against — so it is IN, on the artifact, not on its name. Keying on
    what a repo carries rather than on what it is called is the principle
    ``gen_mgf_libraries.py`` already argues for two functions above its own glob;
    this is the same principle applied where the last three defects were.
    """
    sooth = _sooth_family(root)
    return sorted(
        p.name
        for p in root.iterdir()
        if is_git_repo(p)
        and p.name not in CI_WORKSPACE_TRUTH_EXEMPT
        and (p.name not in sooth or (p / _TRAILER_SCRIPT).is_file())
    )


def _sooth_family(root: Path) -> frozenset[str]:
    """Sooth-family repo names, read from the sibling family's own registry.

    Returns an EMPTY set when the registry is unreadable, which admits the whole
    estate to the roster rather than silently narrowing it. The failure mode of a
    missing roster must be "look at too much", never "look at less and report
    clean" — that direction is how every defect in this programme hid.
    """
    reg = root / "sooth-standard" / "SOOTH_LIBRARIES.json"
    try:
        data = json.loads(reg.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError):
        return frozenset()
    repos = data.get("repos")
    if isinstance(repos, dict):
        return frozenset(repos)
    if isinstance(repos, list):
        return frozenset(
            r if isinstance(r, str) else str(r.get("repo") or r.get("name") or "") for r in repos
        ) - {""}
    return frozenset()


#: The clone-section step that makes ``refs/remotes/origin/<default>`` truthful.
_FETCH_STEP = "fetch-default-branch"

#: The scaffold copy every conformant repo carries byte-exact.
_TRAILER_SCRIPT = "scripts/check_commit_trailers.py"

#: Where canon's copy of the step lives. The template as a WHOLE is not YAML — it
#: carries ``{{EXTRAS_INSTALL_CMD}}`` placeholders that die in a safe_load — but its
#: ``clone:`` section is placeholder-free and parses on its own, which is why the
#: helper below slices before it parses.
_BASE_TEMPLATE = "templates/woodpecker/base.yml"


def _clone_section(text: str) -> Any:
    """The parsed top-level ``clone:`` block of a pipeline *or template*.

    Sliced textually first because a WF-13 template is not valid YAML end-to-end.
    Returns ``None`` when the section is absent or unparseable — callers treat that
    as "could not verify", never as "nothing wrong".
    """
    import yaml

    lines = text.splitlines()
    start = next((i for i, ln in enumerate(lines) if ln.startswith("clone:")), None)
    if start is None:
        return None
    end = next(
        (i for i, ln in enumerate(lines[start + 1 :], start + 1) if ln and not ln[0].isspace()),
        len(lines),
    )
    try:
        doc = yaml.safe_load("\n".join(lines[start:end]))
    except yaml.YAMLError:
        return None
    return doc.get("clone") if isinstance(doc, dict) else None


def _fetch_step(text: str) -> Any:
    """The parsed ``fetch-default-branch`` step, or ``None``.

    Parsed rather than compared as text on purpose: YAML comments are not semantics,
    and the two templates legitimately comment the step differently. What must match
    is what the runner executes.
    """
    for step in _clone_section(text) or []:
        if isinstance(step, dict) and step.get("name") == _FETCH_STEP:
            return step
    return None


def _pipeline_sources(repo: Path, ref: str) -> list[tuple[str, str]]:
    """Every committed Woodpecker workflow: ``[(path, text)]``.

    **Woodpecker accepts TWO layouts** — a root ``.woodpecker.yml``, or a
    ``.woodpecker/`` directory of workflows. These checks read only the first,
    and `hrb-app` uses the second: `.woodpecker/ci.yml` + `.woodpecker/e2e.yml`,
    both live on the server (pipelines #82-84 green).

    So the gate reported *"no .woodpecker.yml on main — no CI gate at all. Add
    one, or declare the repo in CI_WORKSPACE_TRUTH_EXEMPT with a reason"* about a
    repo with two running workflows — and **the remedy it proposed would have
    permanently exempted a repo whose CI is live and unguarded.** A false
    negative that recruits you into making it permanent is the worst shape this
    class takes.

    It also made `hrb-app` a D-18 target for "adopt CI", which it does not need;
    what it lacks is the fetch step, in files nothing was reading.

    Found by a fresh-context court chair, not by CI — the check could not see the
    layout, so nothing it printed could have revealed it.
    """
    root = _git(repo, "show", f"{ref}:.woodpecker.yml")
    if root.strip():
        return [(".woodpecker.yml", root)]
    listing = _git(repo, "ls-tree", "--name-only", ref, ".woodpecker/")
    out: list[tuple[str, str]] = []
    for path in sorted(ln.strip() for ln in listing.splitlines() if ln.strip()):
        if not path.endswith((".yml", ".yaml")):
            continue
        text = _git(repo, "show", f"{ref}:{path}")
        if text.strip():
            out.append((path, text))
    return out


def _describe_step_drift(canon: dict[str, Any], got: dict[str, Any]) -> str:
    """A one-line, actionable account of how a member step differs from canon.

    "Differs from canon" alone makes the reader re-derive what the check already
    knows, and a finding nobody can act on gets waived rather than fixed.
    """
    bits: list[str] = []
    for key in sorted(set(canon) | set(got)):
        if canon.get(key) == got.get(key):
            continue
        if key != "commands":
            bits.append(f"{key}: canon {canon.get(key)!r} != committed {got.get(key)!r}")
            continue
        want, have = list(canon.get(key) or []), list(got.get(key) or [])
        missing = [c for c in want if c not in have]
        extra = [c for c in have if c not in want]
        if missing:
            bits.append(f"{len(missing)} canonical command(s) MISSING, first: {missing[0]!r}")
        if extra:
            bits.append(f"{len(extra)} non-canonical command(s) present, first: {extra[0]!r}")
        if not missing and not extra:
            bits.append("commands are canonical but in a different order")
    return "; ".join(bits) or "no field-level difference (ordering only)"


#: A POSITIVE marker of the fail-CLOSED design, deliberately not a search for the
#: word "skipping".
#:
#: PLAN §3.6(c) proposed grepping member copies for ``"skipping"`` + ``return 0``.
#: That test is unusable: the hardened canonical script *itself* contains the
#: word four times — "This check does not pass by skipping" — so the grep flags
#: every CONFORMANT repo and stays silent about a legacy copy that happens to
#: word its message differently. The searched-for token belongs to the fix, not
#: to the defect. Asking for a symbol only the fail-closed design defines inverts
#: that: absence is evidence, and it cannot be spoofed by a comment.
_FAIL_CLOSED_MARKER = "_NoBaseError"

#: The checker in COMMAND POSITION — at the start of a shell segment, after an
#: optional interpreter. Matched on the path rather than on an exhaustive
#: interpreter list, because `python`, `python3`, `uv run` and a bare
#: `./scripts/...` are all real spellings here.
#:
#: The first version was the bare substring `scripts/check_commit_trailers\.py`,
#: and a court chair broke it in one line: `- echo 'remember to run
#: scripts/check_commit_trailers.py'` satisfied a property whose docstring
#: promises "some step actually RUNS it". A MENTION counted as an invocation.
#: `cat scripts/check_commit_trailers.py` did too.
_TRAILER_INVOCATION = re.compile(
    r"(?:^|[;&|]\s*)\s*(?:sudo\s+)?(?:uv\s+run\s+(?:--\S+\s+)*)?"
    r"(?:python[0-9.]*\s+(?:-\w+\s+)*)?(?:\./)?scripts/check_commit_trailers\.py\b"
)

#: An alternative branch that ends the step non-zero. `cmd || { …; exit 1; }` is
#: fail-CLOSED and must not be indicted — the first version of property 4 flagged
#: it, which is the "cries wolf" failure the property's own comment warns about.
_NONZERO_EXIT = re.compile(r"\bexit\s+(?!0\b)\S")


def _split_top_level(cmd: str, sep: str) -> list[str]:
    """Split on ``sep`` at brace/paren depth 0 only.

    A naive `;` split cuts inside `cmd || { echo …; exit 1; }` and reports the
    fail-CLOSED idiom as fail-open — which is how the first attempt at this fix
    reintroduced the false positive it was written to remove.
    """
    out: list[str] = []
    buf: list[str] = []
    depth = 0
    i = 0
    while i < len(cmd):
        ch = cmd[i]
        if ch in "({":
            depth += 1
        elif ch in ")}":
            depth = max(0, depth - 1)
        if depth == 0 and cmd.startswith(sep, i):
            out.append("".join(buf))
            buf = []
            i += len(sep)
            continue
        buf.append(ch)
        i += 1
    out.append("".join(buf))
    return out


def _invocation_not_load_bearing(cmd: str) -> str | None:
    """Why this command's exit status is NOT the checker's, or ``None``.

    **`||` is not the discriminator. POSITION is** — and the first version of this
    property got that wrong on a claim it stated as measured. POSIX: ``set -e`` is
    ignored for any command of an AND-OR list *other than the last*, so::

        sh -c 'set -e; test -f X && python X'              -> exit 1   fail-CLOSED
        sh -c 'set -e; test -f X && python X; echo AFTER'  -> exit 0   FAIL-OPEN

    Measured in both dash and bash. The original comment asserted `&&` was
    fail-closed full stop, and its control test used the guard as the SOLE
    command — the one position where the claim happens to hold. A court chair
    reproduced the open case in a real pipeline and the check reported CLEAN.

    So the question is not "which operator appears" but "does the step's exit
    status still depend on the checker". Three ways it stops depending:

    * something runs AFTER it in the same command (`;` or a later `&&` element);
    * an `||` alternative that does not itself exit non-zero swallows the failure;
    * the invocation is backgrounded (`&`), so the shell never waits for it.
    """
    segments = [s for s in _split_top_level(cmd, ";") if s.strip()]
    idx = next((i for i, s in enumerate(segments) if _TRAILER_INVOCATION.search(s)), None)
    if idx is None:
        return None
    if idx != len(segments) - 1:
        return "a later `;`-separated command replaces its exit status"
    seg = segments[idx]
    if re.search(r"&\s*$", seg) or re.search(r"\S\s+&\s+\S", seg):
        return "it is backgrounded with `&`, so the shell never waits for it"
    alts = _split_top_level(seg, "||")
    if len(alts) > 1:
        after = "||".join(alts[1:])
        if not _NONZERO_EXIT.search(after):
            return (
                "an `||` alternative that does not itself exit non-zero swallows "
                "the failure, so the step reports SUCCESS when the checker fails"
            )
        return None
    ands = _split_top_level(alts[0], "&&")
    if len(ands) > 1 and not _TRAILER_INVOCATION.search(ands[-1]):
        return (
            "it is a non-final element of an `&&` list, and POSIX `set -e` is "
            "ignored for every element but the last — so its failure is discarded"
        )
    return None


def _named_steps(doc: Any) -> list[tuple[str, dict[str, Any]]]:
    """``[(name, step)]`` for a workflow's ``steps``, in either accepted shape."""
    if not isinstance(doc, dict):
        return []
    steps = doc.get("steps")
    if isinstance(steps, dict):
        return [(str(k), v) for k, v in steps.items() if isinstance(v, dict)]
    if isinstance(steps, list):
        return [(str(s.get("name", "?")), s) for s in steps if isinstance(s, dict)]
    return []


def _step_command_list(step: dict[str, Any]) -> list[str]:
    cmds = step.get("commands")
    if isinstance(cmds, str):
        cmds = [cmds]
    return [c for c in (cmds or []) if isinstance(c, str)]


def _declared_events(when: Any) -> set[str]:
    """Every event a `when:` block selects, or an empty set if it selects none.

    Empty means "no event constraint", which is the permissive case and must NOT
    be read as "selects nothing" — that inversion would indict every conformant
    step in the fleet.
    """
    out: set[str] = set()
    for clause in when if isinstance(when, list) else [when]:
        if not isinstance(clause, dict):
            continue
        ev = clause.get("event")
        if isinstance(ev, str):
            out.add(ev)
        elif isinstance(ev, list):
            out.update(str(e) for e in ev)
    return out


def _step_commands(doc: Any) -> list[tuple[str, str]]:
    """``[(step_name, command)]`` for every command in a workflow's ``steps``.

    Woodpecker accepts ``steps:`` as a LIST of named steps or as a MAP of
    name -> step, and both appear in this fleet. Reading only the list form is the
    `.woodpecker/`-layout mistake one level down: a shape the runner honours and
    the check cannot see reports clean.
    """
    if not isinstance(doc, dict):
        return []
    steps = doc.get("steps")
    if isinstance(steps, dict):
        items = [(k, v) for k, v in steps.items() if isinstance(v, dict)]
    elif isinstance(steps, list):
        items = [(s.get("name", "?"), s) for s in steps if isinstance(s, dict)]
    else:
        return []
    out: list[tuple[str, str]] = []
    for sname, step in items:
        cmds = step.get("commands")
        if isinstance(cmds, str):
            cmds = [cmds]
        for cmd in cmds or []:
            if isinstance(cmd, str):
                out.append((str(sname), cmd))
    return out


def check_ci_workspace_truth(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """The AG-03 gate is pointed at a real default branch, in every repo's CI.

    On a ``pull_request`` the runner does ``git init -b <default>`` and resets to
    the PR head, so a ref *named* ``main`` **is the branch under review**. Any
    gate that asks "what is on main?" by name is answered with its own subject.
    Measured 2026-08-02: that made the trailers gate print ``all 0 commit(s)`` in
    39 of 40 repos, on every event, for its entire life.

    Two halves fix it and NEITHER substitutes for the other:

    - the **checker** resolves its base by provenance and refuses to pass when it
      cannot determine what to check (shipped in ``mgf-standard`` 0.1.75);
    - the **pipeline** fetches the real default branch in its clone section,
      because only a clone step carries the clone credential.

    With the checker alone, the gate degrades to its reduced-scope path and
    checks HEAD's tip **alone**. That is a real check but not this gate's job,
    and the difference was measured rather than argued (2026-08-03): on a
    3-commit branch whose MIDDLE commit lacked ``Co-Authored-By``, the
    reduced-scope path printed ``all 1 commit(s)`` and exited **0**; the same
    branch with ``origin/main`` fetched named the offending SHA and exited 1. So
    a multi-commit PR carries an AG-03 violation straight past any repo whose
    pipeline lacks the fetch step — silently, and while reporting green.

    Four properties, per repo, read from the **committed** tree:

    1. the pipeline carries the ``fetch-default-branch`` clone step **and that step
       matches canon** — P3-F2. This check originally asked only whether a step by
       that NAME existed, and so 43 repos took a step that violated SC-23 (it pulls
       both clone secrets into its shell environment and guarded neither) straight
       past a gate written in the same session to police exactly this file. Only
       ``first-light``'s bespoke ``verify_ci`` objected. *Present* and *conformant*
       are different questions, and asking the cheap one is how a fleet-wide defect
       reads as green. Comparing to canon answers both at once and keeps answering
       them as canon changes — a name test cannot be sharpened, only replaced;
    2. its ``scripts/check_commit_trailers.py`` is byte-identical to the
       canonical scaffold copy;
    3. that copy carries the fail-CLOSED marker, so a legacy fail-open script
       cannot sit there wearing the right filename;
    4. **some step actually runs it, and that invocation can fail** — F-41. The
       first three properties interrogate a FILE. None of them asks whether the
       file is wired to anything, and **7 repos carried the byte-canonical,
       fail-closed checker with no step invoking it** — `first-light` and the six
       Zig members. Three more were
       uninvoked for other reasons (`hrb-app` and `vm-vmanager-app` carry LEGACY
       FAIL-OPEN copies, `magogi-proof` carries none), and `mgf-media` invoked
       one that does not exist through a construct that cannot fail. Ten
       uninvoked in total.

       **The first version of this docstring said "eleven repos carried the
       byte-canonical fail-closed checker", which conflated all four categories
       into the most alarming one.** A fresh-context court chair re-measured and
       got 10 / 7; so did I, when I stopped trusting my own count. The
       exaggeration was in the direction that flatters the finding, which is the
       direction to distrust. Six of the seven are Zig members, because
       ``base-zig.yml`` carries no ``<<INSERT:commit-trailers>>`` marker at all,
       so the renderer cannot emit the gate while `scaffold` keeps vendoring the
       checker in. *A verifier that is not in a gate's exit code does not
       exist* is this estate's own standing rule; this property is the first thing
       that measures it.

    Read from ``origin/<default>`` resolved per repo — never the literal
    ``origin/main``. figrecovery and the four ``sooth*`` repos default to
    ``master``, and hardcoding the fleet's common name is the very no-op this
    check exists to detect. Staleness of the local view is a finding, not an
    assumption, for the same reason every other committed-layer check here says
    so: "I could not verify" must never share an exit code with "I verified".
    """
    import yaml

    res = CheckResult("ci-workspace-truth", (COMMITTED, DECLARED))

    std = root / "mgf-standard"
    std_ref = _default_ref(std) if is_git_repo(std) else ""
    if not std_ref:
        res.skipped = (
            "no mgf-standard default-branch ref — the canonical checker is what "
            "this compares against"
        )
        return res
    canon = _git(std, "show", f"{std_ref}:{_TRAILER_SCRIPT}")
    if not canon.strip():
        res.skipped = (
            f"mgf-standard has no committed {_TRAILER_SCRIPT} — nothing to compare against"
        )
        return res
    canon_hash = hashlib.sha256(canon.encode()).hexdigest()

    # Canon for property 1. Extracted, never hardcoded: a literal copy of the step
    # here would be a second source of truth that drifts from the template silently
    # — the same class this check exists to detect, one layer up.
    canon_step = _fetch_step(_git(std, "show", f"{std_ref}:{_BASE_TEMPLATE}"))
    if canon_step is None:
        res.skipped = (
            f"mgf-standard's {_BASE_TEMPLATE} has no parseable `{_FETCH_STEP}` step — "
            f"there is nothing to compare member pipelines against, and a comparison "
            f"against an empty canon would pass every repo"
        )
        return res

    for name in ci_workspace_truth_roster(root):
        repo = root / name
        ref = _default_ref(repo)
        if not ref:
            res.findings.append(Finding(name, "no origin/* default-branch ref — nothing to audit"))
            continue
        res.examined += 1
        if not offline and (why := _origin_ref_unverified(repo, ref)):
            res.findings.append(Finding(name, why))
            continue

        short = ref.rsplit("/", 1)[-1]
        sources = _pipeline_sources(repo, ref)
        if not sources:
            res.findings.append(
                Finding(
                    name,
                    f"no .woodpecker.yml AND no .woodpecker/*.yml on {short} — no CI gate "
                    f"at all. Add one, or declare the repo in CI_WORKSPACE_TRUTH_EXEMPT "
                    f"with a reason",
                )
            )
            continue

        # --- property 1: the clone section fetches the real default branch ---
        #
        # Evaluated per WORKFLOW. A `.woodpecker/` repo has several, and each is
        # its own pipeline with its own clone section — so "the repo has a fetch
        # step somewhere" is not the question. Every workflow that clones needs a
        # truthful ref, or the gates inside THAT workflow are the starved ones.
        parsed: list[tuple[str, Any]] = []
        unparseable = False
        for path, text in sources:
            try:
                parsed.append((path, yaml.safe_load(text)))
            except yaml.YAMLError as exc:
                res.findings.append(Finding(name, f"UNPARSEABLE {path} on {short}: {exc}"))
                unparseable = True
        if unparseable:
            continue

        # The comment above said "evaluated per WORKFLOW" from the day this
        # property was written — and the loop underneath it `break`ed out on the
        # FIRST workflow carrying the step, which asks the repo-level question the
        # comment explicitly rejects. `hrb-app` is the repo that shape covers: a
        # `.woodpecker/` pair where one workflow can satisfy the gate for both.
        # A docstring arguing the strict reading above an implementation of the
        # loose one is precisely this check's own subject matter, in this check.
        for path, doc in parsed:
            clone = doc.get("clone") if isinstance(doc, dict) else None
            steps = [s for s in (clone or []) if isinstance(s, dict)]
            step = next((s for s in steps if s.get("name") == _FETCH_STEP), None)
            where = f" in {path}" if len(parsed) > 1 else ""
            if step is None:
                res.findings.append(
                    Finding(
                        name,
                        f"pipeline has no `{_FETCH_STEP}` clone step on {short}{where}"
                        f", so CI's `{short}` ref is the PR head itself — the AG-03 gate "
                        f"cannot compute its range and silently checks only HEAD's tip",
                    )
                )
            elif step != canon_step:
                res.findings.append(
                    Finding(
                        name,
                        f"`{_FETCH_STEP}`{where} on {short} differs from canon "
                        f"({_BASE_TEMPLATE}) — {_describe_step_drift(canon_step, step)}. "
                        f"Re-run `mgf-fed scaffold {name}`",
                    )
                )

        # --- property 4: a step actually RUNS the checker, and can fail ---
        #
        # Evaluated BEFORE properties 2 and 3 because those `continue` on a missing
        # script, and the worst instance of this class is exactly a repo with no
        # script AND a step that invokes it anyway through a construct that cannot
        # fail. Ordering the cheap check first would have hidden the expensive one.
        #
        # F-41 (2026-08-05). Properties 2 and 3 ask whether the checker FILE is
        # canonical and fail-closed. Neither asks whether anything runs it. Measured
        # across the roster the day the property was added: **10 repos ran the checker
        # from no step at all — 7 of them carrying the byte-canonical fail-closed
        # copy, 2 a legacy fail-open one, 1 no copy at all.** ("11 carrying the
        # canonical checker" was this comment's first claim and it conflated the
        # three categories; a court chair re-measured it to 7.) Six of the seven
        # are Zig, because `base-zig.yml` has no `<<INSERT:commit-trailers>>` marker,
        # so every Zig member is generated without the gate while passing properties
        # 2 and 3 perfectly. That is this workspace's own standing rule — *a verifier
        # that is not in a gate's exit code does not exist* — holding fleet-wide, in
        # the check written to enforce the gate it describes.
        invocations = [
            (path, sname, cmd)
            for path, doc in parsed
            for sname, cmd in _step_commands(doc)
            if _TRAILER_INVOCATION.search(cmd)
        ]
        if not invocations:
            res.findings.append(
                Finding(
                    name,
                    f"no step in any committed workflow on {short} RUNS "
                    f"`{_TRAILER_SCRIPT}` — the checker is present and canonical and "
                    f"in ZERO exit codes, so AG-03 is ungated here exactly as if the "
                    f"file were absent",
                )
            )
        for path, sname, cmd in invocations:
            if (reason := _invocation_not_load_bearing(cmd)) is not None:
                res.findings.append(
                    Finding(
                        name,
                        f"step `{sname}` in {path} on {short} invokes {_TRAILER_SCRIPT}, "
                        f"but {reason}: {cmd.strip()[:120]!r}",
                    )
                )
        # `failure: ignore` makes a step non-blocking, and `when:` can point it at
        # events the gate is not judging. Both are Woodpecker's own ways of turning
        # a red step green, and a property whose subject is "the invocation can
        # fail" that does not read the key literally named `failure` is incomplete
        # on its own terms — a court chair's finding, verified against a real
        # pipeline before it was accepted.
        for path, doc in parsed:
            for sname, step in _named_steps(doc):
                if not any(_TRAILER_INVOCATION.search(c) for c in _step_command_list(step)):
                    continue
                if str(step.get("failure", "")).lower() == "ignore":
                    res.findings.append(
                        Finding(
                            name,
                            f"step `{sname}` in {path} on {short} runs {_TRAILER_SCRIPT} "
                            f"but declares `failure: ignore`, so its red never blocks",
                        )
                    )
                when = step.get("when")
                events = _declared_events(when)
                if events and "pull_request" not in events:
                    res.findings.append(
                        Finding(
                            name,
                            f"step `{sname}` in {path} on {short} runs {_TRAILER_SCRIPT} "
                            f"but its `when:` selects {sorted(events)} — it never runs on "
                            f"the pull_request it exists to judge",
                        )
                    )

        # --- properties 2 and 3: the checker itself ---
        script = _git(repo, "show", f"{ref}:{_TRAILER_SCRIPT}")
        if not script.strip():
            res.findings.append(
                Finding(name, f"no {_TRAILER_SCRIPT} on {short} — AG-03 is ungated here")
            )
            continue
        if _FAIL_CLOSED_MARKER not in script:
            res.findings.append(
                Finding(
                    name,
                    f"{_TRAILER_SCRIPT} on {short} carries no `{_FAIL_CLOSED_MARKER}` — "
                    f"this is a legacy FAIL-OPEN copy that reports success when it "
                    f"cannot determine what to check",
                )
            )
        elif hashlib.sha256(script.encode()).hexdigest() != canon_hash:
            res.findings.append(
                Finding(
                    name,
                    f"{_TRAILER_SCRIPT} on {short} differs from the canonical scaffold "
                    f"copy — re-run `mgf-fed scaffold {name}`",
                )
            )

    return res


# --------------------------------------------------------------------------- #
# CHECK: ci-secret-guards — committed(pipelines) ↔ declared(SC-23)
# --------------------------------------------------------------------------- #

#: `[ -n "$VAR" ]` / `[[ -z "${VAR}" ]]` / `test -n $VAR` — the variable a guard TESTS.
#:
#: **The `-n`/`-z` must belong to a TEST, and that is not a nicety.** This was
#: byte-identical to first-light's regex, matching `-[nz]` anywhere — so ordinary
#: flags counted as guards:
#:
#:     ssh -n "$INFOMANIAK_SSH_HOST" …  -> "guarded"   (it is `ssh -n`, no test at all)
#:     echo -n "$CLONE_SSH_KEY" > /tmp/k -> "guarded"   (it is `echo -n`)
#:
#: Both appear in real deploy steps in this fleet, so the check could report a
#: secret guarded by the very line that CONSUMES it.
#:
#: The identical-regex decision was defended in the original commit as
#: cross-validation: two implementations of one MUST returning the same 101
#: findings. A court chair took that apart correctly — **the agreement was over
#: byte-identical logic, so it validated the PARSING (YAML tree vs line scanner)
#: and never the RULE.** Two copies of one blind spot agree perfectly.
#:
#: This now deliberately DIVERGES from first-light's copy, which still has the
#: defect; propagating it there is a separate change against that repo.
_GUARD_VAR_RE = re.compile(
    r"""(?:\[\[?|\btest\b)\s+!?\s*-[nz]\s+["']?\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?["']?"""
)

#: Steps that consume a secret they legitimately TOLERATE being empty, so a fatal
#: guard would false-red a correct repo. Keyed ``(step, env_var)`` because these are
#: TEMPLATE-level tolerances — the step is generated into every repo rendered from
#: that template, and enumerating today's repo names would rot on the next scaffold.
#:
#: "Guard the guard" (SPEC-P4 §2): the guard is a MUST for a secret the step
#: REQUIRES. A step that works fine without it must carry none.
#:
#: An entry matching nothing on the fleet is itself a FINDING — D-17's rule for
#: accepted findings, applied here for the same reason: a tolerance list that
#: outlives its subject stops describing the fleet and starts hiding it.
SECRET_GUARD_EXEMPT: dict[tuple[str, str], str] = {
    ("zig-build-and-test", "CODEBERG_CLONE_TOKEN"): (
        "a LEAF Zig repo (no git+https mgf-* deps) legitimately tolerates an empty "
        "codeberg_clone_token: the netrc write is a harmless no-op and agent hosts "
        "use the mounted /root/.netrc instead. A repo that actually needs the token "
        "fails LOUD at `zig build` on the dep fetch, so this is not the silent-empty "
        "class. Declared in mgf-standard templates/woodpecker/base-zig.yml."
    ),
}


def _unguarded_secret_steps(doc: Any) -> list[tuple[str, str, str]]:
    """``[(step, secret, env_var)]`` for every step that runs ``commands:`` AND pulls
    a secret into its environment without a fail-fast guard for that variable.

    A guard TESTS the variable (``-n``/``-z``) and EXITS on the bad branch — testing
    without exiting is a log line, not a gate. Order is not asserted: a guard
    anywhere in the step still turns an empty injection loud, and pinning it to
    position would be a style rule rather than a safety one.

    A step with no ``commands:`` is exempt BY CONSTRUCTION — a plugin step runs no
    shell, so there is no command to put a guard in front of. That is why the whole
    fleet's `clone:` block passes, and it is also the reasoning that wrongly
    absolved `fetch-default-branch`, which overrides the plugin entrypoint WITH
    commands and so was never covered by it (P3-F2).
    """
    out: list[tuple[str, str, str]] = []
    sections: list[dict[str, Any]] = []
    if isinstance(doc, dict):
        for key in ("clone", "steps", "services"):
            block = doc.get(key)
            if isinstance(block, list):
                sections.extend(s for s in block if isinstance(s, dict))
            elif isinstance(block, dict):  # the mapping form: name -> step
                sections.extend({**s, "name": n} for n, s in block.items() if isinstance(s, dict))
    for step in sections:
        cmds = step.get("commands")
        if not isinstance(cmds, list) or not cmds:
            continue
        env = step.get("environment")
        secrets: dict[str, str] = {}
        if isinstance(env, dict):
            for var, val in env.items():
                if isinstance(val, dict) and "from_secret" in val:
                    secrets[str(var)] = str(val["from_secret"])
        # The legacy `secrets:` list — Woodpecker injects the UPPERCASED secret name.
        for item in step.get("secrets") or []:
            if isinstance(item, str):
                secrets[item.upper()] = item
            elif isinstance(item, dict) and "source" in item:
                secrets[str(item.get("target", item["source"])).upper()] = str(item["source"])
        if not secrets:
            continue
        guarded: set[str] = set()
        for cmd in cmds:
            text = cmd if isinstance(cmd, str) else str(cmd)
            if "exit" not in text:
                continue
            guarded.update(m.group(1) for m in _GUARD_VAR_RE.finditer(text))
        name = str(step.get("name", "<unnamed>"))
        for var, secret in sorted(secrets.items()):
            if var not in guarded:
                out.append((name, secret, var))
    return out


def _declared_branches(node: Any, out: set[str]) -> set[str]:
    """Every branch name under any ``when:`` in a parsed workflow.

    Woodpecker spells the constraint four ways — ``branch: main``,
    ``branch: [main, master]``, and either of those nested under
    ``when.branch.include`` / ``.exclude`` — so a grep for one shape reads the
    other three as "no constraint at all", which is the safe-looking answer and
    the wrong one.
    """
    if isinstance(node, dict):
        for k, v in node.items():
            if k != "branch":
                _declared_branches(v, out)
                continue
            if isinstance(v, str):
                out.add(v)
            elif isinstance(v, list):
                out.update(str(x) for x in v)
            elif isinstance(v, dict):  # {include: [...], exclude: [...]}
                for vv in v.values():
                    if isinstance(vv, str):
                        out.add(vv)
                    elif isinstance(vv, list):
                        out.update(str(x) for x in vv)
    elif isinstance(node, list):
        for x in node:
            _declared_branches(x, out)
    return out


#: Branch expressions this check cannot resolve to a literal ref, and must not
#: pretend to: globs, env interpolation, and explicit ref paths.
def _is_literal_branch(name: str) -> bool:
    return bool(name) and not name.startswith(("refs/", "$", "*")) and "*" not in name


def check_ci_branch_reachable(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """A pipeline whose ``when.branch`` matches NO branch on its own origin never runs.

    The failure mode is silence, not red. Woodpecker evaluates ``when.branch``
    against the pushed ref; if none of the declared names is a branch the repo
    actually has, the workflow is skipped for every push and the board shows **no
    run, no red** — PAPER-122's shape, in the file that decides whether any gate
    executes at all. `figrecovery` is the case that made this real: it is the one
    member whose default is `master`, so a single word changed to `main` — the
    fleet's habit, and what a careless re-render writes — silently retires its
    whole pipeline. Nothing looked at ``when.branch``; `ci-workspace-truth` reads
    the clone section, not the trigger.

    **The predicate is "none match", not "any missing", and that distinction is
    the check.** Seven repos across the estate deliberately declare
    ``[main, master]`` so one pipeline serves both conventions — a sensible
    belt-and-braces that leaves one name unresolvable **by design**. Measured
    before this was written: "any missing" flags all seven and finds nothing real;
    "none match" flags none of them and still catches the figrecovery case. A gate
    that cries wolf on the correct pattern is how the real findings get ignored.

    Offline it is NAMED as skipped rather than believed: the origin refs are the
    reality being compared against, and a bench that has not fetched cannot tell
    "this branch does not exist" from "I have not looked".
    """
    res = CheckResult("ci-branch-reachable", (COMMITTED, DECLARED))
    if offline:
        res.skipped = (
            "offline — origin refs are the reality this compares against, and an "
            "unfetched bench cannot tell 'no such branch' from 'I have not looked'"
        )
        return res

    import yaml

    for name in ci_workspace_truth_roster(root):
        repo = root / name
        if not is_git_repo(repo):
            res.findings.append(
                Finding(name, "declared but not a git checkout — cannot be audited")
            )
            continue
        ref = _default_ref(repo)
        if not ref:
            res.findings.append(
                Finding(name, "no origin default-branch ref — cannot resolve its branches")
            )
            continue
        have = {
            ln.split("/", 1)[1]
            for ln in _git(
                repo, "for-each-ref", "--format=%(refname:short)", "refs/remotes/origin"
            ).split()
            if "/" in ln
        }
        if not have:
            res.findings.append(
                Finding(name, "no refs/remotes/origin/* on this bench — cannot verify, not a pass")
            )
            continue
        res.examined += 1
        for path, text in _pipeline_sources(repo, ref):
            try:
                docs = list(yaml.safe_load_all(text))
            except yaml.YAMLError as exc:
                res.findings.append(Finding(name, f"UNPARSEABLE {path}: {exc}"))
                continue
            declared: set[str] = set()
            for doc in docs:
                _declared_branches(doc, declared)
            literal = {b for b in declared if _is_literal_branch(b)}
            if not literal:
                continue  # no branch constraint, or none this check can resolve
            if literal & have:
                continue
            res.findings.append(
                Finding(
                    name,
                    f"{path} runs only on {sorted(literal)}, and this repo's origin has "
                    f"none of them (it has {sorted(have)[:6]}…) — the pipeline can never "
                    f"fire, so it reports no run and no red rather than a failure",
                )
            )
    return res


def check_ci_secret_guards(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """SC-23, fleet-wide: every generated secret-consuming CI step carries the
    fail-fast guard line, so an empty injection turns LOUD at the first affected
    step instead of running on with a silently empty credential.

    **Why this check exists.** SC-23 has been a declared MUST since 2026-07-22, and
    on 2026-08-04 exactly one implementation of it was running anywhere in the
    estate: ``first-light``'s ``tools/verify_ci.py``, wired to that one repo. It was
    correct, and it was the ONLY thing that objected when the ``fetch-default-branch``
    step shipped unguarded to 43 repos (P3-F2). Pointing it at the fleet found 13
    further violations nobody was looking at, in three repos.

    That is this estate's standing failure mode, stated as a rule in ``CLAUDE.md``:
    *a verifier that is not in a gate's exit code does not exist.* A working detector
    scoped to a single repo is knowledge captured and enforcement skipped.

    **Not every violation is fail-closed, and the difference matters.** The fetch
    step already failed red on an empty secret; the guard only made it diagnosable.
    ``mgf-website``'s ``build-release`` does not: an empty ``PUBLIC_TURNSTILE_SITE_KEY``
    builds and DEPLOYS a live site with a broken contact form, green. Same MUST, and
    the second shape is the one that ships a defect to users.

    Read from ``origin/<default>`` resolved per repo. Repos with no pipeline are
    passed over in silence here — ``ci-workspace-truth`` already reports that, and a
    finding worth making once is worth making once.
    """
    import yaml

    res = CheckResult("ci-secret-guards", (COMMITTED, DECLARED))
    seen_exempt: set[tuple[str, str]] = set()
    #: Repos whose pipelines could NOT be read this run (stale/unverifiable ref).
    #: The tolerance-rot detector below is only meaningful over a fleet that was
    #: actually examined, so it records what it could not see.
    unread: set[str] = set()

    for name in ci_workspace_truth_roster(root):
        repo = root / name
        ref = _default_ref(repo)
        if not ref:
            continue  # reported by ci-workspace-truth; not this check's question
        # Both layouts. `hrb-app` keeps its workflows in `.woodpecker/`, and a
        # secret consumed there is exactly as unguarded as one in a root file —
        # reading only the root name made a repo with live CI invisible to SC-23.
        sources = _pipeline_sources(repo, ref)
        if not sources:
            continue  # "no CI at all" is ci-workspace-truth's finding, not a guard gap
        res.examined += 1
        short = ref.rsplit("/", 1)[-1]
        if not offline and (why := _origin_ref_unverified(repo, ref)):
            res.findings.append(Finding(name, why))
            unread.add(name)
            continue
        for path, text in sources:
            try:
                doc = yaml.safe_load(text)
            except yaml.YAMLError as exc:
                res.findings.append(Finding(name, f"UNPARSEABLE {path} on {short}: {exc}"))
                continue
            where = f"{short}" if len(sources) == 1 else f"{short} ({path})"
            for step, secret, var in _unguarded_secret_steps(doc):
                if (step, var) in SECRET_GUARD_EXEMPT:
                    seen_exempt.add((step, var))
                    continue
                res.findings.append(
                    Finding(
                        name,
                        f"step `{step}` on {where} consumes secret `{secret}` as ${var} "
                        f"with no fail-fast guard (SC-23) — add "
                        f'\'[ -n "${var}" ] || {{ echo "FATAL: {secret} injected empty '
                        f'-- check its Woodpecker scope for this event (mgf-secrets doctor)"; '
                        f"exit 1; }}' to the step's commands",
                    )
                )

    # A tolerance that matches nothing has stopped describing the fleet — BUT
    # only if the fleet was actually read.
    #
    # `seen_exempt` fills inside the step loop, AFTER the stale-ref `continue`.
    # So on a bench where the carrier repos are stale, the entry matches nothing
    # NOT because it is dead but because nothing was examined — and the finding
    # then instructs you to delete it. Measured: the `zig-build-and-test` /
    # $CODEBERG_CLONE_TOKEN tolerance is live on SIX repos, and every one was
    # stale at the moment the check ran. Following that advice would have turned
    # six correct repos into six false reds.
    #
    # That is worse than a false finding: it is a false finding whose REMEDIATION
    # causes the damage. The rot detector is only trustworthy over a fleet it
    # could read, so an unread fleet gets "could not determine", never "delete".
    if unread:
        res.findings.append(
            Finding(
                "mgf-fed",
                f"tolerance rot UNCHECKED — {len(unread)} repo(s) could not be read "
                f"({', '.join(sorted(unread)[:4])}"
                + (f" +{len(unread) - 4} more" if len(unread) > 4 else "")
                + "), so an entry matching nothing here may simply be unexamined. "
                "Re-run against a fresh fleet before removing any tolerance",
            )
        )
    for key in sorted(SECRET_GUARD_EXEMPT) if not unread else ():
        if key not in seen_exempt:
            step, var = key
            res.findings.append(
                Finding(
                    "mgf-fed",
                    f"SECRET_GUARD_EXEMPT carries `{step}`/${var}, which matches NO step "
                    f"on the fleet — remove it. An exemption nobody can see the subject "
                    f"of is a hole with a comment on it",
                )
            )
    return res


# --------------------------------------------------------------------------- #
# CHECK: governance — live(forge/CI) ↔ declared(registry)
# --------------------------------------------------------------------------- #

#: Explicitly exempt: on the forge with a pipeline, deliberately NOT a library. Each
#: MUST carry a reason. The point of this table is that an exemption is EXPLICIT and
#: REVIEWED — never silent. Carrying both an exemption and a registry membership is a
#: contradiction, and the check flags it.
GOVERNANCE_EXEMPT: dict[str, str] = {
    "mgf-secrets-store": (
        "the age-encrypted credential vault. It ships no code and no package — it is "
        "ciphertext plus a manifest, and its CI only proves the store is well-formed. "
        "Making it a registry member would imply a release surface it does not have; "
        "leaving it unlisted made it SILENTLY ungoverned."
    ),
}


def check_governance(root: Path, *, token: str | None = None, **_: Any) -> CheckResult:
    """Every repo on the forge is either a registry member or explicitly exempt.

    There is no silent third option: a repo can exist, have a green pipeline, and be
    invisible to every registry-scoped tool (``scaffold``, ``catch-up``,
    ``drift-check``, the conformance audit). Ported from ``verify_governance.py``.
    """
    res = CheckResult("governance", (LIVE, DECLARED))
    if token is None:
        res.skipped = "no Woodpecker token (set $WOODPECKER_TOKEN; mint per MGF_INFRA §2)"
        return res
    try:
        active = set(_wp_mgf_repos(token))
    except (urllib.error.URLError, OSError, ValueError) as exc:
        res.skipped = f"Woodpecker unreachable: {type(exc).__name__}"
        return res
    members = _registry_names(root / "mgf-standard" / "MGF_LIBRARIES.json")
    res.examined = len(active)
    for name in sorted(active - members - set(GOVERNANCE_EXEMPT)):
        res.findings.append(
            Finding(
                name,
                "on the forge with a pipeline, but neither a registry member nor exempt — "
                "silently ungoverned. Add it to MGF_LIBRARIES.json (a wave then sweeps it) "
                "or to GOVERNANCE_EXEMPT with a reason.",
            )
        )
    for name in sorted(set(GOVERNANCE_EXEMPT) & members):
        res.findings.append(
            Finding(name, "exempt AND a registry member — membership wins; drop the exemption")
        )
    for name in sorted(set(GOVERNANCE_EXEMPT) - active):
        res.findings.append(Finding(name, "exempt for a repo no longer on the forge — prune it"))
    return res


# --------------------------------------------------------------------------- #
# CHECK: ci-freshness — live(Woodpecker) ↔ committed(origin/main)
# --------------------------------------------------------------------------- #

#: main may be this many commits past the newest build. 0 = the newest build must be
#: ON the newest commit.
STALE_AFTER_COMMITS = 0


def check_ci_freshness(
    root: Path, *, token: str | None = None, fetch: bool = True, **_: Any
) -> CheckResult:
    """Every repo's newest CI build corresponds to its newest commit on origin/main.

    **"active" is not "receiving events".** ``mgf-hrb-rt`` reported ``active: true``
    in Woodpecker and had zero CI for three weeks — a dead webhook. Sixteen commits
    and two PR merges landed on main behind it. A dead webhook looks EXACTLY like a
    healthy repo from the registry's side. Ported from ``verify_ci_freshness.py``.
    """
    res = CheckResult("ci-freshness", (LIVE, COMMITTED))
    if token is None:
        res.skipped = "no Woodpecker token (set $WOODPECKER_TOKEN; mint per MGF_INFRA §2)"
        return res
    try:
        repos = _wp_mgf_repos(token)
    except (urllib.error.URLError, OSError, ValueError) as exc:
        res.skipped = f"Woodpecker unreachable: {type(exc).__name__}"
        return res

    for name, meta in sorted(repos.items()):
        clone = root / name
        if not is_git_repo(clone):
            continue
        # Fetch FIRST. A stale local clone makes this check report phantom staleness —
        # which would be this gate's own footgun, inside the gate built to catch it.
        if fetch:
            _git(clone, "fetch", "--quiet", "origin")
        head = _git(clone, "rev-parse", "origin/main")
        if not head:
            continue
        res.examined += 1
        try:
            pipelines = _wp(f"/repos/{meta['id']}/pipelines?limit=25", token)
        except (urllib.error.URLError, OSError, ValueError):
            res.findings.append(Finding(name, "could not read its pipelines — treat as unverified"))
            continue
        mains = [
            p
            for p in (pipelines if isinstance(pipelines, list) else [])
            if isinstance(p, dict)
            and p.get("branch") == "main"
            and p.get("event") in ("push", "manual", "cron")
        ]
        if not mains:
            res.findings.append(
                Finding(name, f"NO build of main has EVER run (active={meta.get('active')})")
            )
            continue
        newest = mains[0]
        built = str(newest.get("commit") or "")
        if built == head:
            continue
        behind = _git(clone, "rev-list", "--count", f"{built}..{head}") if built else ""
        if not behind.isdigit():
            res.findings.append(
                Finding(
                    name, f"newest build #{newest.get('number')} is on unknown commit {built[:8]}"
                )
            )
        elif int(behind) > STALE_AFTER_COMMITS:
            res.findings.append(
                Finding(
                    name,
                    f"main is {behind} commit(s) PAST the newest build "
                    f"(#{newest.get('number')} on {built[:8]}, active={meta.get('active')}) — "
                    f"a dead webhook looks exactly like this. Repair: "
                    f"POST /repos/{meta['id']}/repair",
                )
            )
    return res


# --------------------------------------------------------------------------- #
# CHECK: release-currency — committed(main) ↔ published(devpi)
# --------------------------------------------------------------------------- #

# Changes to these never reach a consumer's installed wheel — a wheel is src/ plus
# declared package-data, nothing else. Every member builds
# `[tool.hatch.build.targets.wheel] packages = ["src/mgf"]` (verified fleet-wide), so
# tests/, ops/, examples/, generated fed-resources state, repo scripts, uv.lock and the
# governance docs cannot reach a consumer.
#
# This list is TUNED, not conservative: without it the gate reported 28 distributions
# "whose declared version lies" and 26 were noise (PAPER-130). **A gate that cries wolf
# 26 times is how the two REAL findings get ignored — over-reporting is a correctness
# bug in a gate, not a safe default.** PUBLIC_API.json is generated FROM src/, so a
# change there without a src/ change is a regeneration, not new shipped code.
RELEASE_IGNORED = re.compile(
    r"^(docs/|\.claude/|\.githooks/|court/|CHANGELOG\.md|FEEDBACK\.md|README\.md|"
    r"LESSON_LEARNED\.md|pending-feedback/|\.woodpecker\.yml|\.gitignore|\.gitmessage|"
    r"MGF_STANDARDS_CONFORMANCE\.md|docs/inprogress/|tests/|ops/|examples/|\.gates/|"
    r"\.gitleaks\.toml|scripts/|CONTRIBUTING\.md|DEPS\.md|SCOPE\.md|ETHICS\.md|NOTICE|"
    r"uv\.lock|fed-resources/|MGF_MEMBER\.toml|PUBLIC_API\.json|AGENTS\.md|AUDIT\.json)"
)
# `AUDIT.json` was added ONE HOUR LATER, by the same gate, for the same reason: this
# module's own committed artifact is a repo-root governance file that no wheel ships, and
# leaving it out made the audit report the repo that stores its results. Two entries in one
# session, from opposite directions, is the rule stated as plainly as it can be — **an
# exclusion list decays**, and it decays fastest right after you add something to the repo.
# `AGENTS.md` was added by THIS gate's first live run (2026-07-30): it reported 32 of 33
# distributions stale, and 25 of those said only "shipped files changed: AGENTS.md". The
# fleet-wide AGENTS.md ripple postdated the list above, so a faithful port inherited a list
# that had gone stale — the same over-reporting the list was written to prevent, arriving by
# a different route. A gate's exclusion list is not write-once; it decays as the repo shape
# changes, and the decay shows up as noise long before anyone calls it a bug.
#
# `__pycache__` is excluded from the SOURCE question for the same reason — a compiled artifact
# is never shipped source. It being *tracked in git* is a genuine defect (mgf-brand-qt commits
# 20 .pyc files under src/), but it is a repo-hygiene defect, and answering it here would
# answer it in the wrong gate's voice.
_PYCACHE = re.compile(r"(^|/)__pycache__/")


def _wheel_sources(pyproject_text: str) -> tuple[tuple[str, ...], tuple[str, ...]] | None:
    """What this repo's wheel ACTUALLY ships, read from its own build config.

    Returns ``(package dirs, force-include sources)`` from
    ``[tool.hatch.build.targets.wheel]``, or None when the config cannot be read —
    the caller then degrades to the exclusion list and says so.

    Why this replaced a hand-tuned list. ``RELEASE_IGNORED`` existed because we were
    GUESSING what ships ("a wheel is src/ plus package-data"). The build config is
    not a guess — it is the thing hatchling obeys. Two consequences, both observed:

    * the list **decayed** twice in one session (``AGENTS.md``, then ``AUDIT.json``),
      each time reporting files that never ship;
    * worse, it **under-reported**: ``mgf-standard`` force-includes ``docs/standards``
      into its wheel, and the list excludes ``docs/``, so a change to the standards
      corpus — the repo's entire product — would have shipped unnoticed.

    Over-reporting is noise. **Under-reporting is a gate that lies.** Reading the
    config fixes both directions at once, and deletes the reason the list existed.
    """
    try:
        data = tomllib.loads(pyproject_text)
    except (tomllib.TOMLDecodeError, ValueError):
        return None
    wheel = (
        data.get("tool", {}).get("hatch", {}).get("build", {}).get("targets", {}).get("wheel", {})
    )
    if not isinstance(wheel, dict):
        return None
    packages = tuple(str(x).strip("/") for x in (wheel.get("packages") or []))
    forced = tuple(str(k).strip("/") for k in (wheel.get("force-include") or {}))
    if not packages and not forced:
        return None  # not a hatchling wheel we can reason about
    return packages, forced


def _ships(path: str, packages: tuple[str, ...], forced: tuple[str, ...]) -> bool:
    """True when ``path`` lands in the wheel: under a package dir, or force-included."""
    for pkg in packages:
        if path == pkg or path.startswith(pkg + "/"):
            return True
    for src in forced:
        if path == src or path.startswith(src + "/"):
            return True
    return False


def check_release_currency(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """A version number must mean something.

    ``mgf-fed registry --check`` compares a repo's DECLARED version to the REGISTRY's —
    both said ``0.4.10`` and it passed, while main sat 28 commits past the ``v0.4.10``
    tag including a relicense. The published ``0.4.10`` and main's ``0.4.10`` were
    different code under the same number.

    **A tag is not a release.** ``mgf-vm-libvirt`` had ``v0.1.11`` tagged and the
    artifact never reached devpi — its ``smoke`` step failed before ``publish`` ever
    ran. So this asks the INDEX, not the tag: a tag says what we meant to ship.

    Ported from ``verify_release_currency.py``.
    """
    res = CheckResult("release-currency", (COMMITTED, PUBLISHED))
    for repo in _repos_on_disk(root):
        version = _declared_version(repo)
        if not version:
            continue  # not a Python distribution
        res.examined += 1
        tag = f"v{version}"
        if not _git(repo, "tag", "-l", tag):
            res.findings.append(
                Finding(repo.name, f"declares {version} but no tag {tag} exists — never released")
            )
            continue
        if not offline:
            pubs = _published_versions(repo.name)
            if pubs is not None and version not in pubs:
                newest = _newest(pubs)
                res.findings.append(
                    Finding(
                        repo.name,
                        f"v{version} is TAGGED but devpi does not serve it "
                        f"(newest published: {newest}) — the publish step never ran",
                    )
                )
                continue
        diff = [
            f for f in _git(repo, "diff", "--name-only", f"{tag}..origin/main").splitlines() if f
        ]
        sources = _wheel_sources(_git(repo, "show", "origin/main:pyproject.toml"))
        if sources is None:
            # Degraded path: no readable wheel config, so fall back to the guess.
            changed = [f for f in diff if not RELEASE_IGNORED.match(f)]
            how = " (judged by the exclusion list — no readable wheel config)"
        else:
            changed = [f for f in diff if _ships(f, *sources)]
            how = ""
        changed = [f for f in changed if not _PYCACHE.search(f)]
        if not changed:
            continue
        n = _git(repo, "rev-list", "--count", f"{tag}..origin/main")
        preview = ", ".join(changed[:3]) + (
            f", +{len(changed) - 3} more" if len(changed) > 3 else ""
        )
        res.findings.append(
            Finding(
                repo.name,
                f"main is {n} commit(s) past {tag} and STILL declares {version} — "
                f"the published {version} is different code. Shipped files changed: "
                f"{preview}{how}",
            )
        )
    return res


def _declared_version(repo: Path) -> str | None:
    txt = _git(repo, "show", "origin/main:pyproject.toml")
    m = re.search(r'^version\s*=\s*["\']([^"\']+)["\']', txt, re.M)
    return m.group(1) if m else None


def _published_versions(name: str, index: str = DEVPI) -> set[str] | None:
    """What the index ACTUALLY serves. None when the index is unreachable — the
    caller must not read that as "nothing published"."""
    # The simple index is HTML, not JSON, so this does not go through request_json.
    try:
        with urllib.request.urlopen(  # noqa: S310 — fixed index host
            index.rstrip("/") + "/" + name + "/", timeout=25
        ) as resp:
            body = resp.read().decode()
    except (urllib.error.URLError, OSError, ValueError):
        return None
    return set(re.findall(rf"{name.replace('-', '_')}-([0-9][0-9a-z.]*)-py3", body))


def _newest(versions: set[str]) -> str:
    def key(v: str) -> tuple[int, ...]:
        try:
            return tuple(int(x) for x in v.split("."))
        except ValueError:
            return (0,)

    return max(versions, key=key) if versions else "—"


# --------------------------------------------------------------------------- #
# CHECK: installed-currency — installed ↔ published
# --------------------------------------------------------------------------- #


def check_installed_currency(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """What the operator RUNS versus what the index serves.

    The layer nothing was watching. On 2026-07-30 a lockout-shaped ``rotate`` defect
    was fixed and merged, and the operator's ``mgf-secrets`` stayed at the published
    0.5.2 — so the hazard was live in the command anyone would actually type, with
    the fix sitting in main looking done.

    Read-only, and deliberately narrow: it judges only the console tools that are
    actually installed. A tool the operator has not installed is not a finding.
    """
    res = CheckResult("installed-currency", (INSTALLED, PUBLISHED))
    if offline:
        res.skipped = "--offline (needs the index to know what is published)"
        return res
    installed = _installed_tools()
    if installed is None:
        res.skipped = "`uv tool list` unavailable — cannot see the installed layer"
        return res
    for name, version in sorted(installed.items()):
        if not name.startswith("mgf-"):
            continue
        res.examined += 1
        pubs = _published_versions(name)
        if pubs is None:
            res.findings.append(Finding(name, "index unreachable — installed version unverified"))
            continue
        if not pubs or version in pubs:
            newest = _newest(pubs)
            if pubs and version != newest:
                res.findings.append(
                    Finding(
                        name,
                        f"installed {version}, index serves {newest} — "
                        f"`uv tool upgrade {name}` (a fix that is published but not "
                        f"installed has not reached you)",
                    )
                )
            continue
        res.findings.append(
            Finding(name, f"installed {version} is not on the index (newest: {_newest(pubs)})")
        )
    return res


def _installed_tools() -> dict[str, str] | None:
    """``{tool: version}`` from ``uv tool list``. None when uv is unavailable."""
    try:
        out = subprocess.run(
            ["uv", "tool", "list"],  # noqa: S607 — `uv` from PATH, as the fleet invokes it
            capture_output=True,
            text=True,
            timeout=60,
            check=False,
        )
    except (OSError, subprocess.SubprocessError):
        return None
    if out.returncode != 0:
        return None
    tools: dict[str, str] = {}
    for line in out.stdout.splitlines():
        m = re.match(r"^(\S+)\s+v(\S+)", line)
        if m:
            tools[m.group(1)] = m.group(2)
    return tools


# --------------------------------------------------------------------------- #
# CHECK: secret-scopes — declared(SECRETS.toml/live scopes) ↔ committed(pipeline)
# --------------------------------------------------------------------------- #

_ALL_EVENTS = frozenset({"push", "pull_request", "tag", "cron", "manual", "deployment"})

#: Publish credentials are deliberately ``tag``-only. Least privilege is the design,
#: not a bug: if a repo asks for one outside its allowed events, fix the REPO. This
#: check must never recommend widening these.
LEAST_PRIVILEGE = frozenset(
    {"codeberg_package_token", "codeberg_package_user", "devpi_password", "woodpecker_token"}
)

#: HELD deploy paths — deliberately NOT armed, and this check ENFORCES that.
#: While a path is held, the secrets being unavailable is a PASS and **arming them is
#: a FAILURE**. Reporting a held path as 13 red gaps forever would make this a gate
#: everyone learns to ignore, which is the failure it exists to prevent.
HELD_PATHS: dict[str, frozenset[str]] = {
    "mgf-website": frozenset(
        {
            "cloudflare_account_id",
            "cloudflare_api_token",
            "contact_form_endpoint",
            "resend_api_key",
            "turnstile_secret_key",
            "turnstile_site_key",
            "infomaniak_ssh_host",
            "infomaniak_ssh_key",
            "infomaniak_ssh_path",
            "infomaniak_ssh_port",
            "infomaniak_ssh_user",
            "codeberg_ssh_clone_key",
            "codeberg_ssh_host_key",
        }
    ),
}
HELD_EVENTS = frozenset({"deployment"})


def check_secret_scopes(root: Path, *, token: str | None = None, **_: Any) -> CheckResult:
    """Every secret a pipeline requests is registered and allowed for every event the
    requesting step runs on.

    Woodpecker resolves ``from_secret`` when it COMPILES a pipeline: an unregistered
    or out-of-scope secret kills the run at 0 seconds with no logs. Ported from
    ``verify_secret_scopes.py``.
    """
    res = CheckResult("secret-scopes", (DECLARED, COMMITTED))
    try:
        import yaml
    except ImportError:
        # mgf-fed carries no runtime dependencies by design; PyYAML rides in the dev
        # extra. An honest skip beats either a new fleet-wide dep or a line-based
        # parser that would silently miss nested `from_secret:` keys.
        res.skipped = "PyYAML unavailable (mgf-fed has no runtime deps; install the dev extra)"
        return res
    if token is None:
        res.skipped = "no Woodpecker token — cannot read the registered secret scopes"
        return res
    try:
        org_secrets = _wp("/orgs/1/secrets", token)
        ids = {k: v["id"] for k, v in _wp_mgf_repos(token).items()}
    except (urllib.error.URLError, OSError, ValueError, KeyError) as exc:
        res.skipped = f"Woodpecker unreachable: {type(exc).__name__}"
        return res
    org = {
        str(s["name"]): set(s.get("events", []))
        for s in (org_secrets if isinstance(org_secrets, list) else [])
        if isinstance(s, dict) and "name" in s
    }

    for repo in _repos_on_disk(root):
        raw = _git(repo, "show", "origin/main:.woodpecker.yml")
        if not raw:
            continue
        try:
            doc = yaml.safe_load(raw)
        except yaml.YAMLError as exc:
            res.findings.append(Finding(repo.name, f"UNPARSEABLE .woodpecker.yml: {exc}"))
            continue
        if not isinstance(doc, dict):
            continue
        res.examined += 1
        known = dict(org)
        if repo.name in ids:
            try:
                repo_secrets = _wp(f"/repos/{ids[repo.name]}/secrets", token)
                for s in repo_secrets if isinstance(repo_secrets, list) else []:
                    if isinstance(s, dict) and "name" in s:
                        known[str(s["name"])] = set(s.get("events", []))
            except (urllib.error.URLError, OSError, ValueError):
                pass  # org scopes still judge it; a repo-secret read failure is not a gap
        res.findings.extend(_scope_findings(repo.name, doc, known))
    return res


def _scope_findings(repo: str, doc: dict[str, Any], known: dict[str, set[str]]) -> list[Finding]:
    out: list[Finding] = []
    held = HELD_PATHS.get(repo, frozenset())
    for name, needed in sorted(_secret_demands(doc).items()):
        allowed = known.get(name)
        if name in held and needed & HELD_EVENTS:
            if allowed is not None and (needed & HELD_EVENTS) <= allowed:
                out.append(
                    Finding(
                        f"{repo}:{name}",
                        f"a HELD deploy path has been ARMED on {sorted(needed & HELD_EVENTS)} — "
                        f"registering it PUBLISHES THE SITE. Un-hold deliberately, in a "
                        f"reviewed commit; never by quietly registering a secret.",
                    )
                )
            needed = needed - HELD_EVENTS
            if not needed:
                continue
        if allowed is None:
            if name in held:
                continue  # unregistered *because* it is held — that is the intended state
            out.append(
                Finding(f"{repo}:{name}", "not registered — the pipeline dies at COMPILE (no logs)")
            )
            continue
        missing = needed - allowed
        if not missing:
            continue
        if name in LEAST_PRIVILEGE:
            out.append(
                Finding(
                    f"{repo}:{name}",
                    f"requested on {sorted(missing)} — fix the REPO, never widen the secret",
                )
            )
        else:
            out.append(
                Finding(
                    f"{repo}:{name}",
                    f"not allowed on {sorted(missing)} — the pipeline dies at "
                    f"COMPILE on that event",
                )
            )
    return out


def _when_events(node: object, default: frozenset[str]) -> frozenset[str]:
    """The events a ``when:`` block admits. No ``event:`` key ⇒ no event restriction."""
    whens = node if isinstance(node, list) else [node]
    found: set[str] = set()
    saw_event_key = False
    for w in whens:
        if not isinstance(w, dict):
            continue
        ev = w.get("event")
        if ev is None:
            continue
        saw_event_key = True
        found |= {ev} if isinstance(ev, str) else set(ev)
    return frozenset(found & _ALL_EVENTS) if saw_event_key else default


def _secrets_in(node: object) -> set[str]:
    """Every ``from_secret:`` name anywhere under this node."""
    out: set[str] = set()
    if isinstance(node, dict):
        for k, v in node.items():
            if k == "from_secret" and isinstance(v, str):
                out.add(v)
            else:
                out |= _secrets_in(v)
    elif isinstance(node, list):
        for v in node:
            out |= _secrets_in(v)
    return out


def _secret_demands(doc: dict[str, Any]) -> dict[str, set[str]]:
    """``secret -> the events on which some step that runs will request it``."""
    pipeline_events = _when_events(doc.get("when", {}), frozenset(_ALL_EVENTS))
    req: dict[str, set[str]] = {}

    def add(node: object, events: Iterable[str]) -> None:
        for name in _secrets_in(node):
            req.setdefault(name, set()).update(events)

    # clone + services run on every event the pipeline runs on — never pruned.
    add(doc.get("clone"), pipeline_events)
    add(doc.get("services"), pipeline_events)
    steps = doc.get("steps")
    items = steps.values() if isinstance(steps, dict) else (steps or [])
    for step in items:
        if isinstance(step, dict):
            add(step, _when_events(step.get("when", {}), pipeline_events) & pipeline_events)
    return req


# --------------------------------------------------------------------------- #
# CHECK: feedback-status — declared(FEEDBACK.md) hygiene
# --------------------------------------------------------------------------- #

_PAPER_ID = re.compile(r"`?\b([A-Z][A-Z-]{1,14}-\d+)\b`?")
_TEMPLATE = re.compile(
    r"<one-line title>|<AREA>-<NN>|PAPER-NN|<title>|\*placeholder|original-concern|"
    r"^\d+\.\d+ |^Quick-start|^Submission steps|^What makes|^Don't worry|^Entry (shape|template)|"
    r"^Area prefixes|^Paper shape|^💭|^🟡 Papercuts",
    re.I,
)
# `[^A-Za-z|\n]*` skips a leading status emoji — the fleet writes `✅ SHIPPED`,
# `🟡 PARTIALLY SHIPPED`. Anchoring straight to a letter reported every emoji-prefixed
# status as absent, i.e. it called resolved papers unstated: the same over-reporting
# class that made the release gate cry wolf 26 times.
_STATUS_BULLET = re.compile(r"\*\*Status:?\*\*:?\s*[^A-Za-z\n]*([A-Za-z-]+)")
_STATUS_TABLE = re.compile(r"\|\s*Status\s*\|\s*[^A-Za-z|\n]*([A-Za-z-]+)")


def check_feedback_status(root: Path, **_: Any) -> CheckResult:
    """Every paper in a FEEDBACK.md states a status.

    The 2026-07-24 review found the queue lying in BOTH directions — papers marked
    OPEN that had shipped weeks earlier, and papers marked ACCEPTED with zero
    implementation. Whether a status is TRUE is a judgement; whether one EXISTS is
    mechanical, and an unstated status cannot be trusted either way. Ported from
    ``feedback_census.py``, reduced to its gateable assertion.
    """
    res = CheckResult("feedback-status", (DECLARED, DECLARED))
    for fb in sorted(root.glob("mgf-*/FEEDBACK.md")):
        for heading, body in _papers(fb.read_text(encoding="utf-8")):
            pid = _PAPER_ID.search(heading)
            if not pid or _TEMPLATE.search(heading) or _is_range_heading(heading, pid):
                continue
            res.examined += 1
            if not (_STATUS_BULLET.search(body) or _STATUS_TABLE.search(body)):
                res.findings.append(
                    Finding(
                        f"{fb.parent.name}:{pid.group(1)}",
                        "no Status field — an unstated status cannot be trusted in either "
                        "direction, so the paper is invisible to any queue sweep",
                    )
                )
    return res


def _is_range_heading(heading: str, match: re.Match[str]) -> bool:
    """True when the matched id is the START OF A RANGE — a cohort heading, not a paper.

    ``## Plasma project feedback cohort — filed 2026-06-11 (PAPER-100..106)`` groups
    seven papers that each carry their own ``###`` heading below it; the cohort summary
    has no Status field of its own and never should.

    The test is deliberately narrow: the id must be *immediately* followed by ``..``.
    ``### PAPER-100 — Index of MUSTs omits 5 families + REL-10..13`` is a REAL paper that
    merely mentions a range of a different prefix, and a looser "contains a range" rule
    would silently drop it. This distinction is why the check is stricter than the census
    it was ported from: a noisy row in a report is tolerable, and a noisy row in a GATE is
    how the real findings get ignored.
    """
    return heading[match.span(1)[1] : match.span(1)[1] + 2] == ".."


def _papers(text: str) -> list[tuple[str, str]]:
    """``(heading, body)`` per ``##``/``###`` section."""
    out: list[tuple[str, str]] = []
    heading: str = ""
    buf: list[str] = []
    for line in text.splitlines():
        if line.startswith(("## ", "### ")):
            if heading:
                out.append((heading, "\n".join(buf)))
            heading, buf = line.lstrip("# ").strip(), []
        else:
            buf.append(line)
    if heading:
        out.append((heading, "\n".join(buf)))
    return out


# --------------------------------------------------------------------------- #
# CHECK: pypi-namespace — published-external(pypi.org) ↔ declared(registry)
# --------------------------------------------------------------------------- #


def check_pypi_namespace(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """The ``mgf-*`` public-PyPI namespace is CHECKED, not assumed.

    PKG-06 justified the prefix as "a private convention no public PyPI package uses".
    That was false: our own distributions were live on pypi.org, mislicensed MIT
    against Apache-2.0 source. A name we do not hold is a name someone else can take,
    and a consumer who typos an index gets THEIR package.
    """
    res = CheckResult("pypi-namespace", (PUBLISHED, DECLARED))
    if offline:
        res.skipped = "--offline (needs pypi.org)"
        return res
    names = _registry_names(root / "mgf-standard" / "MGF_LIBRARIES.json")
    if not names:
        res.skipped = "no MGF_LIBRARIES.json on disk"
        return res
    import urllib.request

    for name in sorted(names):
        res.examined += 1
        try:
            with urllib.request.urlopen(f"https://pypi.org/pypi/{name}/json", timeout=20) as resp:
                live = resp.status == 200
        except urllib.error.HTTPError as exc:
            if exc.code == 404:
                continue  # unclaimed — the expected state
            res.findings.append(Finding(name, f"pypi.org returned HTTP {exc.code} — unverified"))
            continue
        except (urllib.error.URLError, OSError):
            res.findings.append(Finding(name, "pypi.org unreachable — namespace unverified"))
            continue
        if live:
            res.findings.append(
                Finding(
                    name,
                    "LIVE on public pypi.org — a fleet name is publicly resolvable, so a "
                    "consumer pointed at the wrong index installs it. Confirm we own it and "
                    "that its license matches the source.",
                )
            )
    return res


# --------------------------------------------------------------------------- #
# The registry of checks + the runner.
# --------------------------------------------------------------------------- #

#: ``name -> (function, needs_network)``. A check that needs the network is SKIPPED
#: under ``--offline`` and, without it, a failure to reach the surface is a finding or
#: an un-requested skip — never a silent pass.
# --------------------------------------------------------------------------- #
# CHECK: lessons-mechanized — declared(LESSONS.toml) ↔ committed(the mechanisms)
# --------------------------------------------------------------------------- #

#: The three forms a `gate` may take. Deliberately narrow, and that IS the check:
#: "documented in X" and "we always do Y" are not gates and cannot be written, so
#: a lesson with no expressible gate shows up as unmechanized instead of dressed
#: up as handled. ONE-ESTATE Phase 4.
_GATE_FORMS = ("audit:", "test:", "ci:")


def check_lessons_mechanized(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """Every lesson in the ledger points at a mechanism and a gate that EXIST.

    This estate's standing failure is that knowledge gets captured and enforcement
    does not. On 2026-07-30 it held FIVE hand-written verifiers referenced by ZERO
    pipelines — each written after a real incident, each run once, none run again;
    `verify_release_currency.py` documented its class perfectly and that class
    recurred the same day it was re-read, because nothing ran it.

    So the ledger is not a document. Each entry names a `mechanism` (a path that
    must exist) and a `gate` in one of three checkable forms:

        audit:<check>        a check registered in CHECKS
        test:<repo>/<path>   a test file that exists
        ci:<repo>:<step>     a step present in that repo's COMMITTED pipeline

    A lesson whose gate is deleted turns this check RED, which is the only thing
    that stops the ledger becoming a museum. Read from the committed tree for the
    `ci:` form, because a step that exists only on a bench gates nothing.
    """
    import tomllib

    res = CheckResult("lessons-mechanized", (DECLARED, COMMITTED))
    path = root / "mgf-standard" / "LESSONS.toml"
    if not path.is_file():
        res.skipped = f"no {path} — the ledger is what this check audits"
        return res
    try:
        data = tomllib.loads(path.read_text(encoding="utf-8"))
    except (OSError, tomllib.TOMLDecodeError) as exc:
        res.findings.append(Finding("LESSONS.toml", f"UNREADABLE ({exc})"))
        return res

    lessons = data.get("lesson") or []
    if not lessons:
        res.findings.append(
            Finding("LESSONS.toml", "declares NO lessons — an empty ledger is not a clean one")
        )
        return res

    seen: set[str] = set()
    for item in lessons:
        lid = str(item.get("id") or "?")
        res.examined += 1
        if lid in seen:
            res.findings.append(Finding(lid, "duplicate lesson id"))
        seen.add(lid)
        for key in ("statement", "incident", "mechanism", "gate"):
            if not str(item.get(key) or "").strip():
                res.findings.append(
                    Finding(lid, f"missing `{key}` — a lesson without one is not a lesson")
                )
        mech = str(item.get("mechanism") or "").strip()
        if mech and not (root / mech).exists():
            res.findings.append(
                Finding(lid, f"mechanism `{mech}` does not exist — the lesson points at nothing")
            )
        gate = str(item.get("gate") or "").strip()
        if not gate:
            continue
        if not gate.startswith(_GATE_FORMS):
            res.findings.append(
                Finding(
                    lid,
                    f"gate `{gate}` is not one of {', '.join(_GATE_FORMS)} — "
                    f"a prose gate is an UNMECHANIZED lesson wearing the word 'gate'",
                )
            )
            continue
        if gate.startswith("audit:"):
            name = gate.split(":", 1)[1]
            if name not in CHECKS:
                res.findings.append(
                    Finding(lid, f"gate names audit check `{name}`, which is not registered")
                )
        elif gate.startswith("test:"):
            rel = gate.split(":", 1)[1]
            if not (root / rel).is_file():
                res.findings.append(
                    Finding(lid, f"gate names test file `{rel}`, which does not exist")
                )
        else:  # ci:
            rest = gate.partition(":")[2]
            repo, _sep, step = rest.partition(":")
            if not step:
                res.findings.append(Finding(lid, f"gate `{gate}` names no step"))
                continue
            ref = _default_ref(root / repo)
            if not ref:
                res.findings.append(
                    Finding(
                        lid, f"gate names repo `{repo}` with no origin default ref — cannot verify"
                    )
                )
                continue
            found = any(
                sname == step
                for _p, text in _pipeline_sources(root / repo, ref)
                for sname, _s in _named_steps(_safe_yaml(text))
            )
            if not found:
                res.findings.append(
                    Finding(
                        lid,
                        f"gate names CI step `{step}` in `{repo}`, which is not in its "
                        f"committed pipeline on {ref.rsplit('/', 1)[-1]}",
                    )
                )
    return res


def _safe_yaml(text: str) -> Any:
    import yaml

    try:
        return yaml.safe_load(text)
    except yaml.YAMLError:
        return None


# --------------------------------------------------------------------------- #
# CHECK: registry-consistency — declared(registry) ↔ committed(members' pins)
# --------------------------------------------------------------------------- #


def check_registry_consistency(root: Path, *, offline: bool = False, **_: Any) -> CheckResult:
    """The REL-13 gate: no member pins a cornerstone version that no longer exists.

    **This check exists because `mgf-fed registry --check` ran in NO pipeline** —
    carried as a known gap since 2026-08-04. It is the gate guarding canon, and
    the reason it was never wired is structural rather than neglect: it shells to
    `mgf-standard/scripts/gen_mgf_libraries.py`, which needs EVERY member repo on
    disk. A single-repo CI clone cannot run it, so wiring it into any member's
    pipeline was never possible.

    Which is precisely the expensive/cheap split this audit already implements.
    As a check it rides `--write` where the fleet is, lands in the committed
    artifact, and is gated in CI by `--check-artifact` — and it inherits
    `AUDIT_ACCEPTED.toml`, so a known-blocked pin can be an explicit, scoped,
    EXPIRING waiver instead of a red gate nobody can turn green.

    Exit 2 from the generator is a SKIP, not a pass: "I could not run the
    registry gate" must never share an outcome with "the registry is consistent".
    """
    import contextlib
    import io

    from mgf.fed._registry import run_registry

    res = CheckResult("registry-consistency", (DECLARED, COMMITTED))
    buf = io.StringIO()
    with contextlib.redirect_stdout(buf):
        rc = run_registry(check=True, root=root)
    out = buf.getvalue()
    if rc == 2:
        first = out.strip().splitlines()[0] if out.strip() else "no output"
        res.skipped = f"the registry gate could not run: {first}"
        return res
    res.examined = 1
    if rc == 0:
        return res
    for line in out.splitlines():
        s = line.strip()
        if not s.startswith("- "):
            continue
        detail = s[2:].strip()
        target = detail.split(" ", 1)[0].strip("`") if detail else "registry"
        if not target or target.endswith((".md", ".json")) or " " in target:
            target = "registry"
        res.findings.append(Finding(target, detail))
    if not res.findings:
        res.findings.append(
            Finding("registry", f"registry gate exited {rc} with no parseable finding: {out[:200]}")
        )
    return res


CHECKS: dict[str, tuple[Callable[..., CheckResult], bool, tuple[str, str]]] = {
    "fleet": (check_fleet, False, (DECLARED, COMMITTED)),
    # Offline-capable: the ledger and every mechanism it names are on disk.
    "lessons-mechanized": (check_lessons_mechanized, False, (DECLARED, COMMITTED)),
    # Offline-capable: it reads members' committed pins from disk, no network.
    "registry-consistency": (check_registry_consistency, False, (DECLARED, COMMITTED)),
    "feedback-status": (check_feedback_status, False, (DECLARED, DECLARED)),
    # Needs the network: it confirms the local origin/* view is current before
    # judging it. Offline it is NAMED as skipped, never quietly believed.
    "agent-context": (check_agent_context, True, (DECLARED, COMMITTED)),
    # Offline-capable: the corpus is installed and the ledgers are already
    # fetched. It answers "would publishing redden the fleet?" before the publish.
    "conformance-ledgers": (check_conformance_ledgers, False, (DECLARED, COMMITTED)),
    # Needs the network: it confirms the local origin/* view is current before
    # judging a committed pipeline. Offline it is NAMED as skipped, never
    # quietly believed.
    "ci-workspace-truth": (check_ci_workspace_truth, True, (COMMITTED, DECLARED)),
    # Needs the network for the same reason as ci-workspace-truth: it judges a
    # committed pipeline, so it must first confirm the local origin/* view is
    # current rather than quietly believing a stale one.
    # Needs the network: origin refs ARE the reality it compares a committed
    # trigger against. Offline it is NAMED as skipped, never quietly believed.
    "ci-branch-reachable": (check_ci_branch_reachable, True, (COMMITTED, DECLARED)),
    "ci-secret-guards": (check_ci_secret_guards, True, (COMMITTED, DECLARED)),
    "release-currency": (check_release_currency, True, (COMMITTED, PUBLISHED)),
    "installed-currency": (check_installed_currency, True, (INSTALLED, PUBLISHED)),
    "governance": (check_governance, True, (LIVE, DECLARED)),
    "ci-freshness": (check_ci_freshness, True, (LIVE, COMMITTED)),
    "secret-scopes": (check_secret_scopes, True, (DECLARED, COMMITTED)),
    "pypi-namespace": (check_pypi_namespace, True, (PUBLISHED, DECLARED)),
}


def run_checks(
    names: Sequence[str] | None = None,
    *,
    offline: bool = False,
    root: Path | None = None,
    token: str | None = None,
) -> list[CheckResult]:
    root = root or federation_root()
    wanted = list(names) if names else list(CHECKS)
    tok = None if offline else _wp_token(token)
    out: list[CheckResult] = []
    for name in wanted:
        fn, needs_net, layers = CHECKS[name]
        if offline and needs_net:
            # A skipped check still REPORTS its boundary: a skip that cannot say what
            # it would have compared is exactly as opaque as no check at all.
            out.append(CheckResult(name, layers, skipped="--offline"))
            continue
        out.append(fn(root, offline=offline, token=tok))
    return out


#: The committed artifact. It lives in mgf-standard because that is the repo whose
#: pipeline gates it — the audit needs the whole federation on disk plus credentials,
#: so it CANNOT run inside a single-repo CI clone. The expensive half runs where the
#: fleet is; the cheap half — "is that artifact fresh, complete and clean?" — rides the
#: ordinary pipeline and needs no clones, no network and no credentials.
AUDIT_ARTIFACT = Path("mgf-standard") / "AUDIT.json"
MAX_AUDIT_AGE_DAYS = 14


#: The artifact's INPUTS — files whose content decides what a full audit would
#: find. Recorded as hashes when the artifact is written and re-checked when it is
#: gated, so the artifact expires on CONTENT, not only on the clock.
#:
#: `MGF_LIBRARIES.json` is the whole list because it is the registry every check
#: rosters from: who is a member, what language, and — since 0.24.0 — what TIER.
#: A member's `kind` decides which gates apply to it (`_drift._LIBRARY_ONLY_PRESENT`,
#: the pipeline step-list fallback), so a two-line edit there silently changes what
#: "clean" means for that repo.
#:
#: **Why a time bound was not enough.** `MAX_AUDIT_AGE_DAYS` is 14. On 2026-08-14 a
#: fresh-context chair found the committed artifact stamped 2026-08-08 — six days
#: old, comfortably inside the limit — describing the registry as it was BEFORE
#: figrecovery was enrolled as an app-tier member. It passed. The audit was not old;
#: it was ANSWERING A DIFFERENT QUESTION, and no clock can detect that.
_ARTIFACT_INPUTS = ("MGF_LIBRARIES.json",)


def _input_digests(near: Path) -> dict[str, str]:
    """sha256 of each audit input, found next to the artifact or under mgf-standard.

    Two layouts, both real: the artifact is committed IN mgf-standard (so its inputs
    are siblings of it), and `--write` runs at the federation root (so they are under
    `mgf-standard/`). A missing input is recorded as ``"absent"`` rather than skipped,
    because "the registry was not there" and "the registry was unchanged" must never
    render the same.
    """
    out: dict[str, str] = {}
    for name in _ARTIFACT_INPUTS:
        for cand in (near.parent / name, near.parent / "mgf-standard" / name):
            if cand.is_file():
                out[name] = hashlib.sha256(cand.read_bytes()).hexdigest()
                break
        else:
            out[name] = "absent"
    return out


def bench_heads(root: Path) -> dict[str, str]:
    """``{repo: sha of the ref the CHECKS read}`` for every checkout under ``root``.

    Taken before and after a `--write` run so the artifact can say whether the
    thing it measured held still while it was being measured.

    **It records the origin default ref, NOT ``HEAD``, and that distinction is the
    whole guard.** The first version ran ``rev-parse HEAD``, which watches the
    working checkout — while every check reads ``refs/remotes/*``. A fresh-context
    chair measured both halves of the resulting mismatch on a two-ref fixture:

    * a commit on a SIDE BRANCH moves ``HEAD`` while ``ls-tree origin/main`` stays
      byte-identical — so the guard **refused a run over a change no check saw**;
    * a fetch advancing ``origin/main`` changes what every check reads while
      ``HEAD`` sits still — so the guard **said nothing about the movement that
      actually matters**.

    Both directions were live: four repos on this bench sit on side branches right
    now, three of them because the implementer was working in them. A guard that
    watches the wrong ref is not a strict guard; it is a guard pointed at the
    wrong thing, loud where it should be quiet and quiet where it should be loud.
    """
    out: dict[str, str] = {}
    for p in sorted(root.iterdir()):
        if not (p.is_dir() and is_git_repo(p)):
            continue
        # The ref the checks read. Falling back to HEAD would reintroduce exactly
        # the defect above for any repo with no origin default, so a repo that
        # cannot be resolved is recorded as such and compared as such — "I could
        # not read this" must not render as "this did not move".
        ref = _default_ref(p)
        sha = _git(p, "rev-parse", ref).strip() if ref else ""
        out[p.name] = sha or "unresolvable"
    return out


def write_artifact(
    results: list[CheckResult],
    path: Path,
    *,
    when: str,
    moved: list[str] | None = None,
) -> None:
    """Record the run, INCLUDING what did not run and what MOVED underneath it.

    A skipped check is written down as skipped so the artifact can never be
    mistaken for a full audit.

    ``moved`` names repos whose HEAD changed between the start and end of the run.
    A full audit takes tens of minutes and reads working trees, so a bench edited
    while it runs yields an artifact describing a state that **never existed** —
    measured 2026-08-14, when a commit landed in `mgf-fed` seven minutes before the
    run finished and the artifact came back asserting `MGF_LIBRARIES.md is STALE`
    about a registry that was provably CURRENT. Recorded rather than guessed at,
    and `check_artifact` refuses an artifact that carries any.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(
        json.dumps(
            {
                "generated": when,
                "inputs": _input_digests(path),
                "bench_moved": sorted(moved or []),
                "checks": [r.to_json() for r in results],
                "findings": sum(len(r.findings) for r in results),
                "skipped": [r.name for r in results if r.skipped],
                "ran": [r.name for r in results if not r.skipped],
            },
            indent=2,
            sort_keys=True,
        )
        + "\n",
        encoding="utf-8",
    )


def check_artifact(path: Path | None = None, max_age_days: int = MAX_AUDIT_AGE_DAYS) -> int:
    """Gate the COMMITTED artifact — the half that rides CI.

    It re-audits nothing. It asks the artifact four questions it can answer about
    itself, and every one of them is a way a checker has actually died here:

    1. **Does it exist, and is it stamped?** An unstamped artifact has no age, so it
       can never be called stale.
    2. **Is it younger than the limit?** On 2026-07-29 the committed conformance
       tracker was found still asserting a result from 2026-07-04 — twenty-five days
       of a stale artifact reading as current, because nothing was ever going to look.
    3. **Did every check actually RUN?** An artifact from an ``--offline`` run has
       real numbers and covers half the boundaries. Zero findings across the checks
       that ran is not a clean audit.
    4. **Was it clean?**

    A checker nobody runs silently becomes a liar; this is what stops that.
    """
    path, where = _resolve_artifact(path)
    if not path.is_file():
        print(f"AUDIT ARTIFACT — MISSING at {path} ({where})")
        print("  run `mgf-fed audit --write` at the federation root and commit the result")
        return 1
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as exc:
        print(f"AUDIT ARTIFACT — UNREADABLE: {exc}")
        return 1
    stamp = str(data.get("generated") or "")
    if not stamp:
        print("AUDIT ARTIFACT — UNSTAMPED (an artifact with no date can never go stale)")
        return 1
    age = _age_days(stamp)
    problems: list[str] = []
    # Question 2b, and the one a clock cannot ask: do the artifact's INPUTS still
    # look the way they did when it was written? An audit of last week's registry is
    # not a stale audit, it is an audit of a different fleet — and the age check
    # cannot tell those apart. Recorded as of 2026-08-14, when a six-day-old artifact
    # describing the pre-app-tier registry passed the fourteen-day bound.
    moved = data.get("bench_moved")
    if moved:
        problems.append(
            f"BENCH MOVED DURING THE RUN ({', '.join(sorted(moved)[:6])}) — these repos' "
            f"HEADs changed while the audit was reading them, so the result describes a "
            f"state that never existed at any single moment. Re-run `mgf-fed audit "
            f"--write` on a quiet bench"
        )
    recorded_inputs = data.get("inputs")
    if recorded_inputs is None:
        problems.append(
            "NO INPUT FINGERPRINT — written before the artifact recorded what it was "
            "computed from, so nothing can tell an audit of THIS fleet from an audit "
            "of a previous one; regenerate with `mgf-fed audit --write`"
        )
    else:
        live = _input_digests(path)
        changed = sorted(k for k, v in live.items() if str(recorded_inputs.get(k, "")) != v)
        if changed:
            problems.append(
                f"INPUTS CHANGED since this audit was written ({', '.join(changed)}) — "
                f"it describes a different fleet, not merely an older one. A registry "
                f"edit changes which gates apply to which member, so the numbers above "
                f"answer a question nobody asked; regenerate with `mgf-fed audit --write`"
            )
    if age is None:
        problems.append(f"unparseable stamp {stamp!r}")
    elif age > max_age_days:
        problems.append(f"STALE — generated {stamp} ({age} days old, limit {max_age_days})")
    skipped = list(data.get("skipped") or [])
    if skipped:
        problems.append(
            f"INCOMPLETE — {len(skipped)} check(s) did not run ({', '.join(skipped)}); "
            f"zero findings across the checks that DID run is not a clean audit"
        )
    # A check REGISTERED SINCE the artifact was written appears in neither list, so
    # asking only "what was skipped?" lets the artifact keep reading complete while
    # a whole boundary goes unexamined. That is this module's own failure class one
    # layer up: `agent-context` could be added and gate nothing until someone
    # happened to regenerate. Absence is not consent.
    unaccounted = sorted(set(CHECKS) - set(skipped) - set(data.get("ran") or []))
    if unaccounted:
        problems.append(
            f"INCOMPLETE — {len(unaccounted)} check(s) registered since this artifact was "
            f"written have never run against it ({', '.join(unaccounted)}); regenerate with "
            f"`mgf-fed audit --write`"
        )
    # Findings, minus any the estate has DECIDED to carry. Waivers are declared in a
    # committed file next to the artifact; everything about them is deliberate and
    # visible. See `_load_accepted` for why this exists and what it refuses to do.
    open_findings, accepted, waiver_problems, enumerated = _apply_waivers(data, path)
    problems.extend(waiver_problems)
    if open_findings:
        # COUNT every finding; NAME each repo once. One check reporting two
        # defects about one repo is two findings and one name, and printing the
        # name twice reads like a duplicate rather than a second defect.
        named = list(dict.fromkeys(f"{c}/{t}" for c, t in open_findings))
        problems.append(
            f"{len(open_findings)} unresolved cross-layer finding(s) across "
            f"{len(named)} target(s): "
            + ", ".join(named[:6])
            + (f" (+{len(named) - 6} more)" if len(named) > 6 else "")
        )
    # The waiver layer reasons over per-finding DETAIL. An artifact whose headline
    # count does not match the detail it carries — an older format, a truncated
    # write — must not be waived by default: "I cannot enumerate the findings" is
    # not "there are none", and that equivalence is the one this module exists to
    # break. Fail on the count instead, unwaivable.
    # `enumerated` is the number of findings the artifact's own detail describes —
    # deliberately NOT `len(open) + len(accepted)`, which would count a bogus waiver
    # as if it were a finding and let this reconciliation fire for a stale waiver's
    # reasons. Each guard answers exactly one question.
    counted = int(data.get("findings") or 0)
    if counted != enumerated:
        problems.append(
            f"{counted} finding(s) reported but {enumerated} enumerable from `checks` — "
            f"the artifact's detail does not account for its own count, so no waiver can "
            f"apply to it; regenerate with `mgf-fed audit --write`"
        )
    print(
        f"AUDIT ARTIFACT — generated {stamp}, {len(data.get('ran') or [])} check(s) ran "
        f"[read from {where}]"
    )
    # Accepted findings are ALWAYS printed, pass or fail. A waiver that stops being
    # mentioned is a waiver nobody re-reads, and that is how an accepted debt becomes
    # an invisible one.
    for check, target, entry in accepted:
        print(
            f"  ~ ACCEPTED {check}/{target} — {entry['reason']} "
            f"[{entry['decision']}, review by {entry['review_by']}]"
        )
    if problems:
        for pr in problems:
            print(f"  - {pr}")
        print("FAIL — re-run `mgf-fed audit --write` at the federation root and commit it")
        return 1
    suffix = f", {len(accepted)} accepted" if accepted else ""
    print(f"PASS — fresh (≤{max_age_days}d), complete, and clean{suffix}")
    return 0


#: Committed waiver declaration, resolved beside the artifact it annotates.
ACCEPTED_FILENAME = "AUDIT_ACCEPTED.toml"

#: Every field is REQUIRED. A waiver without a reason is a silenced finding, and a
#: waiver without a review date is a permanent one.
_ACCEPTED_FIELDS = ("check", "target", "reason", "decision", "review_by")

#: Optional. A substring the finding's DETAIL must contain for the waiver to
#: cover it — so a waiver names the finding it excuses instead of the repo.
#:
#: **Without it, a `(check, target)` waiver silences every finding that check will
#: EVER report about that repo, including ones written after the waiver.** The
#: original docstring said so and invited narrowing "if that ever stops being what
#: you want". It stopped on 2026-08-05: `ci-workspace-truth` gained a property
#: that found a fail-open invocation in `mgf-media` and three repos running the
#: AG-03 checker from no step at all — and every one of those repos already had a
#: waiver written for a DIFFERENT, older defect. The session's headline findings
#: were silenced on the day they were found, by waivers that predate them.
#:
#: A finding is a claim; a repo is not. Waiving the claim is a decision. Waiving
#: the repo is a mute button with a review date on it.
_ACCEPTED_SCOPE_FIELD = "finding"


def _load_accepted(artifact: Path) -> tuple[list[dict[str, str]], list[str]]:
    """Read the committed waiver file beside ``artifact``. Returns (entries, problems).

    **Why this exists.** ``--check-artifact`` failed on ANY finding, and the fleet's
    findings are about OTHER repos. On 2026-08-03 that froze ``mgf-standard``
    entirely: branch protection requires the pipeline, the pipeline runs this gate,
    and the gate was red because eleven unrelated repos have incomplete ledgers —
    a state **D-12 deliberately chose to carry**. So the repository you must change
    to fix the fleet was blocked by the fleet's state. A gate that cannot be
    satisfied by any action available to the person it blocks is not a gate; it is a
    stop, and stops get removed under pressure rather than answered.

    **What it deliberately is NOT.** Not a mute button. An accepted finding is
    printed on every run, pass or fail; it must name a REASON and the DECISION that
    took it; it EXPIRES on a date; and a waiver matching nothing is itself a failure,
    so the list cannot rot quietly after the finding is fixed. Anything not listed
    still reds the gate, so a NEW finding is as loud as it ever was.
    """
    import tomllib

    path = artifact.parent / ACCEPTED_FILENAME
    if not path.is_file():
        return [], []
    try:
        raw = tomllib.loads(path.read_text(encoding="utf-8"))
    except (OSError, tomllib.TOMLDecodeError) as exc:
        return [], [
            f"{ACCEPTED_FILENAME} is UNREADABLE ({exc}) — a waiver file that cannot be "
            f"parsed must not silently waive nothing"
        ]
    entries, problems = [], []
    for i, item in enumerate(raw.get("accepted") or []):
        missing_fields = [f for f in _ACCEPTED_FIELDS if not str(item.get(f) or "").strip()]
        if missing_fields:
            problems.append(
                f"{ACCEPTED_FILENAME} entry #{i + 1} is missing "
                f"{', '.join(missing_fields)} — a waiver without every field is a "
                f"silenced finding"
            )
            continue
        entry = {f: str(item[f]).strip() for f in _ACCEPTED_FIELDS}
        entry[_ACCEPTED_SCOPE_FIELD] = str(item.get(_ACCEPTED_SCOPE_FIELD) or "").strip()
        entries.append(entry)
    return entries, problems


def _apply_waivers(
    data: dict[str, Any], artifact: Path
) -> tuple[list[tuple[str, str]], list[tuple[str, str, dict[str, str]]], list[str], int]:
    """Split the artifact's findings into (still open, accepted), plus problems.

    The fourth return value is how many findings the artifact's ``checks`` detail
    actually describes, so the caller can reconcile it against the headline count
    without that reconciliation being perturbed by the waivers themselves.

    **A ``(check, target)`` pair is a WAIVER key, not a finding identity.** One
    check legitimately reports several findings against one repo —
    ``ci-workspace-truth`` says both *"no fetch step"* and *"fail-open checker"*
    about the same repo — so counting DISTINCT PAIRS undercounts the findings.
    Shipped that way in 0.22.0 and it misfired immediately: a real artifact with
    53 findings across 38 pairs tripped the reconciliation with *"53 reported but
    38 enumerable"*, which is the fail-CLOSED direction but simply wrong, and it
    blocked ``mgf-standard`` for a bogus reason on the very release meant to
    unblock it. Findings are counted as findings; pairs are only used to match
    waivers.

    A waiver therefore covers EVERY finding its ``(check, target)`` names. That is
    deliberate — a repo's findings from one check are one situation — but it means
    a waiver written for a known defect also carries a NEW defect the same check
    later reports about that same repo. Narrow the check or the waiver if that
    ever stops being what you want.
    """
    from datetime import UTC, datetime

    # (check, target, detail) — the DETAIL is what makes a waiver nameable. The
    # returned/reported identity stays (check, target) so nothing downstream
    # changes shape.
    detailed = [
        (str(chk.get("check")), str(f.get("target")), str(f.get("detail") or ""))
        for chk in (data.get("checks") or [])
        for f in (chk.get("findings") or [])
    ]
    findings = [(c, tgt) for c, tgt, _ in detailed]
    entries, problems = _load_accepted(artifact)
    today = datetime.now(UTC).date()

    waived_idx: set[int] = set()
    accepted: list[tuple[str, str, dict[str, str]]] = []
    for e in entries:
        key = (e["check"], e["target"])
        try:
            review_by = datetime.strptime(e["review_by"], "%Y-%m-%d").replace(tzinfo=UTC).date()
        except ValueError:
            problems.append(
                f"waiver {key[0]}/{key[1]} has an unparseable review_by {e['review_by']!r}"
            )
            continue
        if review_by < today:
            problems.append(
                f"waiver {key[0]}/{key[1]} EXPIRED on {e['review_by']} — "
                f"re-decide it or fix the finding"
            )
            continue
        scope = e.get(_ACCEPTED_SCOPE_FIELD, "")
        hits = [
            i
            for i, (c, tgt, detail) in enumerate(detailed)
            if (c, tgt) == key and (not scope or scope in detail)
        ]
        if not hits:
            problems.append(
                f"waiver {key[0]}/{key[1]}"
                + (f" (finding ~ {scope!r})" if scope else "")
                + " matches NO current finding — the finding is fixed or "
                "renamed; delete the waiver so the list cannot rot"
            )
            continue
        waived_idx.update(hits)
        accepted.append((key[0], key[1], e))
    # Count FINDINGS, not distinct pairs, on both sides of the answer.
    return (
        sorted(f for i, f in enumerate(findings) if i not in waived_idx),
        accepted,
        problems,
        len(findings),
    )


def _resolve_artifact(explicit: Path | None) -> tuple[Path, str]:
    """Find the committed artifact, and NAME where it was found.

    Two contexts, and the gate has to work in both:

    * **A single-repo CI clone** — the repo IS the working directory, so the
      artifact sits at ``./AUDIT.json``. There is no federation root; ``$HOME`` is a
      container's, and ``federation_root()`` resolves to a path that does not exist.
    * **A federation-root run** — the artifact is at ``mgf-standard/AUDIT.json``.

    The first version resolved only the second, so the gate passed at the federation
    root and reported MISSING in the pipeline it was written for. It was verified in
    the wrong environment: a module about layer confusion, confusing two contexts.

    The return value carries WHERE it looked, and the caller prints it — an answer
    that cannot say which context produced it is the defect this module exists to end.
    """
    if explicit is not None:
        return explicit, "explicit --root"
    here = Path.cwd() / "AUDIT.json"
    if here.is_file():
        return here, "cwd — single-repo checkout"
    return federation_root() / AUDIT_ARTIFACT, "federation root"


def _today() -> str:
    from datetime import UTC, datetime

    return datetime.now(UTC).strftime("%Y-%m-%d")


def _age_days(stamp: str) -> int | None:
    from datetime import UTC, datetime

    try:
        then = datetime.strptime(stamp[:10], "%Y-%m-%d").replace(tzinfo=UTC)
    except ValueError:
        return None
    return (datetime.now(UTC) - then).days


def run_audit(
    names: Sequence[str] | None = None,
    *,
    offline: bool = False,
    json_only: bool = False,
    root: Path | None = None,
    token: str | None = None,
    write: Path | None = None,
    when: str | None = None,
) -> int:
    """Run the cross-layer audit. Returns the process exit code.

    **0 only when every requested check RAN and found nothing.** An un-requested skip
    (no token, unreachable index) exits 1: "I could not verify" must never share an
    exit code with "I verified". Under ``--offline`` the network checks are skipped by
    request, so they do not fail the run — but they are still named in the output,
    because a check that did not run is not a check that passed.
    """
    _root = root or federation_root()
    before = bench_heads(_root) if write is not None else {}
    results = run_checks(names, offline=offline, root=root, token=token)
    if write is not None:
        after = bench_heads(_root)
        moved = sorted(
            name for name in set(before) | set(after) if before.get(name) != after.get(name)
        )
        if moved:
            print(
                f"\n  ! BENCH MOVED DURING THIS RUN: {', '.join(moved)}\n"
                f"    Their HEADs changed while the audit was reading them, so this "
                f"result describes a state that never existed at any single moment.\n"
                f"    Recorded in the artifact; `--check-artifact` will refuse it. "
                f"Re-run on a quiet bench.",
                file=sys.stderr,
            )
        write_artifact(results, write, when=when or _today(), moved=moved)
    if json_only:
        print(
            json.dumps(
                {
                    "offline": offline,
                    "checks": [r.to_json() for r in results],
                    "findings": sum(len(r.findings) for r in results),
                    "skipped": [r.name for r in results if r.skipped],
                },
                indent=2,
                sort_keys=True,
            )
        )
    else:
        _render(results, offline=offline)
    findings = sum(len(r.findings) for r in results)
    unrequested_skips = [r for r in results if r.skipped and r.skipped != "--offline"]
    return 1 if (findings or unrequested_skips) else 0


def _render(results: list[CheckResult], *, offline: bool) -> None:
    print(
        f"mgf-fed audit — {len(results)} cross-layer check(s)" + (" [offline]" if offline else "")
    )
    print()
    for r in results:
        boundary = f"{r.layers[0]} ↔ {r.layers[1]}"
        if r.skipped:
            print(f"  ⏭  {r.name:<20} {boundary:<26} SKIPPED — {r.skipped}")
            continue
        mark = "✅" if r.ok else "🔴"
        print(
            f"  {mark} {r.name:<20} {boundary:<26} "
            f"{r.examined} examined, {len(r.findings)} finding(s)"
        )
        for f in r.findings:
            print(f"        · {f.target}: {f.detail}")
    print()
    findings = sum(len(r.findings) for r in results)
    skipped = [r for r in results if r.skipped]
    ran = len(results) - len(skipped)
    if skipped:
        # Never let a skip read as a pass. This sentence is the whole point of the
        # module: it states what was NOT checked, every single run.
        print(f"  {len(skipped)} check(s) did NOT run: {', '.join(r.name for r in skipped)}")
    if findings:
        print(f"FAIL — {findings} cross-layer finding(s) across {ran} check(s) that ran")
    elif any(r.skipped and r.skipped != "--offline" for r in results):
        print(f"FAIL — {ran} check(s) clean, but a check could not run (that is not a pass)")
    else:
        print(
            f"PASS — {ran} check(s) ran clean"
            + (f", {len(skipped)} skipped by request" if skipped else "")
        )


__all__ = [
    "AUDIT_ARTIFACT",
    "CHECKS",
    "COMMITTED",
    "DECLARED",
    "INSTALLED",
    "LIVE",
    "MAX_AUDIT_AGE_DAYS",
    "PUBLISHED",
    "CheckResult",
    "Finding",
    "check_artifact",
    "run_audit",
    "run_checks",
    "write_artifact",
]
