"""Tests for the federation release-consistency gate (REL-13).

The gate lives in ``scripts/gen_mgf_libraries.py`` (a supervisor tool,
not shipped in the wheel). These pin the load-bearing logic: the
pin-window acceptance check that decides whether the federation is
consistent, plus the zon-name normalization.
"""

from __future__ import annotations

import importlib.util
import json
import sys
from pathlib import Path

import pytest

_REPO_ROOT = Path(__file__).resolve().parents[2]
_GEN = _REPO_ROOT / "scripts" / "gen_mgf_libraries.py"


def _load_module():
    spec = importlib.util.spec_from_file_location("gen_mgf_libraries", _GEN)
    assert spec and spec.loader
    mod = importlib.util.module_from_spec(spec)
    # Register before exec: the module's @dataclass uses string
    # annotations (from __future__ import annotations), which
    # dataclasses resolves via sys.modules[cls.__module__].
    sys.modules[spec.name] = mod
    spec.loader.exec_module(mod)
    return mod


gen = _load_module()


class TestWindowAccepts:
    @pytest.mark.parametrize(
        ("pin", "version", "expected"),
        [
            # Accepts: current version inside the window.
            (">=0.40,<0.42", "0.41.11", True),
            (">=0.5,<0.6", "0.5.1", True),
            (">=0.41,<0.42", "0.41.0", True),
            # Excludes: version above the upper bound (the drift the gate catches).
            (">=0.1,<0.2", "0.5.1", False),
            (">=0.4,<0.5", "0.5.1", False),
            (">=0.38,<0.39", "0.41.11", False),
            # Excludes: version below the lower bound.
            (">=0.41,<0.42", "0.40.0", False),
        ],
    )
    def test_window(self, pin: str, version: str, expected: bool) -> None:
        assert gen._window_accepts(pin, version) is expected

    def test_non_window_pins_return_none(self) -> None:
        # Exact / git pins aren't windows — the window check abstains.
        assert gen._window_accepts("(any)", "1.0.0") is None
        assert gen._window_accepts("==0.1.0 (git-pinned)", "0.1.0") is None


class TestVerTuple:
    def test_parses_dotted(self) -> None:
        assert gen._ver_tuple("0.41.11") == (0, 41, 11)
        assert gen._ver_tuple("1.0") == (1, 0)

    def test_empty_is_zero(self) -> None:
        assert gen._ver_tuple("") == (0,)


class TestZonName:
    def test_underscore_to_hyphen(self) -> None:
        assert gen._zon_name_to_repo("mgf_hrb_model") == "mgf-hrb-model"


class TestConsistencyGate:
    """A dependent pinned to a window that excludes a current dependency
    is a hard failure (the gate goes RED)."""

    def test_excluding_pin_is_a_problem(self) -> None:
        libs = {
            "mgf-dep": gen.Library(repo="mgf-dep", lang="python", version="0.5.1", purpose="x"),
            "mgf-consumer": gen.Library(
                repo="mgf-consumer",
                lang="python",
                version="0.1.0",
                purpose="y",
                deps={"mgf-dep": ">=0.1,<0.2"},
            ),
        }
        problems = gen.check_consistency(libs)
        assert any("mgf-consumer" in p and "mgf-dep" in p for p in problems)

    def test_accepting_pin_is_clean(self) -> None:
        libs = {
            "mgf-dep": gen.Library(repo="mgf-dep", lang="python", version="0.5.1", purpose="x"),
            "mgf-consumer": gen.Library(
                repo="mgf-consumer",
                lang="python",
                version="0.1.0",
                purpose="y",
                deps={"mgf-dep": ">=0.5,<0.6"},
            ),
        }
        assert gen.check_consistency(libs) == []

    def test_lagging_python_git_ref_is_flagged(self) -> None:
        """A `@ git+...@vX` direct ref that lags the current version is a
        hard failure (the gate's blind-spot fix)."""
        libs = {
            "mgf-dep": gen.Library(repo="mgf-dep", lang="python", version="0.1.6", purpose="x"),
            "mgf-consumer": gen.Library(
                repo="mgf-consumer",
                lang="python",
                version="0.1.0",
                purpose="y",
                deps={"mgf-dep": "@ git+ssh://git@codeberg.org/o/mgf-dep.git@v0.1.1"},
            ),
        }
        problems = gen.check_consistency(libs)
        assert any("LAGS" in p and "mgf-dep" in p for p in problems)

    def test_current_git_ref_is_clean(self) -> None:
        """A git ref pinned at the current version is fine."""
        libs = {
            "mgf-dep": gen.Library(repo="mgf-dep", lang="python", version="0.1.6", purpose="x"),
            "mgf-consumer": gen.Library(
                repo="mgf-consumer",
                lang="python",
                version="0.1.0",
                purpose="y",
                deps={"mgf-dep": "@ git+ssh://git@codeberg.org/o/mgf-dep.git@v0.1.6"},
            ),
        }
        assert gen.check_consistency(libs) == []


class TestPinnedVersion:
    @pytest.mark.parametrize(
        ("pin", "expected"),
        [
            ("==0.1.0 (git-pinned)", "0.1.0"),
            ("@ git+ssh://git@codeberg.org/o/x.git@v0.1.1", "0.1.1"),
            ("@ git+https://codeberg.org/o/x.git@1.2.3", "1.2.3"),
            ("@ git+https://codeberg.org/o/x.git#v2.0.0", "2.0.0"),
            (">=0.5,<0.6", None),  # window — not an exact pin
            ("@ git+https://codeberg.org/o/x.git#deadbeef", None),  # bare sha
        ],
    )
    def test_pinned_version(self, pin: str, expected) -> None:
        assert gen._pinned_version(pin) == expected


class TestDiscoverMembership:
    """A federation member carries a recognised manifest. ``mgf-*``
    dirs without one (e.g. ``mgf-*-review`` audit deliverables) MUST
    NOT land in the registry."""

    @staticmethod
    def _repo(parent: Path, name: str, files: dict[str, str]) -> None:
        d = parent / name
        (d / ".git").mkdir(parents=True)
        for fname, body in files.items():
            (d / fname).write_text(body, encoding="utf-8")

    def test_python_zig_and_template_members_are_discovered(self, tmp_path: Path) -> None:
        self._repo(
            tmp_path,
            "mgf-pylib",
            {"pyproject.toml": '[project]\nname="mgf-pylib"\nversion="1.0.0"\n'},
        )
        self._repo(tmp_path, "mgf-ziglib", {"build.zig.zon": '.{ .version = "0.2.0" }'})
        self._repo(
            tmp_path,
            "mgf-template",
            {
                "cookiecutter.json": "{}",
                "README.md": "# mgf-template\nA template.",
                "CHANGELOG.md": "# Changelog\n\n## [Unreleased]\n\n## [0.3.0] — 2026-01-01\n",
            },
        )
        libs = gen.discover(tmp_path)
        assert set(libs) == {"mgf-pylib", "mgf-ziglib", "mgf-template"}
        assert libs["mgf-pylib"].lang == "python"
        assert libs["mgf-ziglib"].lang == "zig"
        # A cookiecutter member is parsed for real: lang "template", version
        # from the latest released CHANGELOG heading, purpose from the README
        # (skipping the name-only H1).
        assert libs["mgf-template"].lang == "template"
        assert libs["mgf-template"].version == "0.3.0"
        assert libs["mgf-template"].purpose == "A template."

    def test_node_web_member_is_discovered(self, tmp_path: Path) -> None:
        """A Node/web member (e.g. the mgf-website Astro site): lang "web", version +
        purpose from package.json, no mgf-* dep graph."""
        self._repo(
            tmp_path,
            "mgf-site",
            {
                "package.json": '{"name":"mgf-site","version":"0.4.2","description":"A site."}',
                "README.md": "# mgf-site\nignored — package.json wins.",
            },
        )
        libs = gen.discover(tmp_path)
        assert libs["mgf-site"].lang == "web"
        assert libs["mgf-site"].version == "0.4.2"
        assert libs["mgf-site"].purpose == "A site."
        assert libs["mgf-site"].deps == {}

    def test_declared_member_is_discovered_via_mgf_member_toml(self, tmp_path: Path) -> None:
        """A repo with no build manifest declares itself via MGF_MEMBER.toml (lang) +
        a CHANGELOG (version) — e.g. the mgf-brand asset repo."""
        self._repo(
            tmp_path,
            "mgf-assets",
            {
                "MGF_MEMBER.toml": 'lang = "assets"\n',
                "CHANGELOG.md": "# Changelog\n\n## [Unreleased]\n\n## [0.1.0] - 2026-07-17\n",
                "README.md": "# mgf-assets\nDesign tokens + marks.",
            },
        )
        libs = gen.discover(tmp_path)
        assert libs["mgf-assets"].lang == "assets"
        assert libs["mgf-assets"].version == "0.1.0"
        assert libs["mgf-assets"].purpose == "Design tokens + marks."

    def test_a_real_build_manifest_wins_over_the_declared_marker(self, tmp_path: Path) -> None:
        """A python repo that also happens to carry MGF_MEMBER.toml is still parsed as
        python — the standard parsers run first, the declared marker is the fallback."""
        self._repo(
            tmp_path,
            "mgf-pylib",
            {
                "pyproject.toml": '[project]\nname="mgf-pylib"\nversion="1.0.0"\n',
                "MGF_MEMBER.toml": 'lang = "assets"\n',
            },
        )
        assert gen.discover(tmp_path)["mgf-pylib"].lang == "python"

    def test_manifestless_repos_are_excluded(self, tmp_path: Path) -> None:
        # A review deliverable: git repo + docs, but no build manifest.
        self._repo(
            tmp_path,
            "mgf-pylib",
            {"pyproject.toml": '[project]\nname="mgf-pylib"\nversion="1.0.0"\n'},
        )
        self._repo(
            tmp_path, "mgf-pylib-review", {"README.md": "# mgf-pylib review\n", "FINDINGS.md": "x"}
        )
        libs = gen.discover(tmp_path)
        assert "mgf-pylib-review" not in libs
        assert set(libs) == {"mgf-pylib"}

    def test_non_git_dirs_are_excluded(self, tmp_path: Path) -> None:
        # Manifest but no .git — not a tracked member.
        (tmp_path / "mgf-loose").mkdir()
        (tmp_path / "mgf-loose" / "pyproject.toml").write_text('[project]\nname="x"\nversion="1"\n')
        assert gen.discover(tmp_path) == {}


class TestSelfEdgeDrop:
    """discover() must never emit a library that lists itself in deps/used-by.

    The shipped registry carried an ``mgf-fed -> mgf-fed`` edge because its
    pyproject uses the legitimate PEP 508 self-referential-extra idiom
    (``standards = ["mgf-fed[cli]"]`` — a back-compat alias). That is
    packaging, not a dependency edge (F-M6).
    """

    def test_self_referential_extra_is_not_an_edge(self, tmp_path: Path) -> None:
        TestDiscoverMembership._repo(
            tmp_path,
            "mgf-selfy",
            {
                "pyproject.toml": (
                    '[project]\nname="mgf-selfy"\nversion="1.0.0"\n'
                    "[project.optional-dependencies]\n"
                    'cli=["mgf-other>=1,<2"]\nstandards=["mgf-selfy[cli]"]\n'
                )
            },
        )
        TestDiscoverMembership._repo(
            tmp_path,
            "mgf-other",
            {"pyproject.toml": '[project]\nname="mgf-other"\nversion="1.2.0"\n'},
        )
        libs = gen.discover(tmp_path)
        assert "mgf-selfy" not in libs["mgf-selfy"].deps  # the self-edge is dropped
        assert "mgf-selfy" not in libs["mgf-selfy"].used_by
        assert libs["mgf-selfy"].deps == {"mgf-other": ">=1,<2"}  # real edge survives
        assert gen.check_integrity(libs) == []  # and the gate agrees


class TestIntegrityGate:
    """B4 — the deliberate negative tests: ``--check`` (via check_integrity)
    must FAIL on any self-edge or ``version: '?'`` row, so the F-M6 class
    can't return through any future code path."""

    def test_clean_roster_passes(self) -> None:
        assert gen.check_integrity(_libs()) == []

    def test_self_edge_in_deps_fails(self) -> None:
        libs = {
            "mgf-fed": gen.Library(
                repo="mgf-fed",
                lang="python",
                version="0.11.1",
                purpose="x",
                deps={"mgf-fed": "[cli]"},
            ),
        }
        problems = gen.check_integrity(libs)
        assert any("mgf-fed" in p and "self-edge" in p for p in problems)

    def test_self_edge_in_used_by_fails(self) -> None:
        lib = gen.Library(repo="mgf-fed", lang="python", version="0.11.1", purpose="x")
        lib.used_by.append("mgf-fed")
        problems = gen.check_integrity({"mgf-fed": lib})
        assert any("used-by" in p and "self-edge" in p for p in problems)

    def test_unknown_version_fails(self) -> None:
        libs = {
            "mgf-mystery": gen.Library(repo="mgf-mystery", lang="other", version="?", purpose="x"),
        }
        problems = gen.check_integrity(libs)
        assert any("mgf-mystery" in p and "'?'" in p for p in problems)

    def test_template_member_without_changelog_release_is_caught(self, tmp_path: Path) -> None:
        # End-to-end: a cookiecutter member with no released CHANGELOG heading
        # discovers as version '?' and the gate goes RED — the operator signal
        # to give the repo a version source, not a silent '?' row.
        TestDiscoverMembership._repo(
            tmp_path,
            "mgf-tmpl",
            {"cookiecutter.json": "{}", "CHANGELOG.md": "# Changelog\n\n## [Unreleased]\n"},
        )
        libs = gen.discover(tmp_path)
        assert libs["mgf-tmpl"].version == "?"
        problems = gen.check_integrity(libs)
        assert any("mgf-tmpl" in p and "'?'" in p for p in problems)


def _libs(x_pin: str = ">=0.41,<0.43") -> dict:
    """A minimal two-library federation: cornerstone + one consumer."""
    return {
        "mgf-common": gen.Library(
            repo="mgf-common",
            lang="python",
            version="0.42.0",
            purpose="cornerstone",
            requires_python=">=3.11",
        ),
        "mgf-x": gen.Library(
            repo="mgf-x",
            lang="python",
            version="0.1.0",
            purpose="sibling x",
            deps={"mgf-common": x_pin},
            requires_python=">=3.11",
            extras=("dev",),
            third_party_count=2,
        ),
    }


class TestRenderSections:
    def test_has_all_four_sections(self) -> None:
        md = gen.render(_libs())
        for h in (
            "## At a glance",
            "## Release & compatibility",
            "## Per-library detail",
            "## Consistency",
        ):
            assert h in md, f"missing section {h!r}"

    def test_compatibility_matrix_marks_acceptance(self) -> None:
        md = gen.render(_libs())
        assert "✅" in md  # mgf-x accepts mgf-common 0.42.0 (pin <0.43)
        assert "_(cornerstone)_" in md  # mgf-common's own row

    def test_compatibility_marks_exclusion_when_pin_too_low(self) -> None:
        md = gen.render(_libs(x_pin=">=0.41,<0.42"))  # excludes 0.42.0
        assert "❌" in md

    def test_per_library_detail_table(self) -> None:
        md = gen.render(_libs())
        assert "### `mgf-x`" in md
        assert "pip install mgf-x" in md
        assert "Python >=3.11" in md
        assert "`dev`" in md  # extras
        assert "Third-party runtime deps | 2" in md


class TestCurrencyGate:
    def test_current_returns_none(self, tmp_path) -> None:
        libs = _libs()
        p = tmp_path / "MGF_LIBRARIES.md"
        p.write_text(gen.render(libs) + "\n", encoding="utf-8")
        assert gen.check_currency(libs, p) is None

    def test_stale_version_detected(self, tmp_path) -> None:
        libs = _libs()
        p = tmp_path / "MGF_LIBRARIES.md"
        p.write_text(gen.render(libs) + "\n", encoding="utf-8")
        libs["mgf-x"].version = "0.2.0"  # released without regenerating
        msg = gen.check_currency(libs, p)
        assert msg is not None
        assert "STALE" in msg

    def test_date_line_is_ignored(self, tmp_path) -> None:
        import re

        libs = _libs()
        p = tmp_path / "MGF_LIBRARIES.md"
        fresh = gen.render(libs) + "\n"
        altered = re.sub(
            r"_Generated [^\n]*",
            "_Generated 2099-12-31 from the on-disk federation._",
            fresh,
        )
        p.write_text(altered, encoding="utf-8")
        # Only the date differs → still considered current.
        assert gen.check_currency(libs, p) is None

    def test_missing_file_is_stale(self, tmp_path) -> None:
        assert gen.check_currency(_libs(), tmp_path / "nope.md") is not None


class TestRenderJson:
    """The machine-readable registry shipped as wheel data + read by
    ``mgf.standard.libraries()`` (the agent-facing federation map)."""

    def test_payload_shape(self) -> None:
        import json

        data = json.loads(gen.render_json(_libs()))
        assert data["schema"] == 1
        assert data["count"] == 2
        assert data["cornerstone_version"] == "0.42.0"
        assert {lib["repo"] for lib in data["libraries"]} == {"mgf-common", "mgf-x"}

    def test_entry_carries_deps_extras_footprint(self) -> None:
        import json

        data = json.loads(gen.render_json(_libs()))
        mx = next(lib for lib in data["libraries"] if lib["repo"] == "mgf-x")
        assert mx["deps"]["mgf-common"]  # pin string present
        assert mx["extras"] == ["dev"]
        assert mx["third_party_count"] == 2

    def test_deterministic(self) -> None:
        # Two renders of the same libs are byte-identical (sorted keys),
        # so the currency check reacts only to real drift, not ordering.
        assert gen.render_json(_libs()) == gen.render_json(_libs())


class TestJsonCurrencyGate:
    def test_current_returns_none(self, tmp_path) -> None:
        libs = _libs()
        p = tmp_path / "MGF_LIBRARIES.json"
        p.write_text(gen.render_json(libs), encoding="utf-8")
        assert gen.check_json_currency(libs, p) is None

    def test_stale_version_detected(self, tmp_path) -> None:
        libs = _libs()
        p = tmp_path / "MGF_LIBRARIES.json"
        p.write_text(gen.render_json(libs), encoding="utf-8")
        libs["mgf-x"].version = "0.2.0"  # released without regenerating
        assert gen.check_json_currency(libs, p) is not None

    def test_date_ignored(self, tmp_path) -> None:
        import json

        libs = _libs()
        p = tmp_path / "MGF_LIBRARIES.json"
        d = json.loads(gen.render_json(libs))
        d["generated"] = "2099-12-31"
        p.write_text(json.dumps(d, indent=2, sort_keys=True) + "\n", encoding="utf-8")
        assert gen.check_json_currency(libs, p) is None

    def test_missing_file_is_stale(self, tmp_path) -> None:
        assert gen.check_json_currency(_libs(), tmp_path / "nope.json") is not None


# --------------------------------------------------------------------------- #
# The roster (F-39) — and the defects a fresh-context court round found in the
# very commit that fixed it. The roster change shipped with ZERO tests; these
# exist because a court chair, not CI, caught what it broke.
# --------------------------------------------------------------------------- #


def _seed(root: Path, name: str, files: dict[str, str]) -> None:
    d = root / name
    (d / ".git").mkdir(parents=True, exist_ok=True)
    for rel, body in files.items():
        p = d / rel
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(body, encoding="utf-8")


def _sooth_registry(root: Path, names: list[str]) -> None:
    p = root / "sooth-standard" / "SOOTH_LIBRARIES.json"
    p.parent.mkdir(parents=True, exist_ok=True)
    repos = ", ".join(f'{{"name": "{n}", "slug": "{n}"}}' for n in names)
    p.write_text(f'{{"schema": 1, "repos": [{repos}]}}', encoding="utf-8")


def test_family_is_read_from_the_sibling_registry_not_a_name_prefix(tmp_path: Path) -> None:
    """`first-light` is Ring 3 of the SOOTH family — listed in
    SOOTH_LIBRARIES.json, carrying SOOTH_STANDARD.md — and its name does not
    begin with "sooth". The prefix filter therefore pulled it into the MGF
    registry, breaking the terminology guard in the very commit that widened the
    roster: a name pattern, inside the fix for a name pattern."""
    mod = _load_module()
    _sooth_registry(tmp_path, ["sooth-standard", "soothfast", "first-light"])
    _seed(
        tmp_path, "first-light", {"build.zig.zon": '.{ .name = "first_light", .version = "0.1.0" }'}
    )
    _seed(
        tmp_path,
        "mgf-thing",
        {"pyproject.toml": '[project]\nname = "mgf-thing"\nversion = "1.0.0"\n'},
    )
    libs = mod.discover(tmp_path)
    assert "first-light" not in libs, "a SOOTH-family repo must not enter the MGF registry"
    assert "mgf-thing" in libs


def test_an_unreadable_sooth_registry_raises_rather_than_guessing(tmp_path: Path) -> None:
    """Fail-CLOSED. A silent fallback to the prefix heuristic would rebuild the
    defect the moment the sibling checkout is missing — invisibly, which is worse
    than not running at all."""
    mod = _load_module()
    _seed(
        tmp_path,
        "mgf-thing",
        {"pyproject.toml": '[project]\nname = "mgf-thing"\nversion = "1.0.0"\n'},
    )
    # Sooth EVIDENCE with no registry to resolve it. The marker, not the name,
    # is what makes this dangerous — first-light is caught this way.
    _seed(tmp_path, "first-light", {"SOOTH_STANDARD.md": "# sooth", "build.zig.zon": ".{}"})
    with pytest.raises(SystemExit):
        mod.discover(tmp_path)

    # And with no Sooth repo anywhere there is nothing to exclude, so it runs.
    clean = tmp_path / "clean"
    clean.mkdir()
    _seed(
        clean, "mgf-thing", {"pyproject.toml": '[project]\nname = "mgf-thing"\nversion = "1.0.0"\n'}
    )
    assert "mgf-thing" in mod.discover(clean)


def test_the_roster_keys_by_directory_not_by_package_slug(tmp_path: Path) -> None:
    """F-39's second half. `vm-vmanager-app` publishes `vm-vmanager-cli`; keying
    by the published name would enroll it under a key matching no forge repo, so
    `mgf-secrets sync` would never provision its deploy key — a fix that looks
    applied and silently does not work."""
    mod = _load_module()
    _sooth_registry(tmp_path, [])
    _seed(
        tmp_path,
        "vm-vmanager-app",
        {"pyproject.toml": '[project]\nname = "vm-vmanager-cli"\nversion = "0.3.1"\n'},
    )
    libs = mod.discover(tmp_path)
    assert "vm-vmanager-app" in libs, "keyed by REPO directory"
    assert "vm-vmanager-cli" not in libs
    assert libs["vm-vmanager-app"].slug == "vm-vmanager-cli", "the published name is kept, not lost"


def test_the_published_slug_reaches_the_artifact(tmp_path: Path) -> None:
    """The roster commit CLAIMED the package name was "kept as its own slug
    field" while the JSON emitter dropped it — computed, then discarded, so the
    claim was false of the artifact every consumer actually reads."""
    mod = _load_module()
    lib = mod.Library(repo="vm-vmanager-app", lang="python", version="0.3.1", purpose="p")
    lib.slug = "vm-vmanager-cli"
    assert mod._lib_to_dict(lib)["slug"] == "vm-vmanager-cli"
    same = mod.Library(repo="mgf-http", lang="python", version="1.0", purpose="p")
    same.slug = "mgf-http"
    assert "slug" not in mod._lib_to_dict(same), "emitted only when it differs — no noise"


# --------------------------------------------------------------------------- #
# TIER — the registry `kind` key (mgf-fed PAPER-151 / court round L9 §H3)
# --------------------------------------------------------------------------- #


def test_the_app_tier_reaches_the_artifact(tmp_path: Path) -> None:
    """The one thing this key must do: SURVIVE REGENERATION.

    `mgf-fed registry --check` shells this generator and byte-compares the result
    against the committed registry, so a `kind` that is hand-edited into
    `MGF_LIBRARIES.json` but not PRODUCED here reports the committed registry
    stale forever — and the next regeneration silently deletes the field that
    decides TelePlasma's CI contract. This is the `slug` defect (computed, then
    discarded) with a gate wired to it.
    """
    mod = _load_module()
    _sooth_registry(tmp_path, [])
    _seed(
        tmp_path,
        "TelePlasma",
        {"pyproject.toml": '[project]\nname = "teleplasma"\nversion = "0.1.0"\n'},
    )
    _seed(
        tmp_path,
        "mgf-http",
        {"pyproject.toml": '[project]\nname = "mgf-http"\nversion = "1.0.0"\n'},
    )
    libs = mod.discover(tmp_path)
    assert libs["TelePlasma"].kind == "app", "declared in _APP_TIER_REPOS"
    assert libs["mgf-http"].kind == "library", "the default every other member gets"

    rows = {row["repo"]: row for row in json.loads(mod.render_json(libs))["libraries"]}
    assert rows["TelePlasma"]["kind"] == "app", "the tier reaches the shipped artifact"
    assert "kind" not in rows["mgf-http"], (
        "emitted only when it is NOT the default — the absent key is the "
        "'library' answer every consumer already reads (mgf-fed "
        "_roster.Member.kind), so a registry declaring it for nobody grades "
        "byte-identically to one that never heard of the key"
    )


def test_the_app_tier_survives_the_currency_gate(tmp_path: Path) -> None:
    """TS-29 seeded self-test — the negative fixture for the failure above.

    A registry carrying `kind` must read as CURRENT against a fresh render (the
    key round-trips), and a registry with the key STRIPPED — exactly what a
    generator that drops it would produce — must read as STALE. Without the
    second half this test would pass against a generator that emits nothing.
    """
    mod = _load_module()
    libs = _libs()
    libs["mgf-x"].kind = "app"
    p = tmp_path / "MGF_LIBRARIES.json"
    p.write_text(mod.render_json(libs), encoding="utf-8")
    assert mod.check_json_currency(libs, p) is None, "kind round-trips through the gate"

    stripped = json.loads(p.read_text(encoding="utf-8"))
    for row in stripped["libraries"]:
        row.pop("kind", None)
    p.write_text(json.dumps(stripped, indent=2, sort_keys=True) + "\n", encoding="utf-8")
    msg = mod.check_json_currency(libs, p)
    assert msg is not None and "STALE" in msg, (
        "a dropped `kind` MUST red the currency gate — the whole point of "
        "producing it here instead of hand-editing the artifact"
    )


def test_the_app_tier_is_visible_to_a_human_reading_the_registry() -> None:
    """The Markdown registry is the human view of the same data. A reader must be
    able to see WHY a member sits in `[exempt].woodpecker` on the universal step
    subset instead of the library step-list; the tier is that reason."""
    mod = _load_module()
    libs = _libs()
    libs["mgf-x"].kind = "app"
    md = mod.render(libs)
    assert "| Tier | app — consumer product; publishes no package |" in md
    assert md.count("| Tier |") == 1, "rendered only for the non-default tier"


def test_the_fedres_project_kind_is_a_DIFFERENT_vocabulary() -> None:
    """A collision guard with teeth.

    `fed-resources/source/project.toml` carries its own `[project].kind` —
    mgf-fedres's free-text doc-projector vocabulary — and it grades the OPPOSITE
    way: `mgf-cloud`, `mgf-hrb`, `mgf-cloud-web`, `mgf-fed-web` and `mgf-test-web`
    all declare `kind = "app"` there while being published libraries the fleet
    installs, and the members that really are app-tier carry no `fed-resources/`
    at all. Sourcing the registry tier from that file would invert the roster, so
    this generator must never read it.
    """
    src = _GEN.read_text(encoding="utf-8")
    code = "\n".join(ln for ln in src.splitlines() if not ln.lstrip().startswith("#"))
    assert "fed-resources" not in code, "the tier is declared here, never read from fedres"
    # …and the tier really is keyed off the central declaration, not re-derived.
    assert '"app" if repo in _APP_TIER_REPOS' in code
