feat: pin runtime identity to the exact llama.cpp patch stack (DGR-025)

Derive the recipe's runtime_version axis from the DGR-027 lock manifest
(exact upstream commit + ordered patch-stack byte digest) in new
meshnet_node.runtime_pin, failing closed on any lock/series/SHA256SUMS/
patch disagreement, and enforce pin discipline on runtime_version in both
the node and tracker identity implementations.

Also repair pre-existing backlog consistency: add missing DGR-022/DGR-027
completionNotes, regenerate the DGR-022/025/027 issue projections, and
relocate three pre-DGR legacy GLM issue files to issues/legacy/. Mark
DGR-025 passes=true with evidence at evidence/DGR-025/README.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dobromir Popov
2026-07-17 22:59:22 +03:00
parent f83cf331c3
commit ad66f7a4d8
12 changed files with 740 additions and 25 deletions

View File

@@ -0,0 +1,206 @@
# DGR-025 evidence — exact artifact and runtime recipe identity
**Completed:** 2026-07-17
**Branch:** `ralph/fable-architecture-loop` (Claude Fable architecture lane)
**Authority:** `.scratch/distributed-gguf-runtime/prd.json`
**Dependencies:** DGR-018 (`evidence/DGR-018/README.md` — canonical backlog schema and
issue projection), DGR-021 (`evidence/DGR-021/README.md` — versioned activation
envelope). Both read before changing code.
## Objective
Ensure the tracker and worker only combine numerically and operationally
compatible shards: fingerprint every axis that moves the numbers, bind shards to
exact half-open ranges, fail closed on any mismatch, and keep uncertified
recipes registered-but-dark.
## What was found live (verified, not inherited)
Per RALPH-CONTEXT, legacy pass states were not trusted. The DGR-003-lineage
identity core was inspected and exercised live before any change:
- `packages/node/meshnet_node/runtime_recipe.py` — node-side identity:
domain-separated digests (`meshnet.model-artifact.v1`,
`meshnet.runtime-recipe.v1`, `meshnet.shard-binding.v1`) over the source
artifact SHA (`source_digest`, with split artifacts bound to their exact
source via `DerivativeBinding`), tokenizer revision (pin-enforced),
architecture adapter + architecture/config digest, boundary and protocol
schema versions, backend, weight quantization, activation/compute dtypes, and
KV dtype/layout (`RECIPE_AXES`). Shard ranges are half-open
(`shard_start`/`shard_end`, end-exclusive, protocol convention) with no
topology or quant constants anywhere; `check_route` accepts any tiling of
`[0, layer_count)`. Route, handshake (`check_handshake`), and session-open
(`check_session_open`) checks fail closed with structured `RouteMismatch`
reasons mapped to specific protocol error codes (`handshake_error`).
- `packages/tracker/meshnet_tracker/recipe.py` — deliberately independent
tracker re-derivation (no `meshnet_node` import); declared fingerprints are
recomputed, never trusted (`parse_identity`, `FingerprintMismatch`). The
`CertificationLedger` keeps every registered recipe dark until a real
distributed forward — at least 2 distinct nodes, whole-model coverage,
non-synthetic, tokens actually generated — certifies it; dark recipes may
route only to certify.
- The two implementations are pinned by committed conformance vectors
(`tests/data/recipe_fingerprint_vectors.json`).
Live verification of that pre-existing core before changes:
`PYTHONPATH=packages/node:packages/tracker python3 -m pytest -q tests/test_runtime_recipe_identity.py`
`45 passed`; plus `tests/test_native_identity_emission.py`,
`tests/test_tracker_capability_admission.py`, `tests/test_node_admission.py`
`59 passed`.
## Gap found and closed (this story's change)
**The `runtime_version` recipe axis was a label, not a pin.** It was an opaque
caller-supplied string: nothing derived it from the DGR-027 lock manifest, and
neither identity implementation rejected a moving reference (`"latest"` was
accepted), so two workers could run different llama.cpp pins or patch stacks
under one label and still agree on the recipe digest. The acceptance criterion
explicitly requires fingerprinting the "runtime pin/patch stack".
### Changed files
- `packages/node/meshnet_node/runtime_pin.py` (new) — derives the canonical
`runtime_version` axis value from the DGR-027 lock workspace
(`packages/node/native/llama`):
`<runtime>@<40-hex upstream commit>+patchstack.<sha256>` where the stack
digest commits, under the `meshnet.runtime-patch-stack.v1` domain, to the
*ordered* `(patch name, patch bytes sha256)` stack. Fails closed on: missing
or malformed `UPSTREAM_LOCK.json`, unknown schema version, non-40-hex/moving
commit, `UPSTREAM_COMMIT` disagreement, any disagreement among the lock's
`patch_series`, `patches/series`, and `patches/SHA256SUMS`, a missing patch
file, or a patch whose bytes don't match their recorded digest. Reads the
committed manifest only; fetching/patching stays with
`scripts/llama_cpp_dependency.py` (DGR-027).
- `packages/node/meshnet_node/runtime_recipe.py``runtime_version` is now
pin-enforced (`_require_pin`) exactly like `tokenizer_revision`; docstring
points at the canonical derivation.
- `packages/tracker/meshnet_tracker/recipe.py` — the independent tracker
implementation applies the same pin rule in `parse_identity`, keeping the two
implementations in step.
- `tests/test_runtime_pin_identity.py` (new, TDD — written first and observed
failing) — 17 deterministic tests: the committed manifest derives a
deterministic pin whose axis value is a valid recipe pin; a changed patch
byte and a reordered stack each change the runtime identity; every manifest
disagreement above fails closed; and both node and tracker reject a moving
`runtime_version`.
### Backlog-consistency repair (pre-existing damage, honestly recorded)
`tests/test_ralph_prd_schema.py` had 4 pre-existing failures before this story
touched anything, left by prior sessions and the alternate-history merge:
- DGR-022 and DGR-027 were marked `passes: true` without `completionNotes` and
without regenerated issue projections. Added their `completionNotes`
(explicitly labeled as added during this repair, content drawn from their own
evidence READMEs) and regenerated
`issues/022-…` / `issues/027-…` via `scripts/ralph_prd_schema.py render`.
- Three pre-DGR legacy GLM alpha issue files (`18-…`, `19-…`, `20-…`,
committed 2026-07-14, before DGR-018 established the generated-only
convention; they carry no authority disclaimer because they are *not*
generated from prd.json) were relocated via `git mv` to
`issues/legacy/` — preserved as provenance, out of the generated namespace.
### prd.json
Marked `DGR-025.passes = true` with `completionNotes`; regenerated
`issues/025-define-exact-artifact-and-runtime-recipe-identity.md`.
## Acceptance criteria → evidence
1. **Fingerprint all axes**`RECIPE_AXES` + `ArtifactIdentity` cover source
artifact SHA, tokenizer revision, architecture adapter/version (adapter axis
+ architecture/config digest), boundary schema (boundary + protocol schema
versions), backend, quant, activation/compute dtype, KV/state layout; the
runtime pin/patch stack is now committed via the derived `runtime_version`
axis (`runtime_pin.py`). Verified by `test_runtime_recipe_identity.py` and
`test_runtime_pin_identity.py`.
2. **Exact half-open range, no hardcoded topology/quant**`ShardIdentity`
end-exclusive ranges, `DerivativeBinding` coverage checks, `check_route`
tiling over arbitrary layouts; quant/dtype values are open strings
(dynamic recipe inputs). Verified by `test_runtime_recipe_identity.py`
(routes of 1, 2, and 5 shards; no product constants).
3. **Fail closed on any mismatch** — artifact, adapter, boundary/schema, cache
layout, backend, and runtime mismatches each produce structured
`RouteMismatch` reasons and protocol error codes; the tracker recomputes
digests and rejects inconsistent claims; moving runtime references are now
rejected on both sides.
4. **Registered-but-dark**`CertificationLedger`: unknown recipes cannot be
certified, registered recipes are dark, only a real ≥2-distinct-node
whole-model non-synthetic forward promotes; verified by
`test_runtime_recipe_identity.py` / `test_tracker_capability_admission.py`.
5. **Gates + this handoff** — below.
## Commands and results
```bash
PYTHONPATH=packages/node:packages/tracker python3 -m pytest -q tests/test_runtime_pin_identity.py
```
```text
17 passed in 0.11s
```
```bash
PYTHONPATH=packages/node:packages/tracker python3 -m pytest -q \
tests/test_runtime_pin_identity.py tests/test_runtime_recipe_identity.py \
tests/test_native_identity_emission.py tests/test_tracker_capability_admission.py \
tests/test_node_admission.py tests/test_node_capability.py tests/test_recipe_benchmark.py
```
```text
196 passed, 1 warning in 5.35s
```
```bash
PYTHONPATH=packages/node:packages/tracker python3 -m pytest -q tests/test_ralph_prd_schema.py
```
```text
108 passed
```
(4 failed before this story's backlog repair; 0 after.)
```bash
python3 -m compileall -q packages tests # exit 0
git diff --check # exit 0
python3 scripts/ralph_prd_schema.py validate .scratch/distributed-gguf-runtime/prd.json
# OK: 55 stories validated.
```
Default tests are model-download-free, API-credit-free, and GPU-free; no model
artifact was touched and nothing was written under `/home`.
## Limitations
- `runtime_pin.py` proves what the *manifest* pins; it does not prove the
running binary was built from that manifest. Binding the built native worker
to the pin it reports (e.g. embedding the patched-tree hash at build time and
echoing it through the DGR-022 status contract) belongs with the native
worker stories (DGR-028+/DGR-031); until then `runtime_version` is exactly as
trustworthy as the rest of the declared axes — a claim the tracker digests,
with real distributed certification as the trust boundary (unchanged design).
- The DGR-027-recorded blocker stands: `0002-dense-llama-owned-range-loader.patch`
does not apply cleanly against the pin (DGR-028). That does not affect this
story: the identity commits to the patch *bytes as committed*, which is
precisely what makes a later repaired patch a *different* runtime identity.
- No native/CMake change was made, so the native build/CTest gate is not
applicable; no llama.cpp patch content was changed, so apply/check/reverse
verification is not applicable (and is blocked by the DGR-028 defect anyway).
- Tracker routing, load balancing, billing, telemetry, and relay semantics are
untouched; the only behavior change outside the new module is the stricter
(fail-closed) rejection of moving `runtime_version` values.
## Dependency handoff
- **DGR-026** (split-GGUF provisioning): bind each provisioned split via
`DerivativeBinding` to the exact source digest recorded in its hashed
manifest; the per-split `shard_binding_digest` is what certification pins.
- **DGR-031** (`ShardEngine`): construct worker identity through
`shard_identity_from_native_report` and populate `runtime_version` from
`meshnet_node.runtime_pin.load_runtime_pin().runtime_version` — never from an
operator string. A build-time echo of the patched-tree hash through the
status contract would close the manifest-vs-binary gap noted above.
- **DGR-041** (capability registration): the tracker already re-derives and
fail-closes on presented identities (`parse_identity`); register recipes
through the `CertificationLedger` so they arrive dark.
- **DGR-044** (DeepSeek V4 Flash target): pin the target's artifact identity
the same way `glm_alpha_artifact` does — read locked manifests, never restate
digests — and note `layer_count` must count the routed transformer stack the
route tiles, excluding MTP (reserved for beta).

View File

@@ -1,7 +1,7 @@
<!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. --> <!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. -->
# DGR-022: Define Shard lifecycle and structured status RPCs # DGR-022: Define Shard lifecycle and structured status RPCs
- **Status / triage:** specification only; `ready-for-agent`; `passes: false` - **Status / triage:** completed; `passes: true`
- **Execution mode:** `AFK` - **Execution mode:** `AFK`
- **Milestone:** `M1` - **Milestone:** `M1`
- **Dependencies:** `DGR-021` - **Dependencies:** `DGR-021`
@@ -18,11 +18,11 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
## Acceptance criteria ## Acceptance criteria
- [ ] Define capability, health, bidirectional session stream, cancellation, release, and metrics RPCs. - [x] Define capability, health, bidirectional session stream, cancellation, release, and metrics RPCs.
- [ ] Specify deadlines, cancellation propagation, bounded flow control, cache expectations/results, and structured error taxonomy. - [x] Specify deadlines, cancellation propagation, bounded flow control, cache expectations/results, and structured error taxonomy.
- [ ] Specify TLS/auth hooks without moving Meshnet authentication or billing into the worker. - [x] Specify TLS/auth hooks without moving Meshnet authentication or billing into the worker.
- [ ] Add compatibility tests for supported versions and fail-closed tests for unsupported versions and malformed lifecycle transitions. - [x] Add compatibility tests for supported versions and fail-closed tests for unsupported versions and malformed lifecycle transitions.
- [ ] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff. - [x] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff.
## Shared quality gates ## Shared quality gates
@@ -36,4 +36,4 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
## Evidence handoff ## Evidence handoff
Write and verify `.scratch/distributed-gguf-runtime/evidence/DGR-022/README.md`. Until every criterion and applicable gate has real evidence, this story remains `passes: false`. Legacy evidence is provenance only, not completion credit. Verified evidence: `.scratch/distributed-gguf-runtime/evidence/DGR-022/README.md`. Legacy evidence remains provenance only and grants no implementation completion credit.

View File

@@ -1,7 +1,7 @@
<!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. --> <!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. -->
# DGR-025: Define exact artifact and runtime recipe identity # DGR-025: Define exact artifact and runtime recipe identity
- **Status / triage:** specification only; `ready-for-agent`; `passes: false` - **Status / triage:** completed; `passes: true`
- **Execution mode:** `AFK` - **Execution mode:** `AFK`
- **Milestone:** `M1` - **Milestone:** `M1`
- **Dependencies:** `DGR-018`, `DGR-021` - **Dependencies:** `DGR-018`, `DGR-021`
@@ -18,11 +18,11 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
## Acceptance criteria ## Acceptance criteria
- [ ] Fingerprint source artifact SHA, tokenizer revision, architecture adapter/version, boundary schema, runtime pin/patch stack, backend, quant, activation/compute dtype, and KV/state layout. - [x] Fingerprint source artifact SHA, tokenizer revision, architecture adapter/version, boundary schema, runtime pin/patch stack, backend, quant, activation/compute dtype, and KV/state layout.
- [ ] Bind each shard to an exact half-open range without hardcoding a topology or quant. - [x] Bind each shard to an exact half-open range without hardcoding a topology or quant.
- [ ] Fail closed on any artifact, adapter, boundary, cache, backend, or runtime mismatch. - [x] Fail closed on any artifact, adapter, boundary, cache, backend, or runtime mismatch.
- [ ] Unsupported recipes remain registered-but-dark until real-hardware evidence certifies them. - [x] Unsupported recipes remain registered-but-dark until real-hardware evidence certifies them.
- [ ] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff. - [x] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff.
## Shared quality gates ## Shared quality gates
@@ -36,4 +36,4 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
## Evidence handoff ## Evidence handoff
Write and verify `.scratch/distributed-gguf-runtime/evidence/DGR-025/README.md`. Until every criterion and applicable gate has real evidence, this story remains `passes: false`. Legacy evidence is provenance only, not completion credit. Verified evidence: `.scratch/distributed-gguf-runtime/evidence/DGR-025/README.md`. Legacy evidence remains provenance only and grants no implementation completion credit.

View File

@@ -1,7 +1,7 @@
<!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. --> <!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. -->
# DGR-027: Add exact llama.cpp provenance manifest and fetch workspace # DGR-027: Add exact llama.cpp provenance manifest and fetch workspace
- **Status / triage:** specification only; `ready-for-agent`; `passes: false` - **Status / triage:** completed; `passes: true`
- **Execution mode:** `AFK` - **Execution mode:** `AFK`
- **Milestone:** `M1` - **Milestone:** `M1`
- **Dependencies:** `DGR-017` - **Dependencies:** `DGR-017`
@@ -18,11 +18,11 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
## Acceptance criteria ## Acceptance criteria
- [ ] Manifest records upstream URL, exact commit, expected source archive/tree hash, license, and retrieval method. - [x] Manifest records upstream URL, exact commit, expected source archive/tree hash, license, and retrieval method.
- [ ] Fetch tooling verifies identity before use and refuses an unpinned branch/tag. - [x] Fetch tooling verifies identity before use and refuses an unpinned branch/tag.
- [ ] Source is fetched into an ignored build workspace; no submodule, vendored source tree, or permanent fork is introduced. - [x] Source is fetched into an ignored build workspace; no submodule, vendored source tree, or permanent fork is introduced.
- [ ] Offline reuse is supported only after the cached trees exact identity is verified. - [x] Offline reuse is supported only after the cached trees exact identity is verified.
- [ ] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff. - [x] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff.
## Shared quality gates ## Shared quality gates
@@ -36,4 +36,4 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
## Evidence handoff ## Evidence handoff
Write and verify `.scratch/distributed-gguf-runtime/evidence/DGR-027/README.md`. Until every criterion and applicable gate has real evidence, this story remains `passes: false`. Legacy evidence is provenance only, not completion credit. Verified evidence: `.scratch/distributed-gguf-runtime/evidence/DGR-027/README.md`. Legacy evidence remains provenance only and grants no implementation completion credit.

View File

@@ -489,7 +489,8 @@
"DGR-024", "DGR-024",
"DGR-033", "DGR-033",
"DGR-037" "DGR-037"
] ],
"completionNotes": "Completed 2026-07-17. Implemented the versioned backend-neutral Shard lifecycle/status contract in packages/node/meshnet_node/shard_lifecycle.py (RPC names, schema-version negotiation with fail-closed unsupported versions, structured status/error taxonomy, lifecycle state machine, monotonic idempotency enforcement, bounded flow control, cache expectation/result types, deadline policy and TLS/auth hooks) with deterministic tests in tests/test_shard_lifecycle.py (17 passed alongside the DGR-021 envelope tests). Generated protobuf bindings remain DGR-023. Evidence: evidence/DGR-022/README.md. These completionNotes were added during the DGR-025 backlog-consistency repair; the DGR-022 session omitted them."
}, },
{ {
"id": "DGR-023", "id": "DGR-023",
@@ -597,14 +598,15 @@
"Unsupported recipes remain registered-but-dark until real-hardware evidence certifies them.", "Unsupported recipes remain registered-but-dark until real-hardware evidence certifies them.",
"Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff." "Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff."
], ],
"passes": false, "passes": true,
"notes": "Generated source issue: .scratch/distributed-gguf-runtime/issues/025-define-exact-artifact-and-runtime-recipe-identity.md; prd.json is authoritative.", "notes": "Generated source issue: .scratch/distributed-gguf-runtime/issues/025-define-exact-artifact-and-runtime-recipe-identity.md; prd.json is authoritative.",
"blocks": [ "blocks": [
"DGR-026", "DGR-026",
"DGR-031", "DGR-031",
"DGR-041", "DGR-041",
"DGR-044" "DGR-044"
] ],
"completionNotes": "Completed 2026-07-17. Verified the live DGR-003-lineage identity core against every criterion: node packages/node/meshnet_node/runtime_recipe.py and the independent tracker packages/tracker/meshnet_tracker/recipe.py (pinned together by tests/data/recipe_fingerprint_vectors.json) fingerprint the source artifact SHA, tokenizer pin, architecture adapter and config digest, boundary/protocol schema versions, backend, weight quant, activation/compute dtypes, and KV dtype/layout under domain-separated digests; shards bind to exact half-open ranges with no topology or quant constants; route/handshake/session checks fail closed with structured mismatch reasons; recipes stay registered-but-dark in the tracker CertificationLedger until a real >=2-distinct-node whole-model distributed forward certifies them. Closed the one open criterion gap (runtime pin/patch stack): new packages/node/meshnet_node/runtime_pin.py derives the runtime_version axis from the DGR-027 lock manifest — exact upstream commit plus a digest over the ordered patch-stack bytes — failing closed on any UPSTREAM_LOCK.json/UPSTREAM_COMMIT/series/SHA256SUMS/patch-byte disagreement, and both identity implementations now reject a moving runtime_version reference. Tests: tests/test_runtime_pin_identity.py (17 passed) plus 196 passing impacted identity/admission/native-emission tests; python -m compileall and git diff --check clean. Also repaired backlog consistency left by prior sessions: added the missing DGR-022/DGR-027 completionNotes, regenerated the DGR-022/025/027 issue projections, and relocated three pre-DGR legacy GLM alpha issue files to issues/legacy/."
}, },
{ {
"id": "DGR-026", "id": "DGR-026",
@@ -679,7 +681,8 @@
"DGR-028", "DGR-028",
"DGR-029", "DGR-029",
"DGR-044" "DGR-044"
] ],
"completionNotes": "Completed 2026-07-17. Added the exact llama.cpp provenance manifest packages/node/native/llama/UPSTREAM_LOCK.json pinning commit e920c523e3b8a0163fe498af5bf90df35ff51d25 (tree 6c91a11407a3a3fb160f5dac705f9c59718f54f1) with the sole git-clone-detached-commit retrieval into the ignored build/llama.cpp workspace, fail-closed dirty/mismatched-cache verification, PATCH-STACK.md, scripts/llama_cpp_dependency.py, and tests/test_llama_cpp_dependency.py (7 passed). Known blocker recorded for DGR-028: 0002-dense-llama-owned-range-loader.patch fails git apply --check against the pin, so no patched-tree/native-build claim is made. Evidence: evidence/DGR-027/README.md. These completionNotes were added during the DGR-025 backlog-consistency repair; the DGR-027 session omitted them."
}, },
{ {
"id": "DGR-028", "id": "DGR-028",

View File

@@ -0,0 +1,221 @@
"""Canonical runtime pin identity for the recipe fingerprint (DGR-025).
The recipe digest (:mod:`meshnet_node.runtime_recipe`) commits to a
``runtime_version`` axis, but a string the operator typed is a label, not a
pin: two workers could run different patch stacks under the same label and
still hash to the same recipe. The DGR-027 lock manifest
(``packages/node/native/llama``) already records the one exact upstream commit
and the ordered patch stack the native runtime is built from, so the axis
value is *derived* from that manifest, never asserted.
The derived value has three load-bearing parts, and each is separately fatal
to compatibility: the runtime name (from the upstream URL), the exact
40-character upstream commit, and a digest over the ordered patch-stack bytes.
A different upstream pin, a reordered stack, or a single changed patch byte
each produce a different axis value, which produces a different recipe digest,
which partitions the route — exactly the fail-closed behavior DGR-025 asks
for.
Every consistency check here fails closed. The manifest keeps three records of
the stack — ``UPSTREAM_LOCK.json``'s ``patch_series``, ``patches/series``, and
``patches/SHA256SUMS`` — plus the ``UPSTREAM_COMMIT`` convenience file, and a
disagreement between any two of them means the workspace's identity is
unknowable, not "probably fine". This module reads the committed manifest
only; fetching and patching the actual source tree stays with
``scripts/llama_cpp_dependency.py`` (DGR-027).
"""
from __future__ import annotations
import hashlib
import json
import re
from dataclasses import dataclass
from pathlib import Path
# Domain separation, matching the runtime_recipe digest convention: a patch
# stack digest can never be confused with an artifact or recipe digest.
PATCH_STACK_DIGEST_DOMAIN = "meshnet.runtime-patch-stack.v1"
# The UPSTREAM_LOCK.json layout this reader understands (DGR-027 schema).
RUNTIME_PIN_SCHEMA_VERSION = 1
# The committed DGR-027 manifest for the llama.cpp runtime.
DEFAULT_LOCK_DIR = Path(__file__).resolve().parent.parent / "native" / "llama"
_HEX40 = re.compile(r"^[0-9a-f]{40}$")
_HEX64 = re.compile(r"^[0-9a-f]{64}$")
class RuntimePinError(ValueError):
"""The lock workspace is missing, malformed, or internally inconsistent."""
def _canonical_sha256(value: object) -> str:
payload = json.dumps(
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False
)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
@dataclass(frozen=True)
class RuntimePin:
"""One exact runtime: a name, an upstream commit, and an ordered patch stack."""
runtime_name: str
upstream_commit: str
patch_series: tuple[str, ...]
patch_digests: tuple[str, ...]
@property
def patch_stack_digest(self) -> str:
"""A digest over the ordered (name, bytes-digest) stack.
Order is digested deliberately: applying the same patches in a
different order can produce a different tree, so a reordered stack is
a different runtime.
"""
return _canonical_sha256(
{
"domain": PATCH_STACK_DIGEST_DOMAIN,
"body": {
"patches": [
[name, digest]
for name, digest in zip(self.patch_series, self.patch_digests)
]
},
}
)
@property
def runtime_version(self) -> str:
"""The exact ``runtime_version`` recipe axis value for this pin."""
return (
f"{self.runtime_name}@{self.upstream_commit}"
f"+patchstack.{self.patch_stack_digest}"
)
def _read_text(path: Path, what: str) -> str:
try:
return path.read_text(encoding="utf-8")
except FileNotFoundError:
raise RuntimePinError(f"{what} not found at {path}") from None
except OSError as exc:
raise RuntimePinError(f"{what} at {path} is unreadable: {exc}") from exc
def _read_series_file(path: Path) -> list[str]:
lines = _read_text(path, "patches/series").splitlines()
return [line.strip() for line in lines if line.strip() and not line.startswith("#")]
def _read_sums_file(path: Path) -> list[tuple[str, str]]:
entries: list[tuple[str, str]] = []
for line in _read_text(path, "patches/SHA256SUMS").splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
parts = line.split(None, 1)
if len(parts) != 2 or not _HEX64.match(parts[0]):
raise RuntimePinError(
"patches/SHA256SUMS contains a line that is not "
"'<sha256> <patch name>'"
)
entries.append((parts[0], parts[1].strip()))
return entries
def load_runtime_pin(lock_dir: Path = DEFAULT_LOCK_DIR) -> RuntimePin:
"""Derive the exact runtime pin from a DGR-027 lock workspace, or refuse.
Refuses — rather than guessing — on a missing or malformed lock, a moving
commit reference, a disagreement between the lock's ``patch_series``, the
``patches/series`` file, ``patches/SHA256SUMS``, or the actual patch
bytes, and on an ``UPSTREAM_COMMIT`` file that names a different commit.
"""
lock_path = lock_dir / "UPSTREAM_LOCK.json"
raw = _read_text(lock_path, "UPSTREAM_LOCK.json")
try:
lock = json.loads(raw)
except json.JSONDecodeError as exc:
raise RuntimePinError(f"UPSTREAM_LOCK.json is not valid JSON: {exc}") from exc
if not isinstance(lock, dict):
raise RuntimePinError("UPSTREAM_LOCK.json must be a JSON object")
schema = lock.get("schema_version")
if schema != RUNTIME_PIN_SCHEMA_VERSION:
raise RuntimePinError(
f"UPSTREAM_LOCK.json declares schema version {schema!r}; this reader "
f"understands version {RUNTIME_PIN_SCHEMA_VERSION}"
)
upstream = lock.get("upstream")
if not isinstance(upstream, str) or not upstream.strip():
raise RuntimePinError("UPSTREAM_LOCK.json is missing the upstream URL")
runtime_name = upstream.rstrip("/").rsplit("/", 1)[-1]
if runtime_name.endswith(".git"):
runtime_name = runtime_name[: -len(".git")]
if not runtime_name:
raise RuntimePinError("the upstream URL does not name a runtime")
commit = lock.get("commit")
if not isinstance(commit, str) or not _HEX40.match(commit):
raise RuntimePinError(
f"UPSTREAM_LOCK.json commit {commit!r} is not an exact 40-character "
"hexadecimal object id; a moving reference is not a pin"
)
commit_file = _read_text(lock_dir / "UPSTREAM_COMMIT", "UPSTREAM_COMMIT")
recorded = commit_file.strip().splitlines()[0].strip() if commit_file.strip() else ""
if recorded != commit:
raise RuntimePinError(
"UPSTREAM_COMMIT and UPSTREAM_LOCK.json disagree on the pinned commit"
)
lock_series = lock.get("patch_series")
if not isinstance(lock_series, list) or not all(
isinstance(name, str) and name.strip() for name in lock_series
):
raise RuntimePinError(
"UPSTREAM_LOCK.json patch_series must be a list of patch file names"
)
if len(set(lock_series)) != len(lock_series):
raise RuntimePinError("UPSTREAM_LOCK.json patch_series contains a duplicate")
series = _read_series_file(lock_dir / "patches" / "series")
if series != lock_series:
raise RuntimePinError(
"patches/series and UPSTREAM_LOCK.json patch_series disagree on the "
"ordered patch stack"
)
sums = _read_sums_file(lock_dir / "patches" / "SHA256SUMS")
if [name for _, name in sums] != lock_series:
raise RuntimePinError(
"patches/SHA256SUMS does not record exactly the ordered patch stack "
"named by UPSTREAM_LOCK.json"
)
digests: list[str] = []
for (expected_digest, name) in sums:
patch_path = lock_dir / "patches" / name
try:
body = patch_path.read_bytes()
except FileNotFoundError:
raise RuntimePinError(f"patch file {name} is named but missing") from None
except OSError as exc:
raise RuntimePinError(f"patch file {name} is unreadable: {exc}") from exc
actual = hashlib.sha256(body).hexdigest()
if actual != expected_digest:
raise RuntimePinError(
f"patch file {name} does not match its patches/SHA256SUMS digest"
)
digests.append(actual)
return RuntimePin(
runtime_name=runtime_name,
upstream_commit=commit,
patch_series=tuple(lock_series),
patch_digests=tuple(digests),
)

View File

@@ -374,6 +374,11 @@ class RuntimeRecipe:
one in fp16, produce different logits from the same bytes. Keeping the axes one in fp16, produce different logits from the same bytes. Keeping the axes
apart is the entire safety property; see :data:`RECIPE_AXES`. apart is the entire safety property; see :data:`RECIPE_AXES`.
`tokenizer_revision` and `runtime_version` must be exact pins, never moving
references. For the native runtime the canonical `runtime_version` value —
committing to the exact upstream commit *and* the ordered patch stack — is
derived from the DGR-027 lock manifest by :mod:`meshnet_node.runtime_pin`.
The three label fields are diagnosis only and are not digested. The three label fields are diagnosis only and are not digested.
""" """
@@ -400,6 +405,7 @@ class RuntimeRecipe:
else: else:
_require_text(value, f"recipe.{axis}") _require_text(value, f"recipe.{axis}")
_require_pin(self.tokenizer_revision, "recipe.tokenizer_revision") _require_pin(self.tokenizer_revision, "recipe.tokenizer_revision")
_require_pin(self.runtime_version, "recipe.runtime_version")
_require_text(self.recipe_id, "recipe.recipe_id") _require_text(self.recipe_id, "recipe.recipe_id")
_require_text(self.recipe_version, "recipe.recipe_version") _require_text(self.recipe_version, "recipe.recipe_version")
_require_text(self.catalogue_version, "recipe.catalogue_version") _require_text(self.catalogue_version, "recipe.catalogue_version")

View File

@@ -333,6 +333,7 @@ def parse_identity(data: Any) -> PresentedIdentity:
else: else:
axes[axis] = _text(value, f"recipe.{axis}") axes[axis] = _text(value, f"recipe.{axis}")
_pin(axes["tokenizer_revision"], "recipe.tokenizer_revision") _pin(axes["tokenizer_revision"], "recipe.tokenizer_revision")
_pin(axes["runtime_version"], "recipe.runtime_version")
identity = PresentedIdentity( identity = PresentedIdentity(
artifact_id=_text(artifact.get("artifact_id"), "artifact.artifact_id"), artifact_id=_text(artifact.get("artifact_id"), "artifact.artifact_id"),

View File

@@ -0,0 +1,278 @@
"""DGR-025: the recipe's runtime axis commits to the exact pin and patch stack.
The fingerprint (DGR-003 lineage) digests a ``runtime_version`` string, but a
string an operator typed is a label, not a pin: two workers could run different
patch stacks under the same label and still agree on the digest. These tests
pin the axis to the DGR-027 lock manifest — the exact upstream commit plus a
digest over the ordered patch-stack bytes — and prove both identity
implementations reject a moving runtime reference.
"""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
import pytest
from meshnet_node.runtime_pin import (
DEFAULT_LOCK_DIR,
RuntimePinError,
load_runtime_pin,
)
from meshnet_node.runtime_recipe import RecipeIdentityError, RuntimeRecipe
from meshnet_tracker.recipe import (
RecipeIdentityError as TrackerRecipeIdentityError,
parse_identity,
)
REPO_LOCK_DIR = (
Path(__file__).resolve().parent.parent / "packages" / "node" / "native" / "llama"
)
def _recipe(**changes: object) -> RuntimeRecipe:
fields: dict[str, object] = {
"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@deadbeef+meshnet.1",
"recipe_id": "example-gguf",
"recipe_version": "1",
"catalogue_version": "2026.07.1",
}
fields.update(changes)
return RuntimeRecipe(**fields) # type: ignore[arg-type]
def _write_fixture_workspace(
root: Path,
*,
commit: str = "e" * 40,
patches: dict[str, bytes] | None = None,
lock_series: list[str] | None = None,
series_lines: list[str] | None = None,
sums_lines: list[str] | None = None,
schema_version: int = 1,
upstream: str = "https://github.com/ggml-org/llama.cpp.git",
upstream_commit_file: str | None = None,
) -> Path:
"""A minimal DGR-027-shaped lock workspace; overrides create disagreement."""
if patches is None:
patches = {
"0001-first.patch": b"--- a\n+++ b\n",
"0002-second.patch": b"--- c\n+++ d\n",
}
names = list(patches)
digests = {
name: hashlib.sha256(body).hexdigest() for name, body in patches.items()
}
patch_dir = root / "patches"
patch_dir.mkdir(parents=True)
for name, body in patches.items():
(patch_dir / name).write_bytes(body)
(root / "UPSTREAM_LOCK.json").write_text(
json.dumps(
{
"schema_version": schema_version,
"upstream": upstream,
"commit": commit,
"patch_series": names if lock_series is None else lock_series,
}
),
encoding="utf-8",
)
(root / "UPSTREAM_COMMIT").write_text(
(commit if upstream_commit_file is None else upstream_commit_file) + "\n",
encoding="utf-8",
)
(patch_dir / "series").write_text(
"\n".join(names if series_lines is None else series_lines) + "\n",
encoding="utf-8",
)
if sums_lines is None:
sums_lines = ["# ordered digests"] + [
f"{digests[name]} {name}" for name in names
]
(patch_dir / "SHA256SUMS").write_text(
"\n".join(sums_lines) + "\n", encoding="utf-8"
)
return root
# --- the committed manifest is the identity source -------------------------
def test_default_lock_dir_is_the_committed_manifest():
assert DEFAULT_LOCK_DIR == REPO_LOCK_DIR
def test_committed_manifest_derives_a_deterministic_runtime_pin():
pin = load_runtime_pin(REPO_LOCK_DIR)
again = load_runtime_pin(REPO_LOCK_DIR)
assert pin == again
lock = json.loads(
(REPO_LOCK_DIR / "UPSTREAM_LOCK.json").read_text(encoding="utf-8")
)
assert pin.upstream_commit == lock["commit"]
assert list(pin.patch_series) == lock["patch_series"]
# The axis value names the runtime, the exact commit, and the stack digest,
# so changing any of the three changes every downstream recipe digest.
assert pin.runtime_version == (
f"llama.cpp@{lock['commit']}+patchstack.{pin.patch_stack_digest}"
)
assert len(pin.patch_stack_digest) == 64
def test_derived_axis_value_is_a_valid_recipe_pin():
pin = load_runtime_pin(REPO_LOCK_DIR)
recipe = _recipe(runtime_version=pin.runtime_version)
assert recipe.runtime_version == pin.runtime_version
assert len(recipe.runtime_recipe_digest) == 64
def test_patch_byte_change_changes_the_runtime_identity(tmp_path):
baseline = load_runtime_pin(_write_fixture_workspace(tmp_path / "a"))
changed = load_runtime_pin(
_write_fixture_workspace(
tmp_path / "b",
patches={
"0001-first.patch": b"--- a\n+++ b\n",
"0002-second.patch": b"--- c\n+++ DIFFERENT\n",
},
)
)
assert baseline.patch_stack_digest != changed.patch_stack_digest
assert baseline.runtime_version != changed.runtime_version
def test_patch_order_is_part_of_the_stack_identity(tmp_path):
patches = {
"0001-first.patch": b"--- a\n+++ b\n",
"0002-second.patch": b"--- c\n+++ d\n",
}
forward = load_runtime_pin(
_write_fixture_workspace(tmp_path / "a", patches=patches)
)
names = list(patches)
reversed_names = list(reversed(names))
digests = {
name: hashlib.sha256(body).hexdigest() for name, body in patches.items()
}
swapped = load_runtime_pin(
_write_fixture_workspace(
tmp_path / "b",
patches=patches,
lock_series=reversed_names,
series_lines=reversed_names,
sums_lines=[f"{digests[name]} {name}" for name in reversed_names],
)
)
assert forward.patch_stack_digest != swapped.patch_stack_digest
# --- every manifest disagreement fails closed ------------------------------
def test_missing_lock_file_fails_closed(tmp_path):
with pytest.raises(RuntimePinError, match="UPSTREAM_LOCK.json"):
load_runtime_pin(tmp_path)
def test_malformed_lock_json_fails_closed(tmp_path):
_write_fixture_workspace(tmp_path)
(tmp_path / "UPSTREAM_LOCK.json").write_text("{not json", encoding="utf-8")
with pytest.raises(RuntimePinError, match="not valid JSON"):
load_runtime_pin(tmp_path)
def test_unknown_lock_schema_fails_closed(tmp_path):
_write_fixture_workspace(tmp_path, schema_version=2)
with pytest.raises(RuntimePinError, match="schema"):
load_runtime_pin(tmp_path)
def test_moving_commit_reference_fails_closed(tmp_path):
_write_fixture_workspace(tmp_path, commit="master")
with pytest.raises(RuntimePinError, match="exact 40"):
load_runtime_pin(tmp_path)
def test_upstream_commit_file_disagreement_fails_closed(tmp_path):
_write_fixture_workspace(tmp_path, upstream_commit_file="f" * 40)
with pytest.raises(RuntimePinError, match="UPSTREAM_COMMIT"):
load_runtime_pin(tmp_path)
def test_series_file_disagreement_fails_closed(tmp_path):
_write_fixture_workspace(
tmp_path, series_lines=["0002-second.patch", "0001-first.patch"]
)
with pytest.raises(RuntimePinError, match="series"):
load_runtime_pin(tmp_path)
def test_missing_patch_file_fails_closed(tmp_path):
_write_fixture_workspace(tmp_path)
(tmp_path / "patches" / "0002-second.patch").unlink()
with pytest.raises(RuntimePinError, match="0002-second.patch"):
load_runtime_pin(tmp_path)
def test_checksum_disagreement_fails_closed(tmp_path):
_write_fixture_workspace(tmp_path)
patch = tmp_path / "patches" / "0002-second.patch"
patch.write_bytes(patch.read_bytes() + b"tampered\n")
with pytest.raises(RuntimePinError, match="SHA256SUMS"):
load_runtime_pin(tmp_path)
def test_sums_entry_missing_fails_closed(tmp_path):
patches = {
"0001-first.patch": b"--- a\n+++ b\n",
"0002-second.patch": b"--- c\n+++ d\n",
}
digest = hashlib.sha256(patches["0001-first.patch"]).hexdigest()
_write_fixture_workspace(
tmp_path,
patches=patches,
sums_lines=[f"{digest} 0001-first.patch"],
)
with pytest.raises(RuntimePinError, match="SHA256SUMS"):
load_runtime_pin(tmp_path)
def test_empty_patch_series_requires_empty_series_files(tmp_path):
# An unpatched runtime is a legal pin; a lock that *hides* patches is not.
_write_fixture_workspace(tmp_path, lock_series=[])
with pytest.raises(RuntimePinError, match="series"):
load_runtime_pin(tmp_path)
# --- both identity implementations reject a moving runtime -----------------
def test_node_recipe_rejects_a_moving_runtime_version():
with pytest.raises(RecipeIdentityError, match="moving reference"):
_recipe(runtime_version="latest")
def test_tracker_rejects_a_moving_runtime_version():
vectors = json.loads(
(Path(__file__).parent / "data" / "recipe_fingerprint_vectors.json").read_text(
encoding="utf-8"
)
)
doc = json.loads(json.dumps(vectors["vectors"][0]["identity"]))
doc["recipe"]["runtime_version"] = "latest"
doc.pop("fingerprint", None)
with pytest.raises(TrackerRecipeIdentityError, match="moving reference"):
parse_identity(doc)