# DGR-031 evidence — the project-owned `ShardEngine` interface

**Completed:** 2026-07-23
**Branch:** `ralph/distributed-gguf-runtime`
**Authority:** `.scratch/distributed-gguf-runtime/prd.json`
**Dependencies:** DGR-021 (`evidence/DGR-021/README.md` — versioned activation
envelope, `NamedTensor`/`ActivationEnvelope` as the project-owned wire-envelope
layer), DGR-025 (`evidence/DGR-025/README.md` — exact artifact/runtime recipe
identity; both read before changing code).

## Objective

Isolate worker/protocol code from llama.cpp internals behind a stable
project-owned engine contract, so a fake fixture engine (DGR-032) and a real
llama.cpp-backed engine (DGR-037) are interchangeable subclasses of one
interface.

## What was found live before changing code

Per RALPH-CONTEXT, legacy pass states were not trusted; the live surrounding
contracts were read and exercised before designing this one:

- `packages/node/meshnet_node/shard_lifecycle.py` (DGR-022) already defines a
  versioned RPC/session lifecycle contract — `StructuredStatus`, `StatusCode`,
  `CacheExpectation`, `CacheResult`, `LifecycleState`, `SessionLifecycle` — but
  it is explicitly the *wire RPC* contract "consumed by a future generated
  gRPC binding," not an execution-engine boundary.
- `packages/node/meshnet_node/native_backend.py` (DGR-025) is the identity
  boundary for the native GGUF artifact — it derives and attests a
  `ShardIdentity`, but does not define an execution contract either.
- `packages/node/meshnet_node/protocol.py` (DGR-021) defines a project-owned
  `NamedTensor`/`ActivationEnvelope` for activation traffic *between shard
  hops over the network*, distinct from the generated-protobuf wire ABI in
  `native_protocol`.
- `packages/node/meshnet_node/shard_runtime_server.py` (DGR-024) is today a
  real gRPC servicer that proves wire fidelity by checksumming and echoing
  bytes — it has no execution engine behind it yet; that seam is exactly
  where `ShardEngine` plugs in for DGR-037.
- `packages/node/meshnet_node/architecture_boundary.py` established the
  precedent this story follows for tail output: `TailOutput.sampled_token()`
  never exposes raw logits, only a sampled token id.
- No `ShardEngine` (or `shard_engine`) symbol existed anywhere in the
  repository prior to this story (confirmed by
  `grep -rn -i "shardengine\|shard_engine"` across `.py`/`.md`, which returned
  only planning-document prose naming it as future work).

Live verification of the pre-existing dependency contracts before adding new
code: `PYTHONPATH=packages/node:packages/tracker .venv/bin/python3 -m pytest -q
tests/test_shard_lifecycle.py tests/test_activation_envelope.py
tests/test_architecture_boundary.py tests/test_native_shard_protocol.py
tests/test_shard_runtime_harness.py` → `95 passed, 3 skipped`.

## What was added (this story's change)

### `packages/node/meshnet_node/shard_engine.py` (new)

The `ShardEngine` boundary: an `abc.ABC` with eight abstract operations —
`load`, `capabilities`, `prefill`, `decode`, `cancel`, `release`, `health`,
`metrics` — matching the acceptance criterion's list exactly (`prefill`/
`decode` share one operation family; their shared result type is what the
criterion calls the "boundary/logits result"). Every request/result type is a
frozen dataclass built from plain `str`/`int`/`bytes`/`Mapping` values:

- `EngineTensor` / `BoundaryBundle` — the project-owned named-tensor
  activation crossing a shard boundary (head/middle/tail-in). Deliberately a
  *new*, minimal type distinct from both `native_protocol.pb.TensorBundle`
  (generated-protobuf ABI) and `protocol.NamedTensor`/`ActivationEnvelope`
  (wire-framing/fragmentation concerns irrelevant to model execution) — a
  fourth, execution-facing layer underneath the three that already existed.
- `TokenOutput` — a tail shard's sampled result: a token id (+ optional
  decoded text), never a raw logits tensor.
- `MtpHook` — reserved multi-token-prediction hook; its own `__post_init__`
  raises if constructed with `enabled=True`, so the type exists (fixing its
  field shape for DGR-051/DGR-066) without any code path being able to turn it
  on before DGR-066, matching RALPH-CONTEXT's "MTP is reserved and off for
  alpha."
- `ArchitectureAuxStateHook` — reserved per-shard architecture auxiliary state
  (V4 CSA/HCA/SWA/indexer/compressor and similar); has no wire encoding and is
  never embedded in a `BoundaryBundle`, matching RALPH-CONTEXT's "remain local
  ... never carried over the WAN seam."
- `LoadRequest`/`LoadResult`, `EngineCapabilities`, `PrefillRequest`/
  `DecodeRequest` (exactly one of `token_ids`/`token_id` (head) or `input`
  (middle/tail) required — enforced in `__post_init__`), `StepResult` (a
  successful result must carry an output; `cache_result` reuses
  `shard_lifecycle.CacheResult`), `HealthResult`, `MetricsResult`.
- Status vocabulary is reused, not reinvented: `StructuredStatus`/
  `StatusCode`/`CacheExpectation`/`CacheResult` are imported from
  `shard_lifecycle` (already project-owned and version-stable) rather than a
  parallel enum living alongside it.
- The module imports nothing from `native_protocol`, `grpc`, or `ctypes` —
  verified structurally, not just by convention (see tests below).

### `tests/shard_engine_contract.py` (new)

A reusable, non-`test_`-prefixed helper: `assert_shard_engine_contract(make_engine)`
takes a zero-arg engine factory and runs nine lifecycle checks — health before
load, load→capabilities range/MTP-off, prefill→decode determinism (byte-identical
output replayed on a fresh session), middle-shard boundary-bundle-in/out vs.
head/tail token-output, deterministic cache-miss on an unopened session,
stale-route-epoch rejection, cancel-then-decode rejection (+ cancel
idempotency), release-then-decode rejection (+ release idempotency), and
metrics reporting cancelled sessions. DGR-032's fixture and DGR-037's
llama.cpp binding are both expected to import this and pass it against their
own engine, proving identical lifecycle semantics without duplicating the
checks.

### `tests/test_shard_engine.py` (new)

- `_ReferenceEngine`: a minimal in-memory `ShardEngine` used only to prove the
  shared contract is non-vacuous. It is explicitly *not* the DGR-032
  deterministic fixture (no delay/memory-pressure/malformed/crash injection —
  that is DGR-032's own, larger scope); the docstring says so to prevent this
  story's evidence from being read as inherited completion credit for DGR-032.
- Dataclass validation tests: abstract-class instantiation refusal, tensor/
  bundle/token-output field validation, MTP-hook enable refusal, exactly-one-
  input-kind enforcement on `PrefillRequest`/`DecodeRequest`, `LoadRequest`
  shard-range-vs-total-layers validation, `StepResult` output-required-on-OK.
- `test_shard_engine_module_imports_no_native_or_grpc_or_wire_abi_types`:
  walks `vars(shard_engine_module)` and asserts no bound name's `__name__` is
  `ctypes`, `grpc`, or `meshnet_node.native_protocol` — a structural check
  (not a docstring-text grep, which produced a false positive on first draft
  because the module's own docstring *names* `ggml_tensor` as an example of
  what must never appear) that the ABI-isolation acceptance criterion holds.

### `.scratch/distributed-gguf-runtime/prd.json` / issue markdown

Marked `DGR-031.passes = true` with `completionNotes`; regenerated
`issues/031-introduce-the-project-owned-shardengine-interface.md` via
`scripts/ralph_prd_schema.py render` so it matches `prd.json` byte-for-byte.

## Acceptance criteria → evidence

1. **load/capabilities/prefill/decode/boundary-logits-result/cancel/release/
   health/metrics** — `ShardEngine`'s eight abstract methods plus
   `StepResult.output: BoundaryBundle | TokenOutput | None`. Verified by
   `test_reference_engine_obeys_the_shared_shard_engine_contract` and the
   middle-shard-vs-tail-shard assertion inside
   `assert_shard_engine_contract`.
2. **No `ggml_tensor`/llama context/scheduler/ABI-owned structure** — every
   type in `shard_engine.py` is a plain dataclass over `str`/`int`/`bytes`/
   `Mapping`; no import of `native_protocol`, `grpc`, or `ctypes`. Verified by
   `test_shard_engine_module_imports_no_native_or_grpc_or_wire_abi_types`.
3. **Reserved typed MTP/architecture-aux-state hooks, not enabled** —
   `MtpHook.__post_init__` raises on `enabled=True`; `ArchitectureAuxStateHook`
   carries opaque shard-local state with no wire path. Verified by
   `test_mtp_hook_is_reserved_and_refuses_to_enable` and
   `test_architecture_aux_state_hook_carries_opaque_shard_local_state`, plus
   `assert_shard_engine_contract`'s `caps.supports_mtp is False` check.
4. **Contract tests proving fake and future llama implementations obey
   identical lifecycle semantics** — `tests/shard_engine_contract.py` is
   written to be imported by DGR-032 and DGR-037 against their own engines;
   `test_shard_engine.py` proves it is real by running it against
   `_ReferenceEngine`.
5. **Gates + this handoff** — below.

## Commands and results

```bash
PYTHONPATH=packages/node:packages/tracker .venv/bin/python3 -m pytest -q tests/test_shard_engine.py
```
```text
12 passed in 0.13s
```

```bash
PYTHONPATH=packages/node:packages/tracker .venv/bin/python3 -m pytest -q \
  tests/test_shard_engine.py tests/test_shard_lifecycle.py \
  tests/test_architecture_boundary.py tests/test_activation_envelope.py \
  tests/test_native_shard_protocol.py tests/test_shard_runtime_harness.py
```
```text
95 passed, 3 skipped in 3.65s
```

```bash
.venv/bin/python3 -m compileall packages/node/meshnet_node/shard_engine.py tests/shard_engine_contract.py tests/test_shard_engine.py
```
```text
Compiling 'packages/node/meshnet_node/shard_engine.py'...
Compiling 'tests/shard_engine_contract.py'...
Compiling 'tests/test_shard_engine.py'...
```

```bash
git diff --check
```
```text
(no output — clean)
```

## Limitations

- `tests/` as a whole does not collect cleanly in this environment: 27
  pre-existing test modules fail to import for missing optional dependencies
  (`cryptography`, etc.) unrelated to this story. Reproduced identically with
  `git stash` before this session's change (`27 errors during collection`),
  so this is pre-existing environment state, not a regression introduced
  here. This story's own gates were run as the targeted, scoped test set
  above per the shared quality gates' own wording ("Targeted deterministic
  tests pass").
- The contract in `shard_engine_contract.py` proves *lifecycle* semantics
  (gating, cache-miss/stale-epoch/cancel/release, boundary-vs-token output
  shape) are identical across implementations. It does not — and cannot yet
  — prove numerical parity between a fake and a real engine; that is
  DGR-036's explicit job once DGR-032 and DGR-037 both exist.
- `_ReferenceEngine` in `test_shard_engine.py` is intentionally minimal
  (no delay/memory-pressure/malformed-output/crash injection). DGR-032's
  acceptance criteria require those independently; nothing here should be
  read as satisfying them.
- No gRPC/CMake/native-build changes were needed or made — this story is
  pure Python interface/type definition (`evidenceClass: model-free`,
  `hardware: none`), so the native CMake/CTest and patch-stack gates in the
  shared quality-gate list do not apply here (consistent with DGR-021/DGR-025,
  which record the same non-applicability for non-native stories).

## Dependency handoff

- **DGR-032** (fake `ShardEngine`): subclass `ShardEngine`, add delay/memory-
  pressure/malformed-output/crash injection, and pass the *same*
  `assert_shard_engine_contract` from `tests/shard_engine_contract.py`
  against it — no new contract vocabulary should be needed.
- **DGR-034/DGR-035** (range-aware GGUF ownership, boundary I/O): `LoadRequest`
  already carries `shard_start`/`shard_end`/`total_layers`/`recipe`; `capabilities()`
  reports the authoritative range via `EngineCapabilities.is_head`/`is_tail`.
  `BoundaryBundle.token_id_sideband` is reserved for the first-three-hash-
  routed-layers V4 requirement RALPH-CONTEXT documents.
- **DGR-037** (bind llama.cpp to the worker): implement `ShardEngine` as a
  thin wrapper around the native artifact from `native_backend.py`/
  `runtime_recipe.py`; `shard_runtime_server.py`'s `Session`/`GetCapability`/
  `Health`/`Cancel`/`Release` handlers become the translation layer between
  `pb.*` wire messages and this module's request/result types — this story
  intentionally does not touch `shard_runtime_server.py` itself, since that
  wiring is DGR-037's scope.
- **DGR-051** (V4 `ShardEngine` adapter): `MtpHook`/`ArchitectureAuxStateHook`
  fix the field shape now so the V4 adapter does not need a breaking change
  to enable MTP after DGR-066 or to carry CSA/HCA/SWA/indexer/compressor
  state.
