Files
neuron-tai/packages/node/meshnet_node/runtime_recipe.py

1148 lines
43 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Exact Model Artifact and runtime recipe identity (DGR-003).
A route is a chain of Shards that together compute one forward pass. If two
Shards disagree about *anything* that moves the numbers — the weights, the
quantization, the dtype the seam is serialized in, the dtype the kernels
accumulate in, the KV layout, the tokenizer, the architecture adapter, the
backend, or the runtime build — the route still runs and still emits tokens.
They are simply the wrong tokens, and nothing upstream notices. Identity is
therefore a digest over the executable semantics, not a model name.
Four decisions shape this module.
**The axes are separate, and each one is separately fatal.** `Q4_K_M` weights
are not a `bfloat16` seam, which is not an `fp32` accumulate, which is not a
`q8_0` KV cache. Collapsing them into one "precision" label is how a route ends
up numerically split while every node reports agreement. :data:`RECIPE_AXES` is
the full list; the digest commits to each under its own key, so swapping two
axis *values* changes the digest even though the multiset of values did not.
**The fingerprint deliberately excludes the Shard range.** Shards on one route
own *different* ranges; if the range were digested, no two Shards on a route
could ever agree. Range compatibility is a route-level coverage question
(:func:`check_route`), not an identity question.
**A split artifact routes under its source's identity.** A node holding layers
3263 of a GGUF holds a *different file* with a *different content hash* than a
node holding layers 031, and neither equals the whole model. So the digest
binds :attr:`ArtifactIdentity.source_digest` — the whole-model artifact every
Shard descends from — and the derivative's own hash and range are bound to that
source locally (:class:`DerivativeBinding`). A derivative that cannot name the
exact artifact it was cut from is not admissible: it is an anonymous blob that
happens to have the right layer count.
**Labels are not digested.** `recipe_id`, `recipe_version` and
`catalogue_version` ride alongside the digests for diagnosis, mirroring the
capability report an admitted node already registers with (ADR-0023). Renaming
a recipe does not change a single number, so a rename must not partition a
route; changing `kv_dtype` changes every number, so it must. The digest commits
to what changes the numbers.
Recipes are **registered-but-dark** on arrival: known, visible to an operator,
and not routable for user traffic. A recipe leaves the dark only when a *real
distributed forward* over a route of at least two distinct physical nodes,
covering the whole model, has emitted real tokens — see
:class:`DistributedForwardEvidence`. Detected hardware is not a capability, a
single-host forward is not a distributed forward, and a synthetic worker
certifies nothing.
The tracker re-derives all of this independently in
``meshnet_tracker.recipe`` — it does not import this package. The two
implementations are pinned together by a committed conformance vector
(``tests/data/recipe_fingerprint_vectors.json``); if they ever drift, a test
fails rather than a route silently forming.
"""
from __future__ import annotations
import hashlib
import json
import re
import time
from dataclasses import dataclass, field
from typing import Any, Iterable, Mapping, Sequence
from .native_protocol import BUNDLE_VERSION, SCHEMA_VERSION, pb
# Layout of the serialized identity block. Bump when the JSON shape changes.
RECIPE_IDENTITY_SCHEMA_VERSION = 1
# Domain separation. A digest means nothing outside the structure it commits to;
# the prefix guarantees an artifact digest can never be mistaken for — or collide
# with — a recipe digest, even if their canonical JSON were somehow identical.
ARTIFACT_DIGEST_DOMAIN = "meshnet.model-artifact.v1"
RECIPE_DIGEST_DOMAIN = "meshnet.runtime-recipe.v1"
# The axes of a runtime recipe. Every one of these changes the numbers a Shard
# produces, so every one of them is part of identity and none of them may be
# folded into another.
RECIPE_AXES: tuple[str, ...] = (
"weight_quantization",
"activation_dtype",
"compute_dtype",
"kv_dtype",
"kv_layout",
"tokenizer_revision",
"architecture_adapter",
"backend_id",
"runtime_version",
"boundary_schema_version",
"protocol_schema_version",
)
# --- Why two identities failed to match. These are the fail-closed reasons. ---
MISMATCH_ARTIFACT = "artifact"
MISMATCH_WEIGHT_QUANTIZATION = "weight-quantization"
MISMATCH_ACTIVATION_RECIPE = "activation-recipe"
MISMATCH_CACHE_LAYOUT = "cache-layout"
MISMATCH_TOKENIZER = "tokenizer"
MISMATCH_ARCHITECTURE = "architecture"
MISMATCH_BACKEND = "backend"
MISMATCH_RUNTIME = "runtime"
MISMATCH_BOUNDARY_SCHEMA = "boundary-schema"
MISMATCH_RANGE = "range"
MISMATCH_FINGERPRINT = "fingerprint"
MISMATCH_UNCERTIFIED = "uncertified"
# Which fail-closed reason each axis reports. Several axes share a reason
# because they fail for the same operational cause: `activation_dtype` and
# `compute_dtype` are both "the activation recipe disagrees", and `kv_dtype`
# and `kv_layout` are both "the cache layout disagrees".
_AXIS_MISMATCH: Mapping[str, str] = {
"weight_quantization": MISMATCH_WEIGHT_QUANTIZATION,
"activation_dtype": MISMATCH_ACTIVATION_RECIPE,
"compute_dtype": MISMATCH_ACTIVATION_RECIPE,
"kv_dtype": MISMATCH_CACHE_LAYOUT,
"kv_layout": MISMATCH_CACHE_LAYOUT,
"tokenizer_revision": MISMATCH_TOKENIZER,
"architecture_adapter": MISMATCH_ARCHITECTURE,
"backend_id": MISMATCH_BACKEND,
"runtime_version": MISMATCH_RUNTIME,
"boundary_schema_version": MISMATCH_BOUNDARY_SCHEMA,
"protocol_schema_version": MISMATCH_BOUNDARY_SCHEMA,
}
# Certification states. `dark` is the arrival state, not an error state.
STATUS_UNKNOWN = "unknown"
STATUS_DARK = "dark"
STATUS_CERTIFIED = "certified"
# A route that proves a recipe must be a real distributed route.
MIN_CERTIFYING_NODES = 2
_HEX64 = re.compile(r"^[0-9a-f]{64}$")
# A revision that can move is not a pin. DGR-017 learned this on the artifact;
# it is just as true of a tokenizer.
_MOVING_REFS = frozenset({"main", "master", "head", "latest", "dev", "trunk"})
class RecipeIdentityError(ValueError):
"""Malformed identity input. Messages name the field, never echo a payload."""
class RecipeNotCertified(RecipeIdentityError):
"""A recipe was asked to serve user traffic while still dark."""
class RouteIncompatible(RecipeIdentityError):
"""Two Shards cannot form an Inference Route.
Carries the structured reasons, so a caller can map them to a gRPC status
rather than re-parsing a sentence.
"""
def __init__(self, mismatches: Sequence["RouteMismatch"]) -> None:
self.mismatches = tuple(mismatches)
super().__init__("; ".join(m.describe() for m in self.mismatches))
def canonical_sha256(value: Any) -> str:
"""SHA-256 over canonical JSON — the repository's digest convention."""
payload = json.dumps(
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False
)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
def _digest(domain: str, body: Mapping[str, Any]) -> str:
return canonical_sha256({"domain": domain, "body": dict(body)})
def _require_text(value: Any, what: str) -> str:
if not isinstance(value, str) or not value.strip():
raise RecipeIdentityError(f"{what!r} must be a non-empty string")
return value
def _require_hex64(value: Any, what: str) -> str:
text = _require_text(value, what)
if not _HEX64.match(text):
raise RecipeIdentityError(
f"{what!r} must be a lowercase 64-character SHA-256 hex digest"
)
return text
def _require_int(value: Any, what: str, minimum: int) -> int:
if isinstance(value, bool) or not isinstance(value, int):
raise RecipeIdentityError(f"{what!r} must be an integer")
if value < minimum:
raise RecipeIdentityError(f"{what!r} must be >= {minimum}, got {value}")
return value
def _require_pin(value: Any, what: str) -> str:
"""A revision must identify one immutable thing, not a ref that moves."""
text = _require_text(value, what)
lowered = text.strip().lower()
if lowered in _MOVING_REFS or lowered.startswith("refs/"):
raise RecipeIdentityError(
f"{what!r} is {text!r}, which is a moving reference, not a pin; "
"identity requires an exact immutable revision"
)
return text
def _as_mapping(value: Any, what: str) -> Mapping[str, Any]:
if not isinstance(value, Mapping):
raise RecipeIdentityError(
f"{what!r} must be a JSON object, got {type(value).__name__}"
)
return value
@dataclass(frozen=True)
class DerivativeBinding:
"""A split or derived artifact, bound to the exact artifact it was cut from.
Without this binding a split GGUF is an anonymous blob with a plausible
layer count. With it, the Shard's own bytes are checkable *and* its identity
on the route is the source model's, which is what lets a whole-model oracle
and a five-way split agree on a fingerprint.
The range is inclusive start, exclusive end, matching the protocol
(``ShardRange`` in ``shard_runtime.proto``).
"""
source_artifact_digest: str
shard_start: int
shard_end: int
def __post_init__(self) -> None:
_require_hex64(
self.source_artifact_digest, "derived_from.source_artifact_digest"
)
_require_int(self.shard_start, "derived_from.shard_start", 0)
_require_int(self.shard_end, "derived_from.shard_end", 1)
if self.shard_end <= self.shard_start:
raise RecipeIdentityError(
f"'derived_from.shard_end' ({self.shard_end}) must be greater than "
f"'derived_from.shard_start' ({self.shard_start}); an empty split "
"artifact covers no layers and can prove nothing"
)
def covers(self, start: int, end: int) -> bool:
return self.shard_start <= start and end <= self.shard_end
def to_dict(self) -> dict:
return {
"source_artifact_digest": self.source_artifact_digest,
"shard_start": self.shard_start,
"shard_end": self.shard_end,
}
@classmethod
def from_dict(cls, data: Any) -> DerivativeBinding:
doc = _as_mapping(data, "derived_from")
return cls(
source_artifact_digest=_require_hex64(
doc.get("source_artifact_digest"),
"derived_from.source_artifact_digest",
),
shard_start=_require_int(
doc.get("shard_start"), "derived_from.shard_start", 0
),
shard_end=_require_int(doc.get("shard_end"), "derived_from.shard_end", 1),
)
@dataclass(frozen=True)
class ArtifactIdentity:
"""Exactly which weights, config and architecture a Shard loaded.
`content_digest` is *this* file's hash — the whole model for an undivided
artifact, one split's bytes for a derivative. `source_digest` is what the
route compares. For an undivided artifact they are the same value; that
identity is the whole point, because it is what makes the DGR-018
whole-model oracle and the DGR-020 distributed route the same artifact.
"""
artifact_id: str
revision: str
content_digest: str
architecture: str
architecture_digest: str
layer_count: int
derived_from: DerivativeBinding | None = None
def __post_init__(self) -> None:
_require_text(self.artifact_id, "artifact.artifact_id")
_require_pin(self.revision, "artifact.revision")
_require_hex64(self.content_digest, "artifact.content_digest")
_require_text(self.architecture, "artifact.architecture")
_require_hex64(self.architecture_digest, "artifact.architecture_digest")
_require_int(self.layer_count, "artifact.layer_count", 1)
binding = self.derived_from
if binding is None:
return
if binding.source_artifact_digest == self.content_digest:
raise RecipeIdentityError(
"'artifact.derived_from.source_artifact_digest' equals this "
"artifact's own content digest; an artifact is not a split of itself"
)
if binding.shard_end > self.layer_count:
raise RecipeIdentityError(
f"'artifact.derived_from' claims layers "
f"{binding.shard_start}{binding.shard_end}, but the source model "
f"has only {self.layer_count} layers"
)
@property
def is_derivative(self) -> bool:
return self.derived_from is not None
@property
def source_digest(self) -> str:
"""The whole-model artifact this Shard descends from — what a route compares."""
if self.derived_from is None:
return self.content_digest
return self.derived_from.source_artifact_digest
@property
def model_artifact_digest(self) -> str:
"""The artifact half of the compatibility fingerprint.
Commits to the source weights, the architecture and its config/tokenizer
snapshot, and the layer count — and deliberately *not* to the repository
the bytes were fetched from. A mirror of identical bytes is the same
artifact; the repo name buys diagnosis, not numerical identity.
"""
return _digest(
ARTIFACT_DIGEST_DOMAIN,
{
"source_digest": self.source_digest,
"architecture": self.architecture,
"architecture_digest": self.architecture_digest,
"layer_count": self.layer_count,
},
)
def to_dict(self) -> dict:
return {
"artifact_id": self.artifact_id,
"revision": self.revision,
"content_digest": self.content_digest,
"architecture": self.architecture,
"architecture_digest": self.architecture_digest,
"layer_count": self.layer_count,
"derived_from": (
self.derived_from.to_dict() if self.derived_from else None
),
}
@classmethod
def from_dict(cls, data: Any) -> ArtifactIdentity:
doc = _as_mapping(data, "artifact")
raw_binding = doc.get("derived_from")
return cls(
artifact_id=_require_text(doc.get("artifact_id"), "artifact.artifact_id"),
revision=_require_pin(doc.get("revision"), "artifact.revision"),
content_digest=_require_hex64(
doc.get("content_digest"), "artifact.content_digest"
),
architecture=_require_text(
doc.get("architecture"), "artifact.architecture"
),
architecture_digest=_require_hex64(
doc.get("architecture_digest"), "artifact.architecture_digest"
),
layer_count=_require_int(doc.get("layer_count"), "artifact.layer_count", 1),
derived_from=(
None if raw_binding is None else DerivativeBinding.from_dict(raw_binding)
),
)
@dataclass(frozen=True)
class RuntimeRecipe:
"""How a Shard executes the artifact — one field per numerically live axis.
Weight quantization is not activation dtype is not compute dtype is not KV
dtype. Two nodes running `UD-IQ1_S` weights, one accumulating in fp32 and
one in fp16, produce different logits from the same bytes. Keeping the axes
apart is the entire safety property; see :data:`RECIPE_AXES`.
The three label fields are diagnosis only and are not digested.
"""
weight_quantization: str
activation_dtype: str
compute_dtype: str
kv_dtype: str
kv_layout: str
tokenizer_revision: str
architecture_adapter: str
backend_id: str
runtime_version: str
boundary_schema_version: int = BUNDLE_VERSION
protocol_schema_version: int = int(SCHEMA_VERSION)
recipe_id: str = "unnamed"
recipe_version: str = "0"
catalogue_version: str = "0"
def __post_init__(self) -> None:
for axis in RECIPE_AXES:
value = getattr(self, axis)
if axis.endswith("_schema_version"):
_require_int(value, f"recipe.{axis}", 1)
else:
_require_text(value, f"recipe.{axis}")
_require_pin(self.tokenizer_revision, "recipe.tokenizer_revision")
_require_text(self.recipe_id, "recipe.recipe_id")
_require_text(self.recipe_version, "recipe.recipe_version")
_require_text(self.catalogue_version, "recipe.catalogue_version")
@property
def axes(self) -> dict[str, Any]:
"""The digested fields, and only those."""
return {axis: getattr(self, axis) for axis in RECIPE_AXES}
@property
def runtime_recipe_digest(self) -> str:
"""The recipe half of the compatibility fingerprint."""
return _digest(RECIPE_DIGEST_DOMAIN, self.axes)
def to_dict(self) -> dict:
doc = self.axes
doc.update(
{
"recipe_id": self.recipe_id,
"recipe_version": self.recipe_version,
"catalogue_version": self.catalogue_version,
}
)
return doc
@classmethod
def from_dict(cls, data: Any) -> RuntimeRecipe:
doc = _as_mapping(data, "recipe")
missing = [axis for axis in RECIPE_AXES if axis not in doc]
if missing:
raise RecipeIdentityError(
"recipe is missing required axes: "
+ ", ".join(missing)
+ "; an unstated axis is an unproven one, so it cannot default"
)
kwargs: dict[str, Any] = {}
for axis in RECIPE_AXES:
value = doc[axis]
if axis.endswith("_schema_version"):
kwargs[axis] = _require_int(value, f"recipe.{axis}", 1)
else:
kwargs[axis] = _require_text(value, f"recipe.{axis}")
return cls(
**kwargs,
recipe_id=_require_text(doc.get("recipe_id"), "recipe.recipe_id"),
recipe_version=_require_text(
doc.get("recipe_version"), "recipe.recipe_version"
),
catalogue_version=_require_text(
doc.get("catalogue_version"), "recipe.catalogue_version"
),
)
@dataclass(frozen=True)
class CompatibilityFingerprint:
"""The stable identity two peers actually compare.
This is the Python face of the protocol's ``Fingerprint`` message
(DGR-002). Do not invent a second identity struct: capability admission and
the gRPC handshake compare *this*, and they must compare the same thing or
a route can pass one gate and fail the other.
"""
model_artifact_digest: str
runtime_recipe_digest: str
recipe_id: str
recipe_version: str
catalogue_version: str
def __post_init__(self) -> None:
_require_hex64(self.model_artifact_digest, "fingerprint.model_artifact_digest")
_require_hex64(
self.runtime_recipe_digest, "fingerprint.runtime_recipe_digest"
)
@property
def key(self) -> tuple[str, str]:
"""What equality means: the digests, never the labels."""
return (self.model_artifact_digest, self.runtime_recipe_digest)
def matches(self, other: CompatibilityFingerprint) -> bool:
return self.key == other.key
def to_dict(self) -> dict:
return {
"model_artifact_digest": self.model_artifact_digest,
"runtime_recipe_digest": self.runtime_recipe_digest,
"recipe_id": self.recipe_id,
"recipe_version": self.recipe_version,
"catalogue_version": self.catalogue_version,
}
@classmethod
def from_dict(cls, data: Any) -> CompatibilityFingerprint:
doc = _as_mapping(data, "fingerprint")
return cls(
model_artifact_digest=_require_hex64(
doc.get("model_artifact_digest"), "fingerprint.model_artifact_digest"
),
runtime_recipe_digest=_require_hex64(
doc.get("runtime_recipe_digest"), "fingerprint.runtime_recipe_digest"
),
recipe_id=_require_text(doc.get("recipe_id"), "fingerprint.recipe_id"),
recipe_version=_require_text(
doc.get("recipe_version"), "fingerprint.recipe_version"
),
catalogue_version=_require_text(
doc.get("catalogue_version"), "fingerprint.catalogue_version"
),
)
def to_proto(self) -> "pb.Fingerprint":
"""Populate the DGR-002 ``Fingerprint`` message for the gRPC handshake."""
return pb.Fingerprint(
model_artifact_digest=self.model_artifact_digest,
runtime_recipe_digest=self.runtime_recipe_digest,
recipe_id=self.recipe_id,
recipe_version=self.recipe_version,
catalogue_version=self.catalogue_version,
)
@classmethod
def from_proto(cls, message: "pb.Fingerprint") -> CompatibilityFingerprint:
return cls(
model_artifact_digest=_require_hex64(
message.model_artifact_digest, "fingerprint.model_artifact_digest"
),
runtime_recipe_digest=_require_hex64(
message.runtime_recipe_digest, "fingerprint.runtime_recipe_digest"
),
recipe_id=_require_text(message.recipe_id, "fingerprint.recipe_id"),
recipe_version=_require_text(
message.recipe_version, "fingerprint.recipe_version"
),
catalogue_version=_require_text(
message.catalogue_version, "fingerprint.catalogue_version"
),
)
@dataclass(frozen=True)
class RouteMismatch:
"""One structured, fail-closed reason two identities do not compose."""
reason: str
detail: str
shard_index: int | None = None
def describe(self) -> str:
where = "" if self.shard_index is None else f"shard {self.shard_index}: "
return f"{where}{self.reason}: {self.detail}"
def to_dict(self) -> dict:
return {
"reason": self.reason,
"detail": self.detail,
"shard_index": self.shard_index,
}
@dataclass(frozen=True)
class ShardIdentity:
"""What one Shard is: an artifact, a recipe, and the layers it owns.
The owned range is inclusive start, exclusive end (protocol convention). It
is *not* part of the fingerprint — see the module docstring — but it is
validated against the artifact, because a Shard cannot serve layers its
artifact does not contain.
"""
artifact: ArtifactIdentity
recipe: RuntimeRecipe
shard_start: int
shard_end: int
def __post_init__(self) -> None:
_require_int(self.shard_start, "shard_start", 0)
_require_int(self.shard_end, "shard_end", 1)
if self.shard_end <= self.shard_start:
raise RecipeIdentityError(
f"'shard_end' ({self.shard_end}) must be greater than 'shard_start' "
f"({self.shard_start}); a Shard owning no layer computes nothing"
)
if self.shard_end > self.artifact.layer_count:
raise RecipeIdentityError(
f"Shard owns layers {self.shard_start}{self.shard_end}, but the "
f"artifact has only {self.artifact.layer_count} layers"
)
binding = self.artifact.derived_from
if binding is not None and not binding.covers(self.shard_start, self.shard_end):
raise RecipeIdentityError(
f"Shard advertises layers {self.shard_start}{self.shard_end}, but its "
f"split artifact only contains layers {binding.shard_start}"
f"{binding.shard_end}; it cannot serve weights it does not hold"
)
@property
def fingerprint(self) -> CompatibilityFingerprint:
"""The derived identity. Never stored, never trusted from the wire — derived."""
return CompatibilityFingerprint(
model_artifact_digest=self.artifact.model_artifact_digest,
runtime_recipe_digest=self.recipe.runtime_recipe_digest,
recipe_id=self.recipe.recipe_id,
recipe_version=self.recipe.recipe_version,
catalogue_version=self.recipe.catalogue_version,
)
def to_dict(self) -> dict:
return {
"schema_version": RECIPE_IDENTITY_SCHEMA_VERSION,
"artifact": self.artifact.to_dict(),
"recipe": self.recipe.to_dict(),
"shard_start": self.shard_start,
"shard_end": self.shard_end,
"fingerprint": self.fingerprint.to_dict(),
}
@classmethod
def from_dict(cls, data: Any) -> ShardIdentity:
"""Parse an identity block, re-deriving — never trusting — its fingerprint.
A declared fingerprint is a compatibility claim, not authentication.
Recomputing it catches an inconsistent declaration; only tracker-owned
distributed certification decides whether a recipe may serve.
"""
doc = _as_mapping(data, "identity")
declared_schema = doc.get("schema_version")
if declared_schema != RECIPE_IDENTITY_SCHEMA_VERSION:
raise RecipeIdentityError(
f"identity block declares schema version {declared_schema!r}, but this "
f"node reads version {RECIPE_IDENTITY_SCHEMA_VERSION}"
)
identity = cls(
artifact=ArtifactIdentity.from_dict(doc.get("artifact")),
recipe=RuntimeRecipe.from_dict(doc.get("recipe")),
shard_start=_require_int(doc.get("shard_start"), "shard_start", 0),
shard_end=_require_int(doc.get("shard_end"), "shard_end", 1),
)
declared = doc.get("fingerprint")
if declared is not None:
claim = CompatibilityFingerprint.from_dict(declared)
derived = identity.fingerprint
if not claim.matches(derived):
raise RouteIncompatible(
[
RouteMismatch(
MISMATCH_FINGERPRINT,
"declared fingerprint does not match the identity it "
"claims to describe; the digest is derived from the "
"artifact and recipe, it is not an assertion",
)
]
)
return identity
def explain_mismatch(
left: ShardIdentity,
right: ShardIdentity,
*,
shard_index: int | None = None,
) -> tuple[RouteMismatch, ...]:
"""Name every axis on which two Shards disagree.
The fingerprint comparison already answers *whether* they compose. This
answers *why not*, which is the difference between an operator fixing their
node in a minute and filing a bug.
"""
mismatches: list[RouteMismatch] = []
if left.artifact.source_digest != right.artifact.source_digest:
mismatches.append(
RouteMismatch(
MISMATCH_ARTIFACT,
f"source Model Artifact {right.artifact.source_digest[:12]}… does not "
f"match the route's {left.artifact.source_digest[:12]}",
shard_index,
)
)
if left.artifact.architecture != right.artifact.architecture:
mismatches.append(
RouteMismatch(
MISMATCH_ARCHITECTURE,
f"artifact architecture {right.artifact.architecture!r} does not match "
f"the route's {left.artifact.architecture!r}",
shard_index,
)
)
if left.artifact.architecture_digest != right.artifact.architecture_digest:
mismatches.append(
RouteMismatch(
MISMATCH_ARCHITECTURE,
"architecture/config snapshot differs from the route's; the same "
"architecture name with different config is a different model",
shard_index,
)
)
if left.artifact.layer_count != right.artifact.layer_count:
mismatches.append(
RouteMismatch(
MISMATCH_ARTIFACT,
f"artifact has {right.artifact.layer_count} layers, but the route's "
f"has {left.artifact.layer_count}",
shard_index,
)
)
for axis in RECIPE_AXES:
mine = getattr(left.recipe, axis)
theirs = getattr(right.recipe, axis)
if mine != theirs:
mismatches.append(
RouteMismatch(
_AXIS_MISMATCH[axis],
f"{axis} is {theirs!r}, but the route runs {mine!r}",
shard_index,
)
)
if not mismatches and not left.fingerprint.matches(right.fingerprint):
# Unreachable via the fields above; if it ever fires, identity has grown a
# digested field that `explain_mismatch` does not know about, and silently
# reporting "compatible" would be far worse than an unhelpful message.
mismatches.append(
RouteMismatch(
MISMATCH_FINGERPRINT,
"fingerprints differ on a field this comparison does not cover",
shard_index,
)
)
return tuple(mismatches)
@dataclass(frozen=True)
class DistributedForwardEvidence:
"""Proof that a recipe really ran, distributed, end to end.
This is the only thing that takes a recipe out of the dark. The bar is
deliberately the product's bar, not a unit test's: at least two *distinct*
physical nodes, whose Shards cover the whole model with no hole, generating
real tokens. A synthetic worker is a unit fixture and certifies nothing —
the whole risk this guards against is a recipe that passes in a mock and
produces garbage on real weights.
"""
route_session_id: str
route_epoch: int
node_ids: tuple[str, ...]
shard_ranges: tuple[tuple[int, int], ...]
tokens_generated: int
layer_count: int
synthetic: bool = False
certified_at: float = field(default_factory=time.time)
def __post_init__(self) -> None:
_require_text(self.route_session_id, "evidence.route_session_id")
_require_int(self.route_epoch, "evidence.route_epoch", 0)
_require_int(self.tokens_generated, "evidence.tokens_generated", 0)
_require_int(self.layer_count, "evidence.layer_count", 1)
def rejection(self) -> str | None:
"""Why this evidence does not certify, or None when it does."""
if self.synthetic:
return (
"evidence comes from a synthetic worker; only a real distributed "
"forward certifies a recipe"
)
distinct = set(self.node_ids)
if len(distinct) < MIN_CERTIFYING_NODES:
return (
f"evidence covers {len(distinct)} distinct node(s); a distributed "
f"forward requires at least {MIN_CERTIFYING_NODES}"
)
if len(distinct) != len(self.node_ids):
return "the same node is counted more than once in the certifying route"
if self.tokens_generated < 1:
return "the certifying forward generated no tokens"
gap = _coverage_gap(self.shard_ranges, self.layer_count)
if gap is not None:
return gap
return None
def _coverage_gap(
ranges: Iterable[tuple[int, int]], layer_count: int
) -> str | None:
"""Return why `ranges` fail to tile ``[0, layer_count)``, or None if they do.
Ranges may overlap: ADR-0012 lets the Tracker resolve an overlap by telling a
hop where the previous hop stopped, so an overlap is a routing decision, not
a defect. A *hole* is a defect — the layers in it are never computed, and the
route would silently emit tokens from a truncated model.
"""
ordered = sorted(ranges)
if not ordered:
return "the certifying route owns no layers"
if ordered[0][0] != 0:
return f"layers 0{ordered[0][0]} are owned by no Shard on the route"
covered = 0
for start, end in ordered:
if start > covered:
return f"layers {covered}{start} are owned by no Shard on the route"
covered = max(covered, end)
if covered < layer_count:
return f"layers {covered}{layer_count} are owned by no Shard on the route"
if covered > layer_count:
return (
f"the route claims to cover {covered} layers, but the model has only "
f"{layer_count}"
)
return None
@dataclass(frozen=True)
class RecipeStatus:
"""What the registry knows about one fingerprint."""
status: str
fingerprint: CompatibilityFingerprint | None = None
detail: str = ""
certified_at: float | None = None
@property
def may_serve(self) -> bool:
"""Only a certified recipe carries user traffic."""
return self.status == STATUS_CERTIFIED
@property
def may_certify(self) -> bool:
"""A dark recipe is eligible for a certification route — and only that.
Without this, certification is unreachable: serving requires
certification, certification requires a real distributed forward, and a
real distributed forward requires a route. A dark recipe may therefore
be routed *for the express purpose of certifying it*, and never for user
traffic.
"""
return self.status in (STATUS_DARK, STATUS_CERTIFIED)
def to_dict(self) -> dict:
return {
"status": self.status,
"detail": self.detail,
"certified_at": self.certified_at,
"fingerprint": (
self.fingerprint.to_dict() if self.fingerprint is not None else None
),
}
class RecipeRegistry:
"""Registered-but-dark recipes, and the ones a real forward has certified.
An unknown recipe is not routable. A known one is not routable either, until
it has been proven. This is the fail-closed default the roadmap asks for:
"unsupported architectures/backends remain registered-but-dark until real
certification passes."
"""
def __init__(self) -> None:
self._dark: dict[tuple[str, str], CompatibilityFingerprint] = {}
self._certified: dict[tuple[str, str], RecipeStatus] = {}
def register(self, identity: ShardIdentity | CompatibilityFingerprint) -> RecipeStatus:
"""Record a recipe as known. Known is not certified."""
fingerprint = _as_fingerprint(identity)
key = fingerprint.key
if key in self._certified:
return self._certified[key]
self._dark[key] = fingerprint
return RecipeStatus(
STATUS_DARK,
fingerprint,
"registered; dark until a real distributed forward certifies it",
)
def status(self, identity: ShardIdentity | CompatibilityFingerprint) -> RecipeStatus:
fingerprint = _as_fingerprint(identity)
key = fingerprint.key
if key in self._certified:
return self._certified[key]
if key in self._dark:
return RecipeStatus(
STATUS_DARK,
fingerprint,
"registered; dark until a real distributed forward certifies it",
)
return RecipeStatus(
STATUS_UNKNOWN,
fingerprint,
"this recipe has never been registered with the Tracker",
)
def certify(
self,
identity: ShardIdentity | CompatibilityFingerprint,
evidence: DistributedForwardEvidence,
) -> RecipeStatus:
"""Promote a dark recipe, if the evidence is a real distributed forward.
Raises rather than returning a failed status: certifying is a state
change, and a caller that ignores a returned failure would leave a
recipe it believes to be certified in the dark.
"""
fingerprint = _as_fingerprint(identity)
rejection = evidence.rejection()
if rejection is not None:
raise RecipeNotCertified(
f"this evidence does not certify {fingerprint.recipe_id!r}: {rejection}"
)
status = RecipeStatus(
STATUS_CERTIFIED,
fingerprint,
(
f"certified by route session {evidence.route_session_id} across "
f"{len(set(evidence.node_ids))} nodes"
),
certified_at=evidence.certified_at,
)
self._certified[fingerprint.key] = status
self._dark.pop(fingerprint.key, None)
return status
def require_serving(
self, identity: ShardIdentity | CompatibilityFingerprint
) -> RecipeStatus:
"""Admit a recipe for user traffic, or refuse and say why."""
status = self.status(identity)
if not status.may_serve:
raise RecipeNotCertified(
f"recipe {_as_fingerprint(identity).recipe_id!r} is {status.status}: "
f"{status.detail}"
)
return status
def certified_fingerprints(self) -> tuple[CompatibilityFingerprint, ...]:
return tuple(
status.fingerprint
for status in self._certified.values()
if status.fingerprint is not None
)
def to_dict(self) -> dict:
return {
"schema_version": RECIPE_IDENTITY_SCHEMA_VERSION,
"dark": [fp.to_dict() for fp in self._dark.values()],
"certified": [status.to_dict() for status in self._certified.values()],
}
def _as_fingerprint(
identity: ShardIdentity | CompatibilityFingerprint,
) -> CompatibilityFingerprint:
if isinstance(identity, CompatibilityFingerprint):
return identity
if isinstance(identity, ShardIdentity):
return identity.fingerprint
raise RecipeIdentityError(
f"expected a ShardIdentity or CompatibilityFingerprint, got "
f"{type(identity).__name__}"
)
def check_route(
shards: Sequence[ShardIdentity],
*,
registry: RecipeRegistry | None = None,
for_certification: bool = False,
) -> tuple[RouteMismatch, ...]:
"""Decide whether these Shards may form one Inference Route.
Returns every reason they may not, empty when they may. Fail-closed by
construction: an empty route, an unknown recipe, a hole in the layer
coverage and a single differing dtype all produce a reason, and a caller that
only ever proceeds on an empty tuple cannot accidentally admit any of them.
`for_certification` admits a dark recipe onto a route whose only purpose is
to certify it. It never admits an unknown one, and it is not the path user
traffic takes.
"""
if not shards:
return (
RouteMismatch(
MISMATCH_RANGE, "a route needs at least one Shard; this one has none"
),
)
mismatches: list[RouteMismatch] = []
head = shards[0]
for index, shard in enumerate(shards[1:], start=1):
if not head.fingerprint.matches(shard.fingerprint):
mismatches.extend(explain_mismatch(head, shard, shard_index=index))
gap = _coverage_gap(
[(shard.shard_start, shard.shard_end) for shard in shards],
head.artifact.layer_count,
)
if gap is not None:
mismatches.append(RouteMismatch(MISMATCH_RANGE, gap))
if registry is not None:
status = registry.status(head.fingerprint)
allowed = status.may_certify if for_certification else status.may_serve
if not allowed:
mismatches.append(
RouteMismatch(MISMATCH_UNCERTIFIED, f"{status.status}: {status.detail}")
)
return tuple(mismatches)
def require_route(
shards: Sequence[ShardIdentity],
*,
registry: RecipeRegistry | None = None,
for_certification: bool = False,
) -> CompatibilityFingerprint:
"""`check_route`, raising the structured reasons instead of returning them."""
mismatches = check_route(
shards, registry=registry, for_certification=for_certification
)
if mismatches:
raise RouteIncompatible(mismatches)
return shards[0].fingerprint
# ---------------------------------------------------------------------------
# The alpha target (DGR-017)
# ---------------------------------------------------------------------------
def glm_alpha_artifact(
derived_from: DerivativeBinding | None = None,
*,
content_digest: str | None = None,
) -> ArtifactIdentity:
"""Artifact identity for the pinned GLM-5.2 ``UD-IQ1_S`` alpha target.
Reads the locked manifest and architecture snapshot DGR-017 sealed, rather
than restating their digests here — a second copy of a pinned digest is a
second thing that can drift from the target it claims to pin.
`layer_count` is `num_hidden_layers` (78), *not* `total_artifact_layers`
(79). The 79th is the MTP/next-token-prediction layer, which is not part of
the transformer stack a route tiles and which alpha explicitly defers
(roadmap decision 17). Tiling 79 layers would leave every route one layer
short of "covered" forever.
Pass `derived_from` when this node holds a split of the target, and
`content_digest` for that split's own bytes.
"""
from .glm_alpha import load_locked_target
_contract, manifest, snapshot = load_locked_target()
return ArtifactIdentity(
artifact_id=manifest.gguf_repo_id,
revision=manifest.gguf_revision,
content_digest=content_digest or manifest.digest,
architecture=str(snapshot["model_type"]),
architecture_digest=snapshot.digest,
layer_count=int(snapshot["num_hidden_layers"]),
derived_from=derived_from,
)
# ---------------------------------------------------------------------------
# gRPC handshake (DGR-002 `Fingerprint`, `ERROR_CODE_FINGERPRINT_MISMATCH`)
# ---------------------------------------------------------------------------
def check_handshake(
local: ShardIdentity,
remote: "pb.Fingerprint",
) -> tuple[RouteMismatch, ...]:
"""Compare the fingerprint a peer opened the stream with against our own.
An incompatible peer must fail at `SessionOpen`, not mid-generation: by the
time a wrong activation has been folded into a KV cache, the session is
already producing wrong tokens and there is nothing to salvage.
"""
try:
presented = CompatibilityFingerprint.from_proto(remote)
except RecipeIdentityError as exc:
return (
RouteMismatch(
MISMATCH_FINGERPRINT,
f"peer presented an unusable fingerprint: {exc}",
),
)
mine = local.fingerprint
if presented.matches(mine):
return ()
reasons: list[RouteMismatch] = []
if presented.model_artifact_digest != mine.model_artifact_digest:
reasons.append(
RouteMismatch(
MISMATCH_ARTIFACT,
f"peer serves Model Artifact {presented.model_artifact_digest[:12]}…, "
f"this Shard serves {mine.model_artifact_digest[:12]}",
)
)
if presented.runtime_recipe_digest != mine.runtime_recipe_digest:
reasons.append(
RouteMismatch(
MISMATCH_FINGERPRINT,
f"peer runs recipe {presented.runtime_recipe_digest[:12]}"
f"({presented.recipe_id} v{presented.recipe_version}), this Shard runs "
f"{mine.runtime_recipe_digest[:12]}… ({mine.recipe_id} "
f"v{mine.recipe_version})",
)
)
return tuple(reasons)
def handshake_error(
mismatches: Sequence[RouteMismatch],
) -> "pb.ShardError | None":
"""The protocol status a rejected handshake closes the stream with."""
if not mismatches:
return None
return pb.ShardError(
code=pb.ERROR_CODE_FINGERPRINT_MISMATCH,
detail="; ".join(m.describe() for m in mismatches),
retryable=False,
)