diff --git a/.scratch/distributed-gguf-runtime/evidence/DGR-035/README.md b/.scratch/distributed-gguf-runtime/evidence/DGR-035/README.md new file mode 100644 index 0000000..c45a402 --- /dev/null +++ b/.scratch/distributed-gguf-runtime/evidence/DGR-035/README.md @@ -0,0 +1,54 @@ +# DGR-035 evidence — dense architecture boundary input/output + +**Implemented:** 2026-08-01 +**Authority:** `.scratch/distributed-gguf-runtime/prd.json` + +## What changed + +- `DenseRangeBoundaryExecutor` is a strict execution-facing adapter for the certified `dense-llama` architecture. A head range accepts non-empty token IDs and owns the embedding callback. Middle/tail ranges reject token IDs and require the named `dense.residual.v1` `BoundaryBundle`. +- Non-tail execution returns exactly the raw `hidden_states` residual from its local layer callback. Its constructor rejects a final-norm/output callback, preventing final normalization, logits projection, sampling, and tail-only row pruning before the tail. +- Tail execution is the only path allowed to own final output and returns an explicit `TailOutput`: either validated logits or a sampled token. The existing wire `TypedTailResult` now serializes and validates both choices. +- Unknown architectures, wrong boundary points, and tensor bundles other than one named `hidden_states` tensor fail closed. + +## Changed files + +- `packages/node/meshnet_node/architecture_boundary.py` +- `tests/test_dense_range_boundary.py` +- `tests/test_architecture_boundary.py` +- `.ralph-tui/progress.md` +- `.scratch/distributed-gguf-runtime/evidence/DGR-035/README.md` + +## Commands and results + +```bash +TESTPY=/home/popov/.hermes/hermes-agent/venv/bin/python +PYTHONPATH=packages/node:packages/tracker "$TESTPY" -m pytest -q tests/test_dense_range_boundary.py tests/test_architecture_boundary.py tests/test_shard_engine.py tests/test_fake_shard_engine.py +``` + +```text +37 passed in 0.22s +``` + +```bash +"$TESTPY" -m ruff check packages/node/meshnet_node/architecture_boundary.py tests/test_dense_range_boundary.py tests/test_architecture_boundary.py +PYTHONPATH=packages/node "$TESTPY" -m compileall -q packages tests +git diff --check +python3 scripts/ralph_prd_schema.py validate .scratch/distributed-gguf-runtime/prd.json +``` + +```text +All checks passed! +OK: 55 stories validated. +``` + +## Limitations + +- This story adds and proves the project-owned boundary contract with deterministic, model-download-free tests. It does not claim real-model range parity; DGR-036 owns that numerical certification. +- The llama.cpp graph remains fail-closed for partial owned ranges until DGR-037 binds its worker to this execution contract. No native source or patch-stack file was changed here, so native CMake/CTest and patch-cycle gates are not applicable to this Python contract change. +- `.venv/bin/python3` has no `pytest` module in this worktree. The available project validation interpreter above ran the exact targeted tests. + +## Dependency handoff + +- DGR-036 should use `DenseRangeBoundaryExecutor` with its real-engine bridge to compare whole-model and split residual/logits outputs, including prefill and decode. +- DGR-037 must adapt the pinned llama.cpp dense graph to `embed_tokens`, `run_layers`, and tail-only `tail_output`; it must preserve `dense.residual.v1` unnormalized and avoid row pruning until the tail. +- DGR-069 can propose only a generic residual-in/residual-out llama.cpp hook; architecture names and Meshnet wire/session semantics remain outside upstream. diff --git a/packages/node/meshnet_node/architecture_boundary.py b/packages/node/meshnet_node/architecture_boundary.py index af1bed1..6d76df4 100644 --- a/packages/node/meshnet_node/architecture_boundary.py +++ b/packages/node/meshnet_node/architecture_boundary.py @@ -20,6 +20,14 @@ from .native_protocol import ( pb, validate_tail_result, ) +from .shard_engine import BoundaryBundle, EngineTensor + + +# This is deliberately an execution-boundary name, not a transport name. It +# identifies the value *before* final norm/output projection. A future wire +# codec may rename its field, but cannot reinterpret this value as logits. +DENSE_LLAMA_ARCHITECTURE = "dense-llama" +DENSE_RESIDUAL_BOUNDARY_V1 = "dense.residual.v1" class Architecture(str, Enum): @@ -63,6 +71,11 @@ class TailOutput: raise ProtocolError("sampled token id must be non-negative") return cls("sampled_token", token_id) + @classmethod + def logits(cls, logits: object) -> "TailOutput": + """Return raw logits under the explicit tail-only output contract.""" + return cls("logits", logits) + @dataclass(frozen=True) class TypedTailResult: @@ -148,28 +161,153 @@ class ArchitectureBoundaryAdapter: raise ProtocolError("tail result architecture does not match certified adapter") if not identity.request_id or not identity.runtime_recipe_digest: raise ProtocolError("tail result requires exact request and recipe identity") - if output.kind != "sampled_token": + if output.kind == "sampled_token": + if not isinstance(output.value, int): + raise ProtocolError("sampled tail output must carry an integer token id") + message = pb.TailResult( + identity=pb.RequestRecipeIdentity( + request_id=identity.request_id, + runtime_recipe_digest=identity.runtime_recipe_digest, + chat_template_id=identity.chat_template_id, + chat_template_version=identity.chat_template_version, + reasoning_mode=identity.reasoning_mode, + architecture=self.protocol_architecture, + ), + sampling=pb.SamplingParameters( + temperature=sampling.temperature, + top_p=sampling.top_p, + top_k=sampling.top_k, + seed=sampling.seed, + greedy=sampling.temperature == 0.0, + ), + sampled_token_id=output.value, + ) + elif output.kind == "logits": + if not isinstance(output.value, pb.TensorBundle): + raise ProtocolError("logits tail output must carry a TensorBundle") + # Validate the logits bundle before putting it in the result; this + # rejects an incompatible boundary schema rather than passing an + # opaque tensor on to sampling. + from .native_protocol import decode_bundle + + decode_bundle(output.value) + message = pb.TailResult( + identity=pb.RequestRecipeIdentity( + request_id=identity.request_id, + runtime_recipe_digest=identity.runtime_recipe_digest, + chat_template_id=identity.chat_template_id, + chat_template_version=identity.chat_template_version, + reasoning_mode=identity.reasoning_mode, + architecture=self.protocol_architecture, + ), + sampling=pb.SamplingParameters( + temperature=sampling.temperature, + top_p=sampling.top_p, + top_k=sampling.top_k, + seed=sampling.seed, + greedy=sampling.temperature == 0.0, + ), + logits=output.value, + ) + else: raise ProtocolError("uncertified tail output kind") - message = pb.TailResult( - identity=pb.RequestRecipeIdentity( - request_id=identity.request_id, - runtime_recipe_digest=identity.runtime_recipe_digest, - chat_template_id=identity.chat_template_id, - chat_template_version=identity.chat_template_version, - reasoning_mode=identity.reasoning_mode, - architecture=self.protocol_architecture, - ), - sampling=pb.SamplingParameters( - temperature=sampling.temperature, - top_p=sampling.top_p, - top_k=sampling.top_k, - seed=sampling.seed, - greedy=sampling.temperature == 0.0, - ), - sampled_token_id=int(output.value), - ) validate_tail_result(message) - return TypedTailResult(identity, sampling, "sampled_token_id", message) + return TypedTailResult(identity, sampling, message.WhichOneof("output"), message) + + +@dataclass(frozen=True) +class DenseLayerRange: + """A certified, inclusive dense-Llama range within one loaded model.""" + + start_layer: int + end_layer: int + total_layers: int + architecture: str = DENSE_LLAMA_ARCHITECTURE + + def __post_init__(self) -> None: + if self.architecture != DENSE_LLAMA_ARCHITECTURE: + raise ProtocolError("dense boundary executor only certifies dense-llama") + if self.start_layer < 0 or self.end_layer < self.start_layer: + raise ProtocolError("dense range is empty or inverted") + if self.total_layers <= self.end_layer: + raise ProtocolError("dense range lies outside the model") + + @property + def is_head(self) -> bool: + return self.start_layer == 0 + + @property + def is_tail(self) -> bool: + return self.end_layer == self.total_layers - 1 + + +class DenseRangeBoundaryExecutor: + """Execute one dense range without leaking endpoint ownership. + + ``run_layers`` owns only the local transformer blocks and receives/returns + the raw residual. It never receives a final norm/head callback. Only a + tail range receives ``tail_output``; consequently row pruning and logits + projection cannot accidentally happen before the final stage. + """ + + def __init__( + self, + layer_range: DenseLayerRange, + *, + embed_tokens: Callable[[tuple[int, ...]], EngineTensor], + run_layers: Callable[[EngineTensor], EngineTensor], + tail_output: Callable[[EngineTensor], TailOutput] | None = None, + ) -> None: + if layer_range.is_tail != (tail_output is not None): + raise ProtocolError("only a dense tail range may own final norm/output") + self._range = layer_range + self._embed_tokens = embed_tokens + self._run_layers = run_layers + self._tail_output = tail_output + + def execute( + self, + *, + token_ids: tuple[int, ...] | None = None, + boundary: BoundaryBundle | None = None, + ) -> BoundaryBundle | TailOutput: + if self._range.is_head: + if token_ids is None or boundary is not None or not token_ids: + raise ProtocolError("dense head accepts non-empty token ids and no boundary bundle") + residual = self._embed_tokens(token_ids) + else: + if token_ids is not None or boundary is None: + raise ProtocolError("dense middle/tail requires a named residual boundary bundle") + residual = self._residual_from_boundary(boundary) + + residual = self._run_layers(residual) + if residual.name != HIDDEN_STATES: + raise ProtocolError("dense range must return hidden_states residual") + + if self._range.is_tail: + assert self._tail_output is not None + output = self._tail_output(residual) + if output.kind not in {"logits", "sampled_token"}: + raise ProtocolError("dense tail returned an uncertified output kind") + return output + + # Do not normalize, project, sample, or prune rows here: this exact + # raw output becomes the next range's input. + return BoundaryBundle( + tensors=(residual,), + architecture=DENSE_LLAMA_ARCHITECTURE, + boundary_point=DENSE_RESIDUAL_BOUNDARY_V1, + ) + + @staticmethod + def _residual_from_boundary(boundary: BoundaryBundle) -> EngineTensor: + if boundary.architecture != DENSE_LLAMA_ARCHITECTURE: + raise ProtocolError("boundary architecture is not certified dense-llama") + if boundary.boundary_point != DENSE_RESIDUAL_BOUNDARY_V1: + raise ProtocolError("incompatible dense residual boundary schema") + if len(boundary.tensors) != 1 or boundary.tensors[0].name != HIDDEN_STATES: + raise ProtocolError("dense residual boundary requires exactly one hidden_states tensor") + return boundary.tensors[0] _ADAPTERS = { diff --git a/tests/test_architecture_boundary.py b/tests/test_architecture_boundary.py index 70017e1..88df673 100644 --- a/tests/test_architecture_boundary.py +++ b/tests/test_architecture_boundary.py @@ -14,7 +14,7 @@ from meshnet_node.architecture_boundary import ( TailOutput, adapter_for, ) -from meshnet_node.native_protocol import ProtocolError, decode_bundle +from meshnet_node.native_protocol import ProtocolError, decode_bundle, encode_bundle, encode_tensor, pb def _f32(values: list[float]) -> bytes: @@ -119,3 +119,29 @@ def test_typed_tail_result_binds_sampling_and_request_recipe_identity() -> None: assert result.sampled_token_id == 42 assert result.output_kind == "sampled_token_id" assert result.message.WhichOneof("output") == "sampled_token_id" + + +def test_typed_tail_result_accepts_validated_logits_under_the_explicit_contract() -> None: + adapter = adapter_for(Architecture.DENSE) + identity = ProtocolIdentity( + request_id="request-1", + runtime_recipe_digest="sha256:recipe", + chat_template_id="llama3", + chat_template_version="2", + reasoning_mode="max", + architecture=Architecture.DENSE, + ) + logits = encode_bundle( + [encode_tensor("logits", _f32([0.1, 0.9]), [1, 2], pb.DTYPE_FLOAT32)], + architecture=adapter.protocol_architecture, + boundary_point="dense.tail.logits.v1", + ) + + result = adapter.tail_result( + identity=identity, + sampling=SamplingParameters(temperature=0.7, top_p=0.9, top_k=20, seed=9), + output=TailOutput.logits(logits), + ) + + assert result.output_kind == "logits" + assert result.message.WhichOneof("output") == "logits" diff --git a/tests/test_dense_range_boundary.py b/tests/test_dense_range_boundary.py new file mode 100644 index 0000000..d230b28 --- /dev/null +++ b/tests/test_dense_range_boundary.py @@ -0,0 +1,87 @@ +"""DGR-035 dense range boundary execution contract.""" + +from __future__ import annotations + +import struct + +import pytest + +from meshnet_node.architecture_boundary import ( + DENSE_LLAMA_ARCHITECTURE, + DENSE_RESIDUAL_BOUNDARY_V1, + DenseLayerRange, + DenseRangeBoundaryExecutor, + TailOutput, +) +from meshnet_node.native_protocol import HIDDEN_STATES, ProtocolError +from meshnet_node.shard_engine import BoundaryBundle, EngineTensor + + +def _tensor(values: tuple[float, ...]) -> EngineTensor: + return EngineTensor(HIDDEN_STATES, (1, len(values)), "f32", struct.pack("<" + "f" * len(values), *values)) + + +def _values(tensor: EngineTensor) -> tuple[float, ...]: + return struct.unpack("<" + "f" * (len(tensor.data) // 4), tensor.data) + + +def _embed(token_ids: tuple[int, ...]) -> EngineTensor: + return _tensor(tuple(float(token) for token in token_ids)) + + +def _layers(residual: EngineTensor) -> EngineTensor: + return _tensor(tuple(value + 10.0 for value in _values(residual))) + + +def test_head_and_middle_handoff_the_same_unnormalized_named_residual() -> None: + head = DenseRangeBoundaryExecutor(DenseLayerRange(0, 1, 4), embed_tokens=_embed, run_layers=_layers) + middle = DenseRangeBoundaryExecutor(DenseLayerRange(2, 2, 4), embed_tokens=_embed, run_layers=_layers) + + head_out = head.execute(token_ids=(1, 2)) + assert isinstance(head_out, BoundaryBundle) + assert head_out.architecture == DENSE_LLAMA_ARCHITECTURE + assert head_out.boundary_point == DENSE_RESIDUAL_BOUNDARY_V1 + assert _values(head_out.tensors[0]) == (11.0, 12.0) + + middle_out = middle.execute(boundary=head_out) + assert isinstance(middle_out, BoundaryBundle) + # The raw residual is carried through. No tail norm/output or row pruning + # can run because this executor has no tail callback. + assert _values(middle_out.tensors[0]) == (21.0, 22.0) + + +def test_tail_bypasses_embedding_and_has_an_explicit_sampled_output_contract() -> None: + tail = DenseRangeBoundaryExecutor( + DenseLayerRange(3, 3, 4), + embed_tokens=_embed, + run_layers=_layers, + tail_output=lambda residual: TailOutput.sampled_token(int(sum(_values(residual)))), + ) + boundary = BoundaryBundle((_tensor((3.0, 4.0)),), DENSE_LLAMA_ARCHITECTURE, DENSE_RESIDUAL_BOUNDARY_V1) + + result = tail.execute(boundary=boundary) + assert result == TailOutput.sampled_token(27) + with pytest.raises(ProtocolError, match="requires"): + tail.execute(token_ids=(3,)) + + +def test_uncertified_architecture_and_incompatible_schema_fail_closed() -> None: + with pytest.raises(ProtocolError, match="only certifies"): + DenseLayerRange(0, 0, 1, architecture="unchecked") + + middle = DenseRangeBoundaryExecutor(DenseLayerRange(1, 1, 3), embed_tokens=_embed, run_layers=_layers) + bad_architecture = BoundaryBundle((_tensor((1.0,)),), "moe", DENSE_RESIDUAL_BOUNDARY_V1) + with pytest.raises(ProtocolError, match="not certified"): + middle.execute(boundary=bad_architecture) + bad_schema = BoundaryBundle((_tensor((1.0,)),), DENSE_LLAMA_ARCHITECTURE, "post_middle_residual") + with pytest.raises(ProtocolError, match="incompatible"): + middle.execute(boundary=bad_schema) + + +def test_only_tail_can_be_given_final_norm_and_output_ownership() -> None: + with pytest.raises(ProtocolError, match="only a dense tail"): + DenseRangeBoundaryExecutor( + DenseLayerRange(0, 1, 4), embed_tokens=_embed, run_layers=_layers, tail_output=TailOutput.sampled_token + ) + with pytest.raises(ProtocolError, match="only a dense tail"): + DenseRangeBoundaryExecutor(DenseLayerRange(3, 3, 4), embed_tokens=_embed, run_layers=_layers)