#!/usr/bin/env python
"""Generate (or verify) the committed DGR-003 fingerprint conformance vectors.

The node and the tracker derive artifact, recipe and Shard-binding digests from
*separate* implementations on purpose: an admission gate that shares code with
the thing it admits is not an independent check. The cost of that independence
is drift — two canonicalizers that quietly stop agreeing would not fail, they
would silently stop forming routes, or worse, silently form wrong ones.

``tests/data/recipe_fingerprint_vectors.json`` is what makes drift loud. It is a
language-neutral artifact — canonical input blocks, expected digests, and the
serialized DGR-002 ``Fingerprint`` bytes — that the node tests, the tracker tests
and (later) the native C++ worker all check themselves against.

    python scripts/gen_recipe_fingerprint_vectors.py --check   # CI: no drift
    python scripts/gen_recipe_fingerprint_vectors.py           # rewrite vectors

Rewriting is a deliberate act: if this changes a digest, it changed the wire
contract, and every node and tracker in the fleet has to agree at the same time.
"""

from __future__ import annotations

import argparse
import json
import pathlib
import sys

_ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path[:0] = [str(_ROOT / "packages" / "node"), str(_ROOT / "packages" / "tracker")]

from meshnet_node.runtime_recipe import (  # noqa: E402
    ArtifactIdentity,
    DerivativeBinding,
    RuntimeRecipe,
    ShardIdentity,
)
from meshnet_tracker.recipe import parse_identity  # noqa: E402

VECTORS = _ROOT / "tests" / "data" / "recipe_fingerprint_vectors.json"
SCHEMA_VERSION = 1

_RECIPE = RuntimeRecipe(
    weight_quantization="Q4_K_M",
    activation_dtype="bfloat16",
    compute_dtype="float32",
    kv_dtype="q8_0",
    kv_layout="paged-v1",
    tokenizer_revision="0123456789abcdef",
    architecture_adapter="llama/range-v1",
    backend_id="llama.cpp",
    runtime_version="llama.cpp@" + "d" * 40 + "+patchstack." + "e" * 64,
    recipe_id="example-gguf",
    recipe_version="1",
    catalogue_version="2026.07.1",
)

_SOURCE = "a" * 64
_SPLIT_BYTES = "c" * 64
_CONFIG = "b" * 64


def _cases() -> list[tuple[str, str, ShardIdentity]]:
    whole = ShardIdentity(
        ArtifactIdentity(
            "example/model", "0123456789abcdef", _SOURCE, "dense-llama", _CONFIG, 8
        ),
        _RECIPE,
        0,
        4,
    )
    # The same recipe on the same source, held as a split: identical route
    # fingerprint, different Shard binding. Both halves of that are contract.
    derivative = ShardIdentity(
        ArtifactIdentity(
            "example/model",
            "0123456789abcdef",
            _SPLIT_BYTES,
            "dense-llama",
            _CONFIG,
            8,
            DerivativeBinding(_SOURCE, 4, 8),
        ),
        _RECIPE,
        4,
        8,
    )
    return [
        ("example-v1", "An undivided artifact: content digest is the source digest.", whole),
        (
            "example-v1-derivative",
            "A split of the same source: same fingerprint, different Shard binding.",
            derivative,
        ),
    ]


def build() -> dict:
    vectors = []
    for name, description, identity in _cases():
        block = identity.to_dict()
        presented = parse_identity(block)

        # The two implementations must already agree before this is committed.
        assert identity.fingerprint.to_dict() == presented.fingerprint_dict(), name
        assert identity.shard_binding_digest == presented.shard_binding_digest, name

        vectors.append(
            {
                "name": name,
                "description": description,
                "identity": block,
                "fingerprint": identity.fingerprint.to_dict(),
                "shard_binding_digest": identity.shard_binding_digest,
                "fingerprint_proto_hex": identity.fingerprint.to_proto()
                .SerializeToString(deterministic=True)
                .hex(),
            }
        )
    return {"schema_version": SCHEMA_VERSION, "vectors": vectors}


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--check",
        action="store_true",
        help="fail if the committed vectors differ from what this code derives",
    )
    args = parser.parse_args()

    built = json.dumps(build(), indent=2, sort_keys=True) + "\n"
    if not args.check:
        VECTORS.write_text(built, encoding="utf-8")
        print(f"wrote {VECTORS.relative_to(_ROOT)}")
        return 0

    committed = VECTORS.read_text(encoding="utf-8")
    if committed != built:
        print(
            f"{VECTORS.relative_to(_ROOT)} is stale: the identity implementation no "
            "longer derives the committed digests.\nIf that change was intended, it "
            "is a wire-contract change — rerun without --check and roll out node and "
            "tracker together.",
            file=sys.stderr,
        )
        return 1
    print(f"{VECTORS.relative_to(_ROOT)} matches the identity implementation")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
