feat: emit native DGR-003 shard identity
This commit is contained in:
@@ -36,6 +36,7 @@ from .capability import (
|
||||
CapabilityReport,
|
||||
build_capability_report,
|
||||
)
|
||||
from .native_backend import NativeWorkerBackendAdapter
|
||||
from .recipe_manifest import (
|
||||
DEFAULT_RECIPE_ID,
|
||||
Recipe,
|
||||
@@ -449,11 +450,9 @@ def _validate_recipe(
|
||||
category: str | None = None
|
||||
error: BaseException | None = None
|
||||
diagnostics: list[str] = []
|
||||
detail: dict = {}
|
||||
|
||||
try:
|
||||
backend = load_backend(selection, recipe)
|
||||
detail = probe_forward(backend)
|
||||
probe_forward(backend)
|
||||
except DoctorError as exc:
|
||||
category, error = exc.category, exc
|
||||
diagnostics = [str(exc), exc.hint]
|
||||
@@ -464,23 +463,48 @@ def _validate_recipe(
|
||||
duration_ms = int((time.monotonic() - started) * 1000)
|
||||
|
||||
device = _backend_device(backend, selection)
|
||||
# Only the native adapter has an authoritative immutable GGUF report and
|
||||
# deployment pin. The Transformers path deliberately remains dark: a
|
||||
# model/config fingerprint is not an exact ArtifactIdentity.
|
||||
identity = backend.identity if isinstance(backend, NativeWorkerBackendAdapter) else None
|
||||
model_id = selection.model_id if identity is None else identity.artifact.artifact_id
|
||||
shard_start = selection.shard_start if identity is None else identity.shard_start
|
||||
shard_end = selection.shard_end if identity is None else identity.shard_end - 1
|
||||
recipe_id = recipe.id if identity is None else identity.recipe.recipe_id
|
||||
recipe_version = recipe.version if identity is None else identity.recipe.recipe_version
|
||||
catalogue_version = (
|
||||
manifest.catalogue_version if identity is None else identity.recipe.catalogue_version
|
||||
)
|
||||
backend_id = recipe.backend_id if identity is None else identity.recipe.backend_id
|
||||
quantization = (
|
||||
selection.quantization if identity is None else identity.recipe.weight_quantization
|
||||
)
|
||||
runtime = _runtime_versions()
|
||||
model_config = _model_config(backend)
|
||||
revision = None
|
||||
if identity is not None:
|
||||
revision = identity.artifact.revision
|
||||
model_config = "sha256:" + identity.artifact.architecture_digest
|
||||
runtime = {**runtime, "native_runtime": identity.recipe.runtime_version}
|
||||
report = build_capability_report(
|
||||
model_id=selection.model_id,
|
||||
shard_start=selection.shard_start,
|
||||
shard_end=selection.shard_end,
|
||||
recipe_id=recipe.id,
|
||||
recipe_version=recipe.version,
|
||||
catalogue_version=manifest.catalogue_version,
|
||||
backend_id=recipe.backend_id,
|
||||
model_id=model_id,
|
||||
shard_start=shard_start,
|
||||
shard_end=shard_end,
|
||||
recipe_id=recipe_id,
|
||||
recipe_version=recipe_version,
|
||||
catalogue_version=catalogue_version,
|
||||
backend_id=backend_id,
|
||||
device=device,
|
||||
device_name=_backend_device_name(device),
|
||||
quantization=selection.quantization,
|
||||
runtime=_runtime_versions(),
|
||||
model_config=_model_config(backend),
|
||||
quantization=quantization,
|
||||
runtime=runtime,
|
||||
revision=revision,
|
||||
model_config=model_config,
|
||||
status=STATUS_FAILED if category else STATUS_PASSED,
|
||||
duration_ms=duration_ms,
|
||||
diagnostics=[d for d in diagnostics if d] or None,
|
||||
validated_at=clock(),
|
||||
identity=identity,
|
||||
)
|
||||
if category:
|
||||
return RecipeResult(
|
||||
|
||||
185
packages/node/meshnet_node/native_backend.py
Normal file
185
packages/node/meshnet_node/native_backend.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""Authoritative identity boundary for a native GGUF Shard backend.
|
||||
|
||||
The native loader owns the facts about the mapped artifact. This module turns
|
||||
that immutable report and separately pinned deployment inputs into the one
|
||||
``ShardIdentity`` DGR-003 permits a native worker to emit. It is intentionally
|
||||
not an adapter for the legacy Transformers backend: that backend has no
|
||||
authoritative immutable GGUF artifact pin and must remain identity-free.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from .native_protocol import BUNDLE_VERSION, SCHEMA_VERSION, pb
|
||||
from .runtime_recipe import (
|
||||
ArtifactIdentity,
|
||||
DerivativeBinding,
|
||||
RecipeIdentityError,
|
||||
RuntimeRecipe,
|
||||
ShardIdentity,
|
||||
check_session_open,
|
||||
handshake_error,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NativeLoadedArtifactReport:
|
||||
"""Immutable GGUF facts returned by the loaded native model.
|
||||
|
||||
The report is copied from ``llama_model_meshnet_range_report`` plus the
|
||||
parsed GGUF metadata while the model is live. Byte counts are operational
|
||||
evidence rather than compatibility axes, but keeping them beside the range
|
||||
prevents a caller from substituting an unverified range declaration.
|
||||
"""
|
||||
|
||||
owned_start_layer: int
|
||||
owned_end_layer: int
|
||||
mapped_bytes: int
|
||||
resident_bytes: int
|
||||
registered_bytes: int
|
||||
architecture: str
|
||||
architecture_digest: str
|
||||
layer_count: int
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.owned_start_layer < 0 or self.owned_end_layer <= self.owned_start_layer:
|
||||
raise RecipeIdentityError("native report has an invalid owned layer range")
|
||||
if self.layer_count < 1 or self.owned_end_layer > self.layer_count:
|
||||
raise RecipeIdentityError("native report range is outside GGUF layer metadata")
|
||||
if min(self.mapped_bytes, self.resident_bytes, self.registered_bytes) < 0:
|
||||
raise RecipeIdentityError("native report byte counts must be non-negative")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ImmutableArtifactPin:
|
||||
"""Deployment-supplied immutable bytes pin, never inferred from a model name."""
|
||||
|
||||
artifact_id: str
|
||||
revision: str
|
||||
content_digest: str
|
||||
derived_from: DerivativeBinding | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NativeNumericalRecipe:
|
||||
"""Immutable numerical inputs selected for this native worker instance."""
|
||||
|
||||
weight_quantization: str
|
||||
activation_dtype: str
|
||||
compute_dtype: str
|
||||
kv_dtype: str
|
||||
kv_layout: str
|
||||
architecture_adapter: str
|
||||
backend_id: str
|
||||
runtime_version: str
|
||||
recipe_id: str
|
||||
recipe_version: str
|
||||
catalogue_version: str
|
||||
boundary_schema_version: int = BUNDLE_VERSION
|
||||
protocol_schema_version: int = int(SCHEMA_VERSION)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NativeIdentityInputs:
|
||||
"""Everything a native backend needs to emit one exact identity."""
|
||||
|
||||
loaded_artifact: NativeLoadedArtifactReport
|
||||
artifact_pin: ImmutableArtifactPin
|
||||
tokenizer_revision: str
|
||||
numerical_recipe: NativeNumericalRecipe
|
||||
|
||||
|
||||
def shard_identity_from_native_report(inputs: NativeIdentityInputs) -> ShardIdentity:
|
||||
"""Derive identity only from the native report and immutable pinned inputs."""
|
||||
report = inputs.loaded_artifact
|
||||
pin = inputs.artifact_pin
|
||||
recipe = inputs.numerical_recipe
|
||||
artifact = ArtifactIdentity(
|
||||
artifact_id=pin.artifact_id,
|
||||
revision=pin.revision,
|
||||
content_digest=pin.content_digest,
|
||||
architecture=report.architecture,
|
||||
architecture_digest=report.architecture_digest,
|
||||
layer_count=report.layer_count,
|
||||
derived_from=pin.derived_from,
|
||||
)
|
||||
return ShardIdentity(
|
||||
artifact=artifact,
|
||||
recipe=RuntimeRecipe(
|
||||
weight_quantization=recipe.weight_quantization,
|
||||
activation_dtype=recipe.activation_dtype,
|
||||
compute_dtype=recipe.compute_dtype,
|
||||
kv_dtype=recipe.kv_dtype,
|
||||
kv_layout=recipe.kv_layout,
|
||||
tokenizer_revision=inputs.tokenizer_revision,
|
||||
architecture_adapter=recipe.architecture_adapter,
|
||||
backend_id=recipe.backend_id,
|
||||
runtime_version=recipe.runtime_version,
|
||||
boundary_schema_version=recipe.boundary_schema_version,
|
||||
protocol_schema_version=recipe.protocol_schema_version,
|
||||
recipe_id=recipe.recipe_id,
|
||||
recipe_version=recipe.recipe_version,
|
||||
catalogue_version=recipe.catalogue_version,
|
||||
),
|
||||
shard_start=report.owned_start_layer,
|
||||
shard_end=report.owned_end_layer,
|
||||
)
|
||||
|
||||
|
||||
class NativeSessionRejected(RecipeIdentityError):
|
||||
"""A native worker refused a ``SessionOpen`` before allocating session state."""
|
||||
|
||||
def __init__(self, error: "pb.ShardError") -> None:
|
||||
super().__init__(f"native SessionOpen rejected: {error.code}")
|
||||
self.error = error
|
||||
|
||||
|
||||
class NativeWorkerBackendAdapter:
|
||||
"""Small backend-facing adapter around the native loaded-artifact seam."""
|
||||
|
||||
def __init__(self, identity_inputs: NativeIdentityInputs) -> None:
|
||||
self.identity_inputs = identity_inputs
|
||||
self.identity = shard_identity_from_native_report(identity_inputs)
|
||||
|
||||
@property
|
||||
def loaded_artifact_report(self) -> NativeLoadedArtifactReport:
|
||||
return self.identity_inputs.loaded_artifact
|
||||
|
||||
def check_session_open(
|
||||
self,
|
||||
opened: "pb.SessionOpen",
|
||||
*,
|
||||
expected_route_session_id: str | None = None,
|
||||
expected_route_epoch: int | None = None,
|
||||
) -> None:
|
||||
"""Reject incompatible/stale opens at the native worker boundary."""
|
||||
mismatches = check_session_open(
|
||||
self.identity,
|
||||
opened,
|
||||
expected_route_session_id=expected_route_session_id,
|
||||
expected_route_epoch=expected_route_epoch,
|
||||
)
|
||||
error = handshake_error(mismatches)
|
||||
if error is not None:
|
||||
raise NativeSessionRejected(error)
|
||||
|
||||
def on_session_open(
|
||||
self,
|
||||
opened: "pb.SessionOpen",
|
||||
*,
|
||||
expected_route_session_id: str | None = None,
|
||||
expected_route_epoch: int | None = None,
|
||||
) -> "pb.SessionAccepted":
|
||||
"""The native worker's SessionOpen boundary, before session allocation."""
|
||||
self.check_session_open(
|
||||
opened,
|
||||
expected_route_session_id=expected_route_session_id,
|
||||
expected_route_epoch=expected_route_epoch,
|
||||
)
|
||||
return pb.SessionAccepted(
|
||||
schema_version=SCHEMA_VERSION,
|
||||
route_session_id=opened.route_session_id,
|
||||
route_epoch=opened.route_epoch,
|
||||
fingerprint=self.identity.fingerprint.to_proto(),
|
||||
)
|
||||
Reference in New Issue
Block a user