1 Commits

Author SHA1 Message Date
Dobromir Popov
f102be1098 docs: retarget gguf epic to DeepSeek-V4-Flash 2026-07-14 16:24:39 +03:00
82 changed files with 192 additions and 10713 deletions

View File

@@ -8,15 +8,6 @@ metadata:
# Project Status (2026-07-13) # Project Status (2026-07-13)
## Selected-node model placement (2026-07-14)
- Admin Model placement now opens a node selector for load and release; the control-plane accepts optional `node_id` and targets only that registry assignment. Multi-model serving remains supported through `ADD_SHARD` and `max_loaded_shards`.
- Total node pool resource values are rendered from `/v1/network/map`'s `node.capacity` contract. Route selection remains assignment/capability/throughput/queue based; capacity is used for placement and falls back to tracker defaults only if a node truly omits it.
## Distributed inference performance (2026-07-14)
`DIP-001` is done in `.scratch/distributed-inference-performance/`: the deterministic two-node Route Session stub benchmark covers direct/relay plus cached/stateless prefill and decode. Its JSON and concise summary explicitly attribute model execution, activation encode/decode, compression, connection setup, relay queueing, local HTTP forwarding, and end-to-end seam latency. `PYTHONPATH=packages/node pytest -q tests/test_route_session_benchmark.py` passed (7); the fixture assertion checks output-token identity and connection attempts.
> Doc reconciliation 2026-07-13: `docs/prd.json` tracks US-001…US-050 (048 memory budget, 049 mainnet pilot, 050 Qwen demand placement). ADRs 00250026 added (TAI phase B/C, assignment ownership). > Doc reconciliation 2026-07-13: `docs/prd.json` tracks US-001…US-050 (048 memory budget, 049 mainnet pilot, 050 Qwen demand placement). ADRs 00250026 added (TAI phase B/C, assignment ownership).
All 35 user stories in docs/prd.json are done (35/35), including the reward-system arc US-030…US-035 completed 2026-07-02: All 35 user stories in docs/prd.json are done (35/35), including the reward-system arc US-030…US-035 completed 2026-07-02:

View File

@@ -12,10 +12,4 @@ Provide an opt-in, admin-only tracker Dashboard Testing tab that dynamically dis
- One active run. - One active run.
- Real inference stays separately environment-gated and excluded from default suites. - Real inference stays separately environment-gated and excluded from default suites.
## Operator workflow
See [`docs/dev/dashboard-test-runner.md`](../../docs/dev/dashboard-test-runner.md)
for launch configuration, default safe suites vs the gated real-inference suite,
and required environment variables.
See `prd.json` for executable Ralph user stories and acceptance criteria. See `prd.json` for executable Ralph user stories and acceptance criteria.

View File

@@ -51,16 +51,15 @@
"uv run pytest tests/test_dashboard.py tests/test_dynamic_routing.py -q passes." "uv run pytest tests/test_dashboard.py tests/test_dynamic_routing.py -q passes."
], ],
"priority": 3, "priority": 3,
"passes": true, "passes": false,
"notes": "Do not reintroduce --enable-test-runner without implementing its CLI argument in US-001.", "notes": "Do not reintroduce --enable-test-runner without implementing its CLI argument in US-001.",
"dependsOn": [ "dependsOn": [
"US-001", "US-001",
"US-002" "US-002"
], ]
"completionNotes": "Completed by agent"
} }
], ],
"metadata": { "metadata": {
"updatedAt": "2026-07-12T01:58:06.286Z" "updatedAt": "2026-07-11T17:02:30.520Z"
} }
} }

View File

@@ -1,127 +0,0 @@
# DGR-001 — performance contract baseline
## Files changed
- `packages/node/meshnet_node/performance_contract.py`
- `tests/test_performance_contract.py`
- `.scratch/distributed-gguf-runtime/issues/01-lock-the-safetensors-versus-gguf-performance-contract.md`
- `.scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json`
## What this slice does
- Locks the DGR-001 benchmark contract in code.
- Pins the architecture-aligned baseline to **DeepSeek-V2-Lite-Chat** (`deepseek2`).
- Uses the same model on both sides of the comparison:
- **safetensors:** `deepseek-ai/DeepSeek-V2-Lite-Chat` in **BF16**
- **GGUF:** `second-state/DeepSeek-V2-Lite-Chat-GGUF` in **Q2_K**
- Exposes a machine-readable JSON contract with:
- benchmark lanes for `transformers` safetensors and `llama.cpp` GGUF on **CPU** and **GPU**
- concurrency levels `1` and `4`
- the required metrics list
- an explicit stop condition for “no meaningful speed or fit benefit”
- Adds a deterministic stub benchmark report so the contract now has an executable report shape end to end.
## Recent benchmark runner slice
The runner currently uses a deterministic stub backend to exercise the comparison matrix without downloading a model. It emits:
- `.scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json`
- `.scratch/distributed-gguf-runtime/evidence/DGR-001/stub-benchmark-report.json`
The report includes per-device comparisons for:
- `transformers-safetensors-cpu` vs `llama-cpp-gguf-cpu`
- `transformers-safetensors-gpu` vs `llama-cpp-gguf-gpu`
and records the memory metric (`rss_bytes` on CPU, `vram_bytes` on GPU), decode speedup, artifact ratio, and output drift.
## Live endpoint CLI wiring
The contract CLI can now drive the live endpoint runner. Passing one `--live-endpoint LANE_ID=URL` mapping per contract lane (plus `--live-benchmark-out`) invokes `run_real_model_endpoint_benchmark` against already-running OpenAI-compatible servers and writes the report using the same schema as the stub:
```bash
PYTHONPATH=packages/node python -m meshnet_node.performance_contract \
--live-endpoint transformers-safetensors-cpu=http://127.0.0.1:8001 \
--live-endpoint llama-cpp-gguf-cpu=http://127.0.0.1:8002 \
--live-endpoint transformers-safetensors-gpu=http://127.0.0.1:8003 \
--live-endpoint llama-cpp-gguf-gpu=http://127.0.0.1:8004 \
--live-benchmark-out .scratch/distributed-gguf-runtime/evidence/DGR-001/live-benchmark-report.json
```
`--live-model` overrides the model name sent in requests (defaults to the contract's safetensors repo). Without any `--live-endpoint` flags the CLI behaves exactly as before: it writes the contract JSON and, with `--benchmark-out`, the deterministic stub report.
## Exact commands and real results
### Targeted tests
```bash
PYTHONPATH=packages/node pytest -q tests/test_performance_contract.py tests/test_route_session_benchmark.py
```
Result: `19 passed in 0.11s`
### Contract artifact generation
```bash
PYTHONPATH=packages/node python -m meshnet_node.performance_contract --json-out .scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json
```
Result: wrote `.scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json`
### Python compile check
```bash
python -m compileall packages/node/meshnet_node/performance_contract.py tests/test_performance_contract.py
```
Result: passed
## Public relay smoke benchmark (2026-07-15)
A real streamed request was run through the public tracker — **not** by connecting directly to the private node address:
```text
https://meshnet.2.d-popov.com/v1/chat/completions
-> wss://meshnet.2.d-popov.com/ws
-> wss://meshnet.2.d-popov.com/rpc/7j77FsPY1evV8tuf-7000
-> local CUDA node, Qwen/Qwen2.5-0.5B-Instruct layers 0-23
```
The local public-tracker node had an expired proof and a wedged HTTP server. A graceful restart refreshed its CUDA capability proof in `336 ms`, restored `admitted`/`routable` status, and reconnected its relay endpoint.
Measured streaming results after recovery:
| metric | result |
| --- | ---: |
| warm-up TTFT | 420.80 ms |
| warm-up elapsed | 610.23 ms |
| p50 TTFT (3 runs) | 288.26 ms |
| p50 elapsed (3 runs) | 363.20 ms |
| tracker-recorded relay throughput | 58.18-65.25 tok/s |
| HTTP status | 200 for all runs |
The tracker recorded `relay: true` and the local node ID `7j77FsPY-b32476219492` for each completion. Full redacted evidence is in `public-relay-smoke-benchmark.json`.
The other connected node is still alive but **not routable** because its capability proof is stale. It must revalidate before a multi-node shard/relay test can run.
## Limitations
- This slice still uses a deterministic stub backend for the core comparison matrix.
- It now also includes a live endpoint runner, reachable from the CLI via `--live-endpoint`/`--live-benchmark-out`, that fans out one OpenAI-compatible request per lane when the caller provides endpoints; the CLI does not start those servers.
- It does **not** download or run a real model from within the repo.
- Real safetensors vs GGUF execution, TTFT/prefill/decode measurements, RSS/VRAM capture, and output-drift comparison are still to be implemented against the contract.
## Compatibility notes
- The contract stays on the DeepSeek2 family to remain close to the DeepSeek-V4-Flash end goal.
- A smaller non-DeepSeek model can still be used later for loader-plumbing smoke tests, but it does not replace this baseline.
- Model artifacts must stay on the mounted drive and not under `/home`.
## Dependent-story handoff
Next implementation work should attach to this contract and add the live benchmark runner that actually compares:
1. current Transformers/safetensors recipe
2. whole-model llama.cpp GGUF recipe
using the same model architecture/revision and the same prompt/context/concurrency settings.

View File

@@ -1,75 +0,0 @@
{
"benchmark_lanes": [
{
"concurrency_levels": [
1,
4
],
"device": "cpu",
"id": "transformers-safetensors-cpu",
"recipe": "current safetensors recipe",
"runtime": "transformers"
},
{
"concurrency_levels": [
1,
4
],
"device": "cpu",
"id": "llama-cpp-gguf-cpu",
"recipe": "whole-model GGUF recipe",
"runtime": "llama.cpp"
},
{
"concurrency_levels": [
1,
4
],
"device": "gpu",
"id": "transformers-safetensors-gpu",
"recipe": "current safetensors recipe",
"runtime": "transformers"
},
{
"concurrency_levels": [
1,
4
],
"device": "gpu",
"id": "llama-cpp-gguf-gpu",
"recipe": "whole-model GGUF recipe",
"runtime": "llama.cpp"
}
],
"metrics": [
"ttft_ms",
"prefill_tok_per_sec",
"decode_tok_per_sec",
"p50_latency_ms",
"p95_latency_ms",
"aggregate_throughput_tok_per_sec",
"rss_bytes",
"vram_bytes",
"artifact_bytes",
"failure_count",
"output_drift"
],
"model_target": {
"architecture": "deepseek2",
"comparison_policy": "same model/revision, closest practical low-footprint precision pair: BF16 safetensors versus Q2_K GGUF",
"gguf_quant": "Q2_K",
"gguf_repo": "second-state/DeepSeek-V2-Lite-Chat-GGUF",
"gguf_size_gb": 6.43,
"name": "DeepSeek-V2-Lite-Chat",
"rationale": "Smallest DeepSeek-family benchmark anchor that still points toward DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead of falling back to a tiny but architecture-mismatched smoke model.",
"safetensors_precision": "bfloat16",
"safetensors_repo": "deepseek-ai/DeepSeek-V2-Lite-Chat"
},
"notes": [
"Real model execution stays opt-in and must keep model artifacts on the mounted drive.",
"Use the tiny fallback only for loader plumbing smoke tests; it does not replace the architecture-aligned baseline."
],
"schema_version": 1,
"stop_condition": "Stop if GGUF does not provide a meaningful speed or fit benefit over the safetensors baseline for the chosen DeepSeek-family model target.",
"story_id": "DGR-001"
}

View File

@@ -1,83 +0,0 @@
{
"schema_version": 1,
"executed_at_utc": "2026-07-15T10:41:14Z",
"test_kind": "public-relay-single-node-streaming-smoke-benchmark",
"target": {
"public_chat_endpoint": "https://meshnet.2.d-popov.com/v1/chat/completions",
"relay_url": "wss://meshnet.2.d-popov.com/ws",
"model": "qwen2.5-0.5b-instruct",
"quantization": "bfloat16"
},
"recovery": {
"problem": "The local node's capability proof had expired and its port-7000 HTTP server had wedged with CLOSE-WAIT sockets.",
"action": "Gracefully restarted the local public-tracker meshnet-node process on port 7000.",
"startup_validation": {
"device": "cuda",
"capability_proof_ms": 336,
"node_id": "7j77FsPY-b32476219492",
"relay_addr": "wss://meshnet.2.d-popov.com/rpc/7j77FsPY1evV8tuf-7000"
}
},
"tracker_admission_after_recovery": {
"node_id": "7j77FsPY-b32476219492",
"alive": true,
"status": "ready",
"capability_state": "admitted",
"routable": true,
"route_hops": 1
},
"client_measurements": {
"warmup": {
"http_status": 200,
"ttft_ms": 420.8,
"elapsed_ms": 610.23,
"response_text": "MeshNet Relay Benchmark Passed"
},
"runs": [
{
"run": 1,
"ttft_ms": 376.04,
"elapsed_ms": 458.65,
"response_text": "relay benchmark pass"
},
{
"run": 2,
"ttft_ms": 258.33,
"elapsed_ms": 336.71,
"response_text": "relay benchmark pass"
},
{
"run": 3,
"ttft_ms": 288.26,
"elapsed_ms": 363.2,
"response_text": "relay benchmark pass"
}
],
"p50_ttft_ms": 288.26,
"p50_elapsed_ms": 363.2
},
"tracker_relay_evidence": [
{
"status": 200,
"relay": true,
"node_id": "7j77FsPY-b32476219492",
"tokens": 11,
"elapsed_seconds": 0.1686,
"tokens_per_sec": 65.2541
},
{
"status": 200,
"relay": true,
"node_id": "7j77FsPY-b32476219492",
"tokens": 11,
"elapsed_seconds": 0.1891,
"tokens_per_sec": 58.1799
}
],
"scope_and_remaining_work": {
"validated": "Public HTTPS chat endpoint routed a streaming request through the tracker relay to the local CUDA node and completed with HTTP 200.",
"not_validated": "Two-node shard routing was not run because the remote node 5gMLrmyB-88f5cba044d0 still had an expired capability proof and was not routable.",
"next_gate": "Refresh the remote node capability proof, then load a multi-node-compatible assignment and repeat the benchmark through the public tracker relay."
},
"reproduction": "Use a valid bearer API key with the public /v1/chat/completions endpoint and stream a short qwen2.5-0.5b-instruct request. Do not connect directly to private node HTTP endpoints; the tracker relay is the required path."
}

View File

@@ -1,247 +0,0 @@
{
"comparisons": {
"cpu": {
"artifact_bytes_ratio": 0.2048,
"decode_speedup": 2.3333,
"gguf_benefit": true,
"gguf_lane": "llama-cpp-gguf-cpu",
"memory_bytes_ratio": 0.2152,
"memory_metric": "rss_bytes",
"output_drift": 0.0,
"safetensors_lane": "transformers-safetensors-cpu",
"ttft_speedup": 1.8947
},
"gpu": {
"artifact_bytes_ratio": 0.2048,
"decode_speedup": 1.5294,
"gguf_benefit": true,
"gguf_lane": "llama-cpp-gguf-gpu",
"memory_bytes_ratio": 0.2273,
"memory_metric": "vram_bytes",
"output_drift": 0.0,
"safetensors_lane": "transformers-safetensors-gpu",
"ttft_speedup": 1.6154
}
},
"lanes": [
{
"concurrency_levels": [
1,
4
],
"device": "cpu",
"id": "transformers-safetensors-cpu",
"output_tokens": [
"mesh",
"activation",
"seam",
"baseline"
],
"recipe": "current safetensors recipe",
"results": [
{
"concurrency": 1,
"metrics": {
"aggregate_throughput_tok_per_sec": 6.0,
"artifact_bytes": 33715493273,
"decode_tok_per_sec": 6.0,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 166.6667,
"p95_latency_ms": 208.3334,
"prefill_tok_per_sec": 45.0,
"rss_bytes": 35433480192,
"ttft_ms": 1800.0,
"vram_bytes": 0
}
},
{
"concurrency": 4,
"metrics": {
"aggregate_throughput_tok_per_sec": 20.4,
"artifact_bytes": 33715493273,
"decode_tok_per_sec": 5.1,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 196.0784,
"p95_latency_ms": 245.098,
"prefill_tok_per_sec": 38.25,
"rss_bytes": 35433480192,
"ttft_ms": 2340.0,
"vram_bytes": 0
}
}
],
"runtime": "transformers"
},
{
"concurrency_levels": [
1,
4
],
"device": "cpu",
"id": "llama-cpp-gguf-cpu",
"output_tokens": [
"mesh",
"activation",
"seam",
"baseline"
],
"recipe": "whole-model GGUF recipe",
"results": [
{
"concurrency": 1,
"metrics": {
"aggregate_throughput_tok_per_sec": 14.0,
"artifact_bytes": 6904159928,
"decode_tok_per_sec": 14.0,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 71.4286,
"p95_latency_ms": 89.2858,
"prefill_tok_per_sec": 90.0,
"rss_bytes": 7623566950,
"ttft_ms": 950.0,
"vram_bytes": 0
}
},
{
"concurrency": 4,
"metrics": {
"aggregate_throughput_tok_per_sec": 47.6,
"artifact_bytes": 6904159928,
"decode_tok_per_sec": 11.9,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 84.0336,
"p95_latency_ms": 105.042,
"prefill_tok_per_sec": 76.5,
"rss_bytes": 7623566950,
"ttft_ms": 1235.0,
"vram_bytes": 0
}
}
],
"runtime": "llama.cpp"
},
{
"concurrency_levels": [
1,
4
],
"device": "gpu",
"id": "transformers-safetensors-gpu",
"output_tokens": [
"mesh",
"activation",
"seam",
"baseline"
],
"recipe": "current safetensors recipe",
"results": [
{
"concurrency": 1,
"metrics": {
"aggregate_throughput_tok_per_sec": 34.0,
"artifact_bytes": 33715493273,
"decode_tok_per_sec": 34.0,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 29.4118,
"p95_latency_ms": 36.7647,
"prefill_tok_per_sec": 850.0,
"rss_bytes": 4294967296,
"ttft_ms": 420.0,
"vram_bytes": 35433480192
}
},
{
"concurrency": 4,
"metrics": {
"aggregate_throughput_tok_per_sec": 115.6,
"artifact_bytes": 33715493273,
"decode_tok_per_sec": 28.9,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 34.6021,
"p95_latency_ms": 43.2526,
"prefill_tok_per_sec": 722.5,
"rss_bytes": 4294967296,
"ttft_ms": 546.0,
"vram_bytes": 35433480192
}
}
],
"runtime": "transformers"
},
{
"concurrency_levels": [
1,
4
],
"device": "gpu",
"id": "llama-cpp-gguf-gpu",
"output_tokens": [
"mesh",
"activation",
"seam",
"baseline"
],
"recipe": "whole-model GGUF recipe",
"results": [
{
"concurrency": 1,
"metrics": {
"aggregate_throughput_tok_per_sec": 52.0,
"artifact_bytes": 6904159928,
"decode_tok_per_sec": 52.0,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 19.2308,
"p95_latency_ms": 24.0385,
"prefill_tok_per_sec": 640.0,
"rss_bytes": 1610612736,
"ttft_ms": 260.0,
"vram_bytes": 8053063680
}
},
{
"concurrency": 4,
"metrics": {
"aggregate_throughput_tok_per_sec": 176.8,
"artifact_bytes": 6904159928,
"decode_tok_per_sec": 44.2,
"failure_count": 0,
"output_drift": 0.0,
"p50_latency_ms": 22.6244,
"p95_latency_ms": 28.2805,
"prefill_tok_per_sec": 544.0,
"rss_bytes": 1610612736,
"ttft_ms": 338.0,
"vram_bytes": 8053063680
}
}
],
"runtime": "llama.cpp"
}
],
"model_target": {
"architecture": "deepseek2",
"comparison_policy": "same model/revision, closest practical low-footprint precision pair: BF16 safetensors versus Q2_K GGUF",
"gguf_quant": "Q2_K",
"gguf_repo": "second-state/DeepSeek-V2-Lite-Chat-GGUF",
"gguf_size_gb": 6.43,
"name": "DeepSeek-V2-Lite-Chat",
"rationale": "Smallest DeepSeek-family benchmark anchor that still points toward DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead of falling back to a tiny but architecture-mismatched smoke model.",
"safetensors_precision": "bfloat16",
"safetensors_repo": "deepseek-ai/DeepSeek-V2-Lite-Chat"
},
"schema_version": 1,
"source": "stub-backend",
"stop_condition": {
"gguf_benefit": true,
"text": "Stop if GGUF does not provide a meaningful speed or fit benefit over the safetensors baseline for the chosen DeepSeek-family model target.",
"triggered": false
},
"story_id": "DGR-001"
}

View File

@@ -1,176 +0,0 @@
# DGR-002 — Versioned gRPC Shard protocol: evidence
Status: done
Date: 2026-07-15
Evidence kind: **synthetic-unit** (schema round-trip + cross-language protobuf
compatibility). No model download, no GPU, no network, no API credits.
## Summary
Added the versioned Protocol Buffers schema that is the semantic contract between
Python and C++ Shards (ADR-0024), plus reproducible Python and C++ code
generation/build wiring and generated-schema round-trip + compatibility tests in
**both** languages. The schema defines one long-lived bidirectional gRPC stream
per Route Session Activation Seam, bounded prefill chunking, a small decode fast
path, and a versioned named-tensor bundle carrying every required identifier.
No existing runtime code was modified — this story is purely additive (a new
`.proto`, a `native_protocol` loader package, C++ build wiring, and one new test
module). Generated stubs are produced on demand into gitignored `build/`
directories, so nothing generated is committed.
## Files changed (all new)
- `packages/node/native/proto/shard_runtime.proto` — the schema (package
`meshnet.shard.v1`, proto3). Service `ShardRuntime` with `GetCapability`,
`Health`, `ActivateSession` (bidi stream), `Release`, `Cancel`.
- `packages/node/meshnet_node/native_protocol/__init__.py` — reproducible
on-demand `grpc_tools.protoc` codegen + loader (`load()`, `load_grpc()`) and
shared bundle helpers (`compute_checksum`, `verify_checksum`, `fragment_tensor`,
`reassemble_tensor`).
- `packages/node/native/scripts/generate_python.py` — standalone reproducible
Python generation (self-contained; does not import `meshnet_node`).
- `packages/node/native/scripts/generate_cpp.sh` — reproducible C++ generation
(message stubs always; gRPC service stubs when `grpc_cpp_plugin` is present).
- `packages/node/native/CMakeLists.txt` — C++ build wiring; works with both
CONFIG-mode (`protobuf::libprotobuf`/`protobuf::protoc`) and CMake's
`FindProtobuf` module.
- `packages/node/native/tests/roundtrip_test.cpp` — C++ round-trip / compat test
(`--selftest`, `--read`, `--write`).
- `tests/test_native_shard_protocol.py` — Python round-trip + compatibility tests
and the Python↔C++ cross-language driver.
## Acceptance criteria → evidence
- **Capability/health/session-stream/release/cancellation schema** — the
`ShardRuntime` service's five RPCs; `test_capability_and_health_round_trip`,
`test_session_stream_carries_open_prefill_decode_release_cancel`.
- **One long-lived bidi stream per Activation Seam with deadlines, cancellation,
flow control, structured errors** — `rpc ActivateSession (stream ...) returns
(stream ...)`. Deadlines: gRPC call deadline on direct transport, plus
`SessionOpen.deadline_unix_nanos` for relay-carried frames. Cancellation:
`Cancel` RPC and in-stream `CancelRequest`/`PHASE_CANCEL`. Flow control:
`FlowControl` frames (credits + in-flight byte/message caps). Structured errors:
`Status` (canonical code, message, `RetryClass`, details). Verified by
`test_session_response_carries_structured_status_and_results`.
- **Bounded prefill chunking + small decode fast path** — `PrefillChunk`
(`chunk_index`/`chunk_count`/`final_chunk`, `SessionOpen.max_prefill_tokens_per_chunk`)
and `DecodeStep` (minimal single-bundle path). Bounded fragments via
`SessionOpen.max_fragment_bytes` and `fragment_tensor(...)`.
- **Carries schema version, work ID, Route Session ID, route epoch,
artifact/recipe fingerprint, shard range/effective start, phase, position,
idempotency step, cache expectation, compression, checksum** — all on
`MessageHeader` (+ `ArtifactFingerprint.runtime_recipe_fingerprint`,
`ShardRange.effective_start_layer`). Verified field-by-field by
`test_message_header_carries_every_required_field`.
- **Versioned named-tensor bundle (name, shape, dtype, byte order, fragments)** —
`TensorBundle`/`NamedTensor`/`TensorFragment`;
`test_named_tensor_bundle_describes_shape_dtype_byteorder_and_fragments`,
`test_fragment_and_reassemble_round_trip_with_checksums`.
- **Round-trip + compatibility tests in Python and C++** — Python:
`tests/test_native_shard_protocol.py` (11 tests). C++: `roundtrip_test.cpp`
built via CMake; cross-language driver `test_cross_language_roundtrip_python_and_cpp`
exercises Python→C++ and C++→Python in both directions.
- **Targeted pytest** — `11 passed, 1 skipped` (default env); `12 passed` with the
C++ toolchain on PATH.
- **compileall packages tests** — exit 0.
- **git diff --check** — clean.
- **Deterministic / download-free / credit-free / GPU-free** — all tests are pure
protobuf serialization; the C++ path uses only local compilers.
- **Full deterministic pytest** — `704 passed, 14 skipped, 11 failed`. The 11
failures are pre-existing and unrelated (see below).
## Commands and real results
See `commands.txt` for the exact command list. Key results:
- `python packages/node/native/scripts/generate_python.py`
`shard_runtime_pb2.py: ok`, `shard_runtime_pb2_grpc.py: ok`.
- `pytest tests/test_native_shard_protocol.py -q`**11 passed, 1 skipped**
(skip reason: `C++ toolchain unavailable: cmake not found on PATH`).
- With `/tmp/pbsrc/install/bin` (protoc 33.1) and `.venv/bin` (cmake) on PATH and
`CMAKE_PREFIX_PATH=/tmp/pbsrc/install`:
- `generate_cpp.sh``shard_runtime.pb.cc`, `shard_runtime.pb.h`
(grpc service stubs skipped: `grpc_cpp_plugin` absent).
- `cmake -S ... -B ...` + `cmake --build ...` → build OK.
- `shard_protocol_roundtrip_test --selftest``selftest ok (128 bytes)`, exit 0.
- `ctest``1/1 Test #1: shard_protocol_roundtrip ... Passed`.
- `pytest ...::test_cross_language_roundtrip_python_and_cpp -q`**1 passed**
(Python serializes → C++ parses & verifies → C++ serializes → Python parses
& verifies).
- `compileall -q packages tests` → exit 0.
- `git diff --check` → clean.
## Pre-existing unrelated failures (full-suite)
`pytest -q` on the full tree reports 11 failures, all in tracker routing /
dynamic routing / manual route benchmark / toploc calibration — none import the
Shard protocol. Clean-tree reproduction: with **all DGR-002 files moved aside**
(`git status` shows only the pre-existing `.ralph-tui/config.toml` deletion),
re-running exactly these tests gives `11 failed, 3 passed` — identical failures.
They exist on the `ralph/distributed-gguf-runtime` branch independent of this
story. The full list is in `results.json.preexisting_unrelated_failures`.
Note: the earlier `progress.md` (RCR-001, on master) recorded a different set of
6 optional-dependency failures (zstandard, langchain_openai). Those did **not**
recur here; this environment has those deps. The 11 above are branch-local
routing/benchmark failures, not environmental.
## Limitations and deferred work
- **C++ toolchain is host-provided, not vendored.** The default test env has no
`protoc`/`cmake`/protobuf C++ headers on PATH, so the C++ cross-language test
**skips** by default (explicit skip reason). It was executed for this evidence
using an ephemeral from-source protobuf 33.1 install at `/tmp/pbsrc/install`
plus the `.venv` cmake. DGR-004/DGR-008 should pin the C++ protobuf/gRPC
toolchain (upstream commit + reproducible fetch/build) so this test runs in CI
without relying on an ad-hoc `/tmp` install.
- **gRPC C++ service stubs not built here.** `grpc_cpp_plugin` is absent, so
`generate_cpp.sh` produced message stubs only. The round-trip test needs only
message serialization; the service stubs are DGR-008's concern.
- **No live gRPC transport yet.** This story delivers the schema + serialization
contract and generation/build wiring only. Channel setup, the bidi stream
server/client, deadlines/cancellation propagation over a real HTTP/2 channel,
and relay framing are DGR-008/DGR-009.
- **Protobuf runtime version skew.** Python runtime is pip protobuf 7.35.1; the
C++ side used protoc 33.1. Protobuf wire format is stable across these, and the
cross-language round-trip confirms interop; version pinning is deferred to the
toolchain-pinning stories.
## Compatibility / migration notes
- proto3 with a 0-valued `*_UNSPECIFIED` member on every enum and never-reused
field numbers. Forward compatibility (unknown-field preservation) is verified
behaviourally by `test_unknown_fields_are_preserved_for_forward_compatibility`
— note protobuf 7.x's upb backend does not implement the `UnknownFields()`
introspection accessor, so the test asserts the observable re-serialization
outcome instead. Backward defaults verified by
`test_defaults_are_stable_for_backward_compatibility`.
- Wire schema version is `SchemaVersion.SCHEMA_VERSION_1` (int 1), also exposed as
`meshnet_node.native_protocol.SCHEMA_VERSION`.
## Handoff for dependent stories
- **DGR-003 (recipe/fingerprint):** populate `ArtifactFingerprint`
(`model_id`, `revision`, `artifact_hash`, `quantization`,
`runtime_recipe_fingerprint`). Admission compares these before activation; a
mismatch is a fatal `Status` (`RetryClass.RETRY_CLASS_FATAL`).
- **DGR-004 (llama.cpp pin) / DGR-008 (C++ worker):** pin the C++
protobuf + gRPC toolchain and add `grpc_cpp_plugin`; then `generate_cpp.sh`
emits service stubs and the CMake target can link gRPC. Implement the
`ShardRuntime` servicer; map `(route_session_id, route_epoch)` to an isolated
llama sequence. Use `SessionOpen` for stream-scoped bounds and `FlowControl`
for backpressure.
- **DGR-009 (Meshnet integration/relay):** the relay may carry serialized
`SessionActivation`/`SessionResponse` frames as opaque binary; use the in-message
`deadline_unix_nanos`, `CancelRequest`, and `FlowControl` since gRPC call
metadata is lost over relay.
- **Loader usage:** `from meshnet_node import native_protocol as proto;
pb2 = proto.load()`. Stubs regenerate automatically when the `.proto` changes
(mtime check). `proto.load_grpc()` returns the service stubs (needs the `grpc`
runtime).
- **Gotcha:** the `.venv` installs the meshnet packages editable via a PEP 660
meta-path finder pointing at the **main** checkout. Import the worktree copy by
ensuring the worktree `packages/node` is on `sys.path` first (conftest already
does this for pytest); standalone tooling must derive paths from `__file__` and
not `import meshnet_node` (why `generate_python.py` is self-contained).

View File

@@ -1,40 +0,0 @@
# DGR-002 reproduction commands (run from repo root, project .venv = Python 3.14).
# 1. Generate Python stubs (reproducible; writes to gitignored build/ dir).
.venv/bin/python packages/node/native/scripts/generate_python.py
# 2. Python round-trip + compatibility tests (default env; C++ test skips if
# cmake/protoc absent).
.venv/bin/python -m pytest tests/test_native_shard_protocol.py -q
# => 11 passed, 1 skipped
# 3. Quality gates.
.venv/bin/python -m compileall -q packages tests # exit 0
git diff --check # clean
# 4. Full deterministic suite (records pre-existing unrelated failures).
.venv/bin/python -m pytest -q
# => 704 passed, 14 skipped, 11 failed (all pre-existing, unrelated; see below)
# 5. Clean-tree reproduction of the 11 pre-existing failures (DGR-002 files moved
# aside): same 11 fail => not caused by this story.
# --- C++ / cross-language (requires protoc + protobuf C++ dev + cmake) --------
# On this host a from-source protobuf 33.1 toolchain lives under /tmp/pbsrc/install
# and cmake ships in the .venv. To execute the C++ test instead of skipping it:
export PATH="/tmp/pbsrc/install/bin:$PWD/.venv/bin:$PATH"
export CMAKE_PREFIX_PATH="/tmp/pbsrc/install:$CMAKE_PREFIX_PATH"
# 6. Generate C++ stubs (message stubs always; gRPC service stubs if
# grpc_cpp_plugin present).
packages/node/native/scripts/generate_cpp.sh
# 7. Standalone C++ build + selftest + ctest.
cmake -S packages/node/native -B packages/node/native/build/cpp
cmake --build packages/node/native/build/cpp --target shard_protocol_roundtrip_test
packages/node/native/build/cpp/shard_protocol_roundtrip_test --selftest # "selftest ok (128 bytes)"
(cd packages/node/native/build/cpp && ctest --output-on-failure) # 1/1 passed
# 8. Cross-language Python<->C++ round-trip via the pytest driver (now runs, not skips).
.venv/bin/python -m pytest tests/test_native_shard_protocol.py::test_cross_language_roundtrip_python_and_cpp -q
# => 1 passed

View File

@@ -1,63 +0,0 @@
{
"task": "DGR-002",
"title": "Adopt the versioned gRPC Shard protocol",
"schema": {
"proto": "packages/node/native/proto/shard_runtime.proto",
"package": "meshnet.shard.v1",
"syntax": "proto3",
"schema_version": 1,
"service": "ShardRuntime",
"rpcs": ["GetCapability", "Health", "ActivateSession", "Release", "Cancel"],
"streaming_seam": "ActivateSession (bidirectional stream)"
},
"toolchain": {
"python": "3.14.6",
"protobuf_runtime_python": "7.35.1",
"grpcio": "1.82.1",
"grpcio_tools": "1.82.1",
"cpp_protoc": "libprotoc 33.1",
"cpp_protobuf_toolchain": "/tmp/pbsrc/install (from-source protobuf 33.1, ephemeral host build)",
"cmake": "4.4.0 (.venv)",
"cxx": "g++ (system)"
},
"generation": {
"python_cmd": "python packages/node/native/scripts/generate_python.py",
"python_out": "packages/node/native/build/python/shard_runtime_pb2{,_grpc}.py (gitignored)",
"cpp_cmd": "packages/node/native/scripts/generate_cpp.sh",
"cpp_out": "packages/node/native/build/cpp-gen/shard_runtime.pb.{h,cc} (gitignored)",
"cpp_build": "cmake -S packages/node/native -B <build> && cmake --build <build>"
},
"tests": {
"python_default_env": {"passed": 11, "skipped": 1, "note": "C++ cross-language test skips when cmake/protoc absent"},
"python_with_cpp_toolchain": {"passed": 12, "skipped": 0},
"cpp_selftest_bytes": 128,
"cpp_ctest": "1/1 passed",
"cross_language": "Python->C++ and C++->Python round-trip verified in both directions"
},
"quality_gates": {
"targeted_pytest": "11 passed, 1 skipped (default); 12 passed with C++ toolchain",
"compileall_packages_tests": "exit 0",
"git_diff_check": "clean",
"full_pytest": {
"passed": 704,
"skipped": 14,
"failed": 11,
"failed_are_preexisting_unrelated": true,
"clean_tree_reproduction": "same 11 fail with all DGR-002 files removed (11 failed, 3 passed)"
}
},
"preexisting_unrelated_failures": [
"tests/test_dynamic_routing.py::test_admin_can_replace_a_served_model_and_release_it",
"tests/test_manual_route_benchmark.py::test_pinned_route_uses_named_node",
"tests/test_manual_route_benchmark.py::test_unknown_route_node_is_400",
"tests/test_manual_route_benchmark.py::test_invalid_route_shape_is_400",
"tests/test_manual_route_benchmark.py::test_clients_without_route_are_unaffected",
"tests/test_manual_route_benchmark.py::test_benchmark_records_one_and_two_node_routes",
"tests/test_toploc_calibration_dispatch.py::test_calibration_run_dispatches_only_solo_capable_nodes",
"tests/test_toploc_calibration_dispatch.py::test_calibration_run_persists_corpus_and_results_endpoint_reports_it",
"tests/test_toploc_calibration_dispatch.py::test_calibration_run_node_without_commitment_endpoint_is_skipped_not_failed",
"tests/test_tracker_routing.py::test_torch_node_applies_tracker_load_shard_directive",
"tests/test_tracker_routing.py::test_shard_heal_cycle_surviving_node_covers_dead_peers_gap"
],
"evidence_kind": "synthetic-unit (schema round-trip + cross-language protobuf; no model, no GPU, no network, no API credits)"
}

View File

@@ -1,86 +0,0 @@
# DGR-003 — Exact artifact and runtime-recipe identity: evidence
Status: done
Date: 2026-07-15
Evidence kind: **synthetic-unit + repo checks**. No model download, no GPU, no network, no API credits.
## Summary
Implemented exact identity plumbing for shard admission so the node and tracker
compare the same compatibility contract:
- `ArtifactIdentity` binds a shard to an exact source model artifact hash plus
shard range.
- `RuntimeRecipeIdentity` separates weight quantization, activation dtype,
compute dtype, KV dtype/layout, tokenizer revision, architecture adapter,
backend id, runtime version, boundary schema version, and cache layout.
- `compatibility_fingerprint` is stable SHA-256 over the full artifact/runtime
recipe payload.
- Node admission and tracker admission now fail closed on compatibility
mismatches.
- Unsupported recipes remain tracked as dark/unadmitted until a real forward
proves them.
The work also keeps the test helper, doctor path, startup registration payloads,
and tracker storage/admission aligned so the same fingerprint is emitted and
checked across the system.
## Files changed
- `packages/node/meshnet_node/runtime_recipe.py` - new exact artifact/runtime
identity helpers and fingerprint builder.
- `packages/node/meshnet_node/capability.py` - capability report shape now
carries artifact/runtime recipe identity and validates the top-level
compatibility fingerprint.
- `packages/node/meshnet_node/admission.py` - fail-closed admission on
compatibility fingerprint mismatch.
- `packages/node/meshnet_node/doctor.py` - production capability reports now
include the runtime recipe identity.
- `packages/node/meshnet_node/testing.py` - test report builder now mirrors the
production fingerprint fields.
- `packages/node/meshnet_node/startup.py` - registration payload now includes
the compatibility fingerprint.
- `packages/tracker/meshnet_tracker/capability.py` - tracker verdict state now
stores artifact hash and compatibility fingerprints.
- `packages/tracker/meshnet_tracker/server.py` - registration and raft state now
preserve declared compatibility fingerprints.
- `tests/test_node_capability.py` - identity shape and fingerprint regression
tests.
- `tests/test_node_admission.py` - fail-closed admission regression tests.
- `tests/test_tracker_capability_admission.py` - tracker compatibility mismatch
regression tests.
## Commands and real results
- `python -m compileall packages tests` -> exit 0.
- `pytest -q tests/test_node_capability.py` -> `48 passed in 0.09s`.
- `pytest -q tests/test_node_admission.py` -> `20 passed in 0.11s`.
- `pytest -q tests/test_tracker_capability_admission.py -k 'compatibility_mismatch or older_recipe_catalogue or unparseable_catalogue_version or future_dated or unknown_schema_version or malformed_report or recorded_detail_carries_no_credentials or compat_policy_routes_a_legacy_node_but_never_a_broken_proof or policy_is_read_from_the_environment_and_defaults_to_compat or route_selection_drops_every_unadmitted_candidate_under_enforce or node_reassigned_to_a_shard_it_never_proved_stops_routing or admitted_candidates_keep_coverage_first_and_throughput_routing'` -> `18 passed, 17 deselected in 0.11s`.
- `git diff --check` -> exit 0.
- `pytest -q` -> not green in this sandbox. Final result: `210 failed, 423 passed, 13 skipped, 14 warnings, 86 errors in 131.34s`.
## Limitation
The full suite is dominated by tracker and HTTP/socket-backed tests. In this
sandbox, those fail with `PermissionError: [Errno 1] Operation not permitted`
when the tracker attempts to bind a socket. That is an environment restriction,
not a regression from the identity work. The pure unit slices above pass.
## Compatibility notes
- The compatibility fingerprint is now a hash over the exact artifact identity
and runtime recipe payload. It is intended for both node admission and the
gRPC handshake admission path.
- Default fallbacks for fake/test backends are stable and deterministic: cache
layout derives from KV-cache support, architecture adapter falls back to the
backend id, and tokenizer identity prefers model revision/model id rather than
local tokenizer paths.
## Handoff for dependent stories
- DGR-004 / DGR-008 can reuse `runtime_recipe.py` and the compatibility
fingerprint to gate the gRPC handshake before session activation.
- DGR-009 should transmit the same fingerprint over the relay or preserve it in
frame metadata so admission stays aligned end to end.
- Any future recipe expansion should register unsupported recipes as dark until
a real distributed forward certifies them.

View File

@@ -1,130 +0,0 @@
# DGR-004 — reproducible pinned llama.cpp patch stack evidence
Status: done
Date: 2026-07-15
Evidence kind: **synthetic-build + repo checks**. No model download, no GPU,
no network fetch during validation, no API credits.
## Summary
Implemented the reproducible source-dependency boundary for llama.cpp and kept
the fork seam narrow and auditable:
- exact pinned upstream commit and repository metadata
- numbered patch stack isolated under `packages/node/native/llama/patches/`
- build script that verifies the pin, applies the patch stack, stages notices,
and compiles a standalone worker scaffold without manual source copying
- upstream file assumptions and fail-closed pin checking
- license/attribution preservation by staging upstream `LICENSE` and `AUTHORS`
- clean rebuild smoke test that only uses a fake local checkout and does not
download a model
The native smoke path is intentionally minimal in this story. It proves the
reproducible source dependency and build seam without pulling Meshnet protocol
code into llama.cpp.
## Files changed
- `packages/node/native/llama/UPSTREAM_COMMIT`
- `packages/node/native/llama/UPSTREAM_REPOSITORY`
- `packages/node/native/llama/UPSTREAM_ASSUMPTIONS.md`
- `packages/node/native/llama/README.md`
- `packages/node/native/llama/patches/0001-add-meshnet-worker-scaffold.patch`
- `packages/node/native/llama/templates/meshnet_worker.cpp`
- `packages/node/native/scripts/build_llama_worker.sh`
- `tests/test_llama_worker_build.py`
## Exact commands and real results
### Native smoke build against a fake pinned checkout
```bash
tmpdir=$(mktemp -d)
mkdir -p "$tmpdir/llama.cpp"
printf 'MIT\n' > "$tmpdir/llama.cpp/LICENSE"
printf 'AUTHORS\n' > "$tmpdir/llama.cpp/AUTHORS"
printf '# placeholder\n' > "$tmpdir/llama.cpp/CMakeLists.txt"
printf '%s\n' 'b3c9d1b846cc80a6360adb6aeaa4fcd8c4c8dcac' > "$tmpdir/llama.cpp/.meshnet-upstream-commit"
git init -q "$tmpdir/llama.cpp"
packages/node/native/scripts/build_llama_worker.sh \
--source-dir "$tmpdir/llama.cpp" \
--build-dir "$tmpdir/build"
```
Result:
- `meshnet worker scaffold ok`
- `upstream commit: b3c9d1b846cc80a6360adb6aeaa4fcd8c4c8dcac`
- `patchset version: 0001`
- `build ok: /tmp/.../build/meshnet_worker`
### Targeted pytest
```bash
python -m pytest -q tests/test_llama_worker_build.py
```
Result: `1 passed in 0.53s`
### Python compile check
```bash
python -m compileall -q packages tests
```
Result: exit 0
### Diff hygiene
```bash
git diff --check
```
Result: exit 0
### Full deterministic pytest
```bash
python -m pytest -q
```
Result: `424 passed, 13 skipped, 210 failed, 86 errors in 131.04s`
The failures are pre-existing sandbox socket failures in tracker/HTTP-backed
tests. Representative error:
- `PermissionError: [Errno 1] Operation not permitted` when the tracker tries
to bind a socket.
This matches the previously observed environment limitation in the DGR-002 and
DGR-003 evidence and is unrelated to the llama.cpp pin/build scaffold.
## Limitations
- The sandbox does not provide `cmake`, so the smoke build uses the available
direct C++ compiler path (`g++` here) instead of a CMake-generated target.
- The pinned upstream source was not fetched from GitHub during validation.
The script supports fetching the exact commit when network access is
available, but the validation run used a fake local checkout to keep the test
deterministic and model-free.
- The patch stack in this story is deliberately narrow and additive. It creates
a worker scaffold and build seam, not the final llama.cpp runtime patches.
## Compatibility notes
- The exact upstream pin is `b3c9d1b846cc80a6360adb6aeaa4fcd8c4c8dcac`.
- The build script fails closed if the checkout pin differs from that commit or
if the expected upstream files (`LICENSE`, `AUTHORS`, `CMakeLists.txt`) are
missing.
- The patch stack is isolated from Meshnet networking code and can be applied
to a clean pinned checkout before later worker stories extend the scaffold.
- Upstream attribution notices are preserved in the build output by copying the
staged `LICENSE` and `AUTHORS` files into `build/.../upstream-notices/`.
## Dependent-story handoff
- DGR-008 can replace the scaffold source with the real supervised C++ worker
while keeping the same pin metadata, patch stack, and build script boundary.
- DGR-005 and later native stories should keep using the same exact pin so the
worker seam remains reproducible while range-loading and session logic are
added.

View File

@@ -1,96 +0,0 @@
# DGR-005 — dense-Llama range-aware GGUF ownership evidence
Status: done
Date: 2026-07-15
Evidence kind: **synthetic-unit + repo checks**. No model download, no GPU, no network, no API credits.
## Summary
Implemented range-aware dense-Llama ownership so the node reports and admits only the tensors it actually loads:
- `blk.N.*` tensors are selected strictly by assigned layer range.
- Embeddings are owned at the head only, while final norm / LM head are owned at the tail only, including tied embeddings.
- Derivative sub-GGUF slices must carry source and slice hashes and cannot claim final artifact semantics.
- The authoritative loaded range and endpoint ownership now come from backend proof state, not CLI shard claims.
- Registration, capability reports, admission fingerprints, and tracker state now carry the backend-derived ownership proof.
The result is a shard model that can reason about memory and admission from owned tensors instead of pretending the full model was loaded.
## Files changed
- `packages/node/meshnet_node/gguf_ownership.py` - dense-Llama tensor selection and authoritative ownership helpers.
- `packages/node/meshnet_node/capability.py` - shard reports now carry endpoint ownership and parse it round-trip.
- `packages/node/meshnet_node/doctor.py` - capability reports now use backend-derived loaded range and endpoint ownership.
- `packages/node/meshnet_node/testing.py` - test capability reports now mirror the authoritative ownership path.
- `packages/node/meshnet_node/admission.py` - admission compatibility fingerprints now include authoritative range/ownership context.
- `packages/node/meshnet_node/model_backend.py` - loaded-range and endpoint-ownership properties on `TorchModelShard`.
- `packages/node/meshnet_node/startup.py` - registration payloads now use the proof-driven shard range.
- `packages/tracker/meshnet_tracker/capability.py` - tracker capability state preserves endpoint ownership.
- `tests/test_gguf_ownership.py` - dense-Llama ownership selection, derivative-slice guard, and memory-scaling tests.
- `tests/test_node_capability.py` - capability report ownership round-trip tests.
- `tests/test_node_admission.py` - backend-loaded range beats CLI claim regression tests.
- `tests/test_tracker_capability_admission.py` - tracker capability proof parsing tests.
## Exact commands and real results
### Targeted pytest slices
```bash
python -m pytest -q tests/test_gguf_ownership.py tests/test_node_capability.py tests/test_node_admission.py
```
Result: `73 passed`
```bash
python -m pytest -q tests/test_tracker_capability_admission.py -k 'test_a_passing_report_that_covers_the_registration_is_admitted or test_a_missing_report_is_absent_not_admitted or test_a_failed_report_is_recorded_as_failed or test_a_report_for_a_different_model_is_a_model_mismatch or test_a_report_for_a_different_shard_is_a_shard_mismatch or test_a_report_for_a_different_recipe_than_the_node_declares_is_a_recipe_mismatch or test_a_report_for_a_different_compatibility_fingerprint_is_a_compatibility_mismatch or test_an_older_recipe_catalogue_is_incompatible or test_an_unparseable_catalogue_version_is_incompatible or test_a_stale_report_is_not_admitted or test_a_future_dated_report_is_not_admitted or test_a_report_from_an_unknown_schema_version_is_invalid or test_a_malformed_report_is_invalid_and_never_admitted or test_recorded_detail_carries_no_credentials_from_node_diagnostics or test_compat_policy_routes_a_legacy_node_but_never_a_broken_proof or test_the_policy_is_read_from_the_environment_and_defaults_to_compat'
```
Result: `22 passed, 13 deselected`
### Python compile check
```bash
python -m compileall -q packages tests
```
Result: exit 0
### Diff hygiene
```bash
git diff --check
```
Result: exit 0
### Full deterministic pytest
```bash
python -m pytest -q
```
Result: `211 failed, 428 passed, 13 skipped, 14 warnings, 86 errors in 135.03s`
The failing set is not caused by this story. The dominant environment issues were:
- tracker and HTTP/socket-backed tests fail with `PermissionError: [Errno 1] Operation not permitted` when the tracker tries to bind sockets in this sandbox
- native protocol tests fail early with a protobuf runtime/gencode mismatch: generated code expects protobuf 7.35.0 while the installed runtime is 6.33.6
## Limitations
- This evidence is intentionally deterministic and model-free.
- The memory-scaling check is synthetic: it validates that owned tensor bytes scale with selected tensors, not a live GGUF download.
- Native C++ code was not changed by this story, so the pinned llama.cpp build validation remains covered by DGR-004 rather than repeated here.
## Compatibility notes
- Dense-Llama ownership is range-first: the shard interior is `blk.N.*`, and endpoint tensors are only attributed to the head or tail owner as appropriate.
- Derivative GGUF slices are explicitly not final artifacts; they must preserve source and slice hashes if used as a temporary compatibility bridge.
- The model proof path is authoritative for reported range and endpoint ownership, so operator CLI claims no longer control what the node advertises.
- Admission and tracker state now consume the same proof-derived ownership shape, keeping capability reports aligned end to end.
## Handoff for dependent stories
- DGR-006 can reuse `gguf_ownership.py` and the new capability fields to wire the shard protocol to proof-derived ownership without re-deriving tensor names.
- DGR-008 and later routing work should continue to treat endpoint ownership as metadata and `blk.N.*` ownership as the core range contract.
- If a future temporary slice path is needed, it should keep source/slice hashes visible and avoid claiming final-artifact semantics until a real proof exists.

View File

@@ -1,203 +0,0 @@
# DGR-006 — Architecture-defined boundary input/output: evidence
Status: done
Date: 2026-07-15
Evidence kind: **synthetic-unit** (pure-numpy dense-Llama reference + boundary
contract). No model download, no GPU, no torch, no network, no API credit.
## Summary
Implemented the architecture-defined boundary contract that lets disjoint Shard
processes reproduce whole-model execution (ADR-0024, RALPH runtime decisions #1,
#6, #13). A public-network Shard is a contiguous inclusive layer range, and this
story defines exactly what boundary state each range consumes and emits:
- The **head** owns token embedding: it accepts token IDs and produces the
residual stream. It refuses an upstream boundary bundle.
- **Middle and tail** ranges bypass token embedding entirely and accept the
named boundary bundle (the residual stream). They refuse token IDs.
- A **non-tail** range emits the *unnormalized* architecture-defined residual —
before the final norm, before the LM head, and before any tail-only row
pruning — with every sequence position row intact.
- The **tail** owns the final norm + LM head, prunes to the final row, and emits
a token through an explicit `SamplingContract` (greedy, deterministic).
- The adapter **fails closed** for uncertified architectures: only certified
dense-Llama spellings are accepted; Qwen3/Qwen3-MoE/Mixtral/gpt2/empty all
raise `UncertifiedArchitectureError`.
The adapter is backend-agnostic: it drives a duck-typed `ShardComputation`
(`architecture_adapter`, `start_layer`, `end_layer`, `total_layers`,
`embed_tokens`, `run_layers(hidden, *, positions)`, `final_norm`, `lm_head`). A
pure-numpy dense-Llama reference (RMSNorm + RoPE + SwiGLU) implements that
protocol in the tests and proves whole-model versus two-range **and** three-range
prefill + greedy-decode parity. torch/transformers are not installed in the
default `.venv`, so a numpy reference is the only way to keep the parity gate
deterministic, download-free, and GPU-free — the identical protocol will be
satisfied by the pinned llama.cpp worker (DGR-008) and the PyTorch backend.
No existing runtime code was modified — this story is purely additive (one new
module + one new test module). A clean-tree reproduction (files moved aside)
confirms the full-suite failure set is byte-identical with and without this work.
## Files changed (all new)
- `packages/node/meshnet_node/boundary_adapter.py` — the boundary contract:
- `certified_architecture()` / `is_certified_architecture()` and the certified
architecture registry (`ArchitectureBoundary`), fail-closed.
- `ShardRole` + `role_for_range()` (head/middle/tail/full).
- `BoundaryBundle` — the versioned named-tensor bundle carrying the unnormalized
residual + positions + seam `next_layer`; `pack()`/`unpack()` for a truly
disjoint-process round-trip and `named_tensor_fields()` mapping onto the
DGR-002 `NamedTensor` shape (name, shape, dtype, byte order, bytes).
- `SamplingContract` — explicit greedy sampling (fails closed on other modes).
- `TailOutput` — sampled token + pruned final-row logits + the sampling contract.
- `BoundaryAdapter` — enforces the per-role input/output rules and drives the
computation.
- `tests/test_boundary_adapter.py` — pure-numpy dense-Llama reference model
(`_ReferenceDenseLlama`) and range shard (`_ReferenceShard`), plus 22 tests:
certification/fail-closed, role classification, input-side contract
(head-owns-embedding, middle/tail-bypass, seam-layer mismatch, normalized-bundle
rejection), output-side contract (unnormalized full-row boundary, tail pruning +
sampling), wire round-trip, and the parity gate.
## Acceptance criteria → evidence
- **Head accepts token IDs and owns token embedding** —
`test_head_accepts_token_ids_and_owns_embedding`,
`BoundaryAdapter._ingest_tokens` (head requires token IDs, refuses a bundle).
- **Middle/tail bypass token embedding and accept the named boundary bundle** —
`test_middle_and_tail_bypass_embedding_and_require_the_bundle`,
`_ingest_boundary` (rejects token IDs, requires the bundle).
- **Non-tail emits the unnormalized boundary before final norm/head and before
tail-only row pruning** — `test_non_tail_emits_unnormalized_full_row_boundary`
asserts the bundle is `normalized=False`, shape `(1, seq, hidden)` (all rows),
and byte-equal to the whole model's residual after the cut layer while *not*
equal to its normalized form. `_emit_boundary`.
- **Tail emits logits/token through an explicit sampling contract** —
`test_tail_emits_pruned_logits_through_the_sampling_contract` (logits shape
`(1, vocab)` = pruned last row, greedy token = argmax). `_emit_tail`,
`SamplingContract`.
- **Dense-Llama whole-model vs two-range prefill + greedy-decode parity within
tolerance** — `test_two_range_prefill_parity_matches_whole_model`,
`test_three_range_prefill_parity_exercises_the_middle_role`,
`test_two_range_greedy_decode_parity_matches_whole_model`,
`test_alias_architecture_still_parity_matches`. Documented tolerance:
next-token logits `np.allclose(..., atol=1e-6)` and **identical** greedy token
sequences. (The split is bit-exact in practice; the tolerance is a conservative
guard.)
- **Fails closed for uncertified architectures** —
`test_uncertified_architectures_fail_closed`,
`test_adapter_construction_fails_closed_for_uncertified_backend`.
- **Targeted pytest** — `22 passed`.
- **compileall packages tests** — exit 0.
- **git diff --check** — clean.
- **Deterministic / download-free / credit-free / GPU-free** — pure numpy; fixed
RNG seed; no torch, no network, no model files.
- **Full deterministic pytest** — `20 failed, 715 passed, 13 skipped, 12 errors`.
All 20 failures + 12 errors are pre-existing and unrelated (see below).
- **Native C++ / CTest / llama.cpp patch stack** — **not touched by this story.**
The boundary contract is delivered at the Python adapter level with a numpy
parity proof; the equivalent native patches ("architecture-defined intermediate
input/output" and "intermediate output before final norm/head") are wired when
the standalone C++ worker exists in DGR-008. No native code, CMake, or llama.cpp
patch was modified, so those gates are N/A here (same as DGR-005).
## Commands and real results
```bash
# Targeted tests
python -m pytest -q tests/test_boundary_adapter.py
# -> 22 passed in 0.26s
# Python compile check
python -m compileall -q packages tests
# -> exit 0
# Diff hygiene
git diff --check
# -> exit 0
# Full deterministic suite (with DGR-006 files present)
python -m pytest -q -rfE
# -> 20 failed, 715 passed, 13 skipped, 12 errors in 239.77s
# Clean-tree reproduction (DGR-006 files moved aside)
mv packages/node/meshnet_node/boundary_adapter.py /tmp/ && mv tests/test_boundary_adapter.py /tmp/
python -m pytest -q -rfE
# -> 20 failed, 693 passed, 13 skipped, 12 errors in 243.10s
# (693 = 715 - 22; failure/error SET is byte-identical -> DGR-006 introduced none)
```
The `commands.txt` and `results.json` beside this README capture the exact
commands and the machine-readable failure set.
## Pre-existing unrelated failures (full-suite)
`pytest -q` on `ralph/distributed-gguf-runtime` reports 20 failures + 12 errors,
none of which touch the boundary adapter. Moving the two DGR-006 files aside and
re-running yields the **identical** failure/error set (only the passed count drops
by exactly 22). Categories:
- **12 errors — `tests/test_native_shard_protocol.py`:** generated protobuf code
expects a newer protobuf runtime than the one installed
(`ValidateProtobufRuntimeVersion` mismatch). Pre-existing; documented in the
DGR-002 / DGR-005 evidence.
- **20 failures** across `test_activation_compression.py`,
`test_dynamic_routing.py`, `test_gossip_and_relay.py`,
`test_manual_route_benchmark.py`, `test_node_doctor.py`,
`test_openai_gateway.py` (`langchain` optional dep),
`test_toploc_calibration_dispatch.py`, `test_tracker_capability_admission.py`,
`test_tracker_control_plane.py`, `test_tracker_routing.py` — tracker/routing/
benchmark/socket-bind + optional-dependency failures that exist on the branch
independent of this story.
## Limitations and deferred work
- **Numpy reference, not real weights.** The parity gate uses a deterministic
numpy dense-Llama, not a downloaded GGUF/safetensors model. Real-model parity on
a downloaded dense-Llama (CPU/ROCm) belongs to DGR-010 with
`MESHNET_ENABLE_REAL_INFERENCE_TESTS=1` and `.venv-rocm`.
- **Stateless decode for parity.** Greedy-decode parity recomputes the growing
prefix statelessly (no KV reuse). Local Hot KV State + session isolation is
DGR-007; the boundary contract here is KV-agnostic.
- **Native patch wiring deferred.** The C++/llama.cpp expression of this boundary
(range-aware intermediate I/O, pre-final-norm output) is implemented in the
standalone worker (DGR-008) against this same contract; no native code was
touched here.
- **Greedy-only sampling certified.** `SamplingContract` declares temperature /
top-p fields but only certifies `greedy` (deterministic). Stochastic sampling is
out of scope for the deterministic parity gate.
## Compatibility / migration notes
- `BOUNDARY_SCHEMA_VERSION = 1` matches `runtime_recipe.RuntimeRecipeIdentity`'s
`boundary_schema_version`. A receiver rejects a bundle whose schema, architecture
adapter, tensor name, normalization flag, or seam `next_layer` does not match its
own range — no silent reinterpretation.
- `BoundaryBundle.named_tensor_fields()` returns exactly the DGR-002 `NamedTensor`
fields (name, shape, dtype, byte order, bytes), so DGR-008 can serialize the seam
into the gRPC `TensorBundle` without re-deriving them.
- Certified architecture ids are canonicalized: `dense-llama` / `dense_llama` /
`llama` / `LlamaForCausalLM` / `LlamaModel` all map to the one `dense-llama`
adapter. Adding an architecture requires a new certified entry, never a tensor
guess (Qwen3 is DGR-015).
## Handoff for dependent stories
- **DGR-007 (Hot KV State):** wrap the same `ShardComputation` so `run_layers`
consumes/produces per-session KV; the boundary contract (unnormalized residual,
seam `next_layer`, tail pruning) is unchanged. The bundle's `positions` field is
the per-token position vector a KV path needs.
- **DGR-008 (C++ gRPC worker):** implement the `ShardRuntime` servicer against
this contract. Map `BoundaryBundle.named_tensor_fields()` → protobuf
`NamedTensor`; enforce the same head-embeds / middle-tail-bypass /
non-tail-unnormalized / tail-samples rules in native code; expose
`certified_architecture` gating so uncertified GGUFs are refused before activation.
- **DGR-009 (Meshnet integration):** carry `BoundaryBundle.pack()` payloads as
opaque relay frames; the seam `next_layer` is the overlap-safe effective start
the route must honor.
- **DGR-010 (real two-process acceptance):** reuse the parity harness shape
(whole vs N-range, identical greedy tokens) against a real downloaded dense-Llama
under `.venv-rocm`.
- **DGR-015 (Qwen3 adapter):** add a certified `ArchitectureBoundary` entry only
after real certification; today Qwen3 fails closed by design.

View File

@@ -1,26 +0,0 @@
# DGR-006 exact commands (run from repo worktree root)
# Targeted boundary-adapter tests
python -m pytest -q tests/test_boundary_adapter.py
# -> 22 passed in 0.26s
# Python compile check for changed Python
python -m compileall -q packages tests
# -> exit 0
# Diff hygiene
git diff --check
# -> exit 0
# Full deterministic suite with DGR-006 files present
python -m pytest -q -rfE
# -> 20 failed, 715 passed, 13 skipped, 12 errors in 239.77s
# Clean-tree reproduction: move the two new DGR-006 files aside, re-run
mv packages/node/meshnet_node/boundary_adapter.py /tmp/dgr006_boundary_adapter.py
mv tests/test_boundary_adapter.py /tmp/dgr006_test_boundary_adapter.py
python -m pytest -q -rfE
# -> 20 failed, 693 passed, 13 skipped, 12 errors in 243.10s
# (693 = 715 - 22; failure/error set byte-identical to the with-files run)
mv /tmp/dgr006_boundary_adapter.py packages/node/meshnet_node/boundary_adapter.py
mv /tmp/dgr006_test_boundary_adapter.py tests/test_boundary_adapter.py

View File

@@ -1,161 +0,0 @@
{
"story": "DGR-006",
"date": "2026-07-15",
"evidence_kind": "synthetic-unit (pure-numpy dense-Llama parity + boundary contract)",
"targeted_tests": {
"file": "tests/test_boundary_adapter.py",
"result": "22 passed"
},
"compileall": "exit 0",
"git_diff_check": "clean",
"parity_tolerance": {
"logits_atol": 1e-06,
"greedy_tokens": "identical"
},
"full_suite_with_files": {
"failed": 20,
"passed": 715,
"skipped": 13,
"errors": 12,
"seconds": 239.77
},
"full_suite_clean_tree": {
"failed": 20,
"passed": 693,
"skipped": 13,
"errors": 12,
"seconds": 243.1,
"note": "693 = 715 - 22 DGR-006 tests; failure/error set identical"
},
"failure_set_identical_with_and_without_dgr006": true,
"preexisting_unrelated_failures": [
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_capability_and_health_round_trip"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_checksum_algorithms_verify"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_cross_language_roundtrip_python_and_cpp"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_defaults_are_stable_for_backward_compatibility"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_fragment_and_reassemble_round_trip_with_checksums"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_message_header_carries_every_required_field"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_named_tensor_bundle_describes_shape_dtype_byteorder_and_fragments"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_reassemble_detects_fragment_corruption"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_service_descriptor_exposes_all_operations"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_session_response_carries_structured_status_and_results"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_session_stream_carries_open_prefill_decode_release_cancel"
},
{
"kind": "ERROR",
"nodeid": "tests/test_native_shard_protocol.py::test_unknown_fields_are_preserved_for_forward_compatibility"
},
{
"kind": "FAILED",
"nodeid": "tests/test_activation_compression.py::test_compressible_body_uses_zstd_when_it_clears_savings_policy"
},
{
"kind": "FAILED",
"nodeid": "tests/test_activation_compression.py::test_incompressible_body_stays_raw_after_measured_trial"
},
{
"kind": "FAILED",
"nodeid": "tests/test_activation_compression.py::test_malformed_zstd_and_legacy_raw_bodies_are_handled_explicitly"
},
{
"kind": "FAILED",
"nodeid": "tests/test_activation_compression.py::test_threshold_requires_both_byte_and_ratio_savings"
},
{
"kind": "FAILED",
"nodeid": "tests/test_dynamic_routing.py::test_admin_can_replace_a_served_model_and_release_it"
},
{
"kind": "FAILED",
"nodeid": "tests/test_gossip_and_relay.py::test_activation_compression_round_trips_and_skips_small_bodies"
},
{
"kind": "FAILED",
"nodeid": "tests/test_manual_route_benchmark.py::test_benchmark_records_one_and_two_node_routes"
},
{
"kind": "FAILED",
"nodeid": "tests/test_manual_route_benchmark.py::test_clients_without_route_are_unaffected"
},
{
"kind": "FAILED",
"nodeid": "tests/test_manual_route_benchmark.py::test_invalid_route_shape_is_400"
},
{
"kind": "FAILED",
"nodeid": "tests/test_manual_route_benchmark.py::test_pinned_route_uses_named_node"
},
{
"kind": "FAILED",
"nodeid": "tests/test_manual_route_benchmark.py::test_unknown_route_node_is_400"
},
{
"kind": "FAILED",
"nodeid": "tests/test_node_doctor.py::test_cli_doctor_flags_select_what_is_validated"
},
{
"kind": "FAILED",
"nodeid": "tests/test_openai_gateway.py::test_langchain_chat_openai"
},
{
"kind": "FAILED",
"nodeid": "tests/test_toploc_calibration_dispatch.py::test_calibration_run_dispatches_only_solo_capable_nodes"
},
{
"kind": "FAILED",
"nodeid": "tests/test_toploc_calibration_dispatch.py::test_calibration_run_node_without_commitment_endpoint_is_skipped_not_failed"
},
{
"kind": "FAILED",
"nodeid": "tests/test_toploc_calibration_dispatch.py::test_calibration_run_persists_corpus_and_results_endpoint_reports_it"
},
{
"kind": "FAILED",
"nodeid": "tests/test_tracker_capability_admission.py::test_an_enforcing_tracker_never_routes_a_node_whose_proof_does_not_cover_it[invalid]"
},
{
"kind": "FAILED",
"nodeid": "tests/test_tracker_control_plane.py::test_tracker_startup_does_not_import_or_load_model_backends"
},
{
"kind": "FAILED",
"nodeid": "tests/test_tracker_routing.py::test_shard_heal_cycle_surviving_node_covers_dead_peers_gap"
},
{
"kind": "FAILED",
"nodeid": "tests/test_tracker_routing.py::test_torch_node_applies_tracker_load_shard_directive"
}
]
}

View File

@@ -1,229 +0,0 @@
# DGR-007 — Isolated concurrent local Hot KV State: evidence
Status: done
Date: 2026-07-15
Evidence kind: **synthetic-unit** (pure-numpy KV-cached dense-Llama reference +
session/KV manager). No model download, no GPU, no torch, no network, no API
credit.
## Summary
Implemented the local Hot KV State manager that maps every
`(Route Session ID, route epoch)` to an isolated, bounded KV context (RALPH
runtime decisions #7 and #8, ADR-0022/0024). The manager owns all cache
mutation, so eviction, byte accounting, and isolation live in one place instead
of being scattered across backends:
- **`(session_id, route_epoch)` → isolated context.** Each key gets its own
`SessionCache` holding independent per-layer K/V; one session can never read or
clear another's state.
- **KV allocated only for owned layers.** A shard constructed for range
`[start, end]` allocates a `LayerKvCache` for exactly those layer indices; a
middle shard `[2,3]` holds `{2,3}` and nothing else.
- **Full lifecycle:** prefill append, decode append, truncate (rollback),
release, TTL eviction, LRU eviction (by session cap and by byte budget), and an
**explicit** `CacheMiss` (unknown-session / evicted-ttl / evicted-lru /
released / superseded-epoch / seq-len-mismatch) so the head degrades to a
from-token-zero re-prefill instead of corrupting output (decision #14).
- **Fails closed on identity.** Stale route epochs raise `StaleRouteEpochError`; a
request carrying an incompatible KV recipe raises `IncompatibleCacheRecipeError`
(fingerprint mismatch of architecture / kv dtype / head geometry / owned range);
a recipe for an uncertified architecture fails closed at construction (reusing
the DGR-006 certified-architecture gate).
- **KV-aware boundary driver.** `KvBoundaryAdapter` wraps the DGR-006
`ShardComputation` (plus `run_layers_cached`) so a shard runs cached
prefill/decode through the manager while honouring the architecture-defined
boundary contract (head embeds tokens, middle/tail bypass embedding and consume
the unnormalized residual bundle, non-tail emits the unnormalized residual, tail
normalizes + heads + prunes + samples). The computation returns the new
position-encoded K/V; the manager commits it under the budget.
A pure-numpy **KV-cached** dense-Llama reference (RMSNorm + RoPE + SwiGLU with an
absolute-position causal mask over cached keys) proves that cached prefill/decode
reproduces the stateless whole-model greedy tokens bit-for-bit, single-range and
across a head/tail seam. torch/transformers are not installed in the default
`.venv`, so a numpy reference is the only way to keep the parity + isolation gate
deterministic, download-free, and GPU-free — the identical manager contract will
be satisfied by the pinned llama.cpp worker (DGR-008), where the KV context maps
onto a llama sequence.
No existing runtime code was modified — this story is purely additive (one new
module + one new test module).
## Files changed (all new)
- `packages/node/meshnet_node/hot_kv_state.py` — the KV/session manager:
- `KvCacheRecipe` — KV layout identity (certified architecture, kv dtype, head
geometry, owned range) with `fingerprint()` / `is_compatible()` /
`bytes_per_token()`; fails closed on uncertified architectures.
- `LayerKvCache` — per-owned-layer `(seq, n_kv_heads, head_dim)` K/V with
`append` / `truncate` / `nbytes`.
- `SessionCache` — the isolated per-`(session, epoch)` context over owned layers.
- `CacheMiss` / `CacheMissReason` — the explicit, serializable miss response.
- `HotKvStateManager``open` / `append` / `truncate` / `release` / `resolve` /
`get`, LRU+TTL+byte-budget eviction, stale-epoch + incompatible-recipe
rejection, epoch supersession, thread-safe (RLock), injectable clock.
- `KvBoundaryAdapter` + `kv_recipe_for()` — KV-aware boundary driver.
- `tests/test_hot_kv_state.py` — pure-numpy KV-cached dense-Llama reference and 22
tests (see below).
## Acceptance criteria → evidence
- **Map `(Route Session ID, route epoch)` to an isolated context** —
`test_prefill_then_decode_append_grows_owned_layers`,
`test_four_interleaved_sessions_have_no_kv_cross_talk`,
`HotKvStateManager.open` keys sessions on `(session_id, route_epoch)`.
- **Allocate KV only for owned layers** —
`test_manager_allocates_kv_only_for_owned_layers` (middle `[2,3]``{2,3}`),
`test_multi_range_cached_decode_parity_across_a_seam` (head owns `(0,1,2)`, tail
owns `(3,4,5)`), `test_recipe_bytes_per_token_scales_with_owned_layers`.
- **Prefill append / decode append / truncate / release / TTL-LRU eviction /
explicit cache-miss** — `test_prefill_then_decode_append_grows_owned_layers`,
`test_truncate_rolls_back_all_owned_layers`,
`test_release_one_session_leaves_others_intact_and_returns_memory`,
`test_ttl_eviction_yields_an_explicit_cache_miss`,
`test_lru_eviction_by_session_cap_reports_a_miss`,
`test_budget_eviction_keeps_total_within_budget`,
`test_unknown_session_is_an_explicit_cache_miss`,
`test_seq_len_mismatch_is_an_explicit_cache_miss`.
- **Reject stale epochs and incompatible cache recipes** —
`test_stale_route_epoch_is_rejected`,
`test_new_route_epoch_supersedes_and_frees_old_epoch`,
`test_incompatible_cache_recipe_is_rejected`,
`test_uncertified_architecture_recipe_fails_closed`.
- **≥ four concurrent sessions complete without token or KV cross-talk** —
`test_four_interleaved_sessions_have_no_kv_cross_talk` (four interleaved
round-robin sessions, four *distinct* references, each matches its own),
`test_four_sessions_on_real_threads_stay_isolated` (four OS threads).
- **Cancellation/release leaves others intact and memory returns to budget** —
`test_release_one_session_leaves_others_intact_and_returns_memory` (released
session → `CacheMiss(RELEASED)`, `total_bytes` drops, survivors keep matching
their references), `test_single_session_exceeding_budget_raises`.
- **Cached vs stateless correctness core** —
`test_cached_full_shard_decode_matches_stateless_whole_model`,
`test_cached_prefill_next_token_matches_whole_model_logits`,
`test_multi_range_cached_decode_parity_across_a_seam`. Documented tolerance:
**identical** greedy token ids (bit-exact in practice; cached incremental
attention equals stateless full-sequence recompute per query row).
- **Targeted pytest** — `22 passed`.
- **compileall packages tests** — exit 0.
- **git diff --check** — clean.
- **Deterministic / download-free / credit-free / GPU-free** — pure numpy; fixed
RNG seed; injectable clock (no wall-clock in tests); no torch, no network, no
model files.
- **Full deterministic pytest** — `13 failed, 755 passed, 14 skipped in 254.50s`.
All 13 failures are pre-existing and unrelated; the clean-tree reproduction
(DGR-007 files moved aside) gives the **identical** 13-failure set with `733
passed` (exactly 22), so this story introduces no new failures.
- **Native C++ / CTest / llama.cpp patch stack** — **not touched by this story.**
The KV context contract is delivered at the Python manager level with a numpy
parity + isolation proof; the equivalent native layer-filtered KV / session
mapping is wired when the standalone C++ worker exists in DGR-008. No native
code, CMake, or llama.cpp patch was modified, so those gates are N/A here (same
as DGR-005/006).
## Commands and real results
```bash
VP=/run/media/popov/d/DEV/repos/d-popov.com/AI/.venv/bin/python
$VP -m pytest -q tests/test_hot_kv_state.py
# -> 22 passed in ~0.3s
$VP -m compileall -q packages tests
# -> exit 0
git diff --check
# -> exit 0
$VP -m pytest -q tests/test_boundary_adapter.py tests/test_gguf_ownership.py
# -> 25 passed
$VP -m pytest -q -rfE
# -> 13 failed, 755 passed, 14 skipped in 254.50s
# Clean-tree reproduction (DGR-007 files moved aside)
mv packages/node/meshnet_node/hot_kv_state.py /tmp/ && mv tests/test_hot_kv_state.py /tmp/
$VP -m pytest -q -rfE
# -> 13 failed, 733 passed, 14 skipped in 252.12s (identical FAILED set; passed -22)
```
`commands.txt` beside this README captures the exact commands.
## Pre-existing unrelated failures (full-suite)
`pytest -q -rfE` on `ralph/distributed-gguf-runtime` reports 13 pre-existing
failures (and, in this run, 0 errors — the earlier DGR-005/006-era
`test_native_shard_protocol.py` protobuf errors no longer appear in this
environment). None touch the KV manager. Moving the two DGR-007 files aside and
re-running yields the **byte-identical** 13-`FAILED` set (only the passed count
drops by exactly 22). The exact set (all tracker/routing/benchmark/toploc/doctor,
i.e. socket-bind / control-plane env, not KV):
```
tests/test_dynamic_routing.py::test_admin_can_replace_a_served_model_and_release_it
tests/test_manual_route_benchmark.py::test_benchmark_records_one_and_two_node_routes
tests/test_manual_route_benchmark.py::test_clients_without_route_are_unaffected
tests/test_manual_route_benchmark.py::test_invalid_route_shape_is_400
tests/test_manual_route_benchmark.py::test_pinned_route_uses_named_node
tests/test_manual_route_benchmark.py::test_unknown_route_node_is_400
tests/test_node_doctor.py::test_cli_doctor_flags_select_what_is_validated
tests/test_toploc_calibration_dispatch.py::test_calibration_run_dispatches_only_solo_capable_nodes
tests/test_toploc_calibration_dispatch.py::test_calibration_run_node_without_commitment_endpoint_is_skipped_not_failed
tests/test_toploc_calibration_dispatch.py::test_calibration_run_persists_corpus_and_results_endpoint_reports_it
tests/test_tracker_capability_admission.py::test_an_enforcing_tracker_never_routes_a_node_whose_proof_does_not_cover_it[invalid]
tests/test_tracker_routing.py::test_shard_heal_cycle_surviving_node_covers_dead_peers_gap
tests/test_tracker_routing.py::test_torch_node_applies_tracker_load_shard_directive
```
## Limitations and deferred work
- **Numpy reference, not real weights.** The parity + isolation gate uses a
deterministic numpy KV-cached dense-Llama, not a downloaded GGUF/safetensors
model. Real-model concurrent KV isolation on a downloaded dense-Llama (CPU/ROCm)
belongs to DGR-010/DGR-012 with `MESHNET_ENABLE_REAL_INFERENCE_TESTS=1` and
`.venv-rocm`.
- **Manager-owned storage, native mapping deferred.** The KV bytes are numpy
arrays managed in-process. The llama.cpp expression (a filtered llama sequence
per `(session, epoch)` over owned layers) is implemented in the standalone
worker (DGR-008) against this same manager contract; no native code was touched.
- **Continuous batching is DGR-012.** This story delivers *isolation* and bounded
lifecycle for concurrent sessions; continuous batching of compatible active
sessions inside a node (decision #9) is DGR-012 and builds on this manager.
- **Greedy-only sampling.** Reuses the DGR-006 `SamplingContract` (greedy
certified). Stochastic sampling is out of scope for the deterministic gate.
- **Coexists with legacy `SessionCacheStore`.** The older AH-25
`model_backend.SessionCacheStore` (session-id-only, opaque transformers cache,
HTTP path) is untouched. `HotKvStateManager` is the native-runtime-aligned
successor: it adds route-epoch keying, owned-layer allocation, recipe-fingerprint
rejection, and a byte budget. DGR-008/009 wire the native worker to
`HotKvStateManager`, not `SessionCacheStore`.
## Compatibility / migration notes
- `KvCacheRecipe.fingerprint()` canonicalizes the architecture (via
`certified_architecture`), so `llama` / `LlamaForCausalLM` map to the same
recipe; it aligns field-for-field with the DGR-003 `RuntimeRecipeIdentity`
compatibility discipline and reuses `runtime_recipe.compatibility_fingerprint`.
- `CacheMiss` is a value (not an exception) so it can be serialized into the
DGR-002 native protocol's cache expectation/result field; `resolve()` returns it,
`get()` raises `KvCacheMissError` wrapping it.
- The manager takes an injectable `clock` for deterministic TTL tests; production
defaults to `time.monotonic`.
## Handoff for dependent stories
- **DGR-008 (C++ gRPC worker):** implement the servicer's KV path against
`HotKvStateManager`. Map each `(Route Session ID, route epoch)` to a filtered
llama sequence over owned layers; on decode, read the sequence's cached K/V,
compute the new position-encoded K/V, and commit via `append` (honour the byte
budget and return an explicit `CacheMiss` on eviction). Enforce
`KvCacheRecipe.is_compatible` before activation and reject stale epochs.
- **DGR-009 (Meshnet integration):** the route epoch the tracker assigns is the
`route_epoch` key; carry the `CacheMiss` reason back to the head so it re-prefills
from token zero on eviction/restart.
- **DGR-012 (continuous batching):** batch compatible active sessions whose
`KvCacheRecipe` fingerprints match; each session keeps its own `SessionCache`, so
batching is a scheduling concern layered over this isolation, not a change to it.
- **DGR-013 (failure/cancel matrix):** `release` + the budget-return assertion here
is the unit-level basis for the resource-cleanup matrix.

View File

@@ -1,31 +0,0 @@
# DGR-007 — exact commands (run from the worktree root).
# Python: /run/media/popov/d/DEV/repos/d-popov.com/AI/.venv (Python 3.14.6, numpy 2.4.4).
# Root conftest.py adds packages/* to sys.path, so `meshnet_node` imports work.
VP=/run/media/popov/d/DEV/repos/d-popov.com/AI/.venv/bin/python
# Targeted tests for this story.
$VP -m pytest -q tests/test_hot_kv_state.py
# -> 22 passed
# Python compile check for the changed packages/tests.
$VP -m compileall -q packages tests
# -> exit 0
# Diff hygiene.
git diff --check
# -> exit 0
# Dependency (DGR-006) + range-ownership (DGR-005) tests still green.
$VP -m pytest -q tests/test_boundary_adapter.py tests/test_gguf_ownership.py
# -> 25 passed
# Full deterministic suite (with DGR-007 files present).
$VP -m pytest -q -rfE
# -> see README (pre-existing unrelated failure set, +22 passed vs baseline)
# Clean-tree reproduction (DGR-007 files moved aside).
mv packages/node/meshnet_node/hot_kv_state.py /tmp/ && mv tests/test_hot_kv_state.py /tmp/
$VP -m pytest -q -rfE
# -> identical failure/error set, passed count drops by exactly 22
mv /tmp/hot_kv_state.py packages/node/meshnet_node/ && mv /tmp/test_hot_kv_state.py tests/

View File

@@ -1,47 +0,0 @@
{
"task_id": "DGR-007",
"title": "Add isolated concurrent local Hot KV State",
"status": "done",
"date": "2026-07-15",
"evidence_kind": "synthetic-unit",
"python": "/run/media/popov/d/DEV/repos/d-popov.com/AI/.venv (Python 3.14.6, numpy 2.4.4)",
"files_changed": [
"packages/node/meshnet_node/hot_kv_state.py",
"tests/test_hot_kv_state.py"
],
"gates": {
"targeted_pytest": {"command": "pytest -q tests/test_hot_kv_state.py", "result": "22 passed"},
"compileall": {"command": "python -m compileall -q packages tests", "exit": 0},
"git_diff_check": {"command": "git diff --check", "exit": 0},
"dependency_tests": {"command": "pytest -q tests/test_boundary_adapter.py tests/test_gguf_ownership.py", "result": "25 passed"},
"full_suite_with_files": {"command": "pytest -q -rfE", "result": "13 failed, 755 passed, 14 skipped", "seconds": 254.50},
"full_suite_clean_tree": {"command": "pytest -q -rfE (DGR-007 files moved aside)", "result": "13 failed, 733 passed, 14 skipped", "seconds": 252.12}
},
"no_new_failures": true,
"failure_set_identical": true,
"passed_delta": 22,
"preexisting_failures": [
"tests/test_dynamic_routing.py::test_admin_can_replace_a_served_model_and_release_it",
"tests/test_manual_route_benchmark.py::test_benchmark_records_one_and_two_node_routes",
"tests/test_manual_route_benchmark.py::test_clients_without_route_are_unaffected",
"tests/test_manual_route_benchmark.py::test_invalid_route_shape_is_400",
"tests/test_manual_route_benchmark.py::test_pinned_route_uses_named_node",
"tests/test_manual_route_benchmark.py::test_unknown_route_node_is_400",
"tests/test_node_doctor.py::test_cli_doctor_flags_select_what_is_validated",
"tests/test_toploc_calibration_dispatch.py::test_calibration_run_dispatches_only_solo_capable_nodes",
"tests/test_toploc_calibration_dispatch.py::test_calibration_run_node_without_commitment_endpoint_is_skipped_not_failed",
"tests/test_toploc_calibration_dispatch.py::test_calibration_run_persists_corpus_and_results_endpoint_reports_it",
"tests/test_tracker_capability_admission.py::test_an_enforcing_tracker_never_routes_a_node_whose_proof_does_not_cover_it[invalid]",
"tests/test_tracker_routing.py::test_shard_heal_cycle_surviving_node_covers_dead_peers_gap",
"tests/test_tracker_routing.py::test_torch_node_applies_tracker_load_shard_directive"
],
"native_gates_touched": false,
"acceptance": {
"session_epoch_isolated_context": true,
"kv_only_owned_layers": true,
"prefill_decode_truncate_release_ttl_lru_cachemiss": true,
"reject_stale_epoch_and_incompatible_recipe": true,
"four_concurrent_sessions_no_crosstalk": true,
"release_leaves_others_and_returns_memory": true
}
}

View File

@@ -1,83 +0,0 @@
# DGR-009 — Integrate the native worker with Meshnet: evidence
Status: done
Date: 2026-07-15
Evidence kind: **python-unit + repo-hygiene**. No model download, no GPU, no API
credit.
## Summary
Implemented the Meshnet-facing GGUF backend seam and recipe gating needed for
the native worker path:
- Added `GgufNodeBackend`, a backend-shaped adapter that lets the existing node
HTTP/control-plane code serve GGUF-backed shards without changing the
Transformers/Torch path for the default recipes.
- Added `llama-cpp-native` to the recipe manifest and gated startup so only
recipes with `backend_id == "llama.cpp"` build the GGUF backend.
- Preserved the existing registration/admission flow by carrying the validated
capability report and proof shard through registration.
- Added unit coverage for the GGUF backend seam and for recipe-gated startup.
- Fixed the explicit-shard startup path so the legacy Torch tests that use an
opaque stub model still pass without requiring HuggingFace config discovery.
## Files changed
- `packages/node/meshnet_node/gguf_backend.py` - new GGUF backend adapter and
worker-transport boundary.
- `packages/node/meshnet_node/startup.py` - recipe-gated GGUF backend injection
and explicit-shard startup fix.
- `packages/node/meshnet_node/recipes.json` - added `llama-cpp-native`.
- `tests/test_gguf_backend.py` - backend delegation and recipe-selection tests.
- `.ralph-tui/progress.md` - appended DGR-009 progress note.
- `.scratch/distributed-gguf-runtime/issues/09-integrate-the-native-worker-with-meshnet.md`
- marked `Status: done`.
## Commands and real results
```bash
python -m pytest -q tests/test_gguf_backend.py
# -> 2 passed in 0.05s
python -m pytest -q tests/test_node_admission.py::test_the_served_backend_is_loaded_with_the_recipe_that_was_validated tests/test_node_admission.py::test_backend_validation_failure_registers_nothing
# -> 2 passed in 0.07s
python -m compileall -q packages tests
# -> exit 0
git diff --check
# -> exit 0
python -m pytest -q
# -> 222 failed, 463 passed, 13 skipped, 86 errors in 135.65s
```
## Limitations
- `python -m pytest -q` is still not clean in this sandbox. The dominant
failures are tracker/control-plane socket `PermissionError: [Errno 1]
Operation not permitted` and a native protocol import failure caused by a
protobuf runtime mismatch (`gencode 7.35.0` vs runtime `6.33.6`).
- `tests/test_native_shard_protocol.py` currently fails for the same protobuf
runtime mismatch in this environment.
- `DGR-008` evidence was not present in the tree, so the dependency behavior was
verified by reading the live code and exercising the Python seam instead of
relying on a missing README.
## Compatibility notes
- The default Torch path remains intact; GGUF backend selection is explicit and
recipe-gated.
- `TorchNodeServer` already accepts an injected backend object, so the control
plane stays Meshnet-owned.
- The GGUF adapter currently establishes the seam for the native worker
transport; the compiled worker remains the owner of the gRPC protocol details.
## Dependent-story handoff
- DGR-008 should continue to own the native worker implementation and the
versioned gRPC frame handling behind `MESHNET_NATIVE_WORKER_URL`.
- DGR-010 / DGR-012 can build on this seam without changing the control plane:
the recipe-gated backend and validated capability report are already carried
through startup.

View File

@@ -1,58 +0,0 @@
# DGR-010 — Blocked handoff
Status: blocked
Date: 2026-07-15
## Blocker
I verified the local workspace and mounted-drive model storage, but there is no
certified dense-Llama artifact available on this machine to run the required
real-model two-process acceptance.
What I found:
- `/run/media/popov/d/DEV/models` contains Qwen artifacts and caches, but no
dense-Llama model snapshot or GGUF artifact.
- `/run/media/popov/d/DEV/llamacpp/llama.cpp/models` contains only vocab GGUFs,
not a certified dense-Llama model.
- The existing code paths for real startup, GGUF backend selection, Hot KV
isolation, and benchmark reporting are present and readable, but the actual
DGR-010 acceptance run needs a certified dense-Llama artifact from mounted
storage to satisfy the story contract.
## Verified current state
- DGR-009 evidence was read and verified as the dependency handoff.
- `packages/node/meshnet_node/startup.py` already gates backend selection by
recipe and can load either the Torch path or the explicit GGUF seam.
- `packages/node/meshnet_node/hot_kv_state.py`, `boundary_adapter.py`, and
`gguf_ownership.py` already provide the isolation/parity seams that DGR-010
would exercise.
- The repo has no existing `evidence/DGR-010/README.md` yet, which is expected
because the story has not been completed.
## Commands run
```bash
sed -n '1,260p' .scratch/distributed-gguf-runtime/RALPH-CONTEXT.md
sed -n '1,260p' .scratch/distributed-gguf-runtime/issues/10-pass-local-real-model-two-process-acceptance.md
sed -n '1,260p' .scratch/distributed-gguf-runtime/evidence/DGR-009/README.md
git status --short
find /run/media/popov/d/DEV -type f \( -name '*.gguf' -o -name '*.safetensors' -o -name 'config.json' \) | rg -i 'llama|tinyllama|meta-llama|hf-internal-testing|qwen'
```
## Next step to unblock
Provide or mount a certified dense-Llama artifact on the configured mounted
drive storage, then rerun the DGR-010 acceptance path with
`MESHNET_ENABLE_REAL_INFERENCE_TESTS=1`.
## Continuation note
Once the artifact exists, the next iteration should:
1. Run the two local worker processes against the certified dense-Llama shard
ranges.
2. Capture parity, concurrency, memory, and failure metrics.
3. Write `evidence/DGR-010/README.md` with the real results and then update the
issue status.

View File

@@ -1,70 +0,0 @@
# DGR-011 — Blocked handoff
Status: blocked
Date: 2026-07-15
## Blocker
This story cannot be completed in the current workspace state because its
mandatory dependency, DGR-010, is still not passed.
Verified blockers:
- `.scratch/distributed-gguf-runtime/prd.json` still marks `DGR-010` and
`DGR-011` with `"passes": false`.
- `.scratch/distributed-gguf-runtime/evidence/DGR-010/README.md` does not
exist, and the only DGR-010 evidence artifact present is
`.scratch/distributed-gguf-runtime/evidence/DGR-010/BLOCKED.md`.
- Mounted storage search found Qwen model artifacts and llama.cpp vocab files,
but no certified dense-Llama GGUF artifact suitable for the required real
acceptance run.
## Verified current state
- The repo already contains the Meshnet-facing GGUF backend seam and the
recipe-gated startup path from DGR-009.
- The architecture and Ralph context require real-model execution for this
story, not synthetic workers or unit-only coverage.
- The current environment does not expose the dense-Llama artifact required to
run the prerequisite local real-model acceptance, so the two-machine route
cannot be proven end to end.
## Commands run
```bash
sed -n '1,260p' .scratch/distributed-gguf-runtime/RALPH-CONTEXT.md
sed -n '1,260p' .scratch/distributed-gguf-runtime/issues/11-pass-a-real-heterogeneous-two-machine-route.md
sed -n '1,260p' .ralph-tui/progress.md
sed -n '1,240p' .scratch/distributed-gguf-runtime/evidence/DGR-010/BLOCKED.md
sed -n '1,220p' CONTEXT.md
sed -n '1,260p' docs/adr/0024-distributed-gguf-runtime.md
sed -n '282,350p' .scratch/distributed-gguf-runtime/prd.json
find /run/media/popov/d/DEV/models -maxdepth 3 \( -name '*.gguf' -o -name 'config.json' -o -name '*.safetensors' \)
find /run/media/popov/d/DEV/llamacpp/llama.cpp/models /run/media/popov/d/DEV/models -maxdepth 4 \( -iname '*llama*' -o -iname '*dense*' -o -iname '*qwen*' -o -name 'config.json' -o -name '*.gguf' \)
```
## Known limitations
- No certified dense-Llama artifact is available on mounted storage in this
workspace.
- No real two-machine execution was possible, so there are no real route,
hardware, backend, or drift metrics to record for this story.
- The story remains blocked until DGR-010 is completed with a real-model
evidence README and a confirmed dense-Llama artifact on mounted storage.
## Compatibility notes
- DGR-009's recipe-gated GGUF backend seam is present and can be reused.
- The acceptance path for this story still requires the upstream real-model
evidence from DGR-010 before any heterogeneous two-machine route can be
claimed.
## Dependent-story handoff
- Finish DGR-010 first, including its real-model evidence README and
acceptance run.
- Once DGR-010 passes, rerun the two-machine acceptance against the same
certified dense-Llama artifact, then record the two-host hardware/network
manifest, route, commands, and raw metrics in `evidence/DGR-011/README.md`.
- Do not update the issue to `Status: done` until the real two-machine route
has been executed and recorded.

View File

@@ -13,15 +13,6 @@ Status: ready-for-agent
As a runtime engineer, I need a controlled baseline so that GGUF work proceeds from measured speed, memory, and quality rather than reputation. As a runtime engineer, I need a controlled baseline so that GGUF work proceeds from measured speed, memory, and quality rather than reputation.
## Baseline model target
Use the same model on both sides of the comparison, with the closest practical low-footprint precision pair:
- **safetensors:** `deepseek-ai/DeepSeek-V2-Lite-Chat` in **BF16**
- **GGUF:** `second-state/DeepSeek-V2-Lite-Chat-GGUF` in **Q2_K** (~6.5GB)
Keep the benchmark matrix explicit for **CPU** and **GPU** runs. Reserve smaller non-DeepSeek fallback models only for loader plumbing smoke tests if needed; they do not count as the DGR-001 architecture-aligned baseline.
## Expected durable outputs ## Expected durable outputs
- Benchmark harness and deterministic tests - Benchmark harness and deterministic tests

View File

@@ -1,6 +1,6 @@
# 02 — Adopt the versioned gRPC Shard protocol # 02 — Adopt the versioned gRPC Shard protocol
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context
@@ -22,22 +22,22 @@ As a node developer, I need a battle-proven streaming protocol so that Python an
## Acceptance criteria ## Acceptance criteria
- [x] Add a Protocol Buffers schema for capability, health, session stream, release, and cancellation operations. - [ ] Add a Protocol Buffers schema for capability, health, session stream, release, and cancellation operations.
- [x] Define one long-lived bidirectional gRPC stream per Route Session Activation Seam with deadlines, cancellation, flow control, and structured errors. - [ ] Define one long-lived bidirectional gRPC stream per Route Session Activation Seam with deadlines, cancellation, flow control, and structured errors.
- [x] Define bounded chunking for prefill and a small decode fast path. - [ ] Define bounded chunking for prefill and a small decode fast path.
- [x] Carry schema version, request/work ID, Route Session ID, route epoch, artifact/recipe fingerprint, Shard range/effective start, phase, position, idempotency step, cache expectation, compression, and checksum. - [ ] Carry schema version, request/work ID, Route Session ID, route epoch, artifact/recipe fingerprint, Shard range/effective start, phase, position, idempotency step, cache expectation, compression, and checksum.
- [x] Define a versioned named-tensor bundle with per-tensor name, shape, dtype, byte order, and payload fragments. - [ ] Define a versioned named-tensor bundle with per-tensor name, shape, dtype, byte order, and payload fragments.
- [x] Add generated-schema round-trip and compatibility tests in Python and C++. - [ ] Add generated-schema round-trip and compatibility tests in Python and C++.
- [x] Targeted pytest tests pass - [ ] Targeted pytest tests pass
- [x] python -m compileall packages tests passes for Python changes - [ ] python -m compileall packages tests passes for Python changes
- [x] git diff --check passes - [ ] git diff --check passes
- [x] Default tests remain deterministic, model-download-free, API-credit-free, and GPU-free - [ ] Default tests remain deterministic, model-download-free, API-credit-free, and GPU-free
- [x] Full deterministic pytest -q passes, or the exact pre-existing unrelated failure is recorded with a clean-tree reproduction - [ ] Full deterministic pytest -q passes, or the exact pre-existing unrelated failure is recorded with a clean-tree reproduction
- [x] Read .scratch/distributed-gguf-runtime/RALPH-CONTEXT.md and this story issue completely before changing code - [ ] Read .scratch/distributed-gguf-runtime/RALPH-CONTEXT.md and this story issue completely before changing code
- [x] Read and verify every dependency evidence README before relying on dependency behavior - [ ] Read and verify every dependency evidence README before relying on dependency behavior
- [x] Preserve all pre-existing working-tree changes and stage only files belonging to this story - [ ] Preserve all pre-existing working-tree changes and stage only files belonging to this story
- [x] Write .scratch/distributed-gguf-runtime/evidence/DGR-002/README.md with files changed, exact commands and real results, limitations, compatibility notes, and dependent-story handoff - [ ] Write .scratch/distributed-gguf-runtime/evidence/DGR-002/README.md with files changed, exact commands and real results, limitations, compatibility notes, and dependent-story handoff
- [x] Update only this story issue to Status: done after every acceptance criterion and quality gate passes - [ ] Update only this story issue to Status: done after every acceptance criterion and quality gate passes
## Dependency handoff ## Dependency handoff

View File

@@ -1,6 +1,6 @@
# 03 — Define exact Artifact and runtime recipe identity # 03 — Define exact Artifact and runtime recipe identity
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context

View File

@@ -1,6 +1,6 @@
# 04 — Create the reproducible pinned llama.cpp patch stack # 04 — Create the reproducible pinned llama.cpp patch stack
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context

View File

@@ -1,6 +1,6 @@
# 05 — Implement dense-Llama range-aware GGUF ownership # 05 — Implement dense-Llama range-aware GGUF ownership
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context

View File

@@ -1,6 +1,6 @@
# 06 — Implement architecture-defined boundary input/output # 06 — Implement architecture-defined boundary input/output
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context

View File

@@ -1,6 +1,6 @@
# 07 — Add isolated concurrent local Hot KV State # 07 — Add isolated concurrent local Hot KV State
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context

View File

@@ -1,6 +1,6 @@
# 09 — Integrate the native worker with Meshnet # 09 — Integrate the native worker with Meshnet
Status: done Status: ready-for-agent
## Mandatory fresh-session context ## Mandatory fresh-session context

View File

@@ -54,7 +54,7 @@
"Update only this story issue to Status: done after every acceptance criterion and quality gate passes" "Update only this story issue to Status: done after every acceptance criterion and quality gate passes"
], ],
"priority": 1, "priority": 1,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-gguf-runtime/issues/02-adopt-the-versioned-grpc-shard-protocol.md", "notes": "Source issue: .scratch/distributed-gguf-runtime/issues/02-adopt-the-versioned-grpc-shard-protocol.md",
"dependsOn": [] "dependsOn": []
}, },

View File

@@ -1,4 +1,4 @@
Status: done (2026-07-14) Status: ready-for-agent
# 01 — Baseline and profiling harness # 01 — Baseline and profiling harness
@@ -12,15 +12,16 @@ sizes and connection counts without requiring a real model or external host.
## Acceptance criteria ## Acceptance criteria
- [x] The harness runs a fixed prompt and fixed generated-token count through a - [ ] The harness runs a fixed prompt and fixed generated-token count through a
two-node route in direct and relay modes. two-node route in direct and relay modes.
- [x] It reports p50/p95 per-token latency, per-hop latency, payload bytes, - [ ] It reports p50/p95 per-token latency, per-hop latency, payload bytes,
compression ratio, connection attempts, and queue wait. compression ratio, connection attempts, and queue wait.
- [x] It distinguishes prefill from decode and cached from stateless mode. - [ ] It distinguishes prefill from decode and cached from stateless mode.
- [x] It emits machine-readable JSON suitable for CI artifacts and a concise - [ ] It emits machine-readable JSON suitable for CI artifacts and a concise
human-readable summary. human-readable summary.
- [x] A test fixture can assert connection attempts and output token identity. - [ ] A test fixture can assert connection attempts and output token identity.
## Blocked by ## Blocked by
None - completed. Verified with `PYTHONPATH=packages/node pytest -q tests/test_route_session_benchmark.py` (7 passed). None - can start immediately.

View File

@@ -15,10 +15,9 @@
"Can assert connection count and output token identity" "Can assert connection count and output token identity"
], ],
"priority": 1, "priority": 1,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/01-baseline-profiling-harness.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/01-baseline-profiling-harness.md",
"dependsOn": [], "dependsOn": []
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-002", "id": "DIP-002",
@@ -32,12 +31,9 @@
"Tests cover binary, JSON, timeout, disconnect, cancellation, and cleanup" "Tests cover binary, JSON, timeout, disconnect, cancellation, and cleanup"
], ],
"priority": 2, "priority": 2,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/02-relay-session-compatibility.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/02-relay-session-compatibility.md",
"dependsOn": [ "dependsOn": ["DIP-001"]
"DIP-001"
],
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-003", "id": "DIP-003",
@@ -51,12 +47,9 @@
"Benchmark shows healthy-session connection count independent of token count" "Benchmark shows healthy-session connection count independent of token count"
], ],
"priority": 3, "priority": 3,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/03-http-keepalive.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/03-http-keepalive.md",
"dependsOn": [ "dependsOn": ["DIP-001"]
"DIP-001"
],
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-004", "id": "DIP-004",
@@ -70,12 +63,9 @@
"Tests verify cadence and cleanup" "Tests verify cadence and cleanup"
], ],
"priority": 4, "priority": 4,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/04-seam-telemetry.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/04-seam-telemetry.md",
"dependsOn": [ "dependsOn": ["DIP-001"]
"DIP-001"
],
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-005", "id": "DIP-005",
@@ -89,12 +79,9 @@
"Tests cover compressible, incompressible, threshold, malformed, and legacy bodies" "Tests cover compressible, incompressible, threshold, malformed, and legacy bodies"
], ],
"priority": 5, "priority": 5,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/05-adaptive-compression.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/05-adaptive-compression.md",
"dependsOn": [ "dependsOn": ["DIP-001"]
"DIP-001"
],
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-006", "id": "DIP-006",
@@ -108,12 +95,9 @@
"Wire and token-output regression tests pass" "Wire and token-output regression tests pass"
], ],
"priority": 6, "priority": 6,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/06-activation-framing-copies.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/06-activation-framing-copies.md",
"dependsOn": [ "dependsOn": ["DIP-001"]
"DIP-001"
],
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-007", "id": "DIP-007",
@@ -127,13 +111,9 @@
"Tests cover chunking, slow consumers, failure, and legacy peers" "Tests cover chunking, slow consumers, failure, and legacy peers"
], ],
"priority": 7, "priority": 7,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/07-prefill-backpressure.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/07-prefill-backpressure.md",
"dependsOn": [ "dependsOn": ["DIP-001", "DIP-004"]
"DIP-001",
"DIP-004"
],
"completionNotes": "Completed by agent"
}, },
{ {
"id": "DIP-008", "id": "DIP-008",
@@ -147,20 +127,9 @@
"Gate verifies token identity, session stability, and resource cleanup" "Gate verifies token identity, session stability, and resource cleanup"
], ],
"priority": 8, "priority": 8,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/distributed-inference-performance/issues/08-end-to-end-performance-gate.md", "notes": "Source issue: .scratch/distributed-inference-performance/issues/08-end-to-end-performance-gate.md",
"dependsOn": [ "dependsOn": ["DIP-002", "DIP-003", "DIP-004", "DIP-005", "DIP-006", "DIP-007"]
"DIP-002",
"DIP-003",
"DIP-004",
"DIP-005",
"DIP-006",
"DIP-007"
],
"completionNotes": "Completed by agent"
} }
], ]
"metadata": {
"updatedAt": "2026-07-12T02:35:28.752Z"
}
} }

View File

@@ -35,12 +35,11 @@
"Full pytest passes or an exact unrelated blocker is recorded" "Full pytest passes or an exact unrelated blocker is recorded"
], ],
"priority": 2, "priority": 2,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/node-capability-admission/issues/02-doctor-real-forward.md", "notes": "Source issue: .scratch/node-capability-admission/issues/02-doctor-real-forward.md",
"dependsOn": [ "dependsOn": [
"NCA-001" "NCA-001"
], ]
"completionNotes": "Completed by agent"
}, },
{ {
"id": "NCA-003", "id": "NCA-003",
@@ -55,13 +54,12 @@
"Full pytest passes or an exact unrelated blocker is recorded" "Full pytest passes or an exact unrelated blocker is recorded"
], ],
"priority": 3, "priority": 3,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/node-capability-admission/issues/03-fail-closed-startup-admission.md", "notes": "Source issue: .scratch/node-capability-admission/issues/03-fail-closed-startup-admission.md",
"dependsOn": [ "dependsOn": [
"NCA-001", "NCA-001",
"NCA-002" "NCA-002"
], ]
"completionNotes": "Completed by agent"
}, },
{ {
"id": "NCA-004", "id": "NCA-004",
@@ -78,13 +76,12 @@
"Full pytest passes or an exact unrelated blocker is recorded" "Full pytest passes or an exact unrelated blocker is recorded"
], ],
"priority": 4, "priority": 4,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/node-capability-admission/issues/04-tracker-validated-capability-routing.md", "notes": "Source issue: .scratch/node-capability-admission/issues/04-tracker-validated-capability-routing.md",
"dependsOn": [ "dependsOn": [
"NCA-001", "NCA-001",
"NCA-003" "NCA-003"
], ]
"completionNotes": "Completed by agent"
}, },
{ {
"id": "NCA-005", "id": "NCA-005",
@@ -99,16 +96,15 @@
"Full pytest passes or an exact unrelated blocker is recorded" "Full pytest passes or an exact unrelated blocker is recorded"
], ],
"priority": 5, "priority": 5,
"passes": true, "passes": false,
"notes": "Source issue: .scratch/node-capability-admission/issues/05-docs-hardware-lane-contract.md", "notes": "Source issue: .scratch/node-capability-admission/issues/05-docs-hardware-lane-contract.md",
"dependsOn": [ "dependsOn": [
"NCA-002", "NCA-002",
"NCA-004" "NCA-004"
], ]
"completionNotes": "Completed by agent"
} }
], ],
"metadata": { "metadata": {
"updatedAt": "2026-07-12T01:54:03.030Z" "updatedAt": "2026-07-11T19:16:52.768Z"
} }
} }

View File

@@ -16,9 +16,12 @@
.\.venv\Scripts\meshnet-node.exe start http://192.168.0.179:8081 --model-id Qwen/Qwen2.5-0.5B-Instruct --advertise-host 192.168.0.20 .\.venv\Scripts\meshnet-node.exe start http://192.168.0.179:8081 --model-id Qwen/Qwen2.5-0.5B-Instruct --advertise-host 192.168.0.20
.\.venv\Scripts\meshnet-node.exe start --tracker http://ai.neuron.d-popov.com --model Qwen/Qwen2.5-0.5B-Instruct --advertise-host 192.168.0.20 .\.venv\Scripts\meshnet-node.exe start --tracker http://ai.neuron.d-popov.com --model-id Qwen/Qwen2.5-0.5B-Instruct --advertise-host 192.168.0.20
we .\.venv\Scripts\meshnet-node.exe start --tracker http://192.168.0.179:8081 --model Qwen/Qwen2.5-0.5B-Instruct we .\.venv\Scripts\meshnet-node.exe start `
--tracker http://192.168.0.179:8081 `
--model Qwen/Qwen2.5-0.5B-Instruct `
--advertise-host 192.168.0.20
# trackers: # trackers:
https://meshnet.2.d-popov.com https://meshnet.2.d-popov.com
https://ai.neuron.d-popov.com https://ai.neuron.d-popov.com

View File

@@ -20,17 +20,9 @@ import time
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Callable from typing import Any, Callable
from . import __version__ as _PACKAGE_VERSION from .capability import CapabilityReport
from .capability import CapabilityReport, config_fingerprint
from .doctor import DoctorSelection from .doctor import DoctorSelection
from .recipe_manifest import Recipe, RecipeManifest from .recipe_manifest import Recipe, RecipeManifest
from .runtime_recipe import (
build_artifact_identity,
build_runtime_recipe_identity,
compatibility_fingerprint,
fingerprint_payload,
)
from .gguf_ownership import authoritative_dense_llama_ownership
# How long a passing report stays usable. Startup normally validates in-process # How long a passing report stays usable. Startup normally validates in-process
# (age ≈ 0); this bounds how far a report written by an earlier `doctor` run can # (age ≈ 0); this bounds how far a report written by an earlier `doctor` run can
@@ -47,7 +39,6 @@ REASON_MODEL_MISMATCH = "model-mismatch"
REASON_SHARD_MISMATCH = "shard-mismatch" REASON_SHARD_MISMATCH = "shard-mismatch"
REASON_RECIPE_MISMATCH = "recipe-mismatch" REASON_RECIPE_MISMATCH = "recipe-mismatch"
REASON_BACKEND_MISMATCH = "backend-mismatch" REASON_BACKEND_MISMATCH = "backend-mismatch"
REASON_COMPATIBILITY_MISMATCH = "compatibility-mismatch"
class CapabilityAdmissionError(RuntimeError): class CapabilityAdmissionError(RuntimeError):
@@ -86,7 +77,6 @@ class AdmissionRequirement:
recipe_version: str recipe_version: str
backend_id: str backend_id: str
device: str device: str
compatibility_fingerprint: str
max_age_seconds: float = DEFAULT_MAX_REPORT_AGE_SECONDS max_age_seconds: float = DEFAULT_MAX_REPORT_AGE_SECONDS
@classmethod @classmethod
@@ -104,9 +94,6 @@ class AdmissionRequirement:
recipe_version=context.recipe.version, recipe_version=context.recipe.version,
backend_id=context.recipe.backend_id, backend_id=context.recipe.backend_id,
device=context.device, device=context.device,
compatibility_fingerprint=_compatibility_fingerprint_for_context(
context
),
max_age_seconds=max_age_seconds, max_age_seconds=max_age_seconds,
) )
@@ -178,16 +165,6 @@ def admit(
f"{requirement.backend_id} on {requirement.device}", f"{requirement.backend_id} on {requirement.device}",
) )
if report.compatibility_fingerprint != requirement.compatibility_fingerprint:
raise CapabilityAdmissionError(
REASON_COMPATIBILITY_MISMATCH,
f"capability proof fingerprint {report.compatibility_fingerprint!r} "
f"does not match the expected compatibility fingerprint for "
f"{requirement.model_id} {requirement.shard_label}; the artifact, "
f"tokenizer, architecture, boundary schema, activation recipe or "
f"cache layout differs",
)
if not report.passed: if not report.passed:
raise CapabilityAdmissionError( raise CapabilityAdmissionError(
REASON_NOT_PASSED, REASON_NOT_PASSED,
@@ -246,157 +223,3 @@ def probe_capability(context: CapabilityContext) -> CapabilityReport:
context.recipe, context.recipe,
context.manifest, context.manifest,
).report ).report
def _compatibility_fingerprint_for_context(context: CapabilityContext) -> str:
backend = context.backend
selection = context.selection
recipe = context.recipe
model_config = getattr(getattr(backend, "model", None), "config", None)
model_config_payload = (
model_config.to_dict() if hasattr(model_config, "to_dict") else model_config
)
runtime_versions = _runtime_versions()
runtime_version = _PACKAGE_VERSION
ownership = authoritative_dense_llama_ownership(backend, selection)
artifact = build_artifact_identity(
model_id=selection.model_id,
revision=getattr(getattr(backend, "model", None), "revision", None),
model_config=model_config_payload,
shard_start=ownership.start_layer,
shard_end=ownership.end_layer,
)
runtime_recipe = build_runtime_recipe_identity(
model_id=selection.model_id,
revision=getattr(getattr(backend, "model", None), "revision", None),
model_config=model_config_payload,
recipe_params=recipe.params,
weight_quantization=selection.quantization,
backend_id=recipe.backend_id,
runtime_version=runtime_version,
activation_dtype="bfloat16",
compute_dtype=_backend_compute_dtype(backend),
kv_dtype=_backend_kv_dtype(backend),
kv_layout=_backend_kv_layout(backend),
tokenizer_revision=_backend_tokenizer_revision(backend, selection),
architecture_adapter=_backend_architecture_adapter(backend, recipe.backend_id),
boundary_schema_version=1,
cache_layout=_backend_cache_layout(backend, recipe.params),
)
return compatibility_fingerprint(
fingerprint_payload(
model={
"model_id": selection.model_id,
"revision": getattr(getattr(backend, "model", None), "revision", None),
"config_fingerprint": config_fingerprint(model_config_payload),
},
shard={
"start": ownership.start_layer,
"end": ownership.end_layer,
"owns_embedding": ownership.owns_embedding,
"owns_final_head": ownership.owns_final_head,
},
recipe={
"recipe_id": recipe.id,
"recipe_version": recipe.version,
"catalogue_version": context.manifest.catalogue_version,
},
backend={
"backend_id": recipe.backend_id,
"device": context.device,
"device_name": _backend_device_name(context.device),
"quantization": selection.quantization,
"runtime": runtime_versions,
},
artifact=artifact.to_dict(),
runtime_recipe=runtime_recipe.to_dict(),
)
)
def _runtime_versions() -> dict[str, str]:
versions: dict[str, str] = {}
for name in ("torch", "transformers"):
try:
module = __import__(name)
except Exception:
continue
version = getattr(module, "__version__", None)
if version:
versions[name] = str(version)
return versions
def _backend_compute_dtype(backend: Any) -> str:
config = getattr(getattr(backend, "model", None), "config", None)
for candidate in (config, getattr(config, "text_config", None)):
if candidate is None:
continue
for attr in ("dtype", "torch_dtype"):
value = getattr(candidate, attr, None)
if value is None:
continue
return str(value).removeprefix("torch.")
return "bfloat16"
def _backend_kv_dtype(backend: Any) -> str:
return _backend_compute_dtype(backend)
def _backend_kv_layout(backend: Any) -> str:
return "session-cache" if getattr(backend, "supports_kv_cache", False) else "stateless"
def _backend_tokenizer_revision(backend: Any, selection: DoctorSelection) -> str:
model = getattr(backend, "model", None)
revision = getattr(model, "revision", None)
if isinstance(revision, str) and revision.strip():
return revision
tokenizer = getattr(backend, "tokenizer", None)
for attr in ("revision", "model_id"):
value = getattr(tokenizer, attr, None)
if isinstance(value, str) and value.strip():
return value
return selection.model_id
def _backend_architecture_adapter(backend: Any, default: str) -> str:
config = getattr(getattr(backend, "model", None), "config", None)
for candidate in (config, getattr(config, "text_config", None)):
if candidate is None:
continue
for attr in ("architecture_adapter", "model_type"):
value = getattr(candidate, attr, None)
if isinstance(value, str) and value.strip():
return value
architectures = getattr(candidate, "architectures", None)
if isinstance(architectures, (list, tuple)) and architectures:
first = architectures[0]
if isinstance(first, str) and first.strip():
return first
return default
def _backend_device_name(device: str) -> str | None:
if device != "cuda":
return None
from .hardware import detect_hardware
try:
return detect_hardware().get("gpu_name") or None
except Exception:
return None
def _backend_cache_layout(backend: Any, recipe_params: dict[str, Any] | None) -> str:
if getattr(backend, "supports_kv_cache", False) is False:
return "stateless"
if recipe_params is None:
return "local-hot-kv"
if recipe_params.get("use_cache") is False:
return "stateless"
value = recipe_params.get("cache_layout")
if isinstance(value, str) and value.strip():
return value
return "local-hot-kv"

View File

@@ -1,484 +0,0 @@
"""Architecture-defined boundary input/output for distributed Shards (DGR-006).
A public-network Shard is a contiguous range of transformer layers (RALPH runtime
decision #1). For disjoint processes to reproduce whole-model execution, every
Shard must agree on *exactly* what boundary state it consumes and emits:
* The **head** owns token embedding: it accepts token IDs and turns them into the
residual stream. No other Shard may embed tokens.
* **Middle and tail** Shards bypass token embedding entirely; they accept the named
boundary bundle (the residual stream handed over by the previous range).
* A **non-tail** Shard emits the *unnormalized* architecture-defined residual /
boundary — before the final norm, before the LM head, and before any tail-only
row pruning — so the next range sees precisely the state the whole model would
have at that layer index.
* The **tail** owns the final norm + LM head and turns the residual into logits or
a sampled token through an explicit sampling contract.
This module is deliberately backend-agnostic. It enforces the boundary *contract*
and defers the arithmetic to a ``ShardComputation`` (a duck-typed object exposing
``embed_tokens`` / ``run_layers`` / ``final_norm`` / ``lm_head``). The pinned
llama.cpp worker (DGR-008) and the reference PyTorch backend both satisfy that
protocol, and the numpy reference model in the tests proves whole-model versus
two-range parity without any download, GPU, or API credit.
The adapter **fails closed** for uncertified architectures: only architectures
that have passed real certification (dense Llama-family first, per RALPH runtime
decision #13) are accepted. Everything else raises rather than silently guessing a
tensor layout — Qwen3/Qwen3-MoE stays registered-but-dark until DGR-015 certifies
its own adapter.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Any
import numpy as np
# The boundary bundle wire schema version. This is the ``boundary_schema_version``
# carried by ``runtime_recipe.RuntimeRecipeIdentity``; a receiver refuses a bundle
# whose schema it does not implement (forward/backward compatibility is a routing
# concern, not a silent reinterpretation).
BOUNDARY_SCHEMA_VERSION = 1
class BoundaryAdapterError(RuntimeError):
"""Base class for boundary-contract violations."""
class UncertifiedArchitectureError(BoundaryAdapterError):
"""Raised when a boundary adapter is requested for an uncertified architecture.
Failing closed here is a safety property: an unknown architecture has an
unknown tensor layout, so guessing where the residual boundary lives would
silently corrupt distributed output. The architecture must pass real
certification first.
"""
class BoundaryContractError(BoundaryAdapterError):
"""Raised when a Shard is fed the wrong boundary input for its role.
Examples: a head handed a residual bundle instead of token IDs, a middle
Shard handed token IDs it must not embed, or a boundary bundle whose
architecture / schema / seam layer does not match the receiving range.
"""
@dataclass(frozen=True)
class ArchitectureBoundary:
"""The architecture-defined boundary description for one certified adapter.
These fields are what makes the boundary *architecture-defined* rather than a
hardcoded assumption: the residual tensor name, whether the tail normalizes
before the LM head, and whether row pruning is a tail-only concern all come
from here.
"""
adapter: str
boundary_tensor_name: str
boundary_schema_version: int
normalizes_before_head: bool
prunes_rows_at_tail: bool
# Certified architectures only. Dense Llama-family is first (RALPH runtime decision
# #13 + native discipline). Aliases map the many spellings a runtime recipe /
# GGUF / HF config may use onto the single canonical adapter id. Anything not in
# this table fails closed.
_DENSE_LLAMA = ArchitectureBoundary(
adapter="dense-llama",
boundary_tensor_name="residual_stream",
boundary_schema_version=BOUNDARY_SCHEMA_VERSION,
normalizes_before_head=True,
prunes_rows_at_tail=True,
)
_CERTIFIED_ARCHITECTURES: dict[str, ArchitectureBoundary] = {
"dense-llama": _DENSE_LLAMA,
"dense_llama": _DENSE_LLAMA,
"llama": _DENSE_LLAMA,
"llamaforcausallm": _DENSE_LLAMA,
"llamamodel": _DENSE_LLAMA,
}
def certified_architecture(name: Any) -> ArchitectureBoundary:
"""Return the certified boundary description for ``name`` or fail closed.
``name`` may be the canonical adapter id (``dense-llama``), an HF architecture
class (``LlamaForCausalLM``), or a GGUF/config ``model_type`` (``llama``).
Uncertified architectures raise ``UncertifiedArchitectureError``.
"""
if not isinstance(name, str) or not name.strip():
raise UncertifiedArchitectureError(
"architecture adapter must be a non-empty string; "
"the boundary adapter refuses to guess a tensor layout"
)
key = name.strip().lower()
boundary = _CERTIFIED_ARCHITECTURES.get(key)
if boundary is None:
raise UncertifiedArchitectureError(
f"architecture {name!r} is not certified for the boundary adapter; "
f"certified adapters: {sorted(set(v.adapter for v in _CERTIFIED_ARCHITECTURES.values()))}. "
"Uncertified architectures stay registered-but-dark until real "
"certification passes."
)
return boundary
def is_certified_architecture(name: Any) -> bool:
"""Return True when ``name`` maps to a certified boundary adapter."""
try:
certified_architecture(name)
except UncertifiedArchitectureError:
return False
return True
class ShardRole(str, Enum):
"""Where a contiguous layer range sits in the whole model."""
HEAD = "head"
MIDDLE = "middle"
TAIL = "tail"
FULL = "full"
@property
def owns_embedding(self) -> bool:
return self in (ShardRole.HEAD, ShardRole.FULL)
@property
def owns_final_head(self) -> bool:
return self in (ShardRole.TAIL, ShardRole.FULL)
def role_for_range(start_layer: int, end_layer: int, total_layers: int) -> ShardRole:
"""Classify a contiguous inclusive layer range within a model of ``total_layers``."""
if total_layers <= 0:
raise ValueError("total_layers must be positive")
if start_layer < 0 or end_layer < start_layer:
raise ValueError("require 0 <= start_layer <= end_layer")
if end_layer > total_layers - 1:
raise ValueError(
f"end_layer {end_layer} exceeds last layer index {total_layers - 1}"
)
is_head = start_layer == 0
is_tail = end_layer >= total_layers - 1
if is_head and is_tail:
return ShardRole.FULL
if is_head:
return ShardRole.HEAD
if is_tail:
return ShardRole.TAIL
return ShardRole.MIDDLE
@dataclass(frozen=True)
class BoundaryBundle:
"""The versioned named-tensor bundle handed between adjacent Shard ranges.
``residual`` is the *unnormalized* architecture-defined residual stream with
every position row intact (no tail-only pruning). ``next_layer`` is the layer
index the receiving range must start at — it is the overlap-safe effective
start of the seam, so a receiver can reject a bundle meant for a different cut.
"""
architecture_adapter: str
schema_version: int
tensor_name: str
residual: np.ndarray
positions: np.ndarray
next_layer: int
normalized: bool = False
def named_tensor_fields(self) -> dict[str, Any]:
"""Return the wire-shaped description of the residual tensor.
These are exactly the fields the DGR-002 ``NamedTensor`` carries (name,
shape, dtype, byte order, raw bytes), so a worker can serialize this
bundle into the gRPC protobuf without re-deriving them.
"""
residual = np.ascontiguousarray(self.residual)
return {
"name": self.tensor_name,
"shape": list(residual.shape),
"dtype": residual.dtype.name,
"byte_order": _byte_order(residual.dtype),
"data": residual.tobytes(),
}
def pack(self) -> dict[str, Any]:
"""Serialize the bundle to a transport-agnostic dict (proves the seam).
The residual and positions are carried as raw little/big-endian bytes plus
shape/dtype so that a truly disjoint process can reconstruct the exact
array — this is what lets two OS processes reproduce whole-model math.
"""
residual = np.ascontiguousarray(self.residual)
positions = np.ascontiguousarray(self.positions)
return {
"architecture_adapter": self.architecture_adapter,
"schema_version": self.schema_version,
"tensor_name": self.tensor_name,
"next_layer": self.next_layer,
"normalized": self.normalized,
"residual": {
"shape": list(residual.shape),
"dtype": residual.dtype.str,
"data": residual.tobytes(),
},
"positions": {
"shape": list(positions.shape),
"dtype": positions.dtype.str,
"data": positions.tobytes(),
},
}
@classmethod
def unpack(cls, payload: dict[str, Any]) -> "BoundaryBundle":
"""Reconstruct a bundle produced by :meth:`pack`."""
residual = _array_from_wire(payload["residual"])
positions = _array_from_wire(payload["positions"])
return cls(
architecture_adapter=payload["architecture_adapter"],
schema_version=int(payload["schema_version"]),
tensor_name=payload["tensor_name"],
residual=residual,
positions=positions,
next_layer=int(payload["next_layer"]),
normalized=bool(payload.get("normalized", False)),
)
@dataclass(frozen=True)
class SamplingContract:
"""Explicit contract for turning tail logits into a token.
The tail never hides the sampling decision inside the adapter: the contract is
a first-class value so the head/route can reproduce it and so greedy decoding
is deterministic by construction. Only greedy is certified here; temperature /
top-p are declared but must be requested explicitly and are out of scope for
the deterministic parity gate.
"""
mode: str = "greedy"
temperature: float = 1.0
top_p: float = 1.0
def __post_init__(self) -> None:
if self.mode not in ("greedy",):
raise BoundaryContractError(
f"sampling mode {self.mode!r} is not certified; only 'greedy' is "
"deterministic and supported by the boundary adapter today"
)
@classmethod
def greedy(cls) -> "SamplingContract":
return cls(mode="greedy")
def sample(self, last_logits: np.ndarray) -> int:
"""Return the next token id from the final-position logits row."""
logits = np.asarray(last_logits)
if logits.ndim == 2:
# (batch, vocab) — parity harness uses batch size 1.
logits = logits[0]
if logits.ndim != 1:
raise BoundaryContractError(
"sampling expects the pruned final-position logits row"
)
return int(np.argmax(logits))
@dataclass(frozen=True)
class TailOutput:
"""What a tail Shard emits: the sampled token plus the pruned logits row."""
token_id: int
logits: np.ndarray
sampling: SamplingContract
@dataclass
class BoundaryAdapter:
"""Enforces the architecture-defined boundary contract for one Shard range.
Construction fails closed for uncertified architectures. The adapter derives
the Shard's role from its range and drives a duck-typed ``ShardComputation``.
"""
computation: Any
sampling: SamplingContract = field(default_factory=SamplingContract.greedy)
architecture: ArchitectureBoundary = field(init=False)
role: ShardRole = field(init=False)
start_layer: int = field(init=False)
end_layer: int = field(init=False)
total_layers: int = field(init=False)
def __post_init__(self) -> None:
arch_name = getattr(self.computation, "architecture_adapter", None)
self.architecture = certified_architecture(arch_name)
self.start_layer = int(getattr(self.computation, "start_layer"))
self.end_layer = int(getattr(self.computation, "end_layer"))
self.total_layers = int(getattr(self.computation, "total_layers"))
self.role = role_for_range(
self.start_layer, self.end_layer, self.total_layers
)
@property
def is_head(self) -> bool:
return self.role.owns_embedding
@property
def is_tail(self) -> bool:
return self.role.owns_final_head
def forward(
self,
*,
token_ids: Any | None = None,
boundary: BoundaryBundle | None = None,
) -> BoundaryBundle | TailOutput:
"""Run one prefill/decode pass for this range and emit its boundary output.
Head/full ranges require ``token_ids``; middle/tail ranges require the
``boundary`` bundle. Non-tail ranges return a :class:`BoundaryBundle`;
tail/full ranges return a :class:`TailOutput` through the sampling
contract.
"""
hidden, positions = self._ingest(token_ids, boundary)
hidden = self.computation.run_layers(hidden, positions=positions)
if self.is_tail:
return self._emit_tail(hidden)
return self._emit_boundary(hidden, positions)
# -- input side -----------------------------------------------------------
def _ingest(
self, token_ids: Any | None, boundary: BoundaryBundle | None
) -> tuple[np.ndarray, np.ndarray]:
if self.role.owns_embedding:
return self._ingest_tokens(token_ids, boundary)
return self._ingest_boundary(token_ids, boundary)
def _ingest_tokens(
self, token_ids: Any | None, boundary: BoundaryBundle | None
) -> tuple[np.ndarray, np.ndarray]:
if token_ids is None:
raise BoundaryContractError(
"the head owns token embedding and must receive token IDs"
)
if boundary is not None:
raise BoundaryContractError(
"the head owns token embedding; it must not receive a boundary "
"bundle from an upstream range"
)
ids = np.asarray(token_ids)
if ids.ndim == 1:
ids = ids[None, :]
if ids.ndim != 2:
raise BoundaryContractError("token IDs must be (seq,) or (batch, seq)")
hidden = np.asarray(self.computation.embed_tokens(ids))
positions = np.broadcast_to(
np.arange(ids.shape[1], dtype=np.int64), ids.shape
).copy()
return hidden, positions
def _ingest_boundary(
self, token_ids: Any | None, boundary: BoundaryBundle | None
) -> tuple[np.ndarray, np.ndarray]:
if token_ids is not None:
raise BoundaryContractError(
"middle/tail Shards bypass token embedding; they must not receive "
"token IDs"
)
if boundary is None:
raise BoundaryContractError(
"middle/tail Shards must receive the named boundary bundle"
)
self._check_boundary(boundary)
return np.asarray(boundary.residual), np.asarray(boundary.positions)
def _check_boundary(self, boundary: BoundaryBundle) -> None:
if certified_architecture(boundary.architecture_adapter) is not self.architecture:
raise BoundaryContractError(
f"boundary bundle architecture {boundary.architecture_adapter!r} "
f"does not match this Shard's adapter {self.architecture.adapter!r}"
)
if boundary.schema_version != self.architecture.boundary_schema_version:
raise BoundaryContractError(
f"boundary schema v{boundary.schema_version} is not supported by "
f"this Shard (expects v{self.architecture.boundary_schema_version})"
)
if boundary.tensor_name != self.architecture.boundary_tensor_name:
raise BoundaryContractError(
f"boundary tensor {boundary.tensor_name!r} is not the "
f"architecture-defined {self.architecture.boundary_tensor_name!r}"
)
if boundary.normalized:
raise BoundaryContractError(
"boundary bundle is normalized; a Shard range must receive the "
"UNNORMALIZED architecture-defined residual"
)
if boundary.next_layer != self.start_layer:
raise BoundaryContractError(
f"boundary hands over at layer {boundary.next_layer} but this "
f"Shard starts at layer {self.start_layer}"
)
# -- output side ----------------------------------------------------------
def _emit_boundary(
self, hidden: np.ndarray, positions: np.ndarray
) -> BoundaryBundle:
# A non-tail Shard emits the unnormalized residual with every position row
# intact: no final norm, no LM head, no tail-only row pruning. next_layer
# is the receiver's overlap-safe effective start.
return BoundaryBundle(
architecture_adapter=self.architecture.adapter,
schema_version=self.architecture.boundary_schema_version,
tensor_name=self.architecture.boundary_tensor_name,
residual=np.asarray(hidden),
positions=np.asarray(positions),
next_layer=self.end_layer + 1,
normalized=False,
)
def _emit_tail(self, hidden: np.ndarray) -> TailOutput:
hidden = np.asarray(hidden)
# Tail-only row pruning: only the final position is needed to sample the
# next token, so the LM head runs on the pruned row. A non-tail Shard is
# forbidden from doing this (it must forward every row).
if self.architecture.prunes_rows_at_tail:
last_hidden = hidden[:, -1:, :]
else: # pragma: no cover - no certified architecture takes this path yet
last_hidden = hidden
if self.architecture.normalizes_before_head:
last_hidden = np.asarray(self.computation.final_norm(last_hidden))
logits = np.asarray(self.computation.lm_head(last_hidden))
last_logits = logits[:, -1, :]
token_id = self.sampling.sample(last_logits)
return TailOutput(
token_id=token_id, logits=last_logits, sampling=self.sampling
)
def _byte_order(dtype: np.dtype) -> str:
order = dtype.byteorder
if order == "<":
return "little"
if order == ">":
return "big"
# '=' native, '|' not applicable (single byte)
import sys
return sys.byteorder if order in ("=", "|") else "little"
def _array_from_wire(field_payload: dict[str, Any]) -> np.ndarray:
array = np.frombuffer(
field_payload["data"], dtype=np.dtype(field_payload["dtype"])
)
return array.reshape(field_payload["shape"]).copy()

View File

@@ -20,16 +20,6 @@ import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, Mapping from typing import Any, Mapping
from . import __version__ as _PACKAGE_VERSION
from .runtime_recipe import (
ArtifactIdentity,
RuntimeRecipeIdentity,
build_artifact_identity,
build_runtime_recipe_identity,
compatibility_fingerprint,
fingerprint_payload,
)
# Layout of the serialized report. Bump when the JSON shape changes. # Layout of the serialized report. Bump when the JSON shape changes.
CAPABILITY_SCHEMA_VERSION = 1 CAPABILITY_SCHEMA_VERSION = 1
@@ -182,14 +172,6 @@ def _optional_text(value: Any, field_name: str) -> str | None:
return _require_text(value, field_name) return _require_text(value, field_name)
def _optional_bool(value: Any, field_name: str) -> bool:
if value is None:
return False
if isinstance(value, bool):
return value
raise CapabilityReportError(f"{field_name!r} must be a boolean")
def _require_int(value: Any, field_name: str, minimum: int) -> int: def _require_int(value: Any, field_name: str, minimum: int) -> int:
if isinstance(value, bool) or not isinstance(value, int): if isinstance(value, bool) or not isinstance(value, int):
raise CapabilityReportError(f"{field_name!r} must be an integer") raise CapabilityReportError(f"{field_name!r} must be an integer")
@@ -236,8 +218,6 @@ class ShardRange:
start: int start: int
end: int end: int
owns_embedding: bool = False
owns_final_head: bool = False
def __post_init__(self) -> None: def __post_init__(self) -> None:
_require_int(self.start, "shard.start", 0) _require_int(self.start, "shard.start", 0)
@@ -246,18 +226,9 @@ class ShardRange:
raise CapabilityReportError( raise CapabilityReportError(
f"'shard.end' ({self.end}) must be >= 'shard.start' ({self.start})" f"'shard.end' ({self.end}) must be >= 'shard.start' ({self.start})"
) )
if not isinstance(self.owns_embedding, bool):
raise CapabilityReportError("'shard.owns_embedding' must be a boolean")
if not isinstance(self.owns_final_head, bool):
raise CapabilityReportError("'shard.owns_final_head' must be a boolean")
def to_dict(self) -> dict: def to_dict(self) -> dict:
return { return {"start": self.start, "end": self.end}
"start": self.start,
"end": self.end,
"owns_embedding": self.owns_embedding,
"owns_final_head": self.owns_final_head,
}
@classmethod @classmethod
def from_dict(cls, data: Any) -> ShardRange: def from_dict(cls, data: Any) -> ShardRange:
@@ -265,12 +236,6 @@ class ShardRange:
return cls( return cls(
start=_require_int(doc.get("start"), "shard.start", 0), start=_require_int(doc.get("start"), "shard.start", 0),
end=_require_int(doc.get("end"), "shard.end", 0), end=_require_int(doc.get("end"), "shard.end", 0),
owns_embedding=_optional_bool(
doc.get("owns_embedding"), "shard.owns_embedding"
),
owns_final_head=_optional_bool(
doc.get("owns_final_head"), "shard.owns_final_head"
),
) )
@@ -371,8 +336,6 @@ class CapabilityReport:
shard: ShardRange shard: ShardRange
recipe: RecipeIdentity recipe: RecipeIdentity
backend: BackendIdentity backend: BackendIdentity
artifact: ArtifactIdentity
runtime_recipe: RuntimeRecipeIdentity
status: str status: str
validated_at: float validated_at: float
duration_ms: int duration_ms: int
@@ -413,20 +376,6 @@ class CapabilityReport:
self.backend.device, self.backend.device,
) )
@property
def compatibility_fingerprint(self) -> str:
"""Stable compatibility digest over the full routable identity."""
return compatibility_fingerprint(
fingerprint_payload(
model=self.model.to_dict(),
shard=self.shard.to_dict(),
recipe=self.recipe.to_dict(),
backend=self.backend.to_dict(),
artifact=self.artifact.to_dict(),
runtime_recipe=self.runtime_recipe.to_dict(),
)
)
def age_seconds(self, now: float | None = None) -> float: def age_seconds(self, now: float | None = None) -> float:
return max(0.0, (time.time() if now is None else now) - self.validated_at) return max(0.0, (time.time() if now is None else now) - self.validated_at)
@@ -437,9 +386,6 @@ class CapabilityReport:
"shard": self.shard.to_dict(), "shard": self.shard.to_dict(),
"recipe": self.recipe.to_dict(), "recipe": self.recipe.to_dict(),
"backend": self.backend.to_dict(), "backend": self.backend.to_dict(),
"artifact": self.artifact.to_dict(),
"runtime_recipe": self.runtime_recipe.to_dict(),
"compatibility_fingerprint": self.compatibility_fingerprint,
"status": self.status, "status": self.status,
"validated_at": self.validated_at, "validated_at": self.validated_at,
"duration_ms": self.duration_ms, "duration_ms": self.duration_ms,
@@ -452,9 +398,6 @@ class CapabilityReport:
@classmethod @classmethod
def from_dict(cls, data: Any) -> CapabilityReport: def from_dict(cls, data: Any) -> CapabilityReport:
doc = _as_mapping(data, "report") doc = _as_mapping(data, "report")
declared_compatibility_fingerprint = _optional_text(
doc.get("compatibility_fingerprint"), "compatibility_fingerprint"
)
if "schema_version" not in doc: if "schema_version" not in doc:
raise CapabilityReportError( raise CapabilityReportError(
@@ -474,13 +417,7 @@ class CapabilityReport:
): ):
raise CapabilityReportError("'validated_at' must be a Unix timestamp") raise CapabilityReportError("'validated_at' must be a Unix timestamp")
try: return cls(
artifact = ArtifactIdentity.from_dict(doc.get("artifact"))
runtime_recipe = RuntimeRecipeIdentity.from_dict(doc.get("runtime_recipe"))
except ValueError as exc:
raise CapabilityReportError(str(exc)) from exc
report = cls(
schema_version=schema_version, schema_version=schema_version,
model=ModelIdentity.from_dict(doc.get("model")), model=ModelIdentity.from_dict(doc.get("model")),
shard=ShardRange.from_dict(doc.get("shard")), shard=ShardRange.from_dict(doc.get("shard")),
@@ -490,18 +427,7 @@ class CapabilityReport:
validated_at=float(validated_at), validated_at=float(validated_at),
duration_ms=_require_int(doc.get("duration_ms"), "duration_ms", 0), duration_ms=_require_int(doc.get("duration_ms"), "duration_ms", 0),
diagnostics=sanitize_diagnostics(doc.get("diagnostics")), diagnostics=sanitize_diagnostics(doc.get("diagnostics")),
artifact=artifact,
runtime_recipe=runtime_recipe,
) )
if (
declared_compatibility_fingerprint is not None
and report.compatibility_fingerprint != declared_compatibility_fingerprint
):
raise CapabilityReportError(
"report declares a compatibility fingerprint that does not match "
"its artifact/runtime recipe"
)
return report
@classmethod @classmethod
def from_json(cls, text: str) -> CapabilityReport: def from_json(cls, text: str) -> CapabilityReport:
@@ -532,19 +458,6 @@ def build_capability_report(
device_name: str | None = None, device_name: str | None = None,
quantization: str | None = None, quantization: str | None = None,
runtime: Mapping[str, str] | None = None, runtime: Mapping[str, str] | None = None,
artifact_hash: str | None = None,
runtime_recipe: RuntimeRecipeIdentity | None = None,
owns_embedding: bool = False,
owns_final_head: bool = False,
activation_dtype: Any = None,
compute_dtype: Any = None,
kv_dtype: Any = None,
kv_layout: str | None = None,
tokenizer_revision: str | None = None,
architecture_adapter: str | None = None,
boundary_schema_version: int = 1,
cache_layout: str | None = None,
recipe_params: Mapping[str, Any] | None = None,
diagnostics: Any = None, diagnostics: Any = None,
validated_at: float | None = None, validated_at: float | None = None,
environ: Mapping[str, str] | None = None, environ: Mapping[str, str] | None = None,
@@ -555,62 +468,25 @@ def build_capability_report(
or an already-computed ``sha256:…`` string. `validated_at` defaults to now, or an already-computed ``sha256:…`` string. `validated_at` defaults to now,
so callers that need determinism pass it explicitly. so callers that need determinism pass it explicitly.
""" """
model_identity = ModelIdentity( return CapabilityReport(
model_id=model_id, model=ModelIdentity(
revision=revision,
config_fingerprint=config_fingerprint(model_config),
)
shard = ShardRange(
start=shard_start,
end=shard_end,
owns_embedding=owns_embedding,
owns_final_head=owns_final_head,
)
recipe_identity = RecipeIdentity(
recipe_id=recipe_id,
recipe_version=recipe_version,
catalogue_version=catalogue_version,
)
backend_identity = BackendIdentity(
backend_id=backend_id,
device=device,
device_name=device_name,
quantization=quantization,
runtime=dict(runtime or {}),
)
artifact = build_artifact_identity(
model_id=model_id,
revision=revision,
model_config=model_config,
artifact_hash=artifact_hash,
shard_start=shard_start,
shard_end=shard_end,
)
if runtime_recipe is None:
runtime_recipe = build_runtime_recipe_identity(
model_id=model_id, model_id=model_id,
revision=revision, revision=revision,
model_config=model_config, config_fingerprint=config_fingerprint(model_config),
recipe_params=recipe_params, ),
weight_quantization=quantization or "unknown", shard=ShardRange(start=shard_start, end=shard_end),
recipe=RecipeIdentity(
recipe_id=recipe_id,
recipe_version=recipe_version,
catalogue_version=catalogue_version,
),
backend=BackendIdentity(
backend_id=backend_id, backend_id=backend_id,
runtime_version=_PACKAGE_VERSION, device=device,
activation_dtype=activation_dtype, device_name=device_name,
compute_dtype=compute_dtype, quantization=quantization,
kv_dtype=kv_dtype, runtime=dict(runtime or {}),
kv_layout=kv_layout, ),
tokenizer_revision=tokenizer_revision,
architecture_adapter=architecture_adapter,
boundary_schema_version=boundary_schema_version,
cache_layout=cache_layout,
)
return CapabilityReport(
model=model_identity,
shard=shard,
recipe=recipe_identity,
backend=backend_identity,
artifact=artifact,
runtime_recipe=runtime_recipe,
status=status, status=status,
validated_at=time.time() if validated_at is None else validated_at, validated_at=time.time() if validated_at is None else validated_at,
duration_ms=duration_ms, duration_ms=duration_ms,

View File

@@ -36,8 +36,6 @@ from .capability import (
CapabilityReport, CapabilityReport,
build_capability_report, build_capability_report,
) )
from . import __version__ as _PACKAGE_VERSION
from .runtime_recipe import build_runtime_recipe_identity
from .recipe_manifest import ( from .recipe_manifest import (
DEFAULT_RECIPE_ID, DEFAULT_RECIPE_ID,
Recipe, Recipe,
@@ -45,7 +43,6 @@ from .recipe_manifest import (
RecipeManifestError, RecipeManifestError,
load_recipe_manifest, load_recipe_manifest,
) )
from .gguf_ownership import authoritative_dense_llama_ownership
# The probe is deliberately tiny: enough tokens to drive every layer in the # The probe is deliberately tiny: enough tokens to drive every layer in the
# shard once, small enough that `doctor` costs seconds beyond the model load. # shard once, small enough that `doctor` costs seconds beyond the model load.
@@ -467,28 +464,10 @@ def _validate_recipe(
duration_ms = int((time.monotonic() - started) * 1000) duration_ms = int((time.monotonic() - started) * 1000)
device = _backend_device(backend, selection) device = _backend_device(backend, selection)
ownership = authoritative_dense_llama_ownership(backend, selection)
runtime_recipe = build_runtime_recipe_identity(
model_id=selection.model_id,
revision=getattr(getattr(backend, "model", None), "revision", None),
model_config=_model_config(backend),
recipe_params=recipe.params,
weight_quantization=selection.quantization,
backend_id=recipe.backend_id,
runtime_version=_PACKAGE_VERSION,
activation_dtype="bfloat16",
compute_dtype=_backend_compute_dtype(backend),
kv_dtype=_backend_kv_dtype(backend),
kv_layout=_backend_kv_layout(backend),
tokenizer_revision=_backend_tokenizer_revision(backend, selection),
architecture_adapter=_backend_architecture_adapter(backend, recipe.backend_id),
boundary_schema_version=1,
cache_layout=_backend_cache_layout(backend, recipe.params),
)
report = build_capability_report( report = build_capability_report(
model_id=selection.model_id, model_id=selection.model_id,
shard_start=ownership.start_layer, shard_start=selection.shard_start,
shard_end=ownership.end_layer, shard_end=selection.shard_end,
recipe_id=recipe.id, recipe_id=recipe.id,
recipe_version=recipe.version, recipe_version=recipe.version,
catalogue_version=manifest.catalogue_version, catalogue_version=manifest.catalogue_version,
@@ -498,9 +477,6 @@ def _validate_recipe(
quantization=selection.quantization, quantization=selection.quantization,
runtime=_runtime_versions(), runtime=_runtime_versions(),
model_config=_model_config(backend), model_config=_model_config(backend),
runtime_recipe=runtime_recipe,
owns_embedding=ownership.owns_embedding,
owns_final_head=ownership.owns_final_head,
status=STATUS_FAILED if category else STATUS_PASSED, status=STATUS_FAILED if category else STATUS_PASSED,
duration_ms=duration_ms, duration_ms=duration_ms,
diagnostics=[d for d in diagnostics if d] or None, diagnostics=[d for d in diagnostics if d] or None,
@@ -592,65 +568,6 @@ def _runtime_versions() -> dict[str, str]:
return versions return versions
def _backend_compute_dtype(backend: Any) -> str:
config = getattr(getattr(backend, "model", None), "config", None)
for candidate in (config, getattr(config, "text_config", None)):
if candidate is None:
continue
for attr in ("dtype", "torch_dtype"):
value = getattr(candidate, attr, None)
if value is None:
continue
return str(value).removeprefix("torch.")
return "bfloat16"
def _backend_kv_dtype(backend: Any) -> str:
return _backend_compute_dtype(backend)
def _backend_kv_layout(backend: Any) -> str:
return "session-cache" if getattr(backend, "supports_kv_cache", False) else "stateless"
def _backend_tokenizer_revision(backend: Any, selection: DoctorSelection) -> str:
model = getattr(backend, "model", None)
revision = getattr(model, "revision", None)
if isinstance(revision, str) and revision.strip():
return revision
return selection.model_id
def _backend_architecture_adapter(backend: Any, default: str) -> str:
config = getattr(getattr(backend, "model", None), "config", None)
for candidate in (config, getattr(config, "text_config", None)):
if candidate is None:
continue
for attr in ("architecture_adapter", "model_type"):
value = getattr(candidate, attr, None)
if isinstance(value, str) and value.strip():
return value
architectures = getattr(candidate, "architectures", None)
if isinstance(architectures, (list, tuple)) and architectures:
first = architectures[0]
if isinstance(first, str) and first.strip():
return first
return default
def _backend_cache_layout(backend: Any, recipe_params: Mapping[str, Any] | None) -> str:
if getattr(backend, "supports_kv_cache", False) is False:
return "stateless"
if recipe_params is None:
return "local-hot-kv"
if recipe_params.get("use_cache") is False:
return "stateless"
value = recipe_params.get("cache_layout")
if isinstance(value, str) and value.strip():
return value
return "local-hot-kv"
# --- output ----------------------------------------------------------------- # --- output -----------------------------------------------------------------
DEFAULT_REPORT_FILENAME = "capability.json" DEFAULT_REPORT_FILENAME = "capability.json"

View File

@@ -1,423 +0,0 @@
"""Native llama.cpp/GGUF backend adapter for Meshnet node startup.
This module keeps the node-side GGUF seam separate from the Torch-backed
reference path. The public object intentionally looks like the existing
``TorchModelShard`` surface so ``TorchNodeServer`` can serve it without changing
the HTTP/control-plane code that already correlates request ids, telemetry and
billing.
The transport layer is intentionally explicit:
* direct worker calls are expected to use the versioned gRPC Shard protocol
from :mod:`meshnet_node.native_protocol`;
* the backend itself stays transport-agnostic and delegates to a worker
transport object with the same method surface as the existing node backend.
The default factory is strict: if no worker endpoint is configured, it fails
closed rather than silently pretending the native worker exists.
"""
from __future__ import annotations
import os
from dataclasses import dataclass, field
from types import SimpleNamespace
from typing import Any, Protocol, runtime_checkable
from .model_backend import (
MissingModelDependencyError,
ModelBackendError,
TailTokenResult,
TensorPayload,
)
_BACKEND_ID = "llama.cpp"
@runtime_checkable
class NativeWorkerTransport(Protocol):
"""Backend-shaped transport for the supervised native worker."""
def encode_prompt(
self,
prompt: str,
session_id: str | None = None,
) -> TensorPayload | TailTokenResult | str: ...
def encode_next_token(
self,
token_id: int,
session_id: str,
) -> TensorPayload | TailTokenResult | str: ...
def forward_bytes(
self,
body: bytes,
shape: list[int],
attention_mask_header: str | None,
position_ids_header: str | None,
*,
start_layer: int | None = None,
session_id: str | None = None,
cache_mode: str | None = None,
past_len: int | None = None,
) -> TensorPayload | TailTokenResult | str: ...
def decode_tail_token(self, hidden_states: Any) -> TailTokenResult: ...
def generate_text(
self,
messages: list[dict],
max_new_tokens: int = 5120,
temperature: float = 1.0,
top_p: float = 1.0,
) -> str: ...
def generate_text_streaming(
self,
messages: list[dict],
max_new_tokens: int = 5120,
temperature: float = 1.0,
top_p: float = 1.0,
): ...
def count_prompt_tokens(self, messages: list[dict]) -> int: ...
def count_text_tokens(self, text: str) -> int: ...
def eos_token_ids(self) -> list[int]: ...
def release_session(self, session_id: str) -> None: ...
@dataclass(frozen=True)
class _NativeModelConfig:
"""Enough model metadata for admission and capability reporting."""
model_type: str = "llama"
architecture_adapter: str = "dense-llama"
num_hidden_layers: int = 1
torch_dtype: str = "bfloat16"
def to_dict(self) -> dict[str, Any]:
return {
"model_type": self.model_type,
"architecture_adapter": self.architecture_adapter,
"num_hidden_layers": self.num_hidden_layers,
"torch_dtype": self.torch_dtype,
}
@dataclass
class GgufNodeBackend:
"""GGUF shard backend shaped like ``TorchModelShard``.
The adapter keeps the Meshnet-facing surface stable while the actual model
execution is delegated to a worker transport. The backend carries the exact
model, shard and runtime metadata required for admission and registration.
"""
model_id: str
shard_start: int
shard_end: int
quantization: str = "bfloat16"
transport: NativeWorkerTransport | None = None
total_layers: int | None = None
model_revision: str | None = None
loaded_tensor_names: tuple[str, ...] = ()
device_type: str = "cpu"
supports_kv_cache: bool = True
worker_url: str | None = None
architecture_adapter: str = "dense-llama"
tokenizer_revision: str | None = None
runtime_recipe_fingerprint: str | None = None
_model: SimpleNamespace = field(init=False, repr=False)
_tokenizer: SimpleNamespace = field(init=False, repr=False)
is_head: bool = field(init=False)
is_tail: bool = field(init=False)
loaded_shard_start: int = field(init=False)
loaded_shard_end: int = field(init=False)
owns_embedding: bool = field(init=False)
owns_final_head: bool = field(init=False)
backend_id = _BACKEND_ID
def __post_init__(self) -> None:
if self.shard_start < 0 or self.shard_end < self.shard_start:
raise ValueError("shard_start must be <= shard_end and non-negative")
total_layers = self.total_layers or (self.shard_end + 1)
object.__setattr__(
self,
"total_layers",
int(total_layers),
)
object.__setattr__(
self,
"_model",
SimpleNamespace(
revision=self.model_revision or self.model_id,
config=_NativeModelConfig(
num_hidden_layers=int(total_layers),
torch_dtype=self.quantization,
),
),
)
object.__setattr__(
self,
"_tokenizer",
SimpleNamespace(
model_id=self.model_id,
revision=self.tokenizer_revision or self.model_revision or self.model_id,
eos_token="",
eos_token_id=[],
),
)
object.__setattr__(self, "is_head", self.shard_start == 0)
object.__setattr__(self, "is_tail", self.shard_end >= int(total_layers) - 1)
object.__setattr__(self, "loaded_shard_start", self.shard_start)
object.__setattr__(self, "loaded_shard_end", self.shard_end)
object.__setattr__(self, "owns_embedding", self.is_head)
object.__setattr__(self, "owns_final_head", self.is_tail)
if not self.loaded_tensor_names:
object.__setattr__(
self,
"loaded_tensor_names",
self._default_tensor_inventory(),
)
@property
def model(self) -> Any:
return self._model
@property
def tokenizer(self) -> Any:
return self._tokenizer
@property
def device(self) -> SimpleNamespace:
return SimpleNamespace(type=self.device_type)
@property
def shard_range(self) -> tuple[int, int]:
return self.shard_start, self.shard_end
def encode_prompt(self, prompt: str, session_id: str | None = None) -> TensorPayload | TailTokenResult | str:
return self._transport().encode_prompt(prompt, session_id=session_id)
def encode_next_token(self, token_id: int, session_id: str) -> TensorPayload | TailTokenResult | str:
return self._transport().encode_next_token(token_id, session_id)
def forward_bytes(
self,
body: bytes,
shape: list[int],
attention_mask_header: str | None,
position_ids_header: str | None,
start_layer: int | None = None,
session_id: str | None = None,
cache_mode: str | None = None,
past_len: int | None = None,
) -> TensorPayload | TailTokenResult | str:
return self._transport().forward_bytes(
body,
shape,
attention_mask_header,
position_ids_header,
start_layer=start_layer,
session_id=session_id,
cache_mode=cache_mode,
past_len=past_len,
)
def decode_tail(self, hidden_states: Any) -> str:
return self.decode_tail_token(hidden_states).text
def decode_tail_token(self, hidden_states: Any) -> TailTokenResult:
return self._transport().decode_tail_token(hidden_states)
def generate_text(
self,
messages: list[dict],
max_new_tokens: int = 5120,
temperature: float = 1.0,
top_p: float = 1.0,
) -> str:
return self._transport().generate_text(messages, max_new_tokens, temperature, top_p)
def generate_text_streaming(
self,
messages: list[dict],
max_new_tokens: int = 5120,
temperature: float = 1.0,
top_p: float = 1.0,
):
yield from self._transport().generate_text_streaming(messages, max_new_tokens, temperature, top_p)
def count_prompt_tokens(self, messages: list[dict]) -> int:
return self._transport().count_prompt_tokens(messages)
def count_text_tokens(self, text: str) -> int:
return self._transport().count_text_tokens(text)
def eos_token_ids(self) -> list[int]:
return self._transport().eos_token_ids()
def release_session(self, session_id: str) -> None:
self._transport().release_session(session_id)
def _transport(self) -> NativeWorkerTransport:
if self.transport is None:
raise MissingModelDependencyError(
"native GGUF backend needs a worker transport; set MESHNET_NATIVE_WORKER_URL "
"or inject a test transport"
)
return self.transport
def _default_tensor_inventory(self) -> tuple[str, ...]:
tensor_names = [f"blk.{layer}.weight" for layer in range(self.shard_start, self.shard_end + 1)]
if self.is_head:
tensor_names.append("token_embd.weight")
if self.is_tail:
tensor_names.extend(["output_norm.weight", "output.weight"])
return tuple(tensor_names)
class GrpcNativeWorkerTransport:
"""Transport that speaks the versioned gRPC worker protocol.
The transport is intentionally conservative: it provides the unary service
hooks and carries the protocol metadata, but it does not guess at worker
behavior beyond what the compiled protobuf schema already describes.
"""
def __init__(self, worker_url: str, *, timeout: float = 30.0) -> None:
self.worker_url = worker_url
self.timeout = timeout
self._grpc = None
self._channel = None
self._stub = None
def _ensure_stub(self) -> Any:
if self._stub is not None:
return self._stub
try:
import grpc # type: ignore[import]
except ImportError as exc: # pragma: no cover - environment dependent
raise MissingModelDependencyError(
"grpc is required for the native GGUF worker transport"
) from exc
from . import native_protocol
grpc_mod = native_protocol.load_grpc()
self._grpc = grpc
self._channel = grpc.insecure_channel(self.worker_url)
self._stub = grpc_mod.ShardRuntimeStub(self._channel)
return self._stub
def encode_prompt(self, prompt: str, session_id: str | None = None) -> TensorPayload | TailTokenResult | str:
raise ModelBackendError(
"gRPC transport is present, but prompt-to-activation translation is provided "
"by the backend wrapper so it can keep worker framing and tokenizer state aligned"
)
def encode_next_token(self, token_id: int, session_id: str) -> TensorPayload | TailTokenResult | str:
raise ModelBackendError(
"gRPC transport is present, but decode translation is provided by the backend wrapper"
)
def forward_bytes(
self,
body: bytes,
shape: list[int],
attention_mask_header: str | None,
position_ids_header: str | None,
*,
start_layer: int | None = None,
session_id: str | None = None,
cache_mode: str | None = None,
past_len: int | None = None,
) -> TensorPayload | TailTokenResult | str:
raise ModelBackendError(
"gRPC transport is present, but activation streaming is handled by the backend wrapper"
)
def decode_tail_token(self, hidden_states: Any) -> TailTokenResult:
raise ModelBackendError("tail decoding is handled by the backend wrapper")
def generate_text(
self,
messages: list[dict],
max_new_tokens: int = 5120,
temperature: float = 1.0,
top_p: float = 1.0,
) -> str:
raise ModelBackendError("text generation is handled by the backend wrapper")
def generate_text_streaming(
self,
messages: list[dict],
max_new_tokens: int = 5120,
temperature: float = 1.0,
top_p: float = 1.0,
):
raise ModelBackendError("streaming generation is handled by the backend wrapper")
def count_prompt_tokens(self, messages: list[dict]) -> int:
return sum(1 for message in messages if isinstance(message, dict))
def count_text_tokens(self, text: str) -> int:
return len(text.split()) or (1 if text else 0)
def eos_token_ids(self) -> list[int]:
return []
def release_session(self, session_id: str) -> None:
stub = self._ensure_stub()
from . import native_protocol
pb2 = native_protocol.load()
stub.Release(pb2.ReleaseRequest(reason="release from adapter"))
def build_gguf_backend(
*,
model_id: str,
shard_start: int,
shard_end: int,
quantization: str = "bfloat16",
transport: NativeWorkerTransport | None = None,
worker_url: str | None = None,
total_layers: int | None = None,
model_revision: str | None = None,
loaded_tensor_names: tuple[str, ...] = (),
device_type: str = "cpu",
architecture_adapter: str = "dense-llama",
tokenizer_revision: str | None = None,
runtime_recipe_fingerprint: str | None = None,
supports_kv_cache: bool = True,
) -> GgufNodeBackend:
"""Construct a native-worker-backed GGUF node backend."""
if transport is None:
worker_url = worker_url or os.environ.get("MESHNET_NATIVE_WORKER_URL")
if not worker_url:
raise MissingModelDependencyError(
"set MESHNET_NATIVE_WORKER_URL to the local gRPC worker endpoint "
"or inject a fake transport in tests"
)
transport = GrpcNativeWorkerTransport(worker_url)
return GgufNodeBackend(
model_id=model_id,
shard_start=shard_start,
shard_end=shard_end,
quantization=quantization,
transport=transport,
total_layers=total_layers,
model_revision=model_revision,
loaded_tensor_names=loaded_tensor_names,
device_type=device_type,
supports_kv_cache=supports_kv_cache,
worker_url=worker_url,
architecture_adapter=architecture_adapter,
tokenizer_revision=tokenizer_revision,
runtime_recipe_fingerprint=runtime_recipe_fingerprint,
)

View File

@@ -1,287 +0,0 @@
"""Dense-Llama GGUF ownership helpers.
This module keeps two related concerns together:
* selecting the tensors a dense-Llama GGUF shard is allowed to own; and
* inferring the authoritative loaded range / endpoint ownership from the
tensors the model actually exposes.
The first is used by the range-aware loader seam. The second is used by the
doctor/admission/reporting path so the tracker sees what the model loaded, not
what a CLI flag claimed.
"""
from __future__ import annotations
import re
from dataclasses import dataclass
from typing import Any, Iterable, Mapping
_BLOCK_RE = re.compile(r"^blk\.(\d+)\.")
_HEAD_TENSOR_NAMES = {
"token_embd.weight",
"token_embd.bias",
"tok_embeddings.weight",
"tok_embeddings.bias",
"embed_tokens.weight",
"embed_tokens.bias",
}
_TAIL_TENSOR_NAMES = {
"output_norm.weight",
"output_norm.bias",
"output.weight",
"output.bias",
"lm_head.weight",
"lm_head.bias",
}
@dataclass(frozen=True)
class DenseLlamaShardOwnership:
"""Authoritative ownership for one dense-Llama shard."""
start_layer: int
end_layer: int
owns_embedding: bool
owns_final_head: bool
tensor_names: tuple[str, ...] = ()
source_artifact_hash: str | None = None
slice_artifact_hash: str | None = None
derivative_slice: bool = False
final_artifact_semantics: bool = True
def __post_init__(self) -> None:
if self.start_layer < 0:
raise ValueError("start_layer must be non-negative")
if self.end_layer < self.start_layer:
raise ValueError("end_layer must be >= start_layer")
if self.derivative_slice:
if not self.source_artifact_hash or not self.slice_artifact_hash:
raise ValueError(
"temporary derivative sub-GGUFs must carry source and slice hashes"
)
if self.final_artifact_semantics:
raise ValueError(
"temporary derivative sub-GGUFs must not be claimed as final artifacts"
)
@property
def range(self) -> tuple[int, int]:
return self.start_layer, self.end_layer
def to_dict(self) -> dict[str, Any]:
return {
"start_layer": self.start_layer,
"end_layer": self.end_layer,
"owns_embedding": self.owns_embedding,
"owns_final_head": self.owns_final_head,
"tensor_names": list(self.tensor_names),
"source_artifact_hash": self.source_artifact_hash,
"slice_artifact_hash": self.slice_artifact_hash,
"derivative_slice": self.derivative_slice,
"final_artifact_semantics": self.final_artifact_semantics,
}
def select_dense_llama_tensor_names(
tensor_names: Iterable[str],
start_layer: int,
end_layer: int,
*,
total_layers: int | None = None,
) -> set[str]:
"""Return the dense-Llama GGUF tensor names owned by an inclusive range."""
if start_layer < 0:
raise ValueError("start_layer must be non-negative")
if end_layer < start_layer:
raise ValueError("end_layer must be greater than or equal to start_layer")
selected: set[str] = set()
for tensor_name in tensor_names:
if _tensor_belongs_to_range(tensor_name, start_layer, end_layer, total_layers):
selected.add(tensor_name)
return selected
def infer_dense_llama_ownership(
tensor_names: Iterable[str],
*,
total_layers: int | None = None,
source_artifact_hash: str | None = None,
slice_artifact_hash: str | None = None,
derivative_slice: bool = False,
final_artifact_semantics: bool = True,
) -> DenseLlamaShardOwnership:
"""Infer authoritative loaded range and endpoint ownership from tensors."""
names = tuple(str(name) for name in tensor_names if isinstance(name, str))
if not names:
raise ValueError("tensor inventory is empty")
block_layers = sorted(
{
layer
for name in names
if (layer := _layer_index(name)) is not None
}
)
if not block_layers:
raise ValueError("tensor inventory does not contain any blk.N.* tensors")
selected = tuple(sorted(names))
return DenseLlamaShardOwnership(
start_layer=block_layers[0],
end_layer=block_layers[-1],
owns_embedding=any(_is_head_tensor(name) for name in names),
owns_final_head=any(
_is_tail_tensor(name, total_layers=total_layers, loaded_end=block_layers[-1])
for name in names
),
tensor_names=selected,
source_artifact_hash=source_artifact_hash,
slice_artifact_hash=slice_artifact_hash,
derivative_slice=derivative_slice,
final_artifact_semantics=final_artifact_semantics,
)
def authoritative_dense_llama_ownership(
backend: Any,
selection: Any | None = None,
) -> DenseLlamaShardOwnership:
"""Return the most authoritative dense-Llama ownership the backend exposes."""
tensor_names = _tensor_names_from_backend(backend)
if tensor_names:
try:
return infer_dense_llama_ownership(
tensor_names,
total_layers=_backend_total_layers(backend, selection),
)
except ValueError:
pass
start, end = _backend_loaded_bounds(backend, selection)
return DenseLlamaShardOwnership(
start_layer=start,
end_layer=end,
owns_embedding=_backend_owns_embedding(backend, start),
owns_final_head=_backend_owns_final_head(backend, end),
)
def _backend_loaded_bounds(backend: Any, selection: Any | None) -> tuple[int, int]:
start = getattr(backend, "loaded_shard_start", None)
end = getattr(backend, "loaded_shard_end", None)
if start is None:
start = getattr(backend, "shard_start", None)
if end is None:
end = getattr(backend, "shard_end", None)
if start is None or end is None:
if selection is None:
raise ValueError("backend does not expose a loaded shard range")
start = getattr(selection, "shard_start")
end = getattr(selection, "shard_end")
return int(start), int(end)
def _backend_owns_embedding(backend: Any, start: int) -> bool:
value = getattr(backend, "owns_embedding", None)
if value is None:
value = getattr(backend, "is_head", start == 0)
return bool(value)
def _backend_owns_final_head(backend: Any, end: int) -> bool:
value = getattr(backend, "owns_final_head", None)
if value is None:
value = getattr(backend, "is_tail", False)
return bool(value)
def _backend_total_layers(backend: Any, selection: Any | None) -> int | None:
value = getattr(backend, "total_layers", None)
if isinstance(value, int) and value > 0:
return value
if selection is None:
return None
total = getattr(selection, "total_layers", None)
if isinstance(total, int) and total > 0:
return total
return None
def _tensor_names_from_backend(backend: Any) -> tuple[str, ...]:
for attr in ("loaded_tensor_names", "tensor_names", "tensor_inventory"):
value = getattr(backend, attr, None)
names = _normalise_tensor_names(value)
if names:
return names
return ()
def _normalise_tensor_names(value: Any) -> tuple[str, ...]:
if value is None:
return ()
if isinstance(value, Mapping):
items = value.keys()
else:
try:
items = list(value)
except TypeError:
return ()
names = [str(item) for item in items if isinstance(item, str) and item.strip()]
return tuple(names)
def _tensor_belongs_to_range(
tensor_name: str,
start_layer: int,
end_layer: int,
total_layers: int | None,
) -> bool:
layer = _layer_index(tensor_name)
if layer is not None:
return start_layer <= layer <= end_layer
if start_layer == 0 and _is_head_tensor(tensor_name):
return True
if total_layers is not None and end_layer >= total_layers - 1 and _is_tail_tensor(
tensor_name, total_layers=total_layers, loaded_end=end_layer
):
return True
return False
def _layer_index(tensor_name: str) -> int | None:
match = _BLOCK_RE.match(tensor_name)
if match is None:
return None
return int(match.group(1))
def _is_head_tensor(tensor_name: str) -> bool:
lowered = tensor_name.lower()
return lowered in _HEAD_TENSOR_NAMES or any(
lowered.startswith(prefix)
for prefix in ("token_embd.", "tok_embeddings.", "embed_tokens.")
)
def _is_tail_tensor(
tensor_name: str,
*,
total_layers: int | None,
loaded_end: int,
) -> bool:
lowered = tensor_name.lower()
if lowered in _TAIL_TENSOR_NAMES:
return True
if total_layers is not None and loaded_end >= total_layers - 1:
return any(
lowered.startswith(prefix)
for prefix in ("output_norm.", "final_norm.", "norm.")
)
return False

View File

@@ -2,7 +2,6 @@
import json import json
import os import os
import shutil
import subprocess import subprocess
import time import time
@@ -184,17 +183,6 @@ def with_forced_cpu(hw: dict) -> dict:
return forced return forced
def _with_model_drive(profile: dict) -> dict:
"""Attach free space for the default model cache drive to tracker diagnostics."""
try:
cache_root = os.path.expanduser("~/.cache/meshnet/shards")
profile["model_drive_free_bytes"] = shutil.disk_usage(os.path.expanduser("~")).free
profile["model_drive_path"] = cache_root
except OSError:
pass
return profile
def detect_hardware() -> dict: def detect_hardware() -> dict:
"""Detect GPU model and available VRAM. Returns hardware profile dict.""" """Detect GPU model and available VRAM. Returns hardware profile dict."""
ram_mb = _detect_ram_mb() ram_mb = _detect_ram_mb()
@@ -220,23 +208,23 @@ def detect_hardware() -> dict:
} }
if torch_gpu is not None and torch_gpu.get("gcn_arch"): if torch_gpu is not None and torch_gpu.get("gcn_arch"):
profile["gcn_arch"] = torch_gpu["gcn_arch"] profile["gcn_arch"] = torch_gpu["gcn_arch"]
return _with_model_drive(profile) return profile
except ImportError: except ImportError:
pass pass
torch_inventory = _gpu_inventory_profile(torch_gpu, ram_mb) torch_inventory = _gpu_inventory_profile(torch_gpu, ram_mb)
if torch_inventory is not None: if torch_inventory is not None:
return _with_model_drive(torch_inventory) return torch_inventory
nvidia_gpu = _gpu_inventory_profile(_detect_nvidia_smi_gpu_memory(), ram_mb) nvidia_gpu = _gpu_inventory_profile(_detect_nvidia_smi_gpu_memory(), ram_mb)
if nvidia_gpu is not None: if nvidia_gpu is not None:
return _with_model_drive(nvidia_gpu) return nvidia_gpu
windows_gpu = _gpu_inventory_profile(_detect_windows_gpu_memory(), ram_mb) windows_gpu = _gpu_inventory_profile(_detect_windows_gpu_memory(), ram_mb)
if windows_gpu is not None: if windows_gpu is not None:
return _with_model_drive(windows_gpu) return windows_gpu
return _with_model_drive({ return {
"device": "cpu", "device": "cpu",
"gpu_name": None, "gpu_name": None,
"vram_mb": 0, "vram_mb": 0,
@@ -244,7 +232,7 @@ def detect_hardware() -> dict:
"shared_vram_mb": 0, "shared_vram_mb": 0,
"ram_mb": ram_mb, "ram_mb": ram_mb,
"cuda_available": False, "cuda_available": False,
}) }
def benchmark_throughput_checked(device_str: str = "cpu") -> tuple[float, bool, str | None]: def benchmark_throughput_checked(device_str: str = "cpu") -> tuple[float, bool, str | None]:

View File

@@ -1,918 +0,0 @@
"""Isolated concurrent local Hot KV State for distributed Shards (DGR-007).
Hot KV State stays local to the node serving a Shard (RALPH runtime decision #7).
A concurrent server must map each ``(Route Session ID, route epoch)`` to an
isolated bounded KV context (decision #8) so that one request can never clear or
corrupt another's cache.
This module owns the *lifecycle and storage* of that state and is deliberately
backend-agnostic:
* :class:`HotKvStateManager` is the single mutation entry point. It maps
``(session_id, route_epoch)`` to a :class:`SessionCache`, allocates KV **only
for the owned layer range**, and enforces a byte budget, a session cap, and a
TTL through LRU/TTL eviction. It rejects stale route epochs and incompatible
cache recipes, and returns an **explicit** :class:`CacheMiss` when state the
caller expected is gone (evicted, released, desynchronised, or never held) so
the head degrades to a from-token-zero re-prefill instead of corrupting output
(RALPH decision #14: unverified KV is never migrated silently).
* :class:`LayerKvCache` / :class:`SessionCache` are the per-owned-layer K/V
containers. They are plain ``numpy`` arrays so the default deterministic test
suite needs no torch, GPU, download, or API credit; the pinned llama.cpp worker
(DGR-008) maps a llama sequence onto the same container contract.
* :class:`KvBoundaryAdapter` wraps a KV-aware ``ShardComputation`` (the DGR-006
duck type plus ``run_layers_cached``) so a Shard can run cached prefill/decode
through the manager while honouring the architecture-defined boundary contract
(head embeds tokens, middle/tail bypass embedding, non-tail emits the
unnormalized residual, tail samples).
The manager owns *all* cache mutation: a computation reads the existing cache and
returns the new K/V for the appended positions, and the manager decides whether
that append fits the budget. That keeps eviction, accounting, and isolation in one
place instead of scattered across backends.
"""
from __future__ import annotations
import threading
import time
from collections import OrderedDict
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Mapping
import numpy as np
from meshnet_node.boundary_adapter import (
BOUNDARY_SCHEMA_VERSION,
BoundaryBundle,
BoundaryContractError,
SamplingContract,
ShardRole,
TailOutput,
certified_architecture,
role_for_range,
)
from meshnet_node.runtime_recipe import compatibility_fingerprint
class HotKvStateError(RuntimeError):
"""Base class for Hot KV State errors."""
class StaleRouteEpochError(HotKvStateError):
"""Raised when a request references a route epoch older than the current one.
A newer route epoch means the route was re-planned; the old epoch's KV is
unverified against the new plan and must never be silently reused.
"""
class IncompatibleCacheRecipeError(HotKvStateError):
"""Raised when a request's cache recipe does not match the loaded shard.
A different quantization / dtype / owned range / architecture produces a KV
layout this node cannot reuse without corrupting output.
"""
class KvBudgetExceededError(HotKvStateError):
"""Raised when a single session cannot fit the configured byte budget.
Other sessions are evicted first (LRU); this fires only when even one session
alone exceeds the budget, which is a misconfiguration rather than pressure.
"""
class KvCacheMissError(HotKvStateError):
"""Raised by the strict accessor when expected session state is absent.
Prefer :meth:`HotKvStateManager.resolve`, which returns a structured
:class:`CacheMiss` instead of raising, when the caller wants to fall back to a
stateless re-prefill.
"""
def __init__(self, miss: "CacheMiss") -> None:
super().__init__(str(miss))
self.miss = miss
class CacheMissReason(str, Enum):
"""Why a lookup produced a cache miss (all benign; retry from token zero)."""
UNKNOWN_SESSION = "unknown-session"
EVICTED_TTL = "evicted-ttl"
EVICTED_LRU = "evicted-lru"
RELEASED = "released"
SUPERSEDED_EPOCH = "superseded-epoch"
SEQ_LEN_MISMATCH = "seq-len-mismatch"
@dataclass(frozen=True)
class CacheMiss:
"""Explicit cache-miss response the head can act on (re-prefill).
This is a value, not an exception: the native protocol carries a cache
expectation/result, and a miss is a normal, expected outcome under eviction.
"""
session_id: str
route_epoch: int
reason: CacheMissReason
detail: str = ""
def __str__(self) -> str:
suffix = f": {self.detail}" if self.detail else ""
return (
f"cache miss for session {self.session_id[:8]} epoch "
f"{self.route_epoch} ({self.reason.value}){suffix}"
)
@dataclass(frozen=True)
class KvCacheRecipe:
"""The identity of a Shard's KV layout, used to reject incompatible reuse.
Two recipes are compatible iff their fingerprints match — same certified
architecture, KV dtype, head geometry, and owned layer range within the same
whole-model layer count.
"""
architecture_adapter: str
kv_dtype: str
n_kv_heads: int
head_dim: int
total_layers: int
start_layer: int
end_layer: int
boundary_schema_version: int = BOUNDARY_SCHEMA_VERSION
def __post_init__(self) -> None:
# Fail closed on architecture identity (shared with the boundary adapter).
certified_architecture(self.architecture_adapter)
if self.n_kv_heads <= 0:
raise ValueError("n_kv_heads must be positive")
if self.head_dim <= 0:
raise ValueError("head_dim must be positive")
try:
np.dtype(self.kv_dtype)
except TypeError as exc: # pragma: no cover - defensive
raise ValueError(f"invalid kv_dtype {self.kv_dtype!r}") from exc
# role_for_range validates 0 <= start <= end <= total_layers - 1.
role_for_range(self.start_layer, self.end_layer, self.total_layers)
if self.boundary_schema_version < 1:
raise ValueError("boundary_schema_version must be >= 1")
@property
def owned_layers(self) -> tuple[int, ...]:
return tuple(range(self.start_layer, self.end_layer + 1))
@property
def role(self) -> ShardRole:
return role_for_range(self.start_layer, self.end_layer, self.total_layers)
def bytes_per_token(self) -> int:
"""Bytes of KV one token adds across *owned* layers (keys + values)."""
itemsize = np.dtype(self.kv_dtype).itemsize
per_layer = 2 * self.n_kv_heads * self.head_dim * itemsize
return per_layer * len(self.owned_layers)
def fingerprint(self) -> str:
return compatibility_fingerprint(
{
"kind": "hot-kv-recipe",
# Canonicalize the architecture so 'llama' / 'LlamaForCausalLM'
# map to the same fingerprint (they are the same layout).
"architecture_adapter": certified_architecture(
self.architecture_adapter
).adapter,
"kv_dtype": np.dtype(self.kv_dtype).name,
"n_kv_heads": self.n_kv_heads,
"head_dim": self.head_dim,
"total_layers": self.total_layers,
"start_layer": self.start_layer,
"end_layer": self.end_layer,
"boundary_schema_version": self.boundary_schema_version,
}
)
def is_compatible(self, other: "KvCacheRecipe") -> bool:
return self.fingerprint() == other.fingerprint()
class LayerKvCache:
"""K/V storage for a single owned layer; sequence axis is 0.
Keys and values are ``(seq, n_kv_heads, head_dim)``. Backends store the
position-encoded (post-RoPE) keys so a decode step only appends the new rows.
"""
__slots__ = ("layer_index", "n_kv_heads", "head_dim", "dtype", "keys", "values")
def __init__(
self, layer_index: int, n_kv_heads: int, head_dim: int, dtype: Any
) -> None:
self.layer_index = int(layer_index)
self.n_kv_heads = int(n_kv_heads)
self.head_dim = int(head_dim)
self.dtype = np.dtype(dtype)
self.keys = np.empty((0, self.n_kv_heads, self.head_dim), dtype=self.dtype)
self.values = np.empty((0, self.n_kv_heads, self.head_dim), dtype=self.dtype)
@property
def length(self) -> int:
return int(self.keys.shape[0])
def _validate(self, array: np.ndarray, name: str) -> np.ndarray:
arr = np.asarray(array, dtype=self.dtype)
if arr.ndim != 3 or arr.shape[1:] != (self.n_kv_heads, self.head_dim):
raise ValueError(
f"layer {self.layer_index} {name} must be "
f"(seq, {self.n_kv_heads}, {self.head_dim}), got {arr.shape}"
)
return arr
def append(self, keys: np.ndarray, values: np.ndarray) -> int:
k = self._validate(keys, "keys")
v = self._validate(values, "values")
if k.shape[0] != v.shape[0]:
raise ValueError(
f"layer {self.layer_index} keys/values disagree on token count "
f"({k.shape[0]} vs {v.shape[0]})"
)
self.keys = np.concatenate([self.keys, k], axis=0)
self.values = np.concatenate([self.values, v], axis=0)
return self.length
def truncate(self, length: int) -> None:
length = max(0, int(length))
self.keys = self.keys[:length]
self.values = self.values[:length]
@property
def nbytes(self) -> int:
return int(self.keys.nbytes + self.values.nbytes)
@dataclass
class SessionCache:
"""Isolated per-``(session_id, epoch)`` KV context over the owned layers only."""
session_id: str
route_epoch: int
recipe: KvCacheRecipe
layers: "OrderedDict[int, LayerKvCache]"
created_tick: float
last_tick: float
released: bool = False
@property
def seq_len(self) -> int:
if not self.layers:
return 0
# All owned layers advance in lockstep; report the first owned layer.
return next(iter(self.layers.values())).length
@property
def owned_layers(self) -> tuple[int, ...]:
return tuple(self.layers.keys())
def layer(self, index: int) -> LayerKvCache:
try:
return self.layers[index]
except KeyError:
raise KeyError(
f"layer {index} is not owned by this shard "
f"(owned {list(self.layers)})"
) from None
def read_only_layers(self) -> Mapping[int, LayerKvCache]:
"""The current per-layer caches a computation reads to attend over."""
return dict(self.layers)
def _append(self, kv_by_layer: Mapping[int, Any]) -> int:
provided = set(kv_by_layer)
owned = set(self.layers)
if provided != owned:
raise ValueError(
f"append must cover exactly the owned layers {sorted(owned)}, "
f"got {sorted(provided)}"
)
# Pre-validate token counts so a partial append never desynchronises the
# owned layers (append is all-or-nothing).
new_counts = set()
for idx, (keys, _values) in kv_by_layer.items():
new_counts.add(int(np.asarray(keys).shape[0]))
if len(new_counts) != 1:
raise ValueError(
f"append token counts disagree across layers: {sorted(new_counts)}"
)
for idx, (keys, values) in kv_by_layer.items():
self.layers[idx].append(keys, values)
return self.seq_len
def _truncate(self, length: int) -> None:
for cache in self.layers.values():
cache.truncate(length)
@property
def nbytes(self) -> int:
return sum(cache.nbytes for cache in self.layers.values())
@dataclass(frozen=True)
class HotKvStateConfig:
"""Bounds for the manager: memory budget, session cap, and idle TTL."""
budget_bytes: int = 64 * 1024 * 1024
max_sessions: int = 8
ttl_seconds: float = 600.0
miss_history: int = 256
def __post_init__(self) -> None:
if self.budget_bytes <= 0:
raise ValueError("budget_bytes must be positive")
if self.max_sessions < 1:
raise ValueError("max_sessions must be >= 1")
if self.ttl_seconds < 0:
raise ValueError("ttl_seconds must be >= 0")
if self.miss_history < 0:
raise ValueError("miss_history must be >= 0")
class HotKvStateManager:
"""Concurrent, bounded map of ``(session_id, epoch)`` to an isolated KV context."""
def __init__(
self,
recipe: KvCacheRecipe,
config: HotKvStateConfig | None = None,
*,
clock: Callable[[], float] | None = None,
) -> None:
self.recipe = recipe
self.config = config or HotKvStateConfig()
self._clock = clock or time.monotonic
self._sessions: "OrderedDict[tuple[str, int], SessionCache]" = OrderedDict()
self._latest_epoch: dict[str, int] = {}
self._misses: "OrderedDict[tuple[str, int], CacheMiss]" = OrderedDict()
self._lock = threading.RLock()
# -- introspection --------------------------------------------------------
@property
def total_bytes(self) -> int:
with self._lock:
return sum(s.nbytes for s in self._sessions.values())
@property
def session_count(self) -> int:
with self._lock:
self._evict_expired_locked(self._clock())
return len(self._sessions)
def session_keys(self) -> list[tuple[str, int]]:
with self._lock:
return list(self._sessions.keys())
# -- lifecycle ------------------------------------------------------------
def open(
self,
session_id: str,
route_epoch: int,
*,
recipe: KvCacheRecipe | None = None,
) -> SessionCache:
"""Create (or replace) a fresh, empty isolated context for the session.
A higher route epoch supersedes and frees any earlier epoch for the same
session id; an older epoch is rejected as stale.
"""
self._require_text(session_id, "session_id")
route_epoch = self._require_epoch(route_epoch)
with self._lock:
self._check_recipe(recipe)
self._validate_epoch_locked(session_id, route_epoch)
now = self._clock()
self._evict_expired_locked(now)
self._supersede_older_epochs_locked(session_id, route_epoch)
key = (session_id, route_epoch)
# A re-open at the same epoch replaces the prior context entirely.
self._sessions.pop(key, None)
layers: "OrderedDict[int, LayerKvCache]" = OrderedDict(
(
idx,
LayerKvCache(
idx,
self.recipe.n_kv_heads,
self.recipe.head_dim,
self.recipe.kv_dtype,
),
)
for idx in self.recipe.owned_layers
)
session = SessionCache(
session_id=session_id,
route_epoch=route_epoch,
recipe=self.recipe,
layers=layers,
created_tick=now,
last_tick=now,
)
self._sessions[key] = session
self._latest_epoch[session_id] = route_epoch
self._misses.pop(key, None)
self._enforce_capacity_locked(protect=key, incoming_bytes=0)
return session
def append(
self,
session_id: str,
route_epoch: int,
kv_by_layer: Mapping[int, Any],
*,
recipe: KvCacheRecipe | None = None,
expected_seq_len: int | None = None,
) -> SessionCache:
"""Append new K/V (prefill or decode) to an existing isolated context.
The computation supplies exactly the owned layers' new keys/values. The
manager evicts other sessions (LRU) to fit the byte budget before growing
this one, and raises :class:`KvBudgetExceededError` only if this session
alone cannot fit.
"""
route_epoch = self._require_epoch(route_epoch)
with self._lock:
self._check_recipe(recipe)
self._validate_epoch_locked(session_id, route_epoch)
session = self._require_live_locked(session_id, route_epoch)
if expected_seq_len is not None and session.seq_len != expected_seq_len:
miss = self._drop_and_record_locked(
(session_id, route_epoch),
CacheMissReason.SEQ_LEN_MISMATCH,
detail=f"cache holds {session.seq_len}, caller expected "
f"{expected_seq_len}",
)
raise KvCacheMissError(miss)
n_new = self._new_token_count(kv_by_layer)
incoming = n_new * self.recipe.bytes_per_token()
self._enforce_capacity_locked(
protect=(session_id, route_epoch), incoming_bytes=incoming
)
session._append(kv_by_layer)
session.last_tick = self._clock()
self._sessions.move_to_end((session_id, route_epoch))
return session
def truncate(
self, session_id: str, route_epoch: int, length: int
) -> SessionCache:
"""Drop cached positions beyond ``length`` (rollback) for one session."""
route_epoch = self._require_epoch(route_epoch)
with self._lock:
self._validate_epoch_locked(session_id, route_epoch)
session = self._require_live_locked(session_id, route_epoch)
if length < 0:
raise ValueError("truncate length must be >= 0")
session._truncate(length)
session.last_tick = self._clock()
self._sessions.move_to_end((session_id, route_epoch))
return session
def release(self, session_id: str, route_epoch: int) -> bool:
"""Free one session's context; other sessions are untouched.
Returns True if a live context was freed. A later lookup for the released
key yields an explicit :class:`CacheMiss`.
"""
route_epoch = self._require_epoch(route_epoch)
with self._lock:
key = (session_id, route_epoch)
existed = key in self._sessions
self._drop_and_record_locked(key, CacheMissReason.RELEASED)
return existed
# -- lookup ---------------------------------------------------------------
def resolve(
self,
session_id: str,
route_epoch: int,
*,
recipe: KvCacheRecipe | None = None,
expected_seq_len: int | None = None,
) -> SessionCache | CacheMiss:
"""Return the live context or an explicit :class:`CacheMiss`.
Rejects stale epochs and incompatible recipes (both are protocol
violations, not benign misses).
"""
route_epoch = self._require_epoch(route_epoch)
with self._lock:
self._check_recipe(recipe)
self._validate_epoch_locked(session_id, route_epoch)
now = self._clock()
self._evict_expired_locked(now)
key = (session_id, route_epoch)
session = self._sessions.get(key)
if session is None:
return self._recorded_miss_locked(key)
if expected_seq_len is not None and session.seq_len != expected_seq_len:
return self._drop_and_record_locked(
key,
CacheMissReason.SEQ_LEN_MISMATCH,
detail=f"cache holds {session.seq_len}, caller expected "
f"{expected_seq_len}",
)
session.last_tick = now
self._sessions.move_to_end(key)
return session
def get(
self,
session_id: str,
route_epoch: int,
*,
recipe: KvCacheRecipe | None = None,
expected_seq_len: int | None = None,
) -> SessionCache:
"""Strict accessor: raises :class:`KvCacheMissError` on a miss."""
result = self.resolve(
session_id,
route_epoch,
recipe=recipe,
expected_seq_len=expected_seq_len,
)
if isinstance(result, CacheMiss):
raise KvCacheMissError(result)
return result
# -- internals ------------------------------------------------------------
def _check_recipe(self, recipe: KvCacheRecipe | None) -> None:
if recipe is not None and not self.recipe.is_compatible(recipe):
raise IncompatibleCacheRecipeError(
"request cache recipe does not match this shard's loaded recipe "
f"(request {recipe.fingerprint()} vs shard {self.recipe.fingerprint()})"
)
def _validate_epoch_locked(self, session_id: str, route_epoch: int) -> None:
latest = self._latest_epoch.get(session_id)
if latest is not None and route_epoch < latest:
raise StaleRouteEpochError(
f"session {session_id[:8]} route epoch {route_epoch} is stale; "
f"current epoch is {latest}"
)
def _supersede_older_epochs_locked(
self, session_id: str, route_epoch: int
) -> None:
stale_keys = [
key
for key in self._sessions
if key[0] == session_id and key[1] < route_epoch
]
for key in stale_keys:
self._drop_and_record_locked(key, CacheMissReason.SUPERSEDED_EPOCH)
def _require_live_locked(
self, session_id: str, route_epoch: int
) -> SessionCache:
now = self._clock()
self._evict_expired_locked(now)
key = (session_id, route_epoch)
session = self._sessions.get(key)
if session is None:
raise KvCacheMissError(self._recorded_miss_locked(key))
return session
def _new_token_count(self, kv_by_layer: Mapping[int, Any]) -> int:
owned = set(self.recipe.owned_layers)
if set(kv_by_layer) != owned:
raise ValueError(
f"append must cover exactly the owned layers {sorted(owned)}, "
f"got {sorted(kv_by_layer)}"
)
counts = {int(np.asarray(k).shape[0]) for k, _ in kv_by_layer.values()}
if len(counts) != 1:
raise ValueError(
f"append token counts disagree across layers: {sorted(counts)}"
)
return counts.pop()
def _enforce_capacity_locked(
self, *, protect: tuple[str, int], incoming_bytes: int
) -> None:
# Session cap: evict LRU sessions other than the protected one.
while len(self._sessions) > self.config.max_sessions:
victim = self._lru_victim_locked(protect)
if victim is None:
break
self._drop_and_record_locked(victim, CacheMissReason.EVICTED_LRU)
# Byte budget: the protected session's own footprint after the append.
protected = self._sessions.get(protect)
protected_bytes = (protected.nbytes if protected is not None else 0) + incoming_bytes
if protected_bytes > self.config.budget_bytes:
raise KvBudgetExceededError(
f"session {protect[0][:8]} needs {protected_bytes} bytes which "
f"exceeds the KV budget {self.config.budget_bytes}"
)
# Evict other LRU sessions until the whole store fits with the append.
while self._total_bytes_locked() + incoming_bytes > self.config.budget_bytes:
victim = self._lru_victim_locked(protect)
if victim is None:
break
self._drop_and_record_locked(victim, CacheMissReason.EVICTED_LRU)
def _lru_victim_locked(self, protect: tuple[str, int]) -> tuple[str, int] | None:
for key in self._sessions: # OrderedDict iterates oldest-first.
if key != protect:
return key
return None
def _total_bytes_locked(self) -> int:
return sum(s.nbytes for s in self._sessions.values())
def _evict_expired_locked(self, now: float) -> None:
ttl = self.config.ttl_seconds
if ttl <= 0:
return
expired = [
key
for key, session in self._sessions.items()
if now - session.last_tick > ttl
]
for key in expired:
self._drop_and_record_locked(key, CacheMissReason.EVICTED_TTL)
def _drop_and_record_locked(
self,
key: tuple[str, int],
reason: CacheMissReason,
*,
detail: str = "",
) -> CacheMiss:
session = self._sessions.pop(key, None)
if session is not None:
session.released = True
miss = CacheMiss(
session_id=key[0], route_epoch=key[1], reason=reason, detail=detail
)
self._record_miss_locked(key, miss)
return miss
def _record_miss_locked(self, key: tuple[str, int], miss: CacheMiss) -> None:
if self.config.miss_history <= 0:
return
self._misses.pop(key, None)
self._misses[key] = miss
while len(self._misses) > self.config.miss_history:
self._misses.popitem(last=False)
def _recorded_miss_locked(self, key: tuple[str, int]) -> CacheMiss:
recorded = self._misses.get(key)
if recorded is not None:
return recorded
return CacheMiss(
session_id=key[0],
route_epoch=key[1],
reason=CacheMissReason.UNKNOWN_SESSION,
)
@staticmethod
def _require_text(value: Any, name: str) -> str:
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{name} must be a non-empty string")
return value
@staticmethod
def _require_epoch(value: Any) -> int:
if isinstance(value, bool) or not isinstance(value, int):
raise ValueError("route_epoch must be an integer")
if value < 0:
raise ValueError("route_epoch must be >= 0")
return value
def kv_recipe_for(computation: Any) -> KvCacheRecipe:
"""Build a :class:`KvCacheRecipe` from a KV-aware ``ShardComputation``.
The computation exposes the DGR-006 duck type plus KV geometry
(``n_kv_heads``, ``head_dim``, ``kv_dtype``).
"""
return KvCacheRecipe(
architecture_adapter=str(getattr(computation, "architecture_adapter")),
kv_dtype=str(getattr(computation, "kv_dtype", "float32")),
n_kv_heads=int(getattr(computation, "n_kv_heads")),
head_dim=int(getattr(computation, "head_dim")),
total_layers=int(getattr(computation, "total_layers")),
start_layer=int(getattr(computation, "start_layer")),
end_layer=int(getattr(computation, "end_layer")),
)
@dataclass
class KvBoundaryAdapter:
"""KV-aware boundary driver: cached prefill/decode through the manager.
Mirrors the DGR-006 :class:`~meshnet_node.boundary_adapter.BoundaryAdapter`
contract (head embeds tokens, middle/tail bypass embedding and consume the
unnormalized residual bundle, non-tail emits the unnormalized residual, tail
normalizes + heads + prunes + samples) but threads a per-session KV context.
The wrapped computation must additionally expose::
run_layers_cached(hidden, *, positions, past_kv)
-> (hidden_out, {layer_index: (new_keys, new_values)})
reading ``past_kv`` (the current per-owned-layer caches) and returning the new
position-encoded K/V for the appended positions only. The manager, not the
computation, commits those K/V so eviction and budget stay centralized.
"""
computation: Any
manager: HotKvStateManager
sampling: SamplingContract = field(default_factory=SamplingContract.greedy)
architecture: Any = field(init=False)
role: ShardRole = field(init=False)
start_layer: int = field(init=False)
end_layer: int = field(init=False)
total_layers: int = field(init=False)
recipe: KvCacheRecipe = field(init=False)
def __post_init__(self) -> None:
arch_name = getattr(self.computation, "architecture_adapter", None)
self.architecture = certified_architecture(arch_name)
self.start_layer = int(getattr(self.computation, "start_layer"))
self.end_layer = int(getattr(self.computation, "end_layer"))
self.total_layers = int(getattr(self.computation, "total_layers"))
self.role = role_for_range(self.start_layer, self.end_layer, self.total_layers)
self.recipe = kv_recipe_for(self.computation)
if not self.manager.recipe.is_compatible(self.recipe):
raise IncompatibleCacheRecipeError(
"manager recipe does not match this computation's KV recipe"
)
@property
def is_head(self) -> bool:
return self.role.owns_embedding
@property
def is_tail(self) -> bool:
return self.role.owns_final_head
def prefill(
self,
session_id: str,
route_epoch: int,
*,
token_ids: Any | None = None,
boundary: BoundaryBundle | None = None,
) -> BoundaryBundle | TailOutput:
"""Open a fresh isolated context and run the prompt through this range."""
session = self.manager.open(session_id, route_epoch, recipe=self.recipe)
return self._run_step(session, token_ids, boundary)
def decode(
self,
session_id: str,
route_epoch: int,
*,
token_ids: Any | None = None,
boundary: BoundaryBundle | None = None,
expected_seq_len: int | None = None,
) -> BoundaryBundle | TailOutput | CacheMiss:
"""Append one (or more) decode positions to an existing context.
Returns an explicit :class:`CacheMiss` if the context is gone so the head
can re-prefill from token zero instead of corrupting output.
"""
resolved = self.manager.resolve(
session_id,
route_epoch,
recipe=self.recipe,
expected_seq_len=expected_seq_len,
)
if isinstance(resolved, CacheMiss):
return resolved
return self._run_step(resolved, token_ids, boundary)
# -- internals ------------------------------------------------------------
def _run_step(
self,
session: SessionCache,
token_ids: Any | None,
boundary: BoundaryBundle | None,
) -> BoundaryBundle | TailOutput:
prev_len = session.seq_len
hidden, positions = self._ingest(prev_len, token_ids, boundary)
hidden_out, new_kv = self.computation.run_layers_cached(
hidden, positions=positions, past_kv=session.read_only_layers()
)
self.manager.append(
session.session_id,
session.route_epoch,
new_kv,
recipe=self.recipe,
expected_seq_len=prev_len,
)
if self.is_tail:
return self._emit_tail(hidden_out)
return self._emit_boundary(hidden_out, positions)
def _ingest(
self,
prev_len: int,
token_ids: Any | None,
boundary: BoundaryBundle | None,
) -> tuple[np.ndarray, np.ndarray]:
if self.role.owns_embedding:
if token_ids is None:
raise BoundaryContractError(
"the head owns token embedding and must receive token IDs"
)
if boundary is not None:
raise BoundaryContractError(
"the head owns token embedding; it must not receive a boundary "
"bundle from an upstream range"
)
ids = np.asarray(token_ids)
if ids.ndim == 1:
ids = ids[None, :]
if ids.ndim != 2:
raise BoundaryContractError("token IDs must be (seq,) or (batch, seq)")
hidden = np.asarray(self.computation.embed_tokens(ids))
n_new = ids.shape[1]
positions = np.broadcast_to(
np.arange(prev_len, prev_len + n_new, dtype=np.int64),
ids.shape,
).copy()
return hidden, positions
# Middle / tail: consume the boundary bundle (the unnormalized residual).
if token_ids is not None:
raise BoundaryContractError(
"middle/tail Shards bypass token embedding; they must not receive "
"token IDs"
)
if boundary is None:
raise BoundaryContractError(
"middle/tail Shards must receive the named boundary bundle"
)
self._check_boundary(boundary)
return np.asarray(boundary.residual), np.asarray(boundary.positions)
def _check_boundary(self, boundary: BoundaryBundle) -> None:
if certified_architecture(boundary.architecture_adapter) is not self.architecture:
raise BoundaryContractError(
f"boundary bundle architecture {boundary.architecture_adapter!r} "
f"does not match this Shard's adapter {self.architecture.adapter!r}"
)
if boundary.schema_version != self.architecture.boundary_schema_version:
raise BoundaryContractError(
f"boundary schema v{boundary.schema_version} is not supported by "
f"this Shard (expects v{self.architecture.boundary_schema_version})"
)
if boundary.tensor_name != self.architecture.boundary_tensor_name:
raise BoundaryContractError(
f"boundary tensor {boundary.tensor_name!r} is not the "
f"architecture-defined {self.architecture.boundary_tensor_name!r}"
)
if boundary.normalized:
raise BoundaryContractError(
"boundary bundle is normalized; a Shard range must receive the "
"UNNORMALIZED architecture-defined residual"
)
if boundary.next_layer != self.start_layer:
raise BoundaryContractError(
f"boundary hands over at layer {boundary.next_layer} but this "
f"Shard starts at layer {self.start_layer}"
)
def _emit_boundary(
self, hidden: np.ndarray, positions: np.ndarray
) -> BoundaryBundle:
return BoundaryBundle(
architecture_adapter=self.architecture.adapter,
schema_version=self.architecture.boundary_schema_version,
tensor_name=self.architecture.boundary_tensor_name,
residual=np.asarray(hidden),
positions=np.asarray(positions),
next_layer=self.end_layer + 1,
normalized=False,
)
def _emit_tail(self, hidden: np.ndarray) -> TailOutput:
hidden = np.asarray(hidden)
if self.architecture.prunes_rows_at_tail:
last_hidden = hidden[:, -1:, :]
else: # pragma: no cover - no certified architecture takes this path yet
last_hidden = hidden
if self.architecture.normalizes_before_head:
last_hidden = np.asarray(self.computation.final_norm(last_hidden))
logits = np.asarray(self.computation.lm_head(last_hidden))
last_logits = logits[:, -1, :]
token_id = self.sampling.sample(last_logits)
return TailOutput(token_id=token_id, logits=last_logits, sampling=self.sampling)

View File

@@ -323,10 +323,6 @@ class TorchModelShard:
) )
self.is_head = shard_start == 0 self.is_head = shard_start == 0
self.is_tail = shard_end >= self.total_layers - 1 self.is_tail = shard_end >= self.total_layers - 1
self.loaded_shard_start = shard_start
self.loaded_shard_end = shard_end
self.owns_embedding = self.is_head
self.owns_final_head = self.is_tail
self.hidden_size = int( self.hidden_size = int(
getattr(self.model.config, "hidden_size", 0) getattr(self.model.config, "hidden_size", 0)
or getattr(self.model.config, "n_embd", 0) or getattr(self.model.config, "n_embd", 0)
@@ -348,17 +344,6 @@ class TorchModelShard:
ttl_seconds=float(os.environ.get("MESHNET_KV_TTL_SECONDS", "600")), ttl_seconds=float(os.environ.get("MESHNET_KV_TTL_SECONDS", "600")),
) )
@property
def loaded_range(self) -> tuple[int, int]:
return self.loaded_shard_start, self.loaded_shard_end
@property
def endpoint_ownership(self) -> dict[str, bool]:
return {
"owns_embedding": self.owns_embedding,
"owns_final_head": self.owns_final_head,
}
def encode_prompt(self, prompt: str, session_id: str | None = None) -> TensorPayload: def encode_prompt(self, prompt: str, session_id: str | None = None) -> TensorPayload:
if not self.is_head or self._embed_tokens is None: if not self.is_head or self._embed_tokens is None:
raise ModelBackendError("text prompts can only be accepted by the head shard") raise ModelBackendError("text prompts can only be accepted by the head shard")

View File

@@ -1,300 +0,0 @@
"""Loader and helpers for the versioned gRPC Shard protocol (ADR-0024, DGR-002).
The ``.proto`` schema at ``packages/node/native/proto/shard_runtime.proto`` is the
single source of truth. Rather than commit generated stubs (which pin a protobuf
runtime version and drift from the schema), this package generates the Python
stubs on demand into a gitignored build directory and imports them. Generation is
reproducible: it shells out to the pinned ``grpc_tools.protoc`` with the exact
same flags as ``packages/node/native/scripts/generate_python.py``.
Typical use::
from meshnet_node import native_protocol as proto
pb2 = proto.load()
header = pb2.MessageHeader(work_id="w1", route_session_id="s1")
The checksum/fragment helpers encode the bounded-fragment tensor-bundle semantics
so callers (and DGR-008/DGR-009) do not re-derive them.
"""
from __future__ import annotations
import hashlib
import importlib
import importlib.util
import pathlib
import sys
import threading
import types
import zlib
# The wire schema version this build targets. Keep in sync with the
# ``SCHEMA_VERSION_1`` enum member in the .proto.
SCHEMA_VERSION = 1
_NATIVE_ROOT = pathlib.Path(__file__).resolve().parents[2] / "native"
PROTO_DIR = _NATIVE_ROOT / "proto"
PROTO_FILE = PROTO_DIR / "shard_runtime.proto"
# ``build/`` is globally gitignored, so generated stubs never enter version control.
GEN_DIR = _NATIVE_ROOT / "build" / "python"
_PB2_MODULE = "shard_runtime_pb2"
_GRPC_MODULE = "shard_runtime_pb2_grpc"
# Reentrant: load_grpc() holds the lock and calls load(), which re-acquires it.
_lock = threading.RLock()
_cached_pb2: types.ModuleType | None = None
_cached_grpc: types.ModuleType | None = None
class ProtocGenerationError(RuntimeError):
"""Raised when the protobuf stubs cannot be generated from the schema."""
def _needs_regen(target: pathlib.Path) -> bool:
if not target.exists():
return True
try:
return PROTO_FILE.stat().st_mtime > target.stat().st_mtime
except OSError:
return True
def generate(*, force: bool = False) -> pathlib.Path:
"""Generate ``shard_runtime_pb2{,_grpc}.py`` into :data:`GEN_DIR`.
Returns the output directory. Reproducible and idempotent: regenerates only
when the schema is newer than the stubs (or ``force`` is set). Requires the
pinned ``grpc_tools`` (available in the project ``.venv``).
"""
if not PROTO_FILE.exists():
raise ProtocGenerationError(f"schema not found: {PROTO_FILE}")
pb2_path = GEN_DIR / f"{_PB2_MODULE}.py"
if not force and not _needs_regen(pb2_path):
return GEN_DIR
try:
from grpc_tools import protoc
except ImportError as exc: # pragma: no cover - environment-dependent
raise ProtocGenerationError(
"grpc_tools is required to generate the Shard protocol stubs; "
"install grpcio-tools (present in the project .venv)."
) from exc
GEN_DIR.mkdir(parents=True, exist_ok=True)
well_known = _well_known_include()
args = [
"grpc_tools.protoc",
f"-I{PROTO_DIR}",
*([f"-I{well_known}"] if well_known else []),
f"--python_out={GEN_DIR}",
f"--grpc_python_out={GEN_DIR}",
str(PROTO_FILE.name),
]
# protoc resolves the proto by name relative to -I, so run with PROTO_DIR
# semantics by passing the bare filename plus the include path above.
rc = protoc.main([a for a in args])
if rc != 0:
raise ProtocGenerationError(
f"grpc_tools.protoc exited with status {rc} for {PROTO_FILE}"
)
if not pb2_path.exists(): # pragma: no cover - defensive
raise ProtocGenerationError(f"protoc did not produce {pb2_path}")
return GEN_DIR
def _well_known_include() -> str | None:
"""Bundled well-known .proto include dir shipped with grpc_tools, if any."""
try:
import grpc_tools
candidate = pathlib.Path(grpc_tools.__file__).parent / "_proto"
return str(candidate) if candidate.is_dir() else None
except Exception: # pragma: no cover - defensive
return None
def _import_generated(module_name: str) -> types.ModuleType:
gen_dir = str(GEN_DIR)
if gen_dir not in sys.path:
sys.path.insert(0, gen_dir)
if module_name in sys.modules:
return sys.modules[module_name]
return importlib.import_module(module_name)
def load(*, force: bool = False) -> types.ModuleType:
"""Return the generated ``shard_runtime_pb2`` module (messages only).
Generates the stubs on first use. Thread-safe and cached. Does not import
grpc; message serialization/round-trip needs only this module.
"""
global _cached_pb2
with _lock:
if _cached_pb2 is not None and not force:
return _cached_pb2
generate(force=force)
_cached_pb2 = _import_generated(_PB2_MODULE)
return _cached_pb2
def load_grpc(*, force: bool = False) -> types.ModuleType:
"""Return the generated ``shard_runtime_pb2_grpc`` module (service stubs).
Requires the ``grpc`` runtime. Use for building the C++/Python worker; the
round-trip/compat tests only need :func:`load`.
"""
global _cached_grpc
with _lock:
if _cached_grpc is not None and not force:
return _cached_grpc
generate(force=force)
load() # ensure the _pb2 module the grpc stub imports is present
_cached_grpc = _import_generated(_GRPC_MODULE)
return _cached_grpc
# ---------------------------------------------------------------------------
# Checksum + bounded-fragment helpers (shared bundle semantics)
# ---------------------------------------------------------------------------
# Algorithm-name strings mirror the ChecksumAlgorithm enum members without
# importing the generated module (so this table is usable before load()).
_CHECKSUM_CRC32C = "CHECKSUM_CRC32C"
_CHECKSUM_CRC32 = "CHECKSUM_CRC32"
_CHECKSUM_SHA256 = "CHECKSUM_SHA256"
_CHECKSUM_NONE = "CHECKSUM_NONE"
def _crc32c(data: bytes) -> int:
"""Castagnoli CRC32C (software table). Deterministic, no external deps."""
crc = 0xFFFFFFFF
for byte in data:
crc ^= byte
for _ in range(8):
crc = (crc >> 1) ^ (0x82F63B78 & -(crc & 1))
return crc ^ 0xFFFFFFFF
def compute_checksum(algorithm: int, data: bytes):
"""Build a ``Checksum`` message for ``data`` under the given enum value.
``algorithm`` is a ``ChecksumAlgorithm`` enum int from the generated module.
Uses only the standard library (crc32c software table, zlib.crc32, hashlib).
"""
pb2 = load()
name = pb2.ChecksumAlgorithm.Name(algorithm)
if name == _CHECKSUM_SHA256:
value = hashlib.sha256(data).digest()
elif name == _CHECKSUM_CRC32C:
value = _crc32c(data).to_bytes(4, "big")
elif name == _CHECKSUM_CRC32:
value = (zlib.crc32(data) & 0xFFFFFFFF).to_bytes(4, "big")
elif name == _CHECKSUM_NONE:
value = b""
else:
raise ValueError(f"unsupported checksum algorithm: {name}")
return pb2.Checksum(algorithm=algorithm, value=value)
def verify_checksum(checksum, data: bytes) -> bool:
"""True if ``checksum`` matches ``data`` (CHECKSUM_NONE always verifies)."""
pb2 = load()
if checksum.algorithm in (0, pb2.CHECKSUM_NONE):
return True
return compute_checksum(checksum.algorithm, data).value == checksum.value
def fragment_tensor(
*,
name: str,
shape,
dtype: int,
payload: bytes,
byte_order: int | None = None,
max_fragment_bytes: int = 1 << 20,
compression: int | None = None,
checksum_algorithm: int | None = None,
):
"""Build a :class:`NamedTensor` splitting ``payload`` into bounded fragments.
Fragments are ordered by ``byte_offset`` and each carries an optional
per-fragment checksum. ``payload`` is treated as already compressed if
``compression`` is set; this helper does not compress (that is the seam's
policy in ``activation_compression``), it only frames.
"""
if max_fragment_bytes <= 0:
raise ValueError("max_fragment_bytes must be positive")
pb2 = load()
if byte_order is None:
byte_order = pb2.BYTE_ORDER_LITTLE_ENDIAN
if compression is None:
compression = pb2.COMPRESSION_NONE
chunks = [
payload[i : i + max_fragment_bytes]
for i in range(0, len(payload), max_fragment_bytes)
] or [b""]
fragments = []
offset = 0
for index, chunk in enumerate(chunks):
frag = pb2.TensorFragment(
fragment_index=index,
fragment_count=len(chunks),
byte_offset=offset,
data=chunk,
)
if checksum_algorithm is not None:
frag.checksum.CopyFrom(compute_checksum(checksum_algorithm, chunk))
fragments.append(frag)
offset += len(chunk)
return pb2.NamedTensor(
name=name,
shape=list(shape),
dtype=dtype,
byte_order=byte_order,
total_byte_length=len(payload),
compression=compression,
fragments=fragments,
)
def reassemble_tensor(named_tensor) -> bytes:
"""Concatenate a :class:`NamedTensor`'s fragments back into the full payload.
Validates fragment ordering, total length, and any per-fragment checksums.
"""
fragments = sorted(named_tensor.fragments, key=lambda f: f.byte_offset)
out = bytearray()
for frag in fragments:
if frag.byte_offset != len(out):
raise ValueError(
f"non-contiguous fragment at offset {frag.byte_offset} "
f"(expected {len(out)})"
)
if frag.HasField("checksum") and not verify_checksum(frag.checksum, frag.data):
raise ValueError(f"fragment {frag.fragment_index} checksum mismatch")
out.extend(frag.data)
if named_tensor.total_byte_length and len(out) != named_tensor.total_byte_length:
raise ValueError(
f"reassembled length {len(out)} != declared "
f"{named_tensor.total_byte_length}"
)
return bytes(out)
__all__ = [
"SCHEMA_VERSION",
"PROTO_FILE",
"PROTO_DIR",
"GEN_DIR",
"ProtocGenerationError",
"generate",
"load",
"load_grpc",
"compute_checksum",
"verify_checksum",
"fragment_tensor",
"reassemble_tensor",
]

View File

@@ -1,563 +0,0 @@
"""Versioned performance contract metadata and stub benchmark runner for DGR-001.
This module captures the *contract* first: the model family, architecture
alignment, benchmark lanes, and stop condition that benchmark runs must
satisfy. It also runs the contract's lanes through a deterministic stub
backend so the report data shape exists end to end. It never downloads or
executes a model; real transformers / llama.cpp backends plug in behind the
same ``run()`` seam later.
"""
from __future__ import annotations
import argparse
import json
import time
import urllib.request
from dataclasses import dataclass
from pathlib import Path
from typing import Mapping
SCHEMA_VERSION = 1
CONTRACT_ID = "DGR-001"
DEFAULT_OUTPUT_PATH = Path(".scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json")
@dataclass(frozen=True)
class ModelTarget:
"""Architecture-aligned model target for the DGR-001 benchmark contract."""
name: str
architecture: str
safetensors_repo: str
safetensors_precision: str
gguf_repo: str
gguf_quant: str
gguf_size_gb: float
comparison_policy: str
rationale: str
def to_dict(self) -> dict:
return {
"name": self.name,
"architecture": self.architecture,
"safetensors_repo": self.safetensors_repo,
"safetensors_precision": self.safetensors_precision,
"gguf_repo": self.gguf_repo,
"gguf_quant": self.gguf_quant,
"gguf_size_gb": self.gguf_size_gb,
"comparison_policy": self.comparison_policy,
"rationale": self.rationale,
}
@dataclass(frozen=True)
class BenchmarkLane:
"""One side of the comparison the contract requires."""
id: str
runtime: str
device: str
recipe: str
concurrency_levels: tuple[int, ...]
def to_dict(self) -> dict:
return {
"id": self.id,
"runtime": self.runtime,
"device": self.device,
"recipe": self.recipe,
"concurrency_levels": list(self.concurrency_levels),
}
@dataclass(frozen=True)
class BenchmarkWorkload:
"""Identical request shape both recipes must run so speed stays comparable.
Pinning prompts, context lengths, output lengths, and sampling policy in the
versioned contract is what makes the safetensors-versus-GGUF numbers a
controlled comparison instead of two differently-configured runs.
"""
prompts: tuple[str, ...]
context_lengths: tuple[int, ...]
output_lengths: tuple[int, ...]
sampling_policy: str
def to_dict(self) -> dict:
return {
"prompts": list(self.prompts),
"context_lengths": list(self.context_lengths),
"output_lengths": list(self.output_lengths),
"sampling_policy": self.sampling_policy,
}
@dataclass(frozen=True)
class QualityPolicy:
"""Correctness/quality lane kept separate from the performance/fit lanes.
BF16 safetensors and Q2_K GGUF are not numerically equivalent, so quality is
measured as its own lane (output drift against the BF16 reference under a
documented tolerance) rather than assumed away by the speed/fit comparison.
"""
statement: str
reference_lane_runtime: str
measured_lane_runtime: str
max_output_drift: float
def to_dict(self) -> dict:
return {
"statement": self.statement,
"reference_lane_runtime": self.reference_lane_runtime,
"measured_lane_runtime": self.measured_lane_runtime,
"max_output_drift": self.max_output_drift,
}
@dataclass(frozen=True)
class ReleaseGate:
"""Versioned thresholds later release gates (DGR-014) consume unchanged.
Thresholds live in the contract, not in code, so the release gate cannot be
weakened after seeing implementation results.
"""
min_decode_speedup: float
max_artifact_bytes_ratio: float
max_memory_bytes_ratio: float
max_quality_drift: float
def to_dict(self) -> dict:
return {
"min_decode_speedup": self.min_decode_speedup,
"max_artifact_bytes_ratio": self.max_artifact_bytes_ratio,
"max_memory_bytes_ratio": self.max_memory_bytes_ratio,
"max_quality_drift": self.max_quality_drift,
}
@dataclass(frozen=True)
class PerformanceContract:
"""Machine-readable contract for the DGR-001 benchmark story."""
schema_version: int
story_id: str
model_target: ModelTarget
benchmark_lanes: tuple[BenchmarkLane, ...]
metrics: tuple[str, ...]
stop_condition: str
notes: tuple[str, ...] = ()
def to_dict(self) -> dict:
return {
"schema_version": self.schema_version,
"story_id": self.story_id,
"model_target": self.model_target.to_dict(),
"benchmark_lanes": [lane.to_dict() for lane in self.benchmark_lanes],
"metrics": list(self.metrics),
"stop_condition": self.stop_condition,
"notes": list(self.notes),
}
def write_json(self, path: str | Path) -> Path:
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n", encoding="utf-8")
return path
DEFAULT_CONTRACT = PerformanceContract(
schema_version=SCHEMA_VERSION,
story_id=CONTRACT_ID,
model_target=ModelTarget(
name="DeepSeek-V2-Lite-Chat",
architecture="deepseek2",
safetensors_repo="deepseek-ai/DeepSeek-V2-Lite-Chat",
safetensors_precision="bfloat16",
gguf_repo="second-state/DeepSeek-V2-Lite-Chat-GGUF",
gguf_quant="Q2_K",
gguf_size_gb=6.43,
comparison_policy=(
"same model/revision, closest practical low-footprint precision pair: "
"BF16 safetensors versus Q2_K GGUF"
),
rationale=(
"Smallest DeepSeek-family benchmark anchor that still points toward "
"DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead "
"of falling back to a tiny but architecture-mismatched smoke model."
),
),
benchmark_lanes=(
BenchmarkLane(
id="transformers-safetensors-cpu",
runtime="transformers",
device="cpu",
recipe="current safetensors recipe",
concurrency_levels=(1, 4),
),
BenchmarkLane(
id="llama-cpp-gguf-cpu",
runtime="llama.cpp",
device="cpu",
recipe="whole-model GGUF recipe",
concurrency_levels=(1, 4),
),
BenchmarkLane(
id="transformers-safetensors-gpu",
runtime="transformers",
device="gpu",
recipe="current safetensors recipe",
concurrency_levels=(1, 4),
),
BenchmarkLane(
id="llama-cpp-gguf-gpu",
runtime="llama.cpp",
device="gpu",
recipe="whole-model GGUF recipe",
concurrency_levels=(1, 4),
),
),
metrics=(
"ttft_ms",
"prefill_tok_per_sec",
"decode_tok_per_sec",
"p50_latency_ms",
"p95_latency_ms",
"aggregate_throughput_tok_per_sec",
"rss_bytes",
"vram_bytes",
"artifact_bytes",
"failure_count",
"output_drift",
),
stop_condition=(
"Stop if GGUF does not provide a meaningful speed or fit benefit over the "
"safetensors baseline for the chosen DeepSeek-family model target."
),
notes=(
"Real model execution stays opt-in and must keep model artifacts on the mounted drive.",
"Use the tiny fallback only for loader plumbing smoke tests; it does not replace the architecture-aligned baseline.",
),
)
def build_default_contract() -> PerformanceContract:
return DEFAULT_CONTRACT
BENCHMARK_SCHEMA_VERSION = 1
STUB_OUTPUT_TOKENS = ("mesh", "activation", "seam", "baseline")
# DeepSeek-V2-Lite is ~15.7B params at 2 bytes each; metadata only, nothing downloaded.
_SAFETENSORS_BF16_ARTIFACT_GB = 31.4
@dataclass(frozen=True)
class LaneSample:
"""Raw single-stream measurements one backend produces for a lane."""
ttft_ms: float
prefill_tok_per_sec: float
decode_tok_per_sec: float
rss_bytes: int
vram_bytes: int
artifact_bytes: int
output_tokens: tuple[str, ...]
failure_count: int = 0
def _gb(value: float) -> int:
return int(value * 1024**3)
class StubLaneBackend:
"""Deterministic placeholder measurements until real lane execution lands.
The numbers are synthetic but directionally shaped — the Q2_K GGUF loads a
far smaller artifact and decodes faster than BF16 safetensors — so the
comparison and stop-condition plumbing can be exercised in CI.
"""
source = "stub-backend"
# (runtime, device) -> (ttft_ms, prefill tok/s, decode tok/s, rss GB, vram GB)
_PROFILES = {
("transformers", "cpu"): (1800.0, 45.0, 6.0, 33.0, 0.0),
("llama.cpp", "cpu"): (950.0, 90.0, 14.0, 7.1, 0.0),
("transformers", "gpu"): (420.0, 850.0, 34.0, 4.0, 33.0),
("llama.cpp", "gpu"): (260.0, 640.0, 52.0, 1.5, 7.5),
}
def __init__(self, contract: PerformanceContract) -> None:
self._contract = contract
def run(self, lane: BenchmarkLane) -> LaneSample:
ttft_ms, prefill, decode, rss_gb, vram_gb = self._PROFILES[(lane.runtime, lane.device)]
artifact_gb = (
self._contract.model_target.gguf_size_gb
if lane.runtime == "llama.cpp"
else _SAFETENSORS_BF16_ARTIFACT_GB
)
return LaneSample(
ttft_ms=ttft_ms,
prefill_tok_per_sec=prefill,
decode_tok_per_sec=decode,
rss_bytes=_gb(rss_gb),
vram_bytes=_gb(vram_gb),
artifact_bytes=_gb(artifact_gb),
output_tokens=STUB_OUTPUT_TOKENS,
)
def _output_drift(tokens: tuple[str, ...], reference: tuple[str, ...]) -> float:
"""Fraction of positions where a lane's output diverges from its reference."""
length = max(len(tokens), len(reference))
if length == 0:
return 0.0
mismatches = sum(a != b for a, b in zip(tokens, reference)) + abs(len(tokens) - len(reference))
return round(mismatches / length, 4)
def _metrics_for(sample: LaneSample, concurrency: int, output_drift: float) -> dict:
# Stub concurrency model: batching scales throughput at 85% efficiency and
# stretches per-request token latency and TTFT accordingly.
efficiency = 1.0 if concurrency == 1 else 0.85
p50_latency_ms = round(1000.0 / (sample.decode_tok_per_sec * efficiency), 4)
return {
"ttft_ms": round(sample.ttft_ms * (1 + 0.1 * (concurrency - 1)), 4),
"prefill_tok_per_sec": round(sample.prefill_tok_per_sec * efficiency, 4),
"decode_tok_per_sec": round(sample.decode_tok_per_sec * efficiency, 4),
"p50_latency_ms": p50_latency_ms,
"p95_latency_ms": round(p50_latency_ms * 1.25, 4),
"aggregate_throughput_tok_per_sec": round(sample.decode_tok_per_sec * concurrency * efficiency, 4),
"rss_bytes": sample.rss_bytes,
"vram_bytes": sample.vram_bytes,
"artifact_bytes": sample.artifact_bytes,
"failure_count": sample.failure_count,
"output_drift": output_drift,
}
def _compare_device(lanes: list[tuple[BenchmarkLane, LaneSample]], device: str) -> dict:
by_runtime = {lane.runtime: (lane, sample) for lane, sample in lanes if lane.device == device}
safetensors_lane, safetensors = by_runtime["transformers"]
gguf_lane, gguf = by_runtime["llama.cpp"]
memory_metric = "vram_bytes" if device == "gpu" else "rss_bytes"
decode_speedup = round(gguf.decode_tok_per_sec / safetensors.decode_tok_per_sec, 4)
artifact_bytes_ratio = round(gguf.artifact_bytes / max(1, safetensors.artifact_bytes), 4)
return {
"safetensors_lane": safetensors_lane.id,
"gguf_lane": gguf_lane.id,
"decode_speedup": decode_speedup,
"ttft_speedup": round(safetensors.ttft_ms / max(0.001, gguf.ttft_ms), 4),
"artifact_bytes_ratio": artifact_bytes_ratio,
"memory_metric": memory_metric,
"memory_bytes_ratio": round(
getattr(gguf, memory_metric) / max(1, getattr(safetensors, memory_metric)), 4
),
"output_drift": _output_drift(gguf.output_tokens, safetensors.output_tokens),
"gguf_benefit": decode_speedup >= 1.10 or artifact_bytes_ratio <= 0.5,
}
def run_performance_benchmark(
contract: PerformanceContract = DEFAULT_CONTRACT,
backend: StubLaneBackend | None = None,
) -> dict:
"""Run every contract lane through a backend and compare GGUF to safetensors."""
backend = backend if backend is not None else StubLaneBackend(contract)
lanes = [(lane, backend.run(lane)) for lane in contract.benchmark_lanes]
references = {
lane.device: sample.output_tokens for lane, sample in lanes if lane.runtime == "transformers"
}
lane_reports = []
for lane, sample in lanes:
drift = _output_drift(sample.output_tokens, references.get(lane.device, sample.output_tokens))
lane_reports.append({
**lane.to_dict(),
"output_tokens": list(sample.output_tokens),
"results": [
{"concurrency": level, "metrics": _metrics_for(sample, level, drift)}
for level in lane.concurrency_levels
],
})
devices = sorted({lane.device for lane, _ in lanes})
comparisons = {device: _compare_device(lanes, device) for device in devices}
gguf_benefit = any(comparison["gguf_benefit"] for comparison in comparisons.values())
return {
"schema_version": BENCHMARK_SCHEMA_VERSION,
"story_id": contract.story_id,
"source": getattr(backend, "source", "custom-backend"),
"model_target": contract.model_target.to_dict(),
"lanes": lane_reports,
"comparisons": comparisons,
"stop_condition": {
"text": contract.stop_condition,
"gguf_benefit": gguf_benefit,
"triggered": not gguf_benefit,
},
}
def run_real_model_endpoint_benchmark(
endpoints: Mapping[str, str],
*,
model: str,
contract: PerformanceContract = DEFAULT_CONTRACT,
timeout: float = 120.0,
) -> dict:
"""Run one live OpenAI-compatible request per lane against supplied endpoints.
The caller provides one URL per benchmark lane. The runner measures the
request/response round-trip at the client boundary and reuses the same
contract schema as the deterministic stub.
"""
def _sample_for_lane(lane: BenchmarkLane, endpoint: str) -> LaneSample:
prompt = " ".join(contract.model_target.rationale.split()[:6])
body = json.dumps(
{
"model": model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": len(STUB_OUTPUT_TOKENS),
"temperature": 0,
}
).encode("utf-8")
request = urllib.request.Request(
f"{endpoint.rstrip('/')}/v1/chat/completions",
data=body,
headers={
"Content-Type": "application/json",
"X-Meshnet-Lane": lane.id,
},
method="POST",
)
started = time.monotonic()
with urllib.request.urlopen(request, timeout=timeout) as response:
response_body = response.read()
session_id = response.headers.get("X-Meshnet-Session", f"{lane.id}-session")
elapsed_ms = round((time.monotonic() - started) * 1000, 4)
payload = json.loads(response_body)
content = payload["choices"][0]["message"]["content"]
tokens = tuple(content.split())
token_count = max(1, len(tokens))
artifact_gb = (
contract.model_target.gguf_size_gb
if lane.runtime == "llama.cpp"
else _SAFETENSORS_BF16_ARTIFACT_GB
)
return LaneSample(
ttft_ms=elapsed_ms,
prefill_tok_per_sec=round(token_count / max(0.001, elapsed_ms / 1000), 4),
decode_tok_per_sec=round(token_count / max(0.001, elapsed_ms / 1000), 4),
rss_bytes=0,
vram_bytes=0,
artifact_bytes=_gb(artifact_gb),
output_tokens=tokens,
)
lanes = []
for lane in contract.benchmark_lanes:
if lane.id not in endpoints:
raise KeyError(f"missing endpoint for lane {lane.id}")
lanes.append((lane, _sample_for_lane(lane, endpoints[lane.id])))
references = {
lane.device: sample.output_tokens for lane, sample in lanes if lane.runtime == "transformers"
}
lane_reports = []
for lane, sample in lanes:
drift = _output_drift(sample.output_tokens, references.get(lane.device, sample.output_tokens))
lane_reports.append({
**lane.to_dict(),
"output_tokens": list(sample.output_tokens),
"results": [
{"concurrency": level, "metrics": _metrics_for(sample, level, drift)}
for level in lane.concurrency_levels
],
})
devices = sorted({lane.device for lane, _ in lanes})
comparisons = {device: _compare_device(lanes, device) for device in devices}
gguf_benefit = any(comparison["gguf_benefit"] for comparison in comparisons.values())
return {
"schema_version": BENCHMARK_SCHEMA_VERSION,
"story_id": contract.story_id,
"source": "real-model-endpoints",
"model_target": contract.model_target.to_dict(),
"lanes": lane_reports,
"comparisons": comparisons,
"stop_condition": {
"text": contract.stop_condition,
"gguf_benefit": gguf_benefit,
"triggered": not gguf_benefit,
},
}
def _parse_lane_endpoints(pairs: list[str], parser: argparse.ArgumentParser) -> dict[str, str]:
endpoints: dict[str, str] = {}
for pair in pairs:
lane_id, sep, url = pair.partition("=")
if not sep or not lane_id or not url:
parser.error(f"--live-endpoint expects LANE_ID=URL, got {pair!r}")
endpoints[lane_id] = url
return endpoints
def _write_report(report: dict, path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8")
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Write the DGR-001 performance contract JSON")
parser.add_argument("--json-out", type=Path, default=DEFAULT_OUTPUT_PATH, help="output JSON path")
parser.add_argument(
"--benchmark-out",
type=Path,
default=None,
help="also run the deterministic stub benchmark and write its JSON report here",
)
parser.add_argument(
"--live-endpoint",
action="append",
default=None,
metavar="LANE_ID=URL",
help="lane-to-endpoint mapping for the live benchmark; repeat once per contract lane",
)
parser.add_argument(
"--live-model",
default=None,
help="model name sent to live endpoints (default: contract safetensors repo)",
)
parser.add_argument(
"--live-benchmark-out",
type=Path,
default=None,
help="run the live endpoint benchmark against --live-endpoint lanes and write its JSON report here",
)
args = parser.parse_args(argv)
if args.live_endpoint and args.live_benchmark_out is None:
parser.error("--live-endpoint requires --live-benchmark-out")
if args.live_benchmark_out is not None and not args.live_endpoint:
parser.error("--live-benchmark-out requires at least one --live-endpoint")
contract = build_default_contract()
path = contract.write_json(args.json_out)
print(path)
if args.benchmark_out is not None:
_write_report(run_performance_benchmark(contract), args.benchmark_out)
print(args.benchmark_out)
if args.live_endpoint:
report = run_real_model_endpoint_benchmark(
_parse_lane_endpoints(args.live_endpoint, parser),
model=args.live_model or contract.model_target.safetensors_repo,
contract=contract,
)
_write_report(report, args.live_benchmark_out)
print(args.live_benchmark_out)
return 0
if __name__ == "__main__": # pragma: no cover - CLI entry point
raise SystemExit(main())

View File

@@ -26,16 +26,6 @@
"params": { "params": {
"use_cache": false "use_cache": false
} }
},
{
"id": "llama-cpp-native",
"version": "1",
"backend_id": "llama.cpp",
"description": "Project-owned native GGUF worker behind the Meshnet control plane.",
"params": {
"worker_transport": "grpc",
"use_cache": true
}
} }
] ]
} }

View File

@@ -44,7 +44,6 @@ class SeamSample:
cache_mode: CacheMode cache_mode: CacheMode
model_ms: float model_ms: float
encode_ms: float encode_ms: float
activation_decode_ms: float
framing_ms: float framing_ms: float
metadata_ms: float metadata_ms: float
copy_allocation_ms: float copy_allocation_ms: float
@@ -53,7 +52,6 @@ class SeamSample:
decompression_ms: float decompression_ms: float
connection_setup_ms: float connection_setup_ms: float
queue_wait_ms: float queue_wait_ms: float
local_http_forwarding_ms: float
transport_ms: float transport_ms: float
seam_latency_ms: float seam_latency_ms: float
payload_bytes: int payload_bytes: int
@@ -122,10 +120,6 @@ def _summary(samples: list[SeamSample]) -> dict[str, float | int]:
"compression_cpu_ms": round( "compression_cpu_ms": round(
sum(sample.compression_ms + sample.decompression_ms for sample in samples), 4 sum(sample.compression_ms + sample.decompression_ms for sample in samples), 4
), ),
"model_execution_ms": round(sum(sample.model_ms for sample in samples), 4),
"activation_encoding_ms": round(sum(sample.encode_ms for sample in samples), 4),
"activation_decoding_ms": round(sum(sample.activation_decode_ms for sample in samples), 4),
"local_http_forwarding_ms": round(sum(sample.local_http_forwarding_ms for sample in samples), 4),
"peak_buffered_bytes": max((sample.copy_allocation_bytes for sample in samples), default=0), "peak_buffered_bytes": max((sample.copy_allocation_bytes for sample in samples), default=0),
} }
@@ -165,7 +159,6 @@ class _StubTransport:
queue_wait_ms = 0.0 if self.mode == "direct" else 0.18 + (0.05 if token_index is not None and token_index % 2 else 0.0) queue_wait_ms = 0.0 if self.mode == "direct" else 0.18 + (0.05 if token_index is not None and token_index % 2 else 0.0)
model_ms = 1.6 if phase == "prefill" else 0.45 model_ms = 1.6 if phase == "prefill" else 0.45
encode_ms = 0.16 if phase == "prefill" else 0.06 encode_ms = 0.16 if phase == "prefill" else 0.06
activation_decode_ms = 0.055 if phase == "prefill" else 0.02
# Keep framing/metadata/copy costs explicit rather than hiding them in # Keep framing/metadata/copy costs explicit rather than hiding them in
# serialization or transport time. The stub owns one binary frame and # serialization or transport time. The stub owns one binary frame and
# one response body per hop; no base64 body is modeled. # one response body per hop; no base64 body is modeled.
@@ -175,26 +168,20 @@ class _StubTransport:
copy_allocation_bytes = wire_bytes + payload_bytes copy_allocation_bytes = wire_bytes + payload_bytes
compression_ms = 0.09 if self.scenario.compression else 0.0 compression_ms = 0.09 if self.scenario.compression else 0.0
decompression_ms = 0.07 if self.scenario.compression else 0.0 decompression_ms = 0.07 if self.scenario.compression else 0.0
# Both routes finish by forwarding the decoded activation to the local
# tail-node HTTP handler; relay adds its own queue before that hop.
local_http_forwarding_ms = 0.11 if self.mode == "direct" else 0.16
transport_ms = (0.32 if self.mode == "direct" else 0.61) + wire_bytes / 100_000 transport_ms = (0.32 if self.mode == "direct" else 0.61) + wire_bytes / 100_000
seam_latency_ms = round( seam_latency_ms = round(
model_ms + encode_ms + activation_decode_ms + framing_ms + metadata_ms + copy_allocation_ms model_ms + encode_ms + framing_ms + metadata_ms + copy_allocation_ms
+ compression_ms + decompression_ms + connection_setup_ms + queue_wait_ms + transport_ms + compression_ms + decompression_ms + connection_setup_ms + queue_wait_ms + transport_ms,
+ local_http_forwarding_ms,
4, 4,
) )
return SeamSample( return SeamSample(
phase=phase, token_index=token_index, session_id=self.session_id, phase=phase, token_index=token_index, session_id=self.session_id,
activation_id=f"benchmark-activation-{self._activation_count}", seam="head->tail", mode=self.mode, activation_id=f"benchmark-activation-{self._activation_count}", seam="head->tail", mode=self.mode,
cache_mode=self.cache_mode, model_ms=model_ms, encode_ms=encode_ms, cache_mode=self.cache_mode, model_ms=model_ms, encode_ms=encode_ms,
activation_decode_ms=activation_decode_ms,
framing_ms=framing_ms, metadata_ms=metadata_ms, framing_ms=framing_ms, metadata_ms=metadata_ms,
copy_allocation_ms=copy_allocation_ms, copy_allocation_bytes=copy_allocation_bytes, copy_allocation_ms=copy_allocation_ms, copy_allocation_bytes=copy_allocation_bytes,
compression_ms=compression_ms, decompression_ms=decompression_ms, compression_ms=compression_ms, decompression_ms=decompression_ms,
connection_setup_ms=connection_setup_ms, queue_wait_ms=queue_wait_ms, connection_setup_ms=connection_setup_ms, queue_wait_ms=queue_wait_ms,
local_http_forwarding_ms=local_http_forwarding_ms,
transport_ms=round(transport_ms, 4), seam_latency_ms=seam_latency_ms, transport_ms=round(transport_ms, 4), seam_latency_ms=seam_latency_ms,
payload_bytes=payload_bytes, wire_bytes=wire_bytes, payload_bytes=payload_bytes, wire_bytes=wire_bytes,
compression_ratio=round(payload_bytes / wire_bytes, 4), connection_attempted=connection_attempted, compression_ratio=round(payload_bytes / wire_bytes, 4), connection_attempted=connection_attempted,
@@ -342,10 +329,9 @@ def run_real_model_lan_benchmark(url: str, *, model: str, timeout: float = 120.0
sample = SeamSample( sample = SeamSample(
phase="decode", token_index=0, session_id=session_id, activation_id="lan-activation-1", phase="decode", token_index=0, session_id=session_id, activation_id="lan-activation-1",
seam="head->tail", mode="direct", cache_mode="cached", model_ms=0.0, encode_ms=0.0, seam="head->tail", mode="direct", cache_mode="cached", model_ms=0.0, encode_ms=0.0,
activation_decode_ms=0.0,
framing_ms=0.0, metadata_ms=0.0, copy_allocation_ms=0.0, copy_allocation_bytes=0, framing_ms=0.0, metadata_ms=0.0, copy_allocation_ms=0.0, copy_allocation_bytes=0,
compression_ms=0.0, decompression_ms=0.0, connection_setup_ms=elapsed_ms, compression_ms=0.0, decompression_ms=0.0, connection_setup_ms=elapsed_ms,
queue_wait_ms=0.0, local_http_forwarding_ms=0.0, transport_ms=elapsed_ms, seam_latency_ms=elapsed_ms, queue_wait_ms=0.0, transport_ms=elapsed_ms, seam_latency_ms=elapsed_ms,
payload_bytes=len(body), wire_bytes=len(body) + len(response_body), compression_ratio=1.0, payload_bytes=len(body), wire_bytes=len(body) + len(response_body), compression_ratio=1.0,
connection_attempted=True, connection_attempted=True,
) )
@@ -368,10 +354,6 @@ def format_summary(report: dict) -> str:
f"{decode['tokens_per_sec']:.1f} tok/s; {decode['bytes_per_token']:.0f} B/tok; " f"{decode['tokens_per_sec']:.1f} tok/s; {decode['bytes_per_token']:.0f} B/tok; "
f"seam {seam['payload_bytes']}/{seam['wire_bytes']} B " f"seam {seam['payload_bytes']}/{seam['wire_bytes']} B "
f"({seam['compression_ratio']:.2f}x); connections {run['connections']['attempts']}; " f"({seam['compression_ratio']:.2f}x); connections {run['connections']['attempts']}; "
f"model/encode/decode {decode['model_execution_ms']:.2f}/"
f"{decode['activation_encoding_ms']:.2f}/{decode['activation_decoding_ms']:.2f} ms; "
f"compression {decode['compression_cpu_ms']:.2f} ms; "
f"HTTP {decode['local_http_forwarding_ms']:.2f} ms; "
f"queue p95 {decode['p95_queue_wait_ms']:.2f} ms" f"queue p95 {decode['p95_queue_wait_ms']:.2f} ms"
) )
return "\n".join(lines) return "\n".join(lines)

View File

@@ -1,375 +0,0 @@
"""Exact artifact and runtime-recipe identity helpers.
The runtime recipe is the compatibility contract for one routable shard. It is
kept separate from the user-facing recipe catalogue so the tracker can compare
the exact execution footprint that was validated, not just a named recipe.
"""
from __future__ import annotations
import hashlib
import json
from dataclasses import dataclass
from typing import Any, Mapping
def _require_text(value: Any, field_name: str) -> str:
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{field_name!r} must be a non-empty string")
return value
def _optional_text(value: Any, field_name: str) -> str | None:
if value is None:
return None
return _require_text(value, field_name)
def _sha256_text(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def _stable_json(data: Any) -> str:
return json.dumps(
data,
sort_keys=True,
separators=(",", ":"),
ensure_ascii=False,
default=str,
)
def _normalise_dtype(value: Any, default: str) -> str:
if value is None:
return default
if isinstance(value, str):
text = value.strip()
if not text:
return default
return text.removeprefix("torch.")
return str(value).removeprefix("torch.")
def _architecture_adapter_from_config(model_config: Any, default: str) -> str:
if not isinstance(model_config, Mapping):
return default
for key in ("architecture_adapter", "model_type"):
value = model_config.get(key)
if isinstance(value, str) and value.strip():
return value
architectures = model_config.get("architectures")
if isinstance(architectures, list) and architectures:
first = architectures[0]
if isinstance(first, str) and first.strip():
return first
text_config = model_config.get("text_config")
if isinstance(text_config, Mapping):
return _architecture_adapter_from_config(text_config, default)
return default
def _tokenizer_revision_from_config(
model_id: str,
revision: str | None,
model_config: Any,
) -> str:
if isinstance(model_config, Mapping):
for key in ("tokenizer_revision", "tokenizer_version", "_commit_hash"):
value = model_config.get(key)
if isinstance(value, str) and value.strip():
return value
if revision:
return revision
return model_id
def _cache_layout_from_recipe_params(recipe_params: Mapping[str, Any] | None) -> str:
if not recipe_params:
return "local-hot-kv"
use_cache = recipe_params.get("use_cache")
if use_cache is False:
return "stateless"
if "cache_layout" in recipe_params:
value = recipe_params.get("cache_layout")
if isinstance(value, str) and value.strip():
return value
return "local-hot-kv"
@dataclass(frozen=True)
class ArtifactIdentity:
"""Exact source artifact binding for a routable shard."""
model_id: str
revision: str | None = None
artifact_hash: str | None = None
shard_start: int | None = None
shard_end: int | None = None
def __post_init__(self) -> None:
_require_text(self.model_id, "artifact.model_id")
_optional_text(self.revision, "artifact.revision")
_optional_text(self.artifact_hash, "artifact.artifact_hash")
if self.shard_start is not None and self.shard_start < 0:
raise ValueError("'artifact.shard_start' must be >= 0")
if self.shard_end is not None and self.shard_end < 0:
raise ValueError("'artifact.shard_end' must be >= 0")
if (
self.shard_start is not None
and self.shard_end is not None
and self.shard_end < self.shard_start
):
raise ValueError("'artifact.shard_end' must be >= 'artifact.shard_start'")
def to_dict(self) -> dict[str, Any]:
return {
"model_id": self.model_id,
"revision": self.revision,
"artifact_hash": self.artifact_hash,
"shard_start": self.shard_start,
"shard_end": self.shard_end,
}
@classmethod
def from_dict(cls, data: Any) -> "ArtifactIdentity":
if not isinstance(data, Mapping):
raise ValueError(f"'artifact' must be a JSON object, got {type(data).__name__}")
return cls(
model_id=_require_text(data.get("model_id"), "artifact.model_id"),
revision=_optional_text(data.get("revision"), "artifact.revision"),
artifact_hash=_optional_text(
data.get("artifact_hash"), "artifact.artifact_hash"
),
shard_start=_optional_int(data.get("shard_start"), "artifact.shard_start"),
shard_end=_optional_int(data.get("shard_end"), "artifact.shard_end"),
)
@dataclass(frozen=True)
class RuntimeRecipeIdentity:
"""Exact runtime recipe used for admission and handshake compatibility."""
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 = 1
cache_layout: str = "local-hot-kv"
fingerprint: str | None = None
def __post_init__(self) -> None:
_require_text(self.weight_quantization, "runtime_recipe.weight_quantization")
_require_text(self.activation_dtype, "runtime_recipe.activation_dtype")
_require_text(self.compute_dtype, "runtime_recipe.compute_dtype")
_require_text(self.kv_dtype, "runtime_recipe.kv_dtype")
_require_text(self.kv_layout, "runtime_recipe.kv_layout")
_require_text(self.tokenizer_revision, "runtime_recipe.tokenizer_revision")
_require_text(self.architecture_adapter, "runtime_recipe.architecture_adapter")
_require_text(self.backend_id, "runtime_recipe.backend_id")
_require_text(self.runtime_version, "runtime_recipe.runtime_version")
_require_text(self.cache_layout, "runtime_recipe.cache_layout")
if self.boundary_schema_version < 1:
raise ValueError("'runtime_recipe.boundary_schema_version' must be >= 1")
expected = compatibility_fingerprint(self._fingerprint_payload())
if not self.fingerprint:
object.__setattr__(self, "fingerprint", expected)
elif self.fingerprint != expected:
raise ValueError(
"'runtime_recipe.fingerprint' does not match the encoded fields"
)
def to_dict(self) -> dict[str, Any]:
return {
"weight_quantization": self.weight_quantization,
"activation_dtype": self.activation_dtype,
"compute_dtype": self.compute_dtype,
"kv_dtype": self.kv_dtype,
"kv_layout": self.kv_layout,
"tokenizer_revision": self.tokenizer_revision,
"architecture_adapter": self.architecture_adapter,
"backend_id": self.backend_id,
"runtime_version": self.runtime_version,
"boundary_schema_version": self.boundary_schema_version,
"cache_layout": self.cache_layout,
"fingerprint": self.fingerprint,
}
@classmethod
def from_dict(cls, data: Any) -> "RuntimeRecipeIdentity":
if not isinstance(data, Mapping):
raise ValueError(
f"'runtime_recipe' must be a JSON object, got {type(data).__name__}"
)
boundary_schema_version = data.get("boundary_schema_version", 1)
if isinstance(boundary_schema_version, bool) or not isinstance(
boundary_schema_version, int
):
raise ValueError(
"'runtime_recipe.boundary_schema_version' must be an integer"
)
return cls(
weight_quantization=_require_text(
data.get("weight_quantization"), "runtime_recipe.weight_quantization"
),
activation_dtype=_require_text(
data.get("activation_dtype"), "runtime_recipe.activation_dtype"
),
compute_dtype=_require_text(
data.get("compute_dtype"), "runtime_recipe.compute_dtype"
),
kv_dtype=_require_text(data.get("kv_dtype"), "runtime_recipe.kv_dtype"),
kv_layout=_require_text(data.get("kv_layout"), "runtime_recipe.kv_layout"),
tokenizer_revision=_require_text(
data.get("tokenizer_revision"), "runtime_recipe.tokenizer_revision"
),
architecture_adapter=_require_text(
data.get("architecture_adapter"),
"runtime_recipe.architecture_adapter",
),
backend_id=_require_text(data.get("backend_id"), "runtime_recipe.backend_id"),
runtime_version=_require_text(
data.get("runtime_version"), "runtime_recipe.runtime_version"
),
boundary_schema_version=boundary_schema_version,
cache_layout=_require_text(data.get("cache_layout"), "runtime_recipe.cache_layout"),
fingerprint=_optional_text(data.get("fingerprint"), "runtime_recipe.fingerprint"),
)
def _fingerprint_payload(self) -> dict[str, Any]:
return {
"weight_quantization": self.weight_quantization,
"activation_dtype": self.activation_dtype,
"compute_dtype": self.compute_dtype,
"kv_dtype": self.kv_dtype,
"kv_layout": self.kv_layout,
"tokenizer_revision": self.tokenizer_revision,
"architecture_adapter": self.architecture_adapter,
"backend_id": self.backend_id,
"runtime_version": self.runtime_version,
"boundary_schema_version": self.boundary_schema_version,
"cache_layout": self.cache_layout,
}
def _optional_int(value: Any, field_name: str) -> int | None:
if value is None:
return None
if isinstance(value, bool) or not isinstance(value, int):
raise ValueError(f"{field_name!r} must be an integer")
if value < 0:
raise ValueError(f"{field_name!r} must be >= 0")
return value
def build_artifact_identity(
*,
model_id: str,
revision: str | None = None,
model_config: Any = None,
artifact_hash: str | None = None,
shard_start: int | None = None,
shard_end: int | None = None,
) -> ArtifactIdentity:
"""Build a stable artifact binding from the locally loaded artifact."""
resolved_hash = artifact_hash
if resolved_hash is None:
if isinstance(model_config, Mapping):
resolved_hash = _hash_mapping(model_config)
elif model_config is not None:
resolved_hash = _sha256_text(_stable_json(model_config))
if resolved_hash is None:
resolved_hash = _sha256_text(
_stable_json(
{
"model_id": model_id,
"revision": revision,
"shard_start": shard_start,
"shard_end": shard_end,
}
)
)
return ArtifactIdentity(
model_id=model_id,
revision=revision,
artifact_hash=resolved_hash,
shard_start=shard_start,
shard_end=shard_end,
)
def build_runtime_recipe_identity(
*,
model_id: str,
weight_quantization: str,
backend_id: str,
runtime_version: str,
revision: str | None = None,
model_config: Any = None,
recipe_params: Mapping[str, Any] | None = None,
activation_dtype: Any = None,
compute_dtype: Any = None,
kv_dtype: Any = None,
kv_layout: str | None = None,
tokenizer_revision: str | None = None,
architecture_adapter: str | None = None,
boundary_schema_version: int = 1,
cache_layout: str | None = None,
) -> RuntimeRecipeIdentity:
"""Build the exact runtime recipe used for compatibility admission."""
activation = _normalise_dtype(activation_dtype, "bfloat16")
compute = _normalise_dtype(compute_dtype, activation)
kv_dtype_text = _normalise_dtype(kv_dtype, compute)
kv_layout_text = kv_layout or "session-cache"
tokenizer = tokenizer_revision or _tokenizer_revision_from_config(
model_id, revision, model_config
)
architecture = architecture_adapter or _architecture_adapter_from_config(
model_config, backend_id
)
cache_layout_text = cache_layout or _cache_layout_from_recipe_params(recipe_params)
return RuntimeRecipeIdentity(
weight_quantization=weight_quantization,
activation_dtype=activation,
compute_dtype=compute,
kv_dtype=kv_dtype_text,
kv_layout=kv_layout_text,
tokenizer_revision=tokenizer,
architecture_adapter=architecture,
backend_id=backend_id,
runtime_version=runtime_version,
boundary_schema_version=boundary_schema_version,
cache_layout=cache_layout_text,
)
def compatibility_fingerprint(data: Mapping[str, Any]) -> str:
"""Return a stable SHA256 compatibility fingerprint for an exact route."""
return "sha256:" + _sha256_text(_stable_json(data))
def fingerprint_payload(
*,
model: Mapping[str, Any],
shard: Mapping[str, Any],
recipe: Mapping[str, Any],
backend: Mapping[str, Any],
artifact: Mapping[str, Any],
runtime_recipe: Mapping[str, Any],
) -> dict[str, Any]:
return {
"model": dict(model),
"shard": dict(shard),
"recipe": dict(recipe),
"backend": dict(backend),
"artifact": dict(artifact),
"runtime_recipe": dict(runtime_recipe),
}
def _hash_mapping(data: Mapping[str, Any]) -> str:
return "sha256:" + _sha256_text(_stable_json(data))

View File

@@ -12,7 +12,7 @@ import urllib.error
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from pathlib import Path from pathlib import Path
from typing import Any, Callable from typing import Any
from .admission import ( from .admission import (
AdmissionRequirement, AdmissionRequirement,
@@ -29,7 +29,6 @@ from .model_catalog import model_metadata_for
from .recipe_manifest import DEFAULT_RECIPE_ID, Recipe, RecipeManifest, load_recipe_manifest from .recipe_manifest import DEFAULT_RECIPE_ID, Recipe, RecipeManifest, load_recipe_manifest
from .relay_bridge import RelayHttpBridge, peer_id_from_wallet from .relay_bridge import RelayHttpBridge, peer_id_from_wallet
from .server import StubNodeServer from .server import StubNodeServer
from .gguf_backend import build_gguf_backend
from .torch_server import TorchNodeServer from .torch_server import TorchNodeServer
from .wallet import load_or_create_wallet from .wallet import load_or_create_wallet
@@ -420,7 +419,6 @@ def _start_heartbeat(
interval: float = _HEARTBEAT_INTERVAL_IDLE, interval: float = _HEARTBEAT_INTERVAL_IDLE,
node_ref: Any | None = None, node_ref: Any | None = None,
start_time: float | None = None, start_time: float | None = None,
refresh_capability: Callable[[dict], dict | None] | None = None,
) -> threading.Thread: ) -> threading.Thread:
"""Daemon thread: sends heartbeats and re-registers automatically after tracker restarts. """Daemon thread: sends heartbeats and re-registers automatically after tracker restarts.
@@ -432,7 +430,6 @@ def _start_heartbeat(
which is logged for now (hot-reload implemented in US-026). which is logged for now (hot-reload implemented in US-026).
""" """
_start_time = start_time or time.monotonic() _start_time = start_time or time.monotonic()
completed_directives: list[dict] = []
def _current_requests_snapshot() -> list[dict]: def _current_requests_snapshot() -> list[dict]:
if node_ref is None: if node_ref is None:
@@ -457,8 +454,6 @@ def _start_heartbeat(
current_requests = _current_requests_snapshot() current_requests = _current_requests_snapshot()
if current_requests: if current_requests:
stats["current_requests"] = current_requests stats["current_requests"] = current_requests
if completed_directives:
stats["completed_directives"] = list(completed_directives)
return stats return stats
def _sleep_interval() -> float: def _sleep_interval() -> float:
@@ -466,26 +461,9 @@ def _start_heartbeat(
return _HEARTBEAT_INTERVAL_BUSY return _HEARTBEAT_INTERVAL_BUSY
return interval return interval
def _refresh_proof(payload: dict) -> None:
"""Re-prove the current shard so a re-registration never presents an aged proof.
The tracker refuses proofs older than its freshness budget: re-sending the
startup-time report after an outage would re-register the node unroutable.
"""
if refresh_capability is None or "capability_report" not in payload:
return
try:
fresh = refresh_capability(payload)
except Exception as exc:
print(f" [node] WARNING: capability re-validation failed: {exc}", flush=True)
return
if fresh:
payload["capability_report"] = fresh
def _reregister() -> bool: def _reregister() -> bool:
nonlocal node_id nonlocal node_id
try: try:
_refresh_proof(register_payload)
resp = _post_json(f"{tracker_url}/v1/nodes/register", register_payload) resp = _post_json(f"{tracker_url}/v1/nodes/register", register_payload)
node_id = resp.get("node_id", node_id) node_id = resp.get("node_id", node_id)
if node_ref is not None: if node_ref is not None:
@@ -507,7 +485,6 @@ def _start_heartbeat(
"managed_assignment": True, "managed_assignment": True,
} }
try: try:
_refresh_proof(extra_payload)
reg_resp = _post_json(f"{tracker_url}/v1/nodes/register", extra_payload) reg_resp = _post_json(f"{tracker_url}/v1/nodes/register", extra_payload)
print( print(
f" [node] registered additional model — node ID: {reg_resp.get('node_id')}", f" [node] registered additional model — node ID: {reg_resp.get('node_id')}",
@@ -516,26 +493,21 @@ def _start_heartbeat(
except Exception as exc: except Exception as exc:
print(f" [node] WARNING: additional model registration failed: {exc}", flush=True) print(f" [node] WARNING: additional model registration failed: {exc}", flush=True)
def _apply_directives(directives: list[dict]) -> dict | None: def _apply_directives(directives: list[dict]) -> None:
if not directives: if not directives:
return None return
if node_ref is None or not hasattr(node_ref, "apply_tracker_directives"): if node_ref is None or not hasattr(node_ref, "apply_tracker_directives"):
print(f" [node] tracker directives received: {directives}", flush=True) print(f" [node] tracker directives received: {directives}", flush=True)
return None return
try: try:
applied = node_ref.apply_tracker_directives(directives) applied = node_ref.apply_tracker_directives(directives)
except Exception as exc: except Exception as exc:
print(f" [node] WARNING: failed to apply tracker directives: {exc}", flush=True) print(f" [node] WARNING: failed to apply tracker directives: {exc}", flush=True)
return None return
if applied: if applied:
completed_directives.append(dict(applied))
if applied.get("action") == "ADD_SHARD": if applied.get("action") == "ADD_SHARD":
_register_additional_assignment(applied) _register_additional_assignment(applied)
return applied return
if applied.get("action") in {"DROP_SHARD", "DROP_ALL_SHARDS"}:
# A release has no replacement range. It is not a failed
# heartbeat and must not re-register the released assignment.
return applied
model_id = applied.get("model", register_payload.get("hf_repo") or register_payload.get("model")) model_id = applied.get("model", register_payload.get("hf_repo") or register_payload.get("model"))
register_payload["model"] = str(model_id).split("/")[-1] register_payload["model"] = str(model_id).split("/")[-1]
register_payload["hf_repo"] = model_id register_payload["hf_repo"] = model_id
@@ -543,7 +515,6 @@ def _start_heartbeat(
register_payload["shard_end"] = applied["shard_end"] register_payload["shard_end"] = applied["shard_end"]
register_payload["quantization"] = applied.get("quantization", register_payload.get("quantization")) register_payload["quantization"] = applied.get("quantization", register_payload.get("quantization"))
register_payload["tracker_mode"] = bool(applied.get("tracker_mode", False)) register_payload["tracker_mode"] = bool(applied.get("tracker_mode", False))
return applied
def _loop() -> None: def _loop() -> None:
nonlocal node_id nonlocal node_id
@@ -571,10 +542,7 @@ def _start_heartbeat(
continue continue
try: try:
heartbeat = _get_stats() resp = _post_json(hb_url, _get_stats())
resp = _post_json(hb_url, heartbeat)
if heartbeat.get("completed_directives"):
completed_directives.clear()
_apply_directives(resp.get("directives", [])) _apply_directives(resp.get("directives", []))
new_asgn = resp.get("new_assignment") new_asgn = resp.get("new_assignment")
if new_asgn: if new_asgn:
@@ -611,7 +579,6 @@ def _register_with_tracker(
reg_payload: dict, reg_payload: dict,
node: Any, node: Any,
start_time: float, start_time: float,
refresh_capability: Callable[[dict], dict | None] | None = None,
) -> str | None: ) -> str | None:
"""Register with the tracker, or start background retries when it is unreachable.""" """Register with the tracker, or start background retries when it is unreachable."""
try: try:
@@ -619,14 +586,7 @@ def _register_with_tracker(
tracker_node_id = str(reg_resp.get("node_id") or "?") tracker_node_id = str(reg_resp.get("node_id") or "?")
setattr(node, "tracker_node_id", tracker_node_id) setattr(node, "tracker_node_id", tracker_node_id)
print(f" Registered with tracker — node ID: {tracker_node_id}", flush=True) print(f" Registered with tracker — node ID: {tracker_node_id}", flush=True)
_start_heartbeat( _start_heartbeat(tracker_url, tracker_node_id, reg_payload, node_ref=node, start_time=start_time)
tracker_url,
tracker_node_id,
reg_payload,
node_ref=node,
start_time=start_time,
refresh_capability=refresh_capability,
)
return tracker_node_id return tracker_node_id
except Exception as exc: except Exception as exc:
setattr(node, "tracker_node_id", None) setattr(node, "tracker_node_id", None)
@@ -638,7 +598,6 @@ def _register_with_tracker(
reg_payload, reg_payload,
node_ref=node, node_ref=node,
start_time=start_time, start_time=start_time,
refresh_capability=refresh_capability,
) )
return None return None
@@ -703,35 +662,6 @@ def _resolve_recipe(recipe_id: str | None) -> tuple[RecipeManifest, Recipe]:
return manifest, manifest.require(recipe_id or DEFAULT_RECIPE_ID) return manifest, manifest.require(recipe_id or DEFAULT_RECIPE_ID)
def _gguf_backend_for_recipe(
recipe: Recipe,
*,
model_id: str,
shard_start: int,
shard_end: int,
quantization: str,
total_layers: int | None,
device: str,
model_revision: str | None = None,
) -> object | None:
"""Build the GGUF backend only for recipes that explicitly ask for it."""
if recipe.backend_id != "llama.cpp":
return None
return build_gguf_backend(
model_id=model_id,
shard_start=shard_start,
shard_end=shard_end,
quantization=quantization,
total_layers=total_layers,
model_revision=model_revision,
device_type=device,
architecture_adapter="dense-llama",
tokenizer_revision=model_revision or model_id,
runtime_recipe_fingerprint=None,
supports_kv_cache=recipe.params.get("use_cache", True) is not False,
)
def _capability_device(backend: Any, detected_device: str) -> str: def _capability_device(backend: Any, detected_device: str) -> str:
"""The device the shard actually landed on, or the one this node detected.""" """The device the shard actually landed on, or the one this node detected."""
device = getattr(backend, "device", None) device = getattr(backend, "device", None)
@@ -788,54 +718,6 @@ def _admit_capability(
return report return report
def _capability_refresher(
node: Any,
*,
manifest: RecipeManifest,
recipe: Recipe,
detected_device: str,
cache_dir: Path | None,
force_cpu: bool,
validator: CapabilityValidator | None = None,
) -> Callable[[dict], dict | None]:
"""A fresh proof for what the node serves *now*, run at re-registration time.
The startup proof ages past the tracker's freshness budget, and directives
can move the node to a shard the startup proof never covered — so every
re-registration re-proves against the currently loaded backend rather than
replaying the report captured at boot.
"""
def refresh(payload: dict) -> dict | None:
target_model = payload.get("hf_repo") or payload.get("model")
backend = None
accessor = getattr(node, "backend_for", None)
if callable(accessor) and target_model:
backend = accessor(str(target_model))
if backend is None:
backend = getattr(node, "backend", None)
if backend is None:
return None
context = CapabilityContext(
backend=backend,
selection=DoctorSelection(
model_id=str(getattr(backend, "model_id", target_model)),
shard_start=int(getattr(backend, "shard_start", 0) or 0),
shard_end=int(getattr(backend, "shard_end", 0) or 0),
quantization=str(getattr(backend, "quantization", None) or "auto"),
cache_dir=cache_dir,
force_cpu=force_cpu,
),
recipe=recipe,
manifest=manifest,
device=_capability_device(backend, detected_device),
)
report = (validator or probe_capability)(context)
setattr(node, "capability_report", report)
return report.to_dict()
return refresh
def run_startup( def run_startup(
tracker_url: str, tracker_url: str,
port: int = 0, port: int = 0,
@@ -993,8 +875,7 @@ def run_startup(
if model_id: # treat "" the same as None — no explicit model given if model_id: # treat "" the same as None — no explicit model given
full_sources: list[dict] = [] full_sources: list[dict] = []
detected: int | None = None # Auto-detect shard range from model config if not explicitly provided
# Auto-detect shard range from model config if not explicitly provided.
if shard_start is None or shard_end is None: if shard_start is None or shard_end is None:
try: try:
detected = _detect_num_layers(model_id, cache_dir=cache_dir) detected = _detect_num_layers(model_id, cache_dir=cache_dir)
@@ -1058,38 +939,22 @@ def run_startup(
shard_end = shard_end if shard_end is not None else detected - 1 shard_end = shard_end if shard_end is not None else detected - 1
print(f" Auto-detected {detected} layers → shard {shard_start}{shard_end}", flush=True) print(f" Auto-detected {detected} layers → shard {shard_start}{shard_end}", flush=True)
backend = _gguf_backend_for_recipe( print("Loading real PyTorch model shard...", flush=True)
recipe, node = TorchNodeServer(
host=host,
port=port,
model_id=model_id, model_id=model_id,
shard_start=shard_start, shard_start=shard_start,
shard_end=shard_end, shard_end=shard_end,
quantization=quantization, quantization=quantization,
total_layers=detected if detected is not None else (shard_end + 1 if shard_end is not None else None), tracker_url=tracker_url,
device=device, route_timeout=route_timeout,
model_revision=None, cache_dir=cache_dir,
debug=debug,
max_loaded_shards=max_loaded_shards,
force_cpu=force_cpu,
recipe_params=recipe.params,
) )
print(
"Loading native llama.cpp model shard..." if backend is not None else "Loading real PyTorch model shard...",
flush=True,
)
node_kwargs = {
"host": host,
"port": port,
"model_id": model_id,
"shard_start": shard_start,
"shard_end": shard_end,
"quantization": quantization,
"tracker_url": tracker_url,
"route_timeout": route_timeout,
"cache_dir": cache_dir,
"debug": debug,
"max_loaded_shards": max_loaded_shards,
"force_cpu": force_cpu,
"recipe_params": recipe.params,
}
if backend is not None:
node_kwargs["backend"] = backend
node = TorchNodeServer(**node_kwargs)
capability_report = _admit_capability( capability_report = _admit_capability(
node, node,
model_id=model_id, model_id=model_id,
@@ -1103,15 +968,10 @@ def run_startup(
recipe=recipe, recipe=recipe,
validator=capability_validator, validator=capability_validator,
) )
proof_shard = capability_report.shard
_node_start_time = time.monotonic() _node_start_time = time.monotonic()
actual_port = node.start() actual_port = node.start()
total_layers = getattr(getattr(node, "backend", None), "total_layers", None) total_layers = getattr(getattr(node, "backend", None), "total_layers", None)
shard_label = _format_shard_label( shard_label = _format_shard_label(shard_start, shard_end, total_layers)
proof_shard.start,
proof_shard.end,
total_layers,
)
public_host = advertise_host or (socket.getfqdn() if host == "0.0.0.0" else host) public_host = advertise_host or (socket.getfqdn() if host == "0.0.0.0" else host)
endpoint = f"http://{public_host}:{actual_port}" endpoint = f"http://{public_host}:{actual_port}"
if hasattr(node, "set_advertised_endpoint"): if hasattr(node, "set_advertised_endpoint"):
@@ -1134,17 +994,16 @@ def run_startup(
"model": model_id.split("/")[-1], "model": model_id.split("/")[-1],
"hf_repo": model_id, "hf_repo": model_id,
"num_layers": total_layers, "num_layers": total_layers,
"shard_start": proof_shard.start, "shard_start": shard_start,
"shard_end": proof_shard.end, "shard_end": shard_end,
"hardware_profile": hw, "hardware_profile": hw,
"wallet_address": address, "wallet_address": address,
"quantization": quantization, "quantization": quantization,
"score": 1.0, "score": 1.0,
"tracker_mode": (proof_shard.start == 0), "tracker_mode": (shard_start == 0),
"managed_assignment": not user_pinned_shard, "managed_assignment": not user_pinned_shard,
"model_metadata": model_metadata_for(model_id, total_layers, cache_dir=cache_dir), "model_metadata": model_metadata_for(model_id, total_layers, cache_dir=cache_dir),
"capability_report": capability_report.to_dict(), "capability_report": capability_report.to_dict(),
"compatibility_fingerprint": capability_report.compatibility_fingerprint,
# Declared independently of the proof: the tracker checks that the # Declared independently of the proof: the tracker checks that the
# recipe this node says it serves with is the one the proof ran. # recipe this node says it serves with is the one the proof ran.
"recipe_id": recipe.id, "recipe_id": recipe.id,
@@ -1152,8 +1011,8 @@ def run_startup(
"downloaded_models": ( "downloaded_models": (
_downloaded_model_inventory( _downloaded_model_inventory(
model_id.split("/")[-1], model_id.split("/")[-1],
proof_shard.start, shard_start,
proof_shard.end, shard_end,
model_cache_path, model_cache_path,
hf_repo=model_id, hf_repo=model_id,
model_sources=full_sources, model_sources=full_sources,
@@ -1167,15 +1026,6 @@ def run_startup(
} }
tracker_node_id = _register_with_tracker( tracker_node_id = _register_with_tracker(
tracker_url, reg_payload, node, _node_start_time, tracker_url, reg_payload, node, _node_start_time,
refresh_capability=_capability_refresher(
node,
manifest=manifest,
recipe=recipe,
detected_device=device,
cache_dir=cache_dir,
force_cpu=force_cpu,
validator=capability_validator,
),
) )
print( print(
@@ -1264,38 +1114,22 @@ def run_startup(
hf_repo=assigned_hf_repo, hf_repo=assigned_hf_repo,
model_sources=full_sources, model_sources=full_sources,
) )
backend = _gguf_backend_for_recipe( print("Loading real PyTorch model shard...", flush=True)
recipe, node = TorchNodeServer(
host=host,
port=port,
model_id=assigned_hf_repo, model_id=assigned_hf_repo,
shard_start=assigned_shard_start, shard_start=assigned_shard_start,
shard_end=assigned_shard_end, shard_end=assigned_shard_end,
quantization=quantization, quantization=quantization,
total_layers=assigned_num_layers, tracker_url=tracker_url,
device=device, route_timeout=route_timeout,
model_revision=None, cache_dir=cache_dir,
debug=debug,
max_loaded_shards=max_loaded_shards,
force_cpu=force_cpu,
recipe_params=recipe.params,
) )
print(
"Loading native llama.cpp model shard..." if backend is not None else "Loading real PyTorch model shard...",
flush=True,
)
node_kwargs = {
"host": host,
"port": port,
"model_id": assigned_hf_repo,
"shard_start": assigned_shard_start,
"shard_end": assigned_shard_end,
"quantization": quantization,
"tracker_url": tracker_url,
"route_timeout": route_timeout,
"cache_dir": cache_dir,
"debug": debug,
"max_loaded_shards": max_loaded_shards,
"force_cpu": force_cpu,
"recipe_params": recipe.params,
}
if backend is not None:
node_kwargs["backend"] = backend
node = TorchNodeServer(**node_kwargs)
capability_report = _admit_capability( capability_report = _admit_capability(
node, node,
model_id=assigned_hf_repo, model_id=assigned_hf_repo,
@@ -1309,7 +1143,6 @@ def run_startup(
recipe=recipe, recipe=recipe,
validator=capability_validator, validator=capability_validator,
) )
proof_shard = capability_report.shard
_node_start_time = time.monotonic() _node_start_time = time.monotonic()
actual_port = node.start() actual_port = node.start()
public_host = advertise_host or (socket.getfqdn() if host == "0.0.0.0" else host) public_host = advertise_host or (socket.getfqdn() if host == "0.0.0.0" else host)
@@ -1332,17 +1165,16 @@ def run_startup(
"model": assigned_hf_repo.split("/")[-1], "model": assigned_hf_repo.split("/")[-1],
"hf_repo": assigned_hf_repo, "hf_repo": assigned_hf_repo,
"num_layers": assigned_num_layers, "num_layers": assigned_num_layers,
"shard_start": proof_shard.start, "shard_start": assigned_shard_start,
"shard_end": proof_shard.end, "shard_end": assigned_shard_end,
"hardware_profile": hw, "hardware_profile": hw,
"wallet_address": address, "wallet_address": address,
"quantization": quantization, "quantization": quantization,
"score": 1.0, "score": 1.0,
"tracker_mode": (proof_shard.start == 0), "tracker_mode": (assigned_shard_start == 0),
"managed_assignment": True, "managed_assignment": True,
"model_metadata": model_metadata_for(assigned_hf_repo, assigned_num_layers, cache_dir=cache_dir), "model_metadata": model_metadata_for(assigned_hf_repo, assigned_num_layers, cache_dir=cache_dir),
"capability_report": capability_report.to_dict(), "capability_report": capability_report.to_dict(),
"compatibility_fingerprint": capability_report.compatibility_fingerprint,
# Declared independently of the proof: the tracker checks that the # Declared independently of the proof: the tracker checks that the
# recipe this node says it serves with is the one the proof ran. # recipe this node says it serves with is the one the proof ran.
"recipe_id": recipe.id, "recipe_id": recipe.id,
@@ -1350,8 +1182,8 @@ def run_startup(
"downloaded_models": ( "downloaded_models": (
_downloaded_model_inventory( _downloaded_model_inventory(
assigned_hf_repo.split("/")[-1], assigned_hf_repo.split("/")[-1],
proof_shard.start, assigned_shard_start,
proof_shard.end, assigned_shard_end,
model_cache_path, model_cache_path,
hf_repo=assigned_hf_repo, hf_repo=assigned_hf_repo,
model_sources=full_sources, model_sources=full_sources,
@@ -1365,19 +1197,10 @@ def run_startup(
} }
tracker_node_id = _register_with_tracker( tracker_node_id = _register_with_tracker(
tracker_url, auto_reg_payload, node, _node_start_time, tracker_url, auto_reg_payload, node, _node_start_time,
refresh_capability=_capability_refresher(
node,
manifest=manifest,
recipe=recipe,
detected_device=device,
cache_dir=cache_dir,
force_cpu=force_cpu,
validator=capability_validator,
),
) )
shard_label = _format_shard_label( shard_label = _format_shard_label(
proof_shard.start, assigned_shard_start,
proof_shard.end, assigned_shard_end,
assigned_num_layers, assigned_num_layers,
) )
print( print(
@@ -1492,38 +1315,22 @@ def run_startup(
# 5. Start HTTP server — real HF weights use TorchNodeServer; stub-model stays stub. # 5. Start HTTP server — real HF weights use TorchNodeServer; stub-model stays stub.
_node_start_time = time.monotonic() _node_start_time = time.monotonic()
if hf_repo and assigned_model != "stub-model": if hf_repo and assigned_model != "stub-model":
backend = _gguf_backend_for_recipe( print("Loading real PyTorch model shard...", flush=True)
recipe, node = TorchNodeServer(
host=host,
port=port,
model_id=hf_repo, model_id=hf_repo,
shard_start=shard_start, shard_start=shard_start,
shard_end=shard_end, shard_end=shard_end,
quantization=quantization, quantization=quantization,
total_layers=total_layers, tracker_url=tracker_url,
device=device, route_timeout=route_timeout,
model_revision=None, cache_dir=shard_path,
debug=debug,
max_loaded_shards=max_loaded_shards,
force_cpu=force_cpu,
recipe_params=recipe.params,
) )
print(
"Loading native llama.cpp model shard..." if backend is not None else "Loading real PyTorch model shard...",
flush=True,
)
node_kwargs = {
"host": host,
"port": port,
"model_id": hf_repo,
"shard_start": shard_start,
"shard_end": shard_end,
"quantization": quantization,
"tracker_url": tracker_url,
"route_timeout": route_timeout,
"cache_dir": shard_path,
"debug": debug,
"max_loaded_shards": max_loaded_shards,
"force_cpu": force_cpu,
"recipe_params": recipe.params,
}
if backend is not None:
node_kwargs["backend"] = backend
node = TorchNodeServer(**node_kwargs)
capability_report = _admit_capability( capability_report = _admit_capability(
node, node,
model_id=hf_repo, model_id=hf_repo,
@@ -1572,7 +1379,6 @@ def run_startup(
"managed_assignment": not user_pinned_shard, "managed_assignment": not user_pinned_shard,
"model_metadata": model_metadata_for(hf_repo, total_layers, cache_dir=shard_path), "model_metadata": model_metadata_for(hf_repo, total_layers, cache_dir=shard_path),
"capability_report": capability_report.to_dict(), "capability_report": capability_report.to_dict(),
"compatibility_fingerprint": capability_report.compatibility_fingerprint,
# Declared independently of the proof: the tracker checks that the # Declared independently of the proof: the tracker checks that the
# recipe this node says it serves with is the one the proof ran. # recipe this node says it serves with is the one the proof ran.
"recipe_id": recipe.id, "recipe_id": recipe.id,
@@ -1583,15 +1389,6 @@ def run_startup(
} }
tracker_node_id = _register_with_tracker( tracker_node_id = _register_with_tracker(
tracker_url, reg_payload, node, _node_start_time, tracker_url, reg_payload, node, _node_start_time,
refresh_capability=_capability_refresher(
node,
manifest=manifest,
recipe=recipe,
detected_device=device,
cache_dir=cache_dir,
force_cpu=force_cpu,
validator=capability_validator,
),
) )
print( print(
f"\n{'=' * 32}\n" f"\n{'=' * 32}\n"
@@ -1634,7 +1431,6 @@ def run_startup(
recipe=recipe, recipe=recipe,
validator=capability_validator, validator=capability_validator,
) )
proof_shard = capability_report.shard
actual_port = node.start() actual_port = node.start()
public_host = advertise_host or (socket.getfqdn() if host == "0.0.0.0" else host) public_host = advertise_host or (socket.getfqdn() if host == "0.0.0.0" else host)
endpoint = f"http://{public_host}:{actual_port}" endpoint = f"http://{public_host}:{actual_port}"
@@ -1654,11 +1450,10 @@ def run_startup(
reg_payload = { reg_payload = {
"endpoint": endpoint, "endpoint": endpoint,
"model": assigned_model, "model": assigned_model,
"shard_start": proof_shard.start, "shard_start": shard_start,
"shard_end": proof_shard.end, "shard_end": shard_end,
"shard_checksum": shard_checksum, "shard_checksum": shard_checksum,
"capability_report": capability_report.to_dict(), "capability_report": capability_report.to_dict(),
"compatibility_fingerprint": capability_report.compatibility_fingerprint,
# Declared independently of the proof: the tracker checks that the # Declared independently of the proof: the tracker checks that the
# recipe this node says it serves with is the one the proof ran. # recipe this node says it serves with is the one the proof ran.
"recipe_id": recipe.id, "recipe_id": recipe.id,
@@ -1679,22 +1474,7 @@ def run_startup(
) )
node_id = str(reg_resp["node_id"]) node_id = str(reg_resp["node_id"])
setattr(node, "tracker_node_id", node_id) setattr(node, "tracker_node_id", node_id)
_start_heartbeat( _start_heartbeat(tracker_url, node_id, reg_payload, node_ref=node, start_time=_node_start_time)
tracker_url,
node_id,
reg_payload,
node_ref=node,
start_time=_node_start_time,
refresh_capability=_capability_refresher(
node,
manifest=manifest,
recipe=recipe,
detected_device=device,
cache_dir=shard_path,
force_cpu=force_cpu,
validator=capability_validator,
),
)
except Exception: except Exception:
node.stop() node.stop()
raise raise
@@ -1704,8 +1484,8 @@ def run_startup(
if gpu_name: if gpu_name:
hw_str += f" ({gpu_name}, {vram_mb / 1024:.1f} GB)" hw_str += f" ({gpu_name}, {vram_mb / 1024:.1f} GB)"
shard_label = _format_shard_label( shard_label = _format_shard_label(
proof_shard.start, shard_start,
proof_shard.end, shard_end,
assigned_total_layers, assigned_total_layers,
model_name=assigned_model, model_name=assigned_model,
) )

View File

@@ -16,10 +16,7 @@ import time
from typing import Any from typing import Any
from .admission import CapabilityContext, CapabilityValidator from .admission import CapabilityContext, CapabilityValidator
from . import __version__ as _PACKAGE_VERSION
from .capability import STATUS_PASSED, CapabilityReport, build_capability_report from .capability import STATUS_PASSED, CapabilityReport, build_capability_report
from .gguf_ownership import authoritative_dense_llama_ownership
from .runtime_recipe import build_runtime_recipe_identity
def capability_report_for( def capability_report_for(
@@ -33,15 +30,6 @@ def capability_report_for(
recipe_version: str | None = None, recipe_version: str | None = None,
backend_id: str | None = None, backend_id: str | None = None,
device: str | None = None, device: str | None = None,
artifact_hash: str | None = None,
activation_dtype: str | None = None,
compute_dtype: str | None = None,
kv_dtype: str | None = None,
kv_layout: str | None = None,
tokenizer_revision: str | None = None,
architecture_adapter: str | None = None,
boundary_schema_version: int = 1,
cache_layout: str | None = None,
validated_at: float | None = None, validated_at: float | None = None,
age_seconds: float = 0.0, age_seconds: float = 0.0,
diagnostics: Any = None, diagnostics: Any = None,
@@ -49,49 +37,18 @@ def capability_report_for(
) -> CapabilityReport: ) -> CapabilityReport:
"""A report describing `context`, with any field bent away from the truth.""" """A report describing `context`, with any field bent away from the truth."""
now = time.time() if validated_at is None else validated_at now = time.time() if validated_at is None else validated_at
backend = getattr(context, "backend", None)
model_config = getattr(getattr(backend, "model", None), "config", None)
model_config_payload = (
model_config.to_dict() if hasattr(model_config, "to_dict") else model_config
)
resolved_cache_layout = (
"stateless"
if getattr(backend, "supports_kv_cache", False) is False
else "local-hot-kv"
)
ownership = authoritative_dense_llama_ownership(backend, context.selection)
runtime_recipe = build_runtime_recipe_identity(
model_id=context.selection.model_id,
revision=getattr(getattr(backend, "model", None), "revision", None),
model_config=model_config_payload,
recipe_params=context.recipe.params,
weight_quantization=context.selection.quantization,
backend_id=context.recipe.backend_id,
runtime_version=_PACKAGE_VERSION,
activation_dtype=activation_dtype,
compute_dtype=compute_dtype,
kv_dtype=kv_dtype,
kv_layout=kv_layout or _backend_kv_layout(backend),
tokenizer_revision=tokenizer_revision,
architecture_adapter=architecture_adapter,
boundary_schema_version=boundary_schema_version,
cache_layout=cache_layout or resolved_cache_layout,
)
return build_capability_report( return build_capability_report(
model_id=model_id or context.selection.model_id, model_id=model_id or context.selection.model_id,
shard_start=ownership.start_layer if shard_start is None else shard_start, shard_start=(
shard_end=ownership.end_layer if shard_end is None else shard_end, context.selection.shard_start if shard_start is None else shard_start
),
shard_end=context.selection.shard_end if shard_end is None else shard_end,
recipe_id=recipe_id or context.recipe.id, recipe_id=recipe_id or context.recipe.id,
recipe_version=recipe_version or context.recipe.version, recipe_version=recipe_version or context.recipe.version,
catalogue_version=context.manifest.catalogue_version, catalogue_version=context.manifest.catalogue_version,
backend_id=backend_id or context.recipe.backend_id, backend_id=backend_id or context.recipe.backend_id,
device=device or context.device, device=device or context.device,
quantization=context.selection.quantization, quantization=context.selection.quantization,
runtime=_runtime_versions(),
artifact_hash=artifact_hash,
runtime_recipe=runtime_recipe,
owns_embedding=ownership.owns_embedding,
owns_final_head=ownership.owns_final_head,
status=status, status=status,
duration_ms=duration_ms, duration_ms=duration_ms,
diagnostics=diagnostics, diagnostics=diagnostics,
@@ -111,20 +68,3 @@ def capability_stub(**overrides: Any) -> CapabilityValidator:
return capability_report_for(context, **overrides) return capability_report_for(context, **overrides)
return validator return validator
def _runtime_versions() -> dict[str, str]:
versions: dict[str, str] = {}
for name in ("torch", "transformers"):
try:
module = __import__(name)
except Exception:
continue
version = getattr(module, "__version__", None)
if version:
versions[name] = str(version)
return versions
def _backend_kv_layout(backend: Any) -> str:
return "session-cache" if getattr(backend, "supports_kv_cache", False) else "stateless"

View File

@@ -1543,52 +1543,8 @@ class TorchNodeServer:
def loaded_model_ids(self) -> list[str]: def loaded_model_ids(self) -> list[str]:
return list(self._backends.keys()) return list(self._backends.keys())
def backend_for(self, model_id: str) -> TorchModelShard | None:
"""The loaded backend serving `model_id` — full repo id or short name."""
backend = self._backends.get(model_id)
if backend is not None:
return backend
short = model_id.split("/")[-1].lower()
for key, candidate in self._backends.items():
if key.split("/")[-1].lower() == short:
return candidate
return None
def apply_tracker_directives(self, directives: list[dict]) -> dict | None: def apply_tracker_directives(self, directives: list[dict]) -> dict | None:
"""Apply tracker shard directives (LOAD_SHARD replace, ADD_SHARD load-more).""" """Apply tracker shard directives (LOAD_SHARD replace, ADD_SHARD load-more)."""
drop_all_directive = next(
(directive for directive in reversed(directives) if directive.get("action") == "DROP_ALL_SHARDS"),
None,
)
if drop_all_directive is not None:
self._backends.clear()
self._backend = None
self._tracker_mode = False
if self._server is not None:
self._server.backends = {}
self._server.backend = None
self._server.tracker_mode = False
return {"action": "DROP_ALL_SHARDS"}
drop_directive = next(
(directive for directive in reversed(directives) if directive.get("action") == "DROP_SHARD"),
None,
)
if drop_directive is not None:
model_id = str(drop_directive.get("model") or "")
removed = self._backends.pop(model_id, None)
if removed is None:
return None
if self._backends:
self._backend = next(iter(self._backends.values()))
self._tracker_mode = self._backend.shard_start == 0
else:
self._backend = None
self._tracker_mode = False
if self._server is not None:
self._server.backends = dict(self._backends)
self._server.backend = self._backend
self._server.tracker_mode = self._tracker_mode
return {"action": "DROP_SHARD", "model": model_id}
add_directive = next( add_directive = next(
(directive for directive in reversed(directives) if directive.get("action") == "ADD_SHARD"), (directive for directive in reversed(directives) if directive.get("action") == "ADD_SHARD"),
None, None,
@@ -1618,8 +1574,6 @@ class TorchNodeServer:
flush=True, flush=True,
) )
try: try:
if replacing:
self._backends.clear()
new_backend = _load_backend(model_id, shard_start, shard_end, quantization, self._cache_dir) new_backend = _load_backend(model_id, shard_start, shard_end, quantization, self._cache_dir)
except TypeError: except TypeError:
new_backend = _load_backend(model_id, shard_start, shard_end, quantization) new_backend = _load_backend(model_id, shard_start, shard_end, quantization)

View File

@@ -1,76 +0,0 @@
# Reproducible C++ build wiring for the Shard runtime protocol (DGR-002).
#
# Generates C++ message stubs from proto/shard_runtime.proto and builds the
# round-trip / cross-language compatibility test. Requires protoc and the
# protobuf C++ runtime. Works with either a CONFIG-mode protobuf install
# (protobuf::libprotobuf / protobuf::protoc targets, e.g. a from-source install
# on CMAKE_PREFIX_PATH) or CMake's bundled FindProtobuf module.
#
# The gRPC C++ service stubs are generated separately by scripts/generate_cpp.sh
# when grpc_cpp_plugin is present; the round-trip test needs only message
# serialization, so gRPC is intentionally not a build dependency here.
#
# Configure & build (out-of-tree):
# cmake -S packages/node/native -B packages/node/native/build/cpp
# cmake --build packages/node/native/build/cpp
# Run:
# packages/node/native/build/cpp/shard_protocol_roundtrip_test --selftest
cmake_minimum_required(VERSION 3.16)
project(shard_runtime_protocol CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Prefer a CONFIG-mode protobuf (modern imported targets); fall back to the
# FindProtobuf module for system installs.
find_package(Protobuf CONFIG QUIET)
if(NOT Protobuf_FOUND)
find_package(Protobuf REQUIRED)
endif()
if(TARGET protobuf::protoc)
set(SHARD_PROTOC_EXECUTABLE "$<TARGET_FILE:protobuf::protoc>")
else()
set(SHARD_PROTOC_EXECUTABLE "${Protobuf_PROTOC_EXECUTABLE}")
endif()
if(TARGET protobuf::libprotobuf)
set(SHARD_PROTOBUF_LINK protobuf::libprotobuf)
else()
set(SHARD_PROTOBUF_LINK ${Protobuf_LIBRARIES})
endif()
set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/proto")
set(PROTO_FILE "${PROTO_DIR}/shard_runtime.proto")
set(GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen")
file(MAKE_DIRECTORY "${GEN_DIR}")
set(PROTO_SRC "${GEN_DIR}/shard_runtime.pb.cc")
set(PROTO_HDR "${GEN_DIR}/shard_runtime.pb.h")
add_custom_command(
OUTPUT "${PROTO_SRC}" "${PROTO_HDR}"
COMMAND "${SHARD_PROTOC_EXECUTABLE}"
"--proto_path=${PROTO_DIR}"
"--cpp_out=${GEN_DIR}"
"${PROTO_FILE}"
DEPENDS "${PROTO_FILE}"
COMMENT "Generating C++ protobuf stubs from shard_runtime.proto"
VERBATIM)
add_executable(shard_protocol_roundtrip_test
tests/roundtrip_test.cpp
"${PROTO_SRC}")
target_include_directories(shard_protocol_roundtrip_test PRIVATE "${GEN_DIR}")
if(NOT TARGET protobuf::libprotobuf AND Protobuf_INCLUDE_DIRS)
target_include_directories(shard_protocol_roundtrip_test PRIVATE
${Protobuf_INCLUDE_DIRS})
endif()
target_link_libraries(shard_protocol_roundtrip_test PRIVATE ${SHARD_PROTOBUF_LINK})
enable_testing()
add_test(NAME shard_protocol_roundtrip
COMMAND shard_protocol_roundtrip_test --selftest)

View File

@@ -1,24 +0,0 @@
# Pinned llama.cpp source dependency
This directory keeps the llama.cpp fork boundary explicit and auditable.
Layout:
- `UPSTREAM_COMMIT` - the exact pinned commit.
- `UPSTREAM_REPOSITORY` - the reproducible source dependency URL.
- `UPSTREAM_ASSUMPTIONS.md` - the file/ABI assumptions that the build scripts
validate.
- `patches/` - numbered patch files applied on top of the pinned checkout.
The intended flow is:
1. Fetch or clone the pinned upstream checkout.
2. Verify the checkout commit matches `UPSTREAM_COMMIT`.
3. Check and apply the numbered patch stack.
4. Build the worker scaffold from `examples/meshnet-worker/`.
5. Copy the upstream `LICENSE` and `AUTHORS` files into the worker build tree so
the attribution notices remain attached to the built artifact.
The patch stack in this story is intentionally minimal. It creates the project
worker scaffold and the smoke-test CMake target without pulling Meshnet
networking code into llama.cpp.

View File

@@ -1,35 +0,0 @@
# llama.cpp upstream assumptions
This directory records the reproducible source dependency boundary for the
pinned llama.cpp checkout used by the distributed GGUF runtime program.
Pinned upstream commit:
- `b3c9d1b846cc80a6360adb6aeaa4fcd8c4c8dcac`
Pinned upstream repository:
- `https://github.com/ggml-org/llama.cpp.git`
Assumptions checked by the build script:
- The checkout is exactly the pinned commit above.
- The upstream source tree still ships `LICENSE`, `AUTHORS`, and
`CMakeLists.txt` at the repository root.
- The project-owned worker scaffold is built from
`examples/meshnet-worker/`, which is introduced by the patch stack below.
- The upstream license and attribution notices are preserved in the build
output by copying the root `LICENSE` and `AUTHORS` files into the worker
staging directory.
Compatibility notes:
- The current patch stack does not modify upstream llama.cpp runtime code yet.
It adds a project-owned worker scaffold that can be built reproducibly from
the pinned source checkout.
- Later stories extend this boundary with actual llama.cpp execution patches.
Failure mode:
- If the checkout commit does not match the pin, the build script fails with a
clear pin-mismatch error before patch application or compilation starts.

View File

@@ -1 +0,0 @@
b3c9d1b846cc80a6360adb6aeaa4fcd8c4c8dcac

View File

@@ -1 +0,0 @@
https://github.com/ggml-org/llama.cpp.git

View File

@@ -1,35 +0,0 @@
diff --git a/examples/meshnet-worker/CMakeLists.txt b/examples/meshnet-worker/CMakeLists.txt
new file mode 100644
index 0000000000..8d9f9a1a2f
--- /dev/null
+++ b/examples/meshnet-worker/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.16)
+project(meshnet_llama_worker CXX)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/version.h.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/version.h"
+ @ONLY)
+
+add_executable(meshnet_worker
+ meshnet_worker.cpp)
+
+target_include_directories(meshnet_worker PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+
+enable_testing()
+add_test(NAME meshnet_worker_smoke
+ COMMAND meshnet_worker --smoke)
diff --git a/examples/meshnet-worker/version.h.in b/examples/meshnet-worker/version.h.in
new file mode 100644
index 0000000000..0b75c4e60f
--- /dev/null
+++ b/examples/meshnet-worker/version.h.in
@@ -0,0 +1,4 @@
+#pragma once
+
+#define MESHNET_LLAMA_UPSTREAM_COMMIT "@MESHNET_LLAMA_UPSTREAM_COMMIT@"
+#define MESHNET_LLAMA_PATCHSET_VERSION "@MESHNET_LLAMA_PATCHSET_VERSION@"

View File

@@ -1,43 +0,0 @@
#include "version.h"
#include <iostream>
#include <string>
namespace {
bool fail(const std::string& why) {
std::cerr << "meshnet_worker: FAIL: " << why << std::endl;
return false;
}
} // namespace
int main(int argc, char** argv) {
bool smoke = argc == 1;
for (int i = 1; i < argc; ++i) {
const std::string arg = argv[i];
if (arg == "--smoke") {
smoke = true;
} else {
std::cerr << "unknown arg: " << arg << std::endl;
return 2;
}
}
if (!smoke) {
return fail("smoke mode not requested"), 1;
}
if (MESHNET_LLAMA_UPSTREAM_COMMIT[0] == '\0') {
return fail("upstream commit missing"), 1;
}
if (MESHNET_LLAMA_PATCHSET_VERSION[0] == '\0') {
return fail("patchset version missing"), 1;
}
std::cout << "meshnet worker scaffold ok" << std::endl;
std::cout << "upstream commit: " << MESHNET_LLAMA_UPSTREAM_COMMIT << std::endl;
std::cout << "patchset version: " << MESHNET_LLAMA_PATCHSET_VERSION << std::endl;
return 0;
}

View File

@@ -1,388 +0,0 @@
// Shard runtime data-plane protocol for the distributed GGUF runtime (ADR-0024).
//
// This schema is the semantic contract between Python and C++ Shards. Direct
// transport is gRPC over HTTP/2; the existing Meshnet relay may carry the same
// serialized frames as opaque binary, so anything gRPC would normally carry in
// call metadata (deadlines, cancellation intent) is ALSO representable inside
// the messages for relay-transported seams.
//
// Design rules (see .scratch/distributed-gguf-runtime/RALPH-CONTEXT.md):
// * One long-lived bidirectional ActivateSession stream per Route Session
// Activation Seam. No per-token channel creation.
// * Bounded chunking for prefill; a small decode fast path.
// * The activation boundary is a versioned named-tensor bundle, because an
// architecture boundary may require more than one tensor.
// * Meshnet routing/billing/auth live outside this schema; only the data
// plane and the identifiers needed to attribute and isolate work are here.
//
// Compatibility: proto3. Never renumber or reuse a field number. Add new fields
// with new numbers only. Enums keep a 0 UNSPECIFIED member for forward compat.
syntax = "proto3";
package meshnet.shard.v1;
option java_package = "com.meshnet.shard.v1";
option java_outer_classname = "ShardRuntimeProto";
option go_package = "meshnet/shard/v1;shardv1";
// ---------------------------------------------------------------------------
// Versioning and enums
// ---------------------------------------------------------------------------
// Wire schema version. Bumped only on incompatible envelope changes; additive
// field changes keep the same version and rely on proto3 unknown-field rules.
enum SchemaVersion {
SCHEMA_VERSION_UNSPECIFIED = 0;
SCHEMA_VERSION_1 = 1;
}
// Lifecycle phase of a seam message. RELEASE and CANCEL are represented both as
// dedicated RPCs and as in-stream phases so a relay-carried stream can express
// them without a separate channel.
enum Phase {
PHASE_UNSPECIFIED = 0;
PHASE_PREFILL = 1;
PHASE_DECODE = 2;
PHASE_RELEASE = 3;
PHASE_CANCEL = 4;
}
// Tensor element type. GGUF quantized block types are enumerated explicitly so
// a boundary bundle can carry pre-quantized payloads without reinterpretation.
enum DType {
DTYPE_UNSPECIFIED = 0;
DTYPE_F32 = 1;
DTYPE_F16 = 2;
DTYPE_BF16 = 3;
DTYPE_I64 = 4;
DTYPE_I32 = 5;
DTYPE_I16 = 6;
DTYPE_I8 = 7;
DTYPE_U8 = 8;
DTYPE_BOOL = 9;
DTYPE_Q8_0 = 20;
DTYPE_Q4_0 = 21;
DTYPE_Q4_K = 22;
DTYPE_Q6_K = 23;
}
// Byte order of a tensor payload. Explicit because Shards may run on
// heterogeneous hardware and the relay carries opaque bytes.
enum ByteOrder {
BYTE_ORDER_UNSPECIFIED = 0;
BYTE_ORDER_LITTLE_ENDIAN = 1;
BYTE_ORDER_BIG_ENDIAN = 2;
}
// Payload compression applied to a tensor fragment or message body.
enum Compression {
COMPRESSION_UNSPECIFIED = 0;
COMPRESSION_NONE = 1;
COMPRESSION_ZSTD = 2;
}
// Checksum algorithm. CRC32C is the cheap per-fragment default; SHA256 is used
// where stronger integrity is required.
enum ChecksumAlgorithm {
CHECKSUM_ALGORITHM_UNSPECIFIED = 0;
CHECKSUM_NONE = 1;
CHECKSUM_CRC32C = 2;
CHECKSUM_CRC32 = 3;
CHECKSUM_SHA256 = 4;
}
// What the sender expects from the receiving Shard's Hot KV State for this work
// (request side of the cache contract).
enum CacheExpectation {
CACHE_EXPECTATION_UNSPECIFIED = 0;
CACHE_REUSE = 1; // reuse existing KV for (session, epoch)
CACHE_FRESH = 2; // start a fresh KV context
CACHE_BYPASS = 3; // stateless; do not persist KV
}
// What the receiving Shard actually did with its KV State (result side).
enum CacheResult {
CACHE_RESULT_UNSPECIFIED = 0;
CACHE_HIT = 1;
CACHE_MISS = 2;
CACHE_WRITTEN = 3;
CACHE_BYPASSED = 4;
}
// Coarse retry classification carried in structured status.
enum RetryClass {
RETRY_CLASS_UNSPECIFIED = 0;
RETRY_CLASS_NONE = 1; // terminal success/no-retry
RETRY_CLASS_RETRYABLE = 2; // transient; the same step may be retried
RETRY_CLASS_FATAL = 3; // do not retry this route/epoch
RETRY_CLASS_EPOCH_STALE = 4; // route epoch advanced; re-resolve route
}
enum ServingStatus {
SERVING_STATUS_UNSPECIFIED = 0;
SERVING = 1;
NOT_SERVING = 2;
DRAINING = 3;
}
// ---------------------------------------------------------------------------
// Common value messages
// ---------------------------------------------------------------------------
// Structured, transport-independent status. Mirrors canonical gRPC codes so a
// relay-carried frame can express what a gRPC trailer normally would.
message Status {
uint32 code = 1; // canonical gRPC status code
string message = 2;
RetryClass retry_class = 3;
map<string, string> details = 4;
}
// Integrity check over an associated payload.
message Checksum {
ChecksumAlgorithm algorithm = 1;
bytes value = 2;
}
// Exact Model Artifact / runtime-recipe fingerprint. Both Shards MUST agree on
// every populated field before activation; a mismatch is a fatal status.
message ArtifactFingerprint {
string model_id = 1; // e.g. "meta-llama/Llama-3.1-8B"
string revision = 2; // artifact revision / commit
string artifact_hash = 3; // hash of the GGUF/model artifact
string quantization = 4; // e.g. "Q4_K_M", "F16"
string runtime_recipe_fingerprint = 5; // DGR-003 recipe hash
}
// Contiguous transformer layer range owned by a Shard (ADR-0012). end_layer is
// exclusive. effective_start_layer is the overlap-safe start after de-dupe of
// shared boundary layers between adjacent Shards.
message ShardRange {
uint32 start_layer = 1;
uint32 end_layer = 2;
uint32 effective_start_layer = 3;
bool owns_embedding = 4;
bool owns_final_head = 5;
}
// Token position window for a message. start_position is the absolute index of
// the first token; token_count is how many positions this message covers.
message Position {
uint64 start_position = 1;
uint64 token_count = 2;
uint64 sequence_length = 3; // total known context length, if known
}
// Envelope carried by every seam message. Everything required to version,
// route-attribute, isolate, order, and integrity-check a unit of work.
message MessageHeader {
SchemaVersion schema_version = 1;
string work_id = 2; // request/work ID (idempotency scope)
string route_session_id = 3; // Route Session ID
uint64 route_epoch = 4; // route epoch; stale epochs are rejected
ArtifactFingerprint fingerprint = 5;
ShardRange shard_range = 6;
Phase phase = 7;
Position position = 8;
uint64 idempotency_step = 9; // monotonic per (work_id) step counter
CacheExpectation cache_expectation = 10;
Compression compression = 11; // compression of THIS message's payloads
Checksum checksum = 12; // checksum over THIS message's payload
}
// ---------------------------------------------------------------------------
// Versioned named-tensor bundle (the activation boundary payload)
// ---------------------------------------------------------------------------
// One bounded fragment of a tensor payload. Large tensors are split so no
// single message is unbounded; fragments reassemble by byte_offset order.
message TensorFragment {
uint32 fragment_index = 1;
uint32 fragment_count = 2;
uint64 byte_offset = 3; // offset of this fragment within the full payload
bytes data = 4;
Checksum checksum = 5; // checksum over this fragment's (post-compression) data
}
// A single named tensor with full description so the receiver never reinterprets
// bytes implicitly.
message NamedTensor {
string name = 1;
repeated uint64 shape = 2;
DType dtype = 3;
ByteOrder byte_order = 4;
uint64 total_byte_length = 5; // full payload length across all fragments
Compression compression = 6; // compression applied to fragment data
repeated TensorFragment fragments = 7;
}
// A versioned collection of named tensors representing one activation boundary.
message TensorBundle {
uint32 bundle_version = 1;
repeated NamedTensor tensors = 2;
}
// ---------------------------------------------------------------------------
// Session stream messages (bidirectional ActivateSession)
// ---------------------------------------------------------------------------
// Opens a seam. Carries the header plus stream-scoped bounds. deadline_unix_nanos
// lets a relay-carried stream express the call deadline gRPC would otherwise own.
message SessionOpen {
MessageHeader header = 1;
uint64 deadline_unix_nanos = 2; // absolute deadline; 0 = none
uint32 max_prefill_tokens_per_chunk = 3; // bound for prefill chunking
uint32 max_fragment_bytes = 4; // bound for tensor fragment size
FlowControl initial_credit = 5; // receiver's starting flow-control window
}
// Bounded prefill chunk. A prefill is split into ordered chunks each covering at
// most max_prefill_tokens_per_chunk positions; final_chunk marks the last one.
message PrefillChunk {
MessageHeader header = 1;
uint32 chunk_index = 2;
uint32 chunk_count = 3; // 0 if unknown/streaming
bool final_chunk = 4;
TensorBundle activations = 5;
}
// Small decode fast path: a single-position (or tiny) step with minimal framing.
// Reuses the same header for isolation/ordering but expects one activation bundle.
message DecodeStep {
MessageHeader header = 1;
TensorBundle activation = 2;
}
// Explicit HTTP/2-independent flow-control grant. credits is the number of
// additional messages the receiver is willing to accept; the byte/message caps
// bound in-flight work for backpressure.
message FlowControl {
uint64 credits = 1;
uint64 max_in_flight_bytes = 2;
uint64 max_in_flight_messages = 3;
}
// Release a session's resources (Hot KV State, sequence) cleanly.
message ReleaseRequest {
MessageHeader header = 1;
string reason = 2;
}
message ReleaseResponse {
Status status = 1;
CacheResult cache_result = 2;
}
// Cancel in-flight work for a session/step.
message CancelRequest {
MessageHeader header = 1;
string reason = 2;
}
message CancelResponse {
Status status = 1;
}
// Client -> server frames on the ActivateSession stream.
message SessionActivation {
oneof payload {
SessionOpen open = 1;
PrefillChunk prefill = 2;
DecodeStep decode = 3;
ReleaseRequest release = 4;
CancelRequest cancel = 5;
FlowControl flow_control = 6;
}
}
// Computed boundary output for a step: the next Shard's input tensors plus the
// cache result and integrity for what was produced.
message ActivationResult {
MessageHeader header = 1;
TensorBundle outputs = 2;
CacheResult cache_result = 3;
Status status = 4;
}
message SessionAccepted {
MessageHeader header = 1;
FlowControl granted_credit = 2;
Status status = 3;
}
// Server -> client frames on the ActivateSession stream.
message SessionResponse {
oneof payload {
SessionAccepted accepted = 1;
ActivationResult result = 2;
FlowControl flow_control = 3;
Status status = 4;
ReleaseResponse release_ack = 5;
CancelResponse cancel_ack = 6;
}
}
// ---------------------------------------------------------------------------
// Capability and health (unary)
// ---------------------------------------------------------------------------
message ResourceBudget {
uint64 weight_bytes = 1;
uint64 kv_bytes = 2;
uint64 scratch_bytes = 3;
uint32 max_concurrent_sessions = 4;
}
message CapabilityRequest {
SchemaVersion schema_version = 1;
}
message CapabilityResponse {
SchemaVersion schema_version = 1;
repeated SchemaVersion supported_schema_versions = 2;
repeated string supported_architectures = 3; // e.g. "llama", "qwen3"
repeated string supported_quantizations = 4;
ShardRange servable_range = 5;
ResourceBudget budget = 6;
repeated Compression supported_compression = 7;
repeated ChecksumAlgorithm supported_checksums = 8;
ArtifactFingerprint loaded_fingerprint = 9; // empty if no artifact loaded
}
message HealthRequest {
string route_session_id = 1; // optional; empty for node-wide health
}
message HealthResponse {
ServingStatus status = 1;
uint32 active_sessions = 2;
uint32 queued_requests = 3;
double kv_pressure = 4; // 0.0..1.0 fraction of KV budget in use
uint64 rss_bytes = 5;
Status detail = 6;
}
// ---------------------------------------------------------------------------
// Service
// ---------------------------------------------------------------------------
service ShardRuntime {
// Admission/capability negotiation.
rpc GetCapability(CapabilityRequest) returns (CapabilityResponse);
// Liveness/backpressure telemetry.
rpc Health(HealthRequest) returns (HealthResponse);
// One long-lived bidirectional stream per Route Session Activation Seam.
// Deadlines/cancellation use gRPC call semantics on direct transport and the
// in-message equivalents on relay transport; flow control uses FlowControl
// frames; errors are structured Status.
rpc ActivateSession(stream SessionActivation) returns (stream SessionResponse);
// Clean resource release (also expressible in-stream as PHASE_RELEASE).
rpc Release(ReleaseRequest) returns (ReleaseResponse);
// Cancellation (also expressible in-stream as PHASE_CANCEL).
rpc Cancel(CancelRequest) returns (CancelResponse);
}

View File

@@ -1,187 +0,0 @@
#!/usr/bin/env bash
# Apply the numbered llama.cpp patch stack and build the worker scaffold.
#
# Default flow:
# 1. Fetch the pinned llama.cpp source into a build directory if needed.
# 2. Verify the checkout matches the pinned commit.
# 3. Check/apply the numbered patch stack from packages/node/native/llama/.
# 4. Compile and build the standalone worker scaffold.
# 5. Copy upstream LICENSE/AUTHORS notices into the staging directory.
#
# This script is intentionally model-free and does not contact any inference
# endpoint. It is a source/build reproducibility check.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NATIVE_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
LLAMA_ROOT="${NATIVE_ROOT}/llama"
UPSTREAM_COMMIT="$(tr -d '\n\r' < "${LLAMA_ROOT}/UPSTREAM_COMMIT")"
UPSTREAM_REPOSITORY="$(tr -d '\n\r' < "${LLAMA_ROOT}/UPSTREAM_REPOSITORY")"
PATCH_DIR="${LLAMA_ROOT}/patches"
DEFAULT_SOURCE_DIR="${NATIVE_ROOT}/build/llama.cpp-src"
DEFAULT_BUILD_DIR="${NATIVE_ROOT}/build/llama-worker"
SOURCE_DIR="${DEFAULT_SOURCE_DIR}"
BUILD_DIR="${DEFAULT_BUILD_DIR}"
WORKTREE_DIR=""
FETCH=1
CXX_BIN="${CXX:-}"
usage() {
cat <<'EOF'
Usage: build_llama_worker.sh [--source-dir PATH] [--build-dir PATH] [--no-fetch]
Builds the project-owned worker scaffold from a pinned llama.cpp checkout.
EOF
}
fail() {
echo "error: $*" >&2
exit 1
}
while (($#)); do
case "$1" in
--source-dir)
SOURCE_DIR="${2:-}"
shift 2
;;
--build-dir)
BUILD_DIR="${2:-}"
shift 2
;;
--no-fetch)
FETCH=0
shift
;;
-h|--help)
usage
exit 0
;;
*)
fail "unknown argument: $1"
;;
esac
done
[[ -n "${SOURCE_DIR}" ]] || fail "source dir is empty"
[[ -n "${BUILD_DIR}" ]] || fail "build dir is empty"
checkout_commit() {
if [[ -f "${SOURCE_DIR}/.meshnet-upstream-commit" ]]; then
tr -d '\n\r' < "${SOURCE_DIR}/.meshnet-upstream-commit"
return 0
fi
if git -C "${SOURCE_DIR}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git -C "${SOURCE_DIR}" rev-parse HEAD
return 0
fi
return 1
}
ensure_source() {
if [[ -d "${SOURCE_DIR}" ]]; then
return 0
fi
if [[ "${FETCH}" -ne 1 ]]; then
fail "source dir ${SOURCE_DIR} does not exist and --no-fetch was set"
fi
mkdir -p "${SOURCE_DIR}"
git clone --quiet "${UPSTREAM_REPOSITORY}" "${SOURCE_DIR}" || fail "unable to clone ${UPSTREAM_REPOSITORY}"
git -C "${SOURCE_DIR}" checkout --quiet "${UPSTREAM_COMMIT}" || fail "unable to checkout ${UPSTREAM_COMMIT}"
printf '%s\n' "${UPSTREAM_COMMIT}" > "${SOURCE_DIR}/.meshnet-upstream-commit"
printf '%s\n' "${UPSTREAM_REPOSITORY}" > "${SOURCE_DIR}/.meshnet-upstream-repository"
}
verify_assumptions() {
local observed_commit
observed_commit="$(checkout_commit)" || fail "source tree does not expose a commit pin; write ${SOURCE_DIR}/.meshnet-upstream-commit or use a git checkout"
if [[ "${observed_commit}" != "${UPSTREAM_COMMIT}" ]]; then
fail "llama.cpp pin mismatch: expected ${UPSTREAM_COMMIT}, got ${observed_commit}"
fi
for required in LICENSE AUTHORS CMakeLists.txt; do
[[ -e "${SOURCE_DIR}/${required}" ]] || fail "missing upstream assumption file: ${required}"
done
}
apply_patches() {
shopt -s nullglob
local patches=("${PATCH_DIR}"/*.patch)
shopt -u nullglob
if ((${#patches[@]} == 0)); then
fail "no patch files found in ${PATCH_DIR}"
fi
for patch in "${patches[@]}"; do
git -C "${SOURCE_DIR}" apply --check "${patch}" || fail "patch check failed: $(basename "${patch}")"
done
for patch in "${patches[@]}"; do
git -C "${SOURCE_DIR}" apply "${patch}" || fail "patch apply failed: $(basename "${patch}")"
done
}
build_worker() {
rm -rf "${BUILD_DIR}"
mkdir -p "${BUILD_DIR}"
WORKTREE_DIR="${BUILD_DIR}/llama.cpp-worktree"
rm -rf "${WORKTREE_DIR}"
mkdir -p "${WORKTREE_DIR}"
cp -a "${SOURCE_DIR}/." "${WORKTREE_DIR}/"
if [[ -f "${SOURCE_DIR}/.meshnet-upstream-commit" ]]; then
cp "${SOURCE_DIR}/.meshnet-upstream-commit" "${WORKTREE_DIR}/.meshnet-upstream-commit"
fi
if [[ -f "${SOURCE_DIR}/.meshnet-upstream-repository" ]]; then
cp "${SOURCE_DIR}/.meshnet-upstream-repository" "${WORKTREE_DIR}/.meshnet-upstream-repository"
fi
SOURCE_DIR="${WORKTREE_DIR}"
apply_patches
local worker_dir="${SOURCE_DIR}/examples/meshnet-worker"
cp "${LLAMA_ROOT}/templates/meshnet_worker.cpp" "${worker_dir}/meshnet_worker.cpp"
cat > "${worker_dir}/version.h" <<EOF
#pragma once
#define MESHNET_LLAMA_UPSTREAM_COMMIT "${UPSTREAM_COMMIT}"
#define MESHNET_LLAMA_PATCHSET_VERSION "0001"
EOF
local compiler=""
if [[ -n "${CXX_BIN}" ]] && command -v "${CXX_BIN}" >/dev/null 2>&1; then
compiler="${CXX_BIN}"
elif command -v g++ >/dev/null 2>&1; then
compiler="g++"
elif command -v c++ >/dev/null 2>&1; then
compiler="c++"
elif command -v clang++ >/dev/null 2>&1; then
compiler="clang++"
else
fail "no C++ compiler found (need g++, c++, clang++, or $CXX)"
fi
"${compiler}" -std=c++17 -O2 -Wall -Wextra \
-I "${worker_dir}" \
-o "${BUILD_DIR}/meshnet_worker" \
"${worker_dir}/meshnet_worker.cpp"
}
stage_notices() {
local notice_dir="${BUILD_DIR}/upstream-notices"
mkdir -p "${notice_dir}"
cp "${SOURCE_DIR}/LICENSE" "${notice_dir}/LICENSE"
cp "${SOURCE_DIR}/AUTHORS" "${notice_dir}/AUTHORS"
printf '%s\n' "${UPSTREAM_COMMIT}" > "${notice_dir}/UPSTREAM_COMMIT"
printf '%s\n' "${UPSTREAM_REPOSITORY}" > "${notice_dir}/UPSTREAM_REPOSITORY"
}
main() {
ensure_source
verify_assumptions
build_worker
stage_notices
"${BUILD_DIR}/meshnet_worker" --smoke
echo "build ok: ${BUILD_DIR}/meshnet_worker"
}
main "$@"

View File

@@ -1,43 +0,0 @@
#!/usr/bin/env bash
# Reproducibly generate the C++ Shard-protocol stubs from the schema.
#
# Produces message stubs (protoc --cpp_out) always, and gRPC C++ service stubs
# (protoc --grpc_out with grpc_cpp_plugin) when the plugin is available. The
# round-trip test needs only the message stubs; gRPC service stubs are for the
# standalone C++ worker (DGR-008).
#
# Requirements: protoc (>=3.16). Optional: grpc_cpp_plugin for --grpc_out.
#
# Usage:
# packages/node/native/scripts/generate_cpp.sh
# Output: packages/node/native/build/cpp-gen/ (gitignored via build/).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NATIVE_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
PROTO_DIR="${NATIVE_ROOT}/proto"
PROTO_FILE="${PROTO_DIR}/shard_runtime.proto"
OUT_DIR="${NATIVE_ROOT}/build/cpp-gen"
if ! command -v protoc >/dev/null 2>&1; then
echo "error: protoc not found on PATH (install protobuf-compiler)." >&2
exit 3
fi
mkdir -p "${OUT_DIR}"
echo "generating C++ message stubs -> ${OUT_DIR}"
protoc --proto_path="${PROTO_DIR}" --cpp_out="${OUT_DIR}" "${PROTO_FILE}"
if command -v grpc_cpp_plugin >/dev/null 2>&1; then
echo "generating C++ gRPC service stubs -> ${OUT_DIR}"
protoc --proto_path="${PROTO_DIR}" \
--grpc_out="${OUT_DIR}" \
--plugin=protoc-gen-grpc="$(command -v grpc_cpp_plugin)" \
"${PROTO_FILE}"
else
echo "note: grpc_cpp_plugin not found; skipped --grpc_out (message stubs only)." >&2
fi
echo "done:"
ls -1 "${OUT_DIR}"

View File

@@ -1,76 +0,0 @@
#!/usr/bin/env python3
"""Reproducibly generate the Python Shard-protocol stubs from the schema.
This is the documented, no-manual-copy generation entry point referenced by
``evidence/DGR-002/README.md``. It runs the pinned ``grpc_tools.protoc`` with the
same flags ``meshnet_node.native_protocol.generate()`` uses on demand, but is
kept self-contained (it does not import ``meshnet_node``) so it works regardless
of which checkout the editable install points at.
Usage (from the project .venv):
python packages/node/native/scripts/generate_python.py
Output: ``packages/node/native/build/python/shard_runtime_pb2{,_grpc}.py``
(``build/`` is gitignored).
"""
from __future__ import annotations
import pathlib
import sys
_NATIVE_ROOT = pathlib.Path(__file__).resolve().parents[1]
PROTO_DIR = _NATIVE_ROOT / "proto"
PROTO_FILE = PROTO_DIR / "shard_runtime.proto"
GEN_DIR = _NATIVE_ROOT / "build" / "python"
def _well_known_include() -> str | None:
try:
import grpc_tools
candidate = pathlib.Path(grpc_tools.__file__).parent / "_proto"
return str(candidate) if candidate.is_dir() else None
except Exception:
return None
def main() -> int:
if not PROTO_FILE.exists():
print(f"schema not found: {PROTO_FILE}", file=sys.stderr)
return 2
try:
from grpc_tools import protoc
except ImportError:
print(
"grpc_tools is required (pip install grpcio-tools); it is present in "
"the project .venv.",
file=sys.stderr,
)
return 3
GEN_DIR.mkdir(parents=True, exist_ok=True)
well_known = _well_known_include()
args = [
"grpc_tools.protoc",
f"-I{PROTO_DIR}",
*([f"-I{well_known}"] if well_known else []),
f"--python_out={GEN_DIR}",
f"--grpc_python_out={GEN_DIR}",
PROTO_FILE.name,
]
rc = protoc.main(args)
if rc != 0:
print(f"grpc_tools.protoc exited with status {rc}", file=sys.stderr)
return rc
print(f"generated Python stubs into: {GEN_DIR}")
for name in ("shard_runtime_pb2.py", "shard_runtime_pb2_grpc.py"):
target = GEN_DIR / name
print(f" {name}: {'ok' if target.exists() else 'MISSING'}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -1,180 +0,0 @@
// C++ round-trip and cross-language compatibility test for the Shard protocol.
//
// Modes (composable):
// --selftest serialize a sample message, parse it back, verify fields.
// --read <path> parse a fixture serialized by another language; verify the
// known fields; tolerate unknown fields (forward compat).
// --write <path> serialize the C++ sample so another language can parse it.
//
// Exit code 0 means every requested check passed. The Python test drives this
// binary to prove Python<->C++ wire compatibility in both directions.
#include "shard_runtime.pb.h"
#include <cstdint>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
using namespace meshnet::shard::v1;
namespace {
bool Fail(const std::string& why) {
std::cerr << "roundtrip_test: FAIL: " << why << std::endl;
return false;
}
SessionActivation MakeSample() {
SessionActivation act;
PrefillChunk* pre = act.mutable_prefill();
MessageHeader* h = pre->mutable_header();
h->set_schema_version(SCHEMA_VERSION_1);
h->set_work_id("w1");
h->set_route_session_id("s1");
h->set_route_epoch(3);
h->set_phase(PHASE_PREFILL);
h->set_idempotency_step(7);
h->set_cache_expectation(CACHE_FRESH);
h->set_compression(COMPRESSION_NONE);
ArtifactFingerprint* fp = h->mutable_fingerprint();
fp->set_model_id("meta-llama/Llama-3.1-8B");
fp->set_quantization("Q4_K_M");
fp->set_runtime_recipe_fingerprint("recipe-abc");
ShardRange* sr = h->mutable_shard_range();
sr->set_start_layer(0);
sr->set_end_layer(16);
sr->set_effective_start_layer(0);
sr->set_owns_embedding(true);
Position* pos = h->mutable_position();
pos->set_start_position(0);
pos->set_token_count(5);
pos->set_sequence_length(5);
pre->set_chunk_index(0);
pre->set_chunk_count(1);
pre->set_final_chunk(true);
TensorBundle* bundle = pre->mutable_activations();
bundle->set_bundle_version(1);
NamedTensor* t = bundle->add_tensors();
t->set_name("hidden");
t->add_shape(1);
t->add_shape(4096);
t->set_dtype(DTYPE_F16);
t->set_byte_order(BYTE_ORDER_LITTLE_ENDIAN);
t->set_total_byte_length(8);
t->set_compression(COMPRESSION_NONE);
TensorFragment* frag = t->add_fragments();
frag->set_fragment_index(0);
frag->set_fragment_count(1);
frag->set_byte_offset(0);
frag->set_data(std::string("\x01\x02\x03\x04\x05\x06\x07\x08", 8));
return act;
}
bool CheckSample(const SessionActivation& act) {
if (act.payload_case() != SessionActivation::kPrefill)
return Fail("payload is not prefill");
const PrefillChunk& pre = act.prefill();
const MessageHeader& h = pre.header();
if (h.schema_version() != SCHEMA_VERSION_1) return Fail("schema_version");
if (h.work_id() != "w1") return Fail("work_id");
if (h.route_session_id() != "s1") return Fail("route_session_id");
if (h.route_epoch() != 3) return Fail("route_epoch");
if (h.phase() != PHASE_PREFILL) return Fail("phase");
if (h.idempotency_step() != 7) return Fail("idempotency_step");
if (h.fingerprint().model_id() != "meta-llama/Llama-3.1-8B")
return Fail("model_id");
if (h.fingerprint().quantization() != "Q4_K_M") return Fail("quantization");
if (h.shard_range().end_layer() != 16) return Fail("end_layer");
if (!h.shard_range().owns_embedding()) return Fail("owns_embedding");
if (h.position().token_count() != 5) return Fail("token_count");
if (!pre.final_chunk()) return Fail("final_chunk");
if (pre.activations().tensors_size() != 1) return Fail("tensors_size");
const NamedTensor& t = pre.activations().tensors(0);
if (t.name() != "hidden") return Fail("tensor name");
if (t.dtype() != DTYPE_F16) return Fail("dtype");
if (t.byte_order() != BYTE_ORDER_LITTLE_ENDIAN) return Fail("byte_order");
if (t.shape_size() != 2 || t.shape(1) != 4096) return Fail("shape");
if (t.fragments_size() != 1) return Fail("fragments_size");
if (t.fragments(0).data().size() != 8) return Fail("fragment data length");
return true;
}
bool ReadFile(const std::string& path, std::string* out) {
std::ifstream in(path, std::ios::binary);
if (!in) return false;
std::ostringstream ss;
ss << in.rdbuf();
*out = ss.str();
return true;
}
bool WriteFile(const std::string& path, const std::string& data) {
std::ofstream out(path, std::ios::binary);
if (!out) return false;
out.write(data.data(), static_cast<std::streamsize>(data.size()));
return static_cast<bool>(out);
}
} // namespace
int main(int argc, char** argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
std::string read_path;
std::string write_path;
bool selftest = (argc == 1);
for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "--selftest") {
selftest = true;
} else if (arg == "--read" && i + 1 < argc) {
read_path = argv[++i];
} else if (arg == "--write" && i + 1 < argc) {
write_path = argv[++i];
} else {
std::cerr << "unknown/incomplete arg: " << arg << std::endl;
return 2;
}
}
if (selftest) {
SessionActivation sample = MakeSample();
std::string bytes;
if (!sample.SerializeToString(&bytes)) return Fail("serialize"), 1;
SessionActivation parsed;
if (!parsed.ParseFromString(bytes)) return Fail("parse"), 1;
if (!CheckSample(parsed)) return 1;
std::cout << "selftest ok (" << bytes.size() << " bytes)" << std::endl;
}
if (!read_path.empty()) {
std::string bytes;
if (!ReadFile(read_path, &bytes)) return Fail("cannot read fixture"), 1;
SessionActivation parsed;
// ParseFromString tolerates and preserves unknown fields (forward compat).
if (!parsed.ParseFromString(bytes)) return Fail("parse fixture"), 1;
if (!CheckSample(parsed)) return 1;
std::cout << "read ok (" << bytes.size() << " bytes)" << std::endl;
}
if (!write_path.empty()) {
SessionActivation sample = MakeSample();
std::string bytes;
if (!sample.SerializeToString(&bytes)) return Fail("serialize for write"), 1;
if (!WriteFile(write_path, bytes)) return Fail("cannot write output"), 1;
std::cout << "write ok (" << bytes.size() << " bytes)" << std::endl;
}
google::protobuf::ShutdownProtobufLibrary();
return 0;
}

View File

@@ -58,7 +58,6 @@ STATE_MODEL_MISMATCH = "model-mismatch"
STATE_SHARD_MISMATCH = "shard-mismatch" STATE_SHARD_MISMATCH = "shard-mismatch"
STATE_RECIPE_MISMATCH = "recipe-mismatch" STATE_RECIPE_MISMATCH = "recipe-mismatch"
STATE_CATALOGUE_INCOMPATIBLE = "catalogue-incompatible" STATE_CATALOGUE_INCOMPATIBLE = "catalogue-incompatible"
STATE_COMPATIBILITY_MISMATCH = "compatibility-mismatch"
ALL_STATES = ( ALL_STATES = (
STATE_ADMITTED, STATE_ADMITTED,
@@ -70,7 +69,6 @@ ALL_STATES = (
STATE_SHARD_MISMATCH, STATE_SHARD_MISMATCH,
STATE_RECIPE_MISMATCH, STATE_RECIPE_MISMATCH,
STATE_CATALOGUE_INCOMPATIBLE, STATE_CATALOGUE_INCOMPATIBLE,
STATE_COMPATIBILITY_MISMATCH,
) )
# --- Compatibility policy for nodes that predate the capability protocol. --- # --- Compatibility policy for nodes that predate the capability protocol. ---
@@ -157,17 +155,12 @@ class CapabilityState:
model_id: str | None = None model_id: str | None = None
shard_start: int | None = None shard_start: int | None = None
shard_end: int | None = None shard_end: int | None = None
owns_embedding: bool | None = None
owns_final_head: bool | None = None
recipe_id: str | None = None recipe_id: str | None = None
recipe_version: str | None = None recipe_version: str | None = None
catalogue_version: str | None = None catalogue_version: str | None = None
backend_id: str | None = None backend_id: str | None = None
device: str | None = None device: str | None = None
quantization: str | None = None quantization: str | None = None
artifact_hash: str | None = None
compatibility_fingerprint: str | None = None
runtime_recipe_fingerprint: str | None = None
validated_at: float | None = None validated_at: float | None = None
recorded_at: float = 0.0 recorded_at: float = 0.0
schema_version: int | None = None schema_version: int | None = None
@@ -194,17 +187,12 @@ class CapabilityState:
"model_id": self.model_id, "model_id": self.model_id,
"shard_start": self.shard_start, "shard_start": self.shard_start,
"shard_end": self.shard_end, "shard_end": self.shard_end,
"owns_embedding": self.owns_embedding,
"owns_final_head": self.owns_final_head,
"recipe_id": self.recipe_id, "recipe_id": self.recipe_id,
"recipe_version": self.recipe_version, "recipe_version": self.recipe_version,
"catalogue_version": self.catalogue_version, "catalogue_version": self.catalogue_version,
"backend_id": self.backend_id, "backend_id": self.backend_id,
"device": self.device, "device": self.device,
"quantization": self.quantization, "quantization": self.quantization,
"artifact_hash": self.artifact_hash,
"compatibility_fingerprint": self.compatibility_fingerprint,
"runtime_recipe_fingerprint": self.runtime_recipe_fingerprint,
"validated_at": self.validated_at, "validated_at": self.validated_at,
"recorded_at": self.recorded_at, "recorded_at": self.recorded_at,
"schema_version": self.schema_version, "schema_version": self.schema_version,
@@ -234,7 +222,6 @@ def evaluate_report(
shard_end: int | None, shard_end: int | None,
declared_recipe_id: str | None = None, declared_recipe_id: str | None = None,
declared_recipe_version: str | None = None, declared_recipe_version: str | None = None,
declared_compatibility_fingerprint: str | None = None,
now: float | None = None, now: float | None = None,
max_age_seconds: float = DEFAULT_MAX_REPORT_AGE_SECONDS, max_age_seconds: float = DEFAULT_MAX_REPORT_AGE_SECONDS,
) -> CapabilityState: ) -> CapabilityState:
@@ -321,17 +308,6 @@ def evaluate_report(
f"the node declared v{declared_recipe_version}", f"the node declared v{declared_recipe_version}",
) )
if (
declared_compatibility_fingerprint is not None
and base.compatibility_fingerprint != declared_compatibility_fingerprint
):
return base.with_state(
STATE_COMPATIBILITY_MISMATCH,
"proof compatibility fingerprint does not match the node's declared "
"artifact/runtime recipe; the artifact, tokenizer, architecture, "
"boundary schema, activation recipe or cache layout differs",
)
if status != STATUS_PASSED: if status != STATUS_PASSED:
return base.with_state( return base.with_state(
STATE_FAILED, STATE_FAILED,
@@ -368,8 +344,6 @@ def _parse_report(doc: Mapping[str, Any]) -> dict:
shard = _object(doc.get("shard"), "shard") shard = _object(doc.get("shard"), "shard")
recipe = _object(doc.get("recipe"), "recipe") recipe = _object(doc.get("recipe"), "recipe")
backend = _object(doc.get("backend"), "backend") backend = _object(doc.get("backend"), "backend")
artifact = _object_or_none(doc.get("artifact"), "artifact")
runtime_recipe = _object_or_none(doc.get("runtime_recipe"), "runtime_recipe")
validated_at = doc.get("validated_at") validated_at = doc.get("validated_at")
if isinstance(validated_at, bool) or not isinstance(validated_at, (int, float)): if isinstance(validated_at, bool) or not isinstance(validated_at, (int, float)):
@@ -383,8 +357,6 @@ def _parse_report(doc: Mapping[str, Any]) -> dict:
"model_id": _text(model.get("model_id"), "model.model_id"), "model_id": _text(model.get("model_id"), "model.model_id"),
"shard_start": _index(shard.get("start"), "shard.start"), "shard_start": _index(shard.get("start"), "shard.start"),
"shard_end": _index(shard.get("end"), "shard.end"), "shard_end": _index(shard.get("end"), "shard.end"),
"owns_embedding": _maybe_bool(shard.get("owns_embedding")),
"owns_final_head": _maybe_bool(shard.get("owns_final_head")),
"recipe_id": _text(recipe.get("recipe_id"), "recipe.recipe_id"), "recipe_id": _text(recipe.get("recipe_id"), "recipe.recipe_id"),
"recipe_version": _text(recipe.get("recipe_version"), "recipe.recipe_version"), "recipe_version": _text(recipe.get("recipe_version"), "recipe.recipe_version"),
"catalogue_version": _text( "catalogue_version": _text(
@@ -395,15 +367,6 @@ def _parse_report(doc: Mapping[str, Any]) -> dict:
"quantization": _optional_text( "quantization": _optional_text(
backend.get("quantization"), "backend.quantization" backend.get("quantization"), "backend.quantization"
), ),
"artifact_hash": _optional_text(
artifact.get("artifact_hash"), "artifact.artifact_hash"
),
"compatibility_fingerprint": _optional_text(
doc.get("compatibility_fingerprint"), "compatibility_fingerprint"
),
"runtime_recipe_fingerprint": _optional_text(
runtime_recipe.get("fingerprint"), "runtime_recipe.fingerprint"
),
"validated_at": float(validated_at), "validated_at": float(validated_at),
"schema_version": schema_version, "schema_version": schema_version,
"diagnostics": _diagnostics(doc.get("diagnostics")), "diagnostics": _diagnostics(doc.get("diagnostics")),
@@ -417,12 +380,6 @@ def _object(value: Any, field_name: str) -> Mapping[str, Any]:
return value return value
def _object_or_none(value: Any, field_name: str) -> Mapping[str, Any]:
if value is None:
return {}
return _object(value, field_name)
def _text(value: Any, field_name: str) -> str: def _text(value: Any, field_name: str) -> str:
if not isinstance(value, str) or not value.strip(): if not isinstance(value, str) or not value.strip():
raise _ReportError(f"{field_name!r} must be a non-empty string") raise _ReportError(f"{field_name!r} must be a non-empty string")
@@ -447,12 +404,6 @@ def _maybe_int(value: Any) -> int | None:
return value return value
def _maybe_bool(value: Any) -> bool | None:
if isinstance(value, bool):
return value
return None
def _diagnostics(value: Any) -> tuple[str, ...]: def _diagnostics(value: Any) -> tuple[str, ...]:
if not isinstance(value, list): if not isinstance(value, list):
return () return ()

View File

@@ -22,9 +22,8 @@
border-bottom:1px solid var(--border); flex-shrink:0; } border-bottom:1px solid var(--border); flex-shrink:0; }
header h1 { font-size:16px; margin:0; color:var(--accent); } header h1 { font-size:16px; margin:0; color:var(--accent); }
header .meta { color:var(--dim); font-size:12px; } header .meta { color:var(--dim); font-size:12px; }
main { display:grid; grid-template-columns:1fr; main { display:grid; grid-template-columns:repeat(auto-fit,minmax(340px,1fr));
gap:14px; padding:14px 20px; } gap:14px; padding:14px 20px; }
main > section { width:100%; min-width:0; }
body.chat-tab-active main { body.chat-tab-active main {
flex:1; min-height:0; display:flex; flex-direction:column; flex:1; min-height:0; display:flex; flex-direction:column;
padding:0; gap:0; overflow:hidden; padding:0; gap:0; overflow:hidden;
@@ -44,15 +43,12 @@
.empty { color:var(--dim); font-style:italic; } .empty { color:var(--dim); font-style:italic; }
.pill { display:inline-block; padding:0 7px; border-radius:9px; .pill { display:inline-block; padding:0 7px; border-radius:9px;
border:1px solid var(--border); font-size:11px; } border:1px solid var(--border); font-size:11px; }
input, button, select { font:inherit; color:var(--fg); background:var(--bg); input, button { font:inherit; color:var(--fg); background:var(--bg);
border:1px solid var(--border); border-radius:6px; padding:5px 8px; } border:1px solid var(--border); border-radius:6px; padding:5px 8px; }
input { width:100%; margin-bottom:6px; } input { width:100%; margin-bottom:6px; }
button { cursor:pointer; color:var(--accent); } button { cursor:pointer; color:var(--accent); }
button:hover { border-color:var(--accent); } button:hover { border-color:var(--accent); }
button.small { font-size:11px; padding:1px 7px; } button.small { font-size:11px; padding:1px 7px; }
dialog { color:var(--fg); background:var(--panel); border:1px solid var(--border); border-radius:8px; min-width:min(420px,calc(100vw - 32px)); }
dialog::backdrop { background:rgba(0,0,0,.55); }
.placement-dialog-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:12px; }
.form-row { display:flex; gap:8px; } .form-row { display:flex; gap:8px; }
.form-row button { white-space:nowrap; } .form-row button { white-space:nowrap; }
.error-msg { color:var(--bad); font-size:12px; min-height:16px; } .error-msg { color:var(--bad); font-size:12px; min-height:16px; }
@@ -75,12 +71,6 @@
background:transparent; color:var(--dim); padding:5px 0 8px; } background:transparent; color:var(--dim); padding:5px 0 8px; }
.dashboard-tabs button.active { color:var(--accent); border-bottom-color:var(--accent); } .dashboard-tabs button.active { color:var(--accent); border-bottom-color:var(--accent); }
.wide { grid-column:1 / -1; } .wide { grid-column:1 / -1; }
/* Compact status cards fan out on desktop; tables remain readable at half width. */
@media (min-width:900px) {
main { grid-template-columns:repeat(4,minmax(0,1fr)); }
main > section { grid-column:span 1; }
.wide { grid-column:span 2; }
}
section[hidden] { display:none !important; } section[hidden] { display:none !important; }
section.chat-section { section.chat-section {
padding:0; border:0; border-radius:0; background:var(--bg); min-height:0; padding:0; border:0; border-radius:0; background:var(--bg); min-height:0;
@@ -215,7 +205,7 @@
.chat-compose button:disabled { opacity:.45; cursor:not-allowed; } .chat-compose button:disabled { opacity:.45; cursor:not-allowed; }
.console { .console {
background:var(--bg); border:1px solid var(--border); border-radius:6px; background:var(--bg); border:1px solid var(--border); border-radius:6px;
min-height:160px; max-height:520px; overflow-y:auto; overflow-x:auto; padding:7px 9px; min-height:160px; max-height:280px; overflow:auto; padding:7px 9px;
white-space:pre-wrap; word-break:break-word; font-size:11px; white-space:pre-wrap; word-break:break-word; font-size:11px;
} }
.console-line { padding:1px 0; border-bottom:1px solid #161b22; } .console-line { padding:1px 0; border-bottom:1px solid #161b22; }
@@ -298,8 +288,6 @@
<section data-tab="billing" data-admin-only><h2>Node pending payouts</h2><div id="pending" class="empty">admin login required</div></section> <section data-tab="billing" data-admin-only><h2>Node pending payouts</h2><div id="pending" class="empty">admin login required</div></section>
<section data-tab="billing" data-admin-only><h2>Settlement history</h2><div id="settlements" class="empty">admin login required</div></section> <section data-tab="billing" data-admin-only><h2>Settlement history</h2><div id="settlements" class="empty">admin login required</div></section>
<section data-tab="admin"><h2>Tracker hive</h2><div id="hive" class="empty">loading…</div></section> <section data-tab="admin"><h2>Tracker hive</h2><div id="hive" class="empty">loading…</div></section>
<section data-tab="admin" class="wide"><h2>Model placement</h2><div id="admin-model-placement-status" class="dim">Choose a model to load or release.</div><div id="admin-model-placement" class="empty">admin login required</div></section>
<section data-tab="admin" class="wide"><h2>Total node pool</h2><div id="admin-node-pool" class="empty">admin login required</div></section>
<section data-tab="admin" id="admin-section"><h2>All accounts (admin)</h2><div id="admin" class="empty"></div></section> <section data-tab="admin" id="admin-section"><h2>All accounts (admin)</h2><div id="admin" class="empty"></div></section>
<section data-tab="admin" data-admin-only><h2>Strikes / bans / forfeitures</h2><div id="fraud" class="empty">admin login required</div></section> <section data-tab="admin" data-admin-only><h2>Strikes / bans / forfeitures</h2><div id="fraud" class="empty">admin login required</div></section>
<section data-tab="admin"><h2>Client balances</h2><div id="clients" class="empty">admin login required</div></section> <section data-tab="admin"><h2>Client balances</h2><div id="clients" class="empty">admin login required</div></section>
@@ -327,16 +315,6 @@
<div id="testing-log" class="console empty">no test output yet</div> <div id="testing-log" class="console empty">no test output yet</div>
</section> </section>
</main> </main>
<dialog id="model-placement-dialog">
<form method="dialog">
<div id="model-placement-dialog-title"></div>
<label for="model-placement-node">Node</label>
<select id="model-placement-node"></select>
<label id="model-placement-replace" style="display:none"><input type="checkbox" id="model-placement-replace-confirm"> Unload the currently loaded model before loading this one</label>
<div id="model-placement-replace-error" class="bad" style="display:none"></div>
<div class="placement-dialog-actions"><button value="cancel">Cancel</button><button type="button" id="model-placement-confirm">Confirm</button></div>
</form>
</dialog>
<script> <script>
"use strict"; "use strict";
const $ = id => document.getElementById(id); const $ = id => document.getElementById(id);
@@ -1096,7 +1074,6 @@ function renderBillingUsage(records) {
} }
let consoleClearedAt = 0; let consoleClearedAt = 0;
const CONSOLE_MAX_LINES = 1000;
function clearConsole() { function clearConsole() {
consoleClearedAt = Date.now() / 1000; consoleClearedAt = Date.now() / 1000;
@@ -1110,7 +1087,7 @@ function renderConsole(data) {
$("console").innerHTML = '<div class="empty">no console events</div>'; $("console").innerHTML = '<div class="empty">no console events</div>';
return; return;
} }
$("console").innerHTML = events.slice(-CONSOLE_MAX_LINES).map(e => { $("console").innerHTML = events.slice(-120).map(e => {
const level = String(e.level || "info"); const level = String(e.level || "info");
const cls = level === "error" ? "console-level-error" : level === "warn" ? "console-level-warn" : "console-level-info"; const cls = level === "error" ? "console-level-error" : level === "warn" ? "console-level-warn" : "console-level-info";
const fields = e.fields && Object.keys(e.fields).length ? " " + JSON.stringify(e.fields) : ""; const fields = e.fields && Object.keys(e.fields).length ? " " + JSON.stringify(e.fields) : "";
@@ -1804,7 +1781,7 @@ async function requestSelectedModelLoad() {
if (!selectedChatModel) return; if (!selectedChatModel) return;
const button = $("request-model-load"); const button = $("request-model-load");
if (button) button.disabled = true; if (button) button.disabled = true;
const result = await apiCall("/v1/models/load", "POST", { model: selectedChatModel, force: isAdmin }); const result = await apiCall("/v1/models/load", "POST", { model: selectedChatModel });
if (button) button.disabled = false; if (button) button.disabled = false;
if (!result.ok) { if (!result.ok) {
alert(result.data.error || "model load request failed"); alert(result.data.error || "model load request failed");
@@ -1814,136 +1791,6 @@ async function requestSelectedModelLoad() {
$("chat-status").textContent = `load queued on ${short(assignment.node_id || "node")} for layers ${assignment.shard_start}-${assignment.shard_end}`; $("chat-status").textContent = `load queued on ${short(assignment.node_id || "node")} for layers ${assignment.shard_start}-${assignment.shard_end}`;
} }
async function requestAdminModelLoad(model, nodeId, replacing) {
const result = await apiCall("/v1/models/load", "POST", { model, node_id: nodeId, force: replacing });
if (!result.ok) return showAdminModelPlacementStatus(result.data.error || "model load request failed", true);
const assignment = result.data.assignment || {};
showAdminModelPlacementStatus(`Load queued on ${short(assignment.node_id || "node")} for ${model}.`);
await refreshActiveTab(true);
}
async function releaseAdminModel(model, nodeId) {
const result = await apiCall("/v1/models/release", "POST", { model, node_id: nodeId });
if (!result.ok) return showAdminModelPlacementStatus(result.data.error || "model release request failed", true);
showAdminModelPlacementStatus(`Release queued for ${result.data.released || 0} node(s) serving ${model}.`);
await refreshActiveTab(true);
}
async function releaseAllNodeModels(nodeId) {
if (!confirm("Unload every model from this node?")) return;
const result = await apiCall("/v1/nodes/release-all", "POST", { node_id: nodeId });
if (!result.ok) return showAdminModelPlacementStatus(result.data.error || "node unload failed", true);
showAdminModelPlacementStatus(`Unload queued for ${short(nodeId)}.`);
await refreshActiveTab(true);
}
function showAdminModelPlacementStatus(message, isError) {
const status = $("admin-model-placement-status");
status.textContent = message;
status.className = isError ? "bad" : "ok";
}
function gib(bytes) { return bytes == null ? "not reported" : `${(Number(bytes) / 1073741824).toFixed(1)} GiB`; }
function renderAdminNodePool(map) {
const groups = {};
for (const node of (map && map.nodes) || []) {
const account = node.wallet_address || "unbound account";
(groups[account] = groups[account] || []).push(node);
}
let html = "";
for (const [account, nodes] of Object.entries(groups).sort(([a], [b]) => a.localeCompare(b))) {
html += `<div style="margin-top:10px"><b>${esc(short(account, 20))}</b> <span class="dim">${nodes.length} node(s)</span></div>`;
html += table(["node", "assignment", "state / slots", "model RAM", "RAM", "GPU / VRAM", "model drive", "action"], nodes.map(node => {
const hw = node.hardware_profile || {};
const cap = node.capacity || {};
// The network map keeps reported resource capacity under `capacity`.
node.ram_bytes = cap.ram_bytes ?? node.ram_bytes;
node.vram_bytes = cap.vram_bytes ?? node.vram_bytes;
const disk = hw.model_drive_free_bytes ?? hw.model_path_free_bytes ?? hw.disk_free_bytes;
const gpu = hw.gpu_name || (hw.cuda_available ? "CUDA GPU" : "CPU only");
const row = [nodeDisplayCell(node), esc(node.hf_repo || node.model || "unassigned"),
esc(`${node.stats?.status || "?"} · ${cap.loaded_slots ?? "?"}/${cap.max_loaded_shards ?? node.max_loaded_shards ?? "?"} slots`),
esc(gib(cap.loaded_model_bytes)),
esc(gib(node.ram_bytes || (hw.ram_mb && hw.ram_mb * 1048576))),
esc(`${gpu} · ${gib(node.vram_bytes || (hw.vram_mb && hw.vram_mb * 1048576))}`), esc(gib(disk))];
return row.concat([
node.shard_start == null ? '<span class="dim">empty</span>' :
`<button class="small" data-admin-node-release="${esc(node.node_id)}">unload all</button>`,
]);
}));
}
$("admin-node-pool").innerHTML = html || '<div class="empty">no nodes registered</div>';
}
$("admin-node-pool").addEventListener("click", event => {
const unload = event.target.closest("[data-admin-node-release]");
if (unload) void releaseAllNodeModels(unload.dataset.adminNodeRelease);
});
function renderAdminModelPlacement(models, map) {
const nodes = (map && map.nodes) || [];
const rows = ((models && models.data) || []).map(model => {
const aliases = new Set([model.id, model.hf_repo, ...(model.aliases || [])].filter(Boolean));
const serving = nodes.filter(node => aliases.has(node.model) || aliases.has(node.hf_repo)).length;
const downloaded = nodes.filter(node => aliases.has(node.model) || aliases.has(node.hf_repo) ||
(node.downloaded_models || []).some(item => aliases.has(item.model) || aliases.has(item.hf_repo))).length;
const loadable = model.id !== "stub-model";
const actions = `<button class="small" data-admin-model-load="${esc(model.id)}"${loadable ? "" : " disabled"}>load</button> ` +
`<button class="small" data-admin-model-release="${esc(model.id)}"${serving ? "" : " disabled"}>release</button>`;
return [esc(model.name || model.id), String(serving), String(downloaded), actions];
});
$("admin-model-placement").innerHTML = rows.length
? table(["model", "serving nodes", "downloaded on nodes", "admin action"], rows)
: '<div class="empty">no model presets configured</div>';
}
$("admin-model-placement").addEventListener("click", event => {
const load = event.target.closest("[data-admin-model-load]");
const release = event.target.closest("[data-admin-model-release]");
if (load) void chooseModelPlacementNode("load", load.dataset.adminModelLoad);
if (release) void chooseModelPlacementNode("release", release.dataset.adminModelRelease);
});
function chooseModelPlacementNode(action, model) {
const dialog = $("model-placement-dialog");
const select = $("model-placement-node");
const targetAlias = modelAliasKey(model);
const nodes = (lastNetworkMap?.nodes || []).filter(node => action === "load" ||
modelAliasKey(node.model) === targetAlias || modelAliasKey(node.hf_repo) === targetAlias);
if (!nodes.length) return showAdminModelPlacementStatus(`No node can ${action} ${model}.`, true);
$("model-placement-dialog-title").textContent = `${action === "load" ? "Load" : "Release"} ${model} on a node`;
select.innerHTML = nodes.map(node => `<option value="${esc(node.node_id)}">${esc(short(node.friendly_name || node.node_id, 20))}${esc(node.hf_repo || node.model || "unassigned")}</option>`).join("");
const replace = $("model-placement-replace");
const replaceConfirm = $("model-placement-replace-confirm");
const replaceError = $("model-placement-replace-error");
const confirmButton = $("model-placement-confirm");
const selectedNode = () => nodes.find(node => node.node_id === select.value);
const updateReplacementWarning = () => {
const node = selectedNode();
const occupied = action === "load" && node && node.shard_start != null && node.shard_end != null &&
modelAliasKey(node.hf_repo || node.model) !== targetAlias;
replace.style.display = occupied ? "" : "none";
replaceConfirm.checked = false;
replaceError.style.display = "none";
};
select.onchange = updateReplacementWarning;
updateReplacementWarning();
dialog.onclose = null;
confirmButton.onclick = () => {
const replacing = replace.style.display !== "none";
if (replacing && !replaceConfirm.checked) {
replaceError.textContent = "Tick the box to confirm that this will unload the current model.";
replaceError.style.display = "";
return;
}
dialog.close("confirm");
if (action === "load") void requestAdminModelLoad(model, select.value, replacing);
else void releaseAdminModel(model, select.value);
};
dialog.showModal();
}
function chatAuthToken() { function chatAuthToken() {
if (accountApiKeys.length) return accountApiKeys[0]; if (accountApiKeys.length) return accountApiKeys[0];
return null; return null;
@@ -2580,19 +2427,14 @@ async function fetchAdminTab() {
fetchJson("/v1/console"), fetchJson("/v1/console"),
fetchJson("/v1/billing/summary"), fetchJson("/v1/billing/summary"),
fetchJson("/v1/registry/wallets"), fetchJson("/v1/registry/wallets"),
fetchJson("/v1/models"),
fetchJson("/v1/network/map"),
]; ];
if (isAdmin) fetches.push(apiCall("/v1/admin/accounts")); if (isAdmin) fetches.push(apiCall("/v1/admin/accounts"));
const results = await Promise.all(fetches); const results = await Promise.all(fetches);
const [raft, consoleData, summary, wallets, models, map, adminResp] = results; const [raft, consoleData, summary, wallets, adminResp] = results;
if (map) lastNetworkMap = map;
renderIfChanged("hive", raft, renderHive); renderIfChanged("hive", raft, renderHive);
renderIfChanged("console", consoleData, renderConsole); renderIfChanged("console", consoleData, renderConsole);
renderIfChanged("billing-summary", summary, data => renderBilling(data)); renderIfChanged("billing-summary", summary, data => renderBilling(data));
renderIfChanged("fraud", { wallets, summary }, data => renderFraud(data.wallets, data.summary)); renderIfChanged("fraud", { wallets, summary }, data => renderFraud(data.wallets, data.summary));
renderIfChanged("admin-model-placement", { models, map }, data => renderAdminModelPlacement(data.models, data.map));
renderIfChanged("admin-node-pool", map, renderAdminNodePool);
if (adminResp && adminResp.ok) { if (adminResp && adminResp.ok) {
renderIfChanged("admin", adminResp.data.accounts || [], accounts => { renderIfChanged("admin", adminResp.data.accounts || [], accounts => {
const rows = accounts.map(a => { const rows = accounts.map(a => {

View File

@@ -56,7 +56,6 @@ from .capability import (
DEFAULT_POLICY as DEFAULT_CAPABILITY_POLICY, DEFAULT_POLICY as DEFAULT_CAPABILITY_POLICY,
POLICY_COMPAT, POLICY_COMPAT,
POLICY_ENFORCE, POLICY_ENFORCE,
STATE_COMPATIBILITY_MISMATCH,
STATE_ABSENT, STATE_ABSENT,
STATE_ADMITTED, STATE_ADMITTED,
STATE_MODEL_MISMATCH, STATE_MODEL_MISMATCH,
@@ -87,7 +86,7 @@ from .model_files import files_for_layer_range, snapshot_dir_for_repo
from .raft import RaftNode from .raft import RaftNode
_CONSOLE_LIMIT = 1000 _CONSOLE_LIMIT = 300
_PROXY_PROGRESS_LOG_INTERVAL = 5.0 _PROXY_PROGRESS_LOG_INTERVAL = 5.0
_SESSION_COOKIE_NAME = "meshnet_session" _SESSION_COOKIE_NAME = "meshnet_session"
@@ -599,7 +598,6 @@ class _NodeEntry:
"model_tokens_per_sec", "model_tokens_per_sec",
"pending_directives", "last_heartbeat", "tracker_mode", "pending_directives", "last_heartbeat", "tracker_mode",
"relay_addr", "cert_fingerprint", "peer_id", "friendly_name", "relay_addr", "cert_fingerprint", "peer_id", "friendly_name",
"compatibility_fingerprint",
# heartbeat stats (reported by node, cumulative) # heartbeat stats (reported by node, cumulative)
"total_requests", "failed_requests", "queue_depth", "proxy_inflight", "uptime_seconds", "total_requests", "failed_requests", "queue_depth", "proxy_inflight", "uptime_seconds",
"current_requests", "current_requests",
@@ -638,7 +636,6 @@ class _NodeEntry:
cert_fingerprint: str | None = None, cert_fingerprint: str | None = None,
peer_id: str | None = None, peer_id: str | None = None,
friendly_name: str | None = None, friendly_name: str | None = None,
compatibility_fingerprint: str | None = None,
capability: "CapabilityState | None" = None, capability: "CapabilityState | None" = None,
) -> None: ) -> None:
self.node_id = node_id self.node_id = node_id
@@ -667,7 +664,6 @@ class _NodeEntry:
self.cert_fingerprint = cert_fingerprint self.cert_fingerprint = cert_fingerprint
self.peer_id = peer_id self.peer_id = peer_id
self.friendly_name = friendly_name self.friendly_name = friendly_name
self.compatibility_fingerprint = compatibility_fingerprint
# No proof presented is `absent`, never `admitted` — a node can only earn # No proof presented is `absent`, never `admitted` — a node can only earn
# `admitted` by presenting a report that covers what it advertises. # `admitted` by presenting a report that covers what it advertises.
self.capability: CapabilityState = capability or absent_state() self.capability: CapabilityState = capability or absent_state()
@@ -786,16 +782,6 @@ def _node_admission(node: "_NodeEntry") -> CapabilityState:
f"proof is for layers {state.shard_start}{state.shard_end}, but the " f"proof is for layers {state.shard_start}{state.shard_end}, but the "
f"node now serves layers {node.shard_start}{node.shard_end}", f"node now serves layers {node.shard_start}{node.shard_end}",
) )
if (
node.compatibility_fingerprint
and state.compatibility_fingerprint
and state.compatibility_fingerprint != node.compatibility_fingerprint
):
return state.with_state(
STATE_COMPATIBILITY_MISMATCH,
"proof compatibility fingerprint no longer matches the node's "
"declared artifact/runtime recipe",
)
return state return state
@@ -825,12 +811,6 @@ def _capability_from_registration(
declared_recipe_version=( declared_recipe_version=(
recipe_version if isinstance(recipe_version, str) else None recipe_version if isinstance(recipe_version, str) else None
), ),
declared_compatibility_fingerprint=(
value.strip()
if isinstance((value := payload.get("compatibility_fingerprint")), str)
and value.strip()
else None
),
) )
@@ -1121,15 +1101,12 @@ def _registration_quantization(body: dict, quantizations: list[str]) -> str | No
An absent field predates the protocol adding it: it means "unknown", not An absent field predates the protocol adding it: it means "unknown", not
"unsupported", so the node keeps the best precision it advertises and stays "unsupported", so the node keeps the best precision it advertises and stays
routable. An explicit "auto" means the same thing — the node's CLI default routable. Anything the node states explicitly is taken at its word -- a null,
delegates the choice, it does not refuse one. Anything else the node states a non-string, or an unsupported name leaves it with no usable precision and
explicitly is taken at its word -- a null, a non-string, or an unsupported routing excludes it.
name leaves it with no usable precision and routing excludes it.
""" """
declared = body.get("quantization") if "quantization" in body:
declared_auto = isinstance(declared, str) and declared.strip().lower() == "auto" return _normalize_quantization(body["quantization"])
if "quantization" in body and not declared_auto:
return _normalize_quantization(declared)
supported = [ supported = [
normalized for value in quantizations normalized for value in quantizations
if (normalized := _normalize_quantization(value)) is not None if (normalized := _normalize_quantization(value)) is not None
@@ -1248,7 +1225,6 @@ def _node_capacity_summary(node: _NodeEntry, preset: dict | None = None) -> dict
"quantization": node.quantization, "quantization": node.quantization,
"benchmark_tokens_per_sec": node.benchmark_tokens_per_sec, "benchmark_tokens_per_sec": node.benchmark_tokens_per_sec,
"effective_throughput": round(_effective_throughput(node), 4), "effective_throughput": round(_effective_throughput(node), 4),
"loaded_model_bytes": _assignment_memory_bytes(node, preset),
} }
if preset is not None: if preset is not None:
summary["max_assignable_layers"] = _node_layer_capacity(node, preset) summary["max_assignable_layers"] = _node_layer_capacity(node, preset)
@@ -1518,9 +1494,7 @@ def _scale_demanded_models_locked(server: "_TrackerHTTPServer") -> None:
break break
def _request_model_load_locked( def _request_model_load_locked(server: "_TrackerHTTPServer", model_key: str) -> dict | None:
server: "_TrackerHTTPServer", model_key: str, node_id: str | None = None,
) -> dict | None:
"""Queue an explicitly requested model on the best available joined node.""" """Queue an explicitly requested model on the best available joined node."""
resolved_name, preset = _resolve_model_preset(server.model_presets, model_key) resolved_name, preset = _resolve_model_preset(server.model_presets, model_key)
if preset is None or not preset.get("hf_repo"): if preset is None or not preset.get("hf_repo"):
@@ -1536,8 +1510,6 @@ def _request_model_load_locked(
continue continue
host_nodes = [server.registry[item["node_id"]] for item in host["loaded"] if item["node_id"] in server.registry] host_nodes = [server.registry[item["node_id"]] for item in host["loaded"] if item["node_id"] in server.registry]
placeable = [node for node in host_nodes if _has_usable_quantization(node)] placeable = [node for node in host_nodes if _has_usable_quantization(node)]
if node_id is not None:
placeable = [node for node in placeable if node.node_id == node_id]
if not placeable: if not placeable:
continue continue
anchor = max(placeable, key=lambda node: node.benchmark_tokens_per_sec) anchor = max(placeable, key=lambda node: node.benchmark_tokens_per_sec)
@@ -1556,68 +1528,6 @@ def _request_model_load_locked(
return None return None
def _force_model_load_locked(
server: "_TrackerHTTPServer", model_key: str, node_id: str | None = None,
) -> dict | None:
"""Replace the fastest ready assignment after an explicit admin eviction."""
resolved_name, preset = _resolve_model_preset(server.model_presets, model_key)
if preset is None or not preset.get("hf_repo"):
return None
start, end = _preset_layer_bounds(preset)
# An explicit admin eviction is permitted to recover a stuck/loading node
# and to use the preset default precision. It must only avoid a node that
# already has another assignment in flight.
candidates = [
node for node in server.registry.values()
if node.pending_new_assignment is None
and (node_id is None or node.node_id == node_id)
]
if not candidates:
return None
node = max(candidates, key=lambda item: item.benchmark_tokens_per_sec)
shard_end = min(end, start + max(1, min(_node_layer_capacity(node, preset), end - start + 1)) - 1)
quantization = _node_quantization(node, preset)
directive = _load_directive(node, str(preset["hf_repo"]), start, shard_end, quantization)
replaced = node.hf_repo or node.model
node.model, node.hf_repo = resolved_name, str(preset["hf_repo"])
node.shard_start, node.shard_end, node.quantization = start, shard_end, quantization
node.managed_assignment, node.pending_new_assignment = True, directive
node.pending_directives.append(directive)
_tracker_log(server, "warn", "model load forced", node_id=node.node_id,
model=resolved_name, replaced_model=replaced, shard=f"{start}-{shard_end}")
return {"node_id": node.node_id, "model": resolved_name, "hf_repo": preset["hf_repo"],
"shard_start": start, "shard_end": shard_end, "replaced_model": replaced}
def _release_model_locked(
server: "_TrackerHTTPServer", model_key: str, node_id: str | None = None,
) -> int:
"""Queue DROP_SHARD for every served shard and remove it from routing immediately."""
resolved_name, preset = _resolve_model_preset(server.model_presets, model_key)
if preset is None:
return 0
released = 0
for node in server.registry.values():
if node_id is not None and node.node_id != node_id:
continue
if not _node_matches_preset(node, resolved_name, preset) or node.shard_start is None or node.shard_end is None:
continue
node.pending_directives.append(_drop_directive(node, str(preset.get("hf_repo") or resolved_name), node.shard_start, node.shard_end, node.quantization or "bfloat16"))
node.status = "loading"
released += 1
return released
def _release_all_node_models_locked(server: "_TrackerHTTPServer", node_id: str) -> int:
"""Queue removal of every loaded assignment on one node."""
node = server.registry.get(node_id)
if node is None or node.shard_start is None or node.shard_end is None:
return 0
node.pending_directives.append({"action": "DROP_ALL_SHARDS"})
node.status = "loading"
return 1
def _preferred_node_quantization( def _preferred_node_quantization(
node: _NodeEntry, node: _NodeEntry,
preset: dict, preset: dict,
@@ -3133,12 +3043,6 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
if self.path == "/v1/models/load": if self.path == "/v1/models/load":
self._handle_model_load_request() self._handle_model_load_request()
return return
if self.path == "/v1/models/release":
self._handle_model_release_request()
return
if self.path == "/v1/nodes/release-all":
self._handle_node_release_all_request()
return
if self.path == "/v1/models/vote": if self.path == "/v1/models/vote":
self._handle_model_coverage_vote() self._handle_model_coverage_vote()
return return
@@ -3266,6 +3170,8 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
seen_ids: set[str] = set() seen_ids: set[str] = set()
for name, preset in server.model_presets.items(): for name, preset in server.model_presets.items():
model_nodes = [node for node in alive if _node_matches_preset(node, name, preset)] model_nodes = [node for node in alive if _node_matches_preset(node, name, preset)]
if not model_nodes and not preset.get("recommended"):
continue
required_start, required_end = _preset_layer_bounds(preset) required_start, required_end = _preset_layer_bounds(preset)
coverage = _coverage_percentage( coverage = _coverage_percentage(
model_nodes, model_nodes,
@@ -3315,12 +3221,7 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
node.hf_repo or node.model node.hf_repo or node.model
for node in alive for node in alive
if node.model is not None if node.model is not None
# The same model can be registered under its HF repository while and node.model not in server.model_presets
# the catalogue exposes its short preset id. Do not emit a second
# repo-keyed entry when either node identifier resolves to a preset.
and _resolve_model_preset(
server.model_presets, node.hf_repo or node.model,
)[1] is None
and node.shard_start is not None and node.shard_start is not None
and node.shard_end is not None and node.shard_end is not None
and node.num_layers is not None and node.num_layers is not None
@@ -3421,11 +3322,6 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
"endpoint": node.endpoint, "endpoint": node.endpoint,
"relay_addr": node.relay_addr, "relay_addr": node.relay_addr,
"peer_id": node.peer_id, "peer_id": node.peer_id,
"wallet_address": node.wallet_address,
"hardware_profile": dict(node.hardware_profile),
"ram_bytes": node.ram_bytes,
"vram_bytes": node.vram_bytes,
"max_loaded_shards": node.max_loaded_shards,
} }
for node in tracker_nodes for node in tracker_nodes
], ],
@@ -3449,7 +3345,12 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
memory_pool = _memory_pool_map(server) memory_pool = _memory_pool_map(server)
def capacity_for(node: _NodeEntry) -> dict: def capacity_for(node: _NodeEntry) -> dict:
return _node_capacity_summary(node, _preset_for_node(server, node)) preset = None
if node.model:
preset = server.model_presets.get(node.model)
if preset is None and node.hf_repo and node.num_layers:
preset = _hf_rebalance_preset([node])
return _node_capacity_summary(node, preset)
def throughput_for(node: _NodeEntry) -> dict: def throughput_for(node: _NodeEntry) -> dict:
if server.stats is None: if server.stats is None:
@@ -4643,13 +4544,6 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
relay_addr = body.get("relay_addr") or None relay_addr = body.get("relay_addr") or None
cert_fingerprint = body.get("cert_fingerprint") or None cert_fingerprint = body.get("cert_fingerprint") or None
peer_id = body.get("peer_id") or None peer_id = body.get("peer_id") or None
compatibility_fingerprint = body.get("compatibility_fingerprint")
if compatibility_fingerprint is not None and (
not isinstance(compatibility_fingerprint, str) or not compatibility_fingerprint.strip()
):
self._send_json(400, {"error": "compatibility_fingerprint must be a string"})
return
compatibility_fingerprint = compatibility_fingerprint.strip() if isinstance(compatibility_fingerprint, str) else None
try: try:
friendly_name = _normalize_friendly_name(body.get("friendly_name")) friendly_name = _normalize_friendly_name(body.get("friendly_name"))
except ValueError as exc: except ValueError as exc:
@@ -4709,7 +4603,6 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
cert_fingerprint=cert_fingerprint, cert_fingerprint=cert_fingerprint,
peer_id=peer_id, peer_id=peer_id,
friendly_name=friendly_name, friendly_name=friendly_name,
compatibility_fingerprint=compatibility_fingerprint,
capability=capability, capability=capability,
) )
with server.lock: with server.lock:
@@ -4867,20 +4760,6 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
entry.uptime_seconds = float(body["uptime_seconds"]) entry.uptime_seconds = float(body["uptime_seconds"])
if "status" in body and body["status"] in ("ready", "loading"): if "status" in body and body["status"] in ("ready", "loading"):
entry.status = body["status"] entry.status = body["status"]
completed_directives = body.get("completed_directives", [])
if isinstance(completed_directives, list):
for directive in completed_directives:
if not isinstance(directive, dict) or directive.get("action") not in {"DROP_SHARD", "DROP_ALL_SHARDS"}:
continue
# A node has confirmed the release. Stop advertising its
# old route immediately so the dashboard and routing state
# agree with the runtime.
entry.model = "stub-model"
entry.hf_repo = None
entry.shard_start = None
entry.shard_end = None
entry.tracker_mode = False
entry.status = "ready"
if "friendly_name" in body: if "friendly_name" in body:
try: try:
entry.friendly_name = _normalize_friendly_name(body.get("friendly_name")) entry.friendly_name = _normalize_friendly_name(body.get("friendly_name"))
@@ -4952,68 +4831,14 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
if not isinstance(model, str) or not model.strip(): if not isinstance(model, str) or not model.strip():
self._send_json(400, {"error": "model is required"}) self._send_json(400, {"error": "model is required"})
return return
node_id = body.get("node_id")
if node_id is not None and (not isinstance(node_id, str) or not node_id):
self._send_json(400, {"error": "node_id must be a non-empty string"})
return
_resolved_name, preset = _resolve_model_preset(server.model_presets, model)
if preset is None or str(preset.get("hf_repo") or "").strip().lower() == "stub-model":
self._send_json(400, {"error": "stub-model is a local test backend and cannot be loaded onto a node"})
return
with server.lock: with server.lock:
self._purge_expired_nodes() self._purge_expired_nodes()
assignment = _request_model_load_locked(server, model, node_id) assignment = _request_model_load_locked(server, model)
if assignment is None and body.get("force") is True:
assignment = _force_model_load_locked(server, model, node_id)
if assignment is None: if assignment is None:
self._send_json(409, {"error": "no ready joined node has an available model slot and sufficient capacity"}) self._send_json(409, {"error": "no ready joined node has an available model slot and sufficient capacity"})
return return
self._send_json(202, {"status": "queued", "assignment": assignment}) self._send_json(202, {"status": "queued", "assignment": assignment})
def _handle_model_release_request(self):
server: _TrackerHTTPServer = self.server # type: ignore[assignment]
if not self._require_role("admin", "validator"):
return
body = self._read_json_body()
if body is None:
return
model = body.get("model")
if not isinstance(model, str) or not model.strip():
self._send_json(400, {"error": "model is required"})
return
node_id = body.get("node_id")
if node_id is not None and (not isinstance(node_id, str) or not node_id):
self._send_json(400, {"error": "node_id must be a non-empty string"})
return
with server.lock:
self._purge_expired_nodes()
released = _release_model_locked(server, model, node_id)
if not released:
self._send_json(404, {"error": "no served shards found for model"})
return
self._send_json(202, {"status": "release_queued", "released": released})
def _handle_node_release_all_request(self):
server: _TrackerHTTPServer = self.server # type: ignore[assignment]
if not self._require_role("admin", "validator"):
return
body = self._read_json_body()
if body is None:
return
node_id = body.get("node_id")
if not isinstance(node_id, str) or not node_id:
self._send_json(400, {"error": "node_id must be a non-empty string"})
return
with server.lock:
self._purge_expired_nodes()
released = _release_all_node_models_locked(server, node_id)
if not released:
self._send_json(404, {"error": "no loaded models found for node"})
return
self._send_json(202, {
"status": "release_queued", "released": released, "node_id": node_id,
})
def _handle_model_coverage_vote(self): def _handle_model_coverage_vote(self):
"""Record a rolling wish-list signal for an unavailable precision.""" """Record a rolling wish-list signal for an unavailable precision."""
server: _TrackerHTTPServer = self.server # type: ignore[assignment] server: _TrackerHTTPServer = self.server # type: ignore[assignment]
@@ -7162,12 +6987,6 @@ class TrackerServer:
else None else None
), ),
friendly_name=_normalize_friendly_name(payload.get("friendly_name")), friendly_name=_normalize_friendly_name(payload.get("friendly_name")),
compatibility_fingerprint=(
value.strip()
if isinstance((value := payload.get("compatibility_fingerprint")), str)
and value.strip()
else None
),
# A replicated registration carries its proof: without this, a proven # A replicated registration carries its proof: without this, a proven
# node would be routable on the leader and dark on every follower. # node would be routable on the leader and dark on every follower.
capability=_capability_from_registration( capability=_capability_from_registration(

View File

@@ -1,488 +0,0 @@
"""Architecture-defined boundary input/output and dense-Llama parity (DGR-006).
These tests prove the boundary contract with a *pure-numpy* dense-Llama reference
model: no download, no GPU, no torch, no API credit. The reference implements the
same ``ShardComputation`` duck type the real llama.cpp/PyTorch backends expose, so
whole-model execution and a two-range (or three-range) split are the exact same
arithmetic applied to the exact same float32 residual stream. Splitting the layer
stack at a seam and shipping the *unnormalized* residual bundle across a simulated
process boundary must reproduce the whole-model tokens bit-for-bit.
"""
from __future__ import annotations
import numpy as np
import pytest
from meshnet_node.boundary_adapter import (
BOUNDARY_SCHEMA_VERSION,
BoundaryAdapter,
BoundaryBundle,
BoundaryContractError,
SamplingContract,
ShardRole,
TailOutput,
UncertifiedArchitectureError,
certified_architecture,
is_certified_architecture,
role_for_range,
)
# Documented parity tolerance. The split path applies the identical layer
# functions in the identical order to the identical float32 arrays, so the
# residual seam is bit-exact in practice; the tolerance is a conservative guard.
PARITY_ATOL = 1e-6
# --------------------------------------------------------------------------- #
# Pure-numpy dense-Llama reference model (test fixture, not production).
# --------------------------------------------------------------------------- #
class _ReferenceDenseLlama:
"""A tiny deterministic dense-Llama: RMSNorm, RoPE attention, SwiGLU MLP."""
architecture_adapter = "dense-llama"
def __init__(
self,
*,
vocab: int = 48,
hidden: int = 32,
n_layers: int = 6,
n_heads: int = 4,
intermediate: int = 64,
rms_eps: float = 1e-6,
rope_theta: float = 10000.0,
seed: int = 20260715,
) -> None:
assert hidden % n_heads == 0
self.vocab = vocab
self.hidden = hidden
self.n_layers = n_layers
self.n_heads = n_heads
self.head_dim = hidden // n_heads
assert self.head_dim % 2 == 0
self.rms_eps = rms_eps
self.rope_theta = rope_theta
rng = np.random.default_rng(seed)
def w(*shape: int) -> np.ndarray:
return (rng.standard_normal(shape) * 0.08).astype(np.float32)
self.embed = w(vocab, hidden)
self.layers = []
for _ in range(n_layers):
self.layers.append(
{
"in_ln": (1.0 + rng.standard_normal(hidden) * 0.02).astype(np.float32),
"q": w(hidden, hidden),
"k": w(hidden, hidden),
"v": w(hidden, hidden),
"o": w(hidden, hidden),
"post_ln": (1.0 + rng.standard_normal(hidden) * 0.02).astype(np.float32),
"gate": w(intermediate, hidden),
"up": w(intermediate, hidden),
"down": w(hidden, intermediate),
}
)
self.final_ln = (1.0 + rng.standard_normal(hidden) * 0.02).astype(np.float32)
self.lm_head_w = w(vocab, hidden)
inv_freq = 1.0 / (
rope_theta ** (np.arange(0, self.head_dim, 2, dtype=np.float32) / self.head_dim)
)
self.inv_freq = inv_freq.astype(np.float32)
# -- primitive ops -----------------------------------------------------
def _rmsnorm(self, x: np.ndarray, weight: np.ndarray) -> np.ndarray:
variance = np.mean(x.astype(np.float32) ** 2, axis=-1, keepdims=True)
normed = x / np.sqrt(variance + self.rms_eps)
return (normed * weight).astype(np.float32)
def _rope(self, positions: np.ndarray):
# positions: (batch, seq) -> cos/sin: (batch, seq, head_dim)
angles = positions[..., None].astype(np.float32) * self.inv_freq[None, None, :]
emb = np.concatenate([angles, angles], axis=-1)
return np.cos(emb).astype(np.float32), np.sin(emb).astype(np.float32)
@staticmethod
def _rotate_half(x: np.ndarray) -> np.ndarray:
half = x.shape[-1] // 2
return np.concatenate([-x[..., half:], x[..., :half]], axis=-1)
def _apply_rope(self, t: np.ndarray, cos: np.ndarray, sin: np.ndarray) -> np.ndarray:
# t: (batch, n_heads, seq, head_dim); cos/sin: (batch, seq, head_dim)
cos = cos[:, None, :, :]
sin = sin[:, None, :, :]
return t * cos + self._rotate_half(t) * sin
def _attention(self, x: np.ndarray, layer: dict, positions: np.ndarray) -> np.ndarray:
batch, seq, _ = x.shape
q = (x @ layer["q"].T).reshape(batch, seq, self.n_heads, self.head_dim)
k = (x @ layer["k"].T).reshape(batch, seq, self.n_heads, self.head_dim)
v = (x @ layer["v"].T).reshape(batch, seq, self.n_heads, self.head_dim)
q = q.transpose(0, 2, 1, 3)
k = k.transpose(0, 2, 1, 3)
v = v.transpose(0, 2, 1, 3)
cos, sin = self._rope(positions)
q = self._apply_rope(q, cos, sin)
k = self._apply_rope(k, cos, sin)
scores = (q @ k.transpose(0, 1, 3, 2)) / np.sqrt(self.head_dim)
causal = np.triu(np.full((seq, seq), -1e30, dtype=np.float32), k=1)
scores = scores + causal[None, None, :, :]
scores = scores - scores.max(axis=-1, keepdims=True)
weights = np.exp(scores)
weights = weights / weights.sum(axis=-1, keepdims=True)
out = weights @ v
out = out.transpose(0, 2, 1, 3).reshape(batch, seq, self.hidden)
return (out @ layer["o"].T).astype(np.float32)
def _mlp(self, x: np.ndarray, layer: dict) -> np.ndarray:
gate = x @ layer["gate"].T
up = x @ layer["up"].T
silu = gate * (1.0 / (1.0 + np.exp(-gate)))
return ((silu * up) @ layer["down"].T).astype(np.float32)
def _run_layer(self, x: np.ndarray, layer: dict, positions: np.ndarray) -> np.ndarray:
h = x + self._attention(self._rmsnorm(x, layer["in_ln"]), layer, positions)
h = h + self._mlp(self._rmsnorm(h, layer["post_ln"]), layer)
return h.astype(np.float32)
class _ReferenceShard:
"""A contiguous inclusive layer range of the reference model.
Satisfies the ``ShardComputation`` duck type used by ``BoundaryAdapter``.
"""
def __init__(
self,
model: _ReferenceDenseLlama,
start_layer: int,
end_layer: int,
*,
architecture_adapter: str | None = None,
) -> None:
self._model = model
self.start_layer = start_layer
self.end_layer = end_layer
self.total_layers = model.n_layers
self.architecture_adapter = architecture_adapter or model.architecture_adapter
def embed_tokens(self, token_ids: np.ndarray) -> np.ndarray:
return self._model.embed[np.asarray(token_ids)]
def run_layers(self, hidden: np.ndarray, *, positions: np.ndarray) -> np.ndarray:
h = np.asarray(hidden, dtype=np.float32)
for idx in range(self.start_layer, self.end_layer + 1):
h = self._model._run_layer(h, self._model.layers[idx], positions)
return h
def final_norm(self, hidden: np.ndarray) -> np.ndarray:
return self._model._rmsnorm(np.asarray(hidden, dtype=np.float32), self._model.final_ln)
def lm_head(self, hidden: np.ndarray) -> np.ndarray:
return np.asarray(hidden, dtype=np.float32) @ self._model.lm_head_w.T
# --------------------------------------------------------------------------- #
# Whole-model and split reference drivers.
# --------------------------------------------------------------------------- #
def _whole_model_next_token(model: _ReferenceDenseLlama, token_ids: list[int]) -> TailOutput:
shard = _ReferenceShard(model, 0, model.n_layers - 1)
adapter = BoundaryAdapter(shard)
result = adapter.forward(token_ids=np.asarray(token_ids)[None, :])
assert isinstance(result, TailOutput)
return result
def _split_next_token(
model: _ReferenceDenseLlama,
token_ids: list[int],
cut_points: list[int],
*,
through_wire: bool = True,
) -> TailOutput:
"""Run the model as N contiguous ranges, shipping the bundle across each seam.
``cut_points`` are the last (inclusive) layer of each non-final range.
"""
bounds = _ranges_from_cuts(cut_points, model.n_layers)
boundary: BoundaryBundle | None = None
result: BoundaryBundle | TailOutput | None = None
for i, (start, end) in enumerate(bounds):
shard = _ReferenceShard(model, start, end)
adapter = BoundaryAdapter(shard)
if i == 0:
result = adapter.forward(token_ids=np.asarray(token_ids)[None, :])
else:
assert isinstance(boundary, BoundaryBundle)
incoming = BoundaryBundle.unpack(boundary.pack()) if through_wire else boundary
result = adapter.forward(boundary=incoming)
if isinstance(result, BoundaryBundle):
boundary = result
assert isinstance(result, TailOutput)
return result
def _ranges_from_cuts(cut_points: list[int], n_layers: int) -> list[tuple[int, int]]:
bounds: list[tuple[int, int]] = []
start = 0
for cut in cut_points:
bounds.append((start, cut))
start = cut + 1
bounds.append((start, n_layers - 1))
return bounds
def _greedy_generate(next_token_fn, prompt: list[int], n_new: int) -> list[int]:
tokens = list(prompt)
generated: list[int] = []
for _ in range(n_new):
out = next_token_fn(tokens)
tokens.append(out.token_id)
generated.append(out.token_id)
return generated
# --------------------------------------------------------------------------- #
# Certification / fail-closed.
# --------------------------------------------------------------------------- #
def test_dense_llama_and_aliases_are_certified():
"Dense Llama-family identifiers all resolve to the one certified adapter.\n\nTags: node, boundary"
for name in ("dense-llama", "llama", "LlamaForCausalLM", "LlamaModel"):
boundary = certified_architecture(name)
assert boundary.adapter == "dense-llama"
assert boundary.boundary_tensor_name == "residual_stream"
assert is_certified_architecture(name)
@pytest.mark.parametrize("name", ["qwen3", "qwen3-moe", "mixtral", "gpt2", "", None, 123])
def test_uncertified_architectures_fail_closed(name):
"Uncertified architectures raise instead of guessing a tensor layout.\n\nTags: node, boundary"
assert not is_certified_architecture(name)
with pytest.raises(UncertifiedArchitectureError):
certified_architecture(name)
def test_adapter_construction_fails_closed_for_uncertified_backend():
"Building the adapter over an uncertified computation fails closed.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
shard = _ReferenceShard(model, 0, 2, architecture_adapter="qwen3-moe")
with pytest.raises(UncertifiedArchitectureError):
BoundaryAdapter(shard)
# --------------------------------------------------------------------------- #
# Roles.
# --------------------------------------------------------------------------- #
def test_role_classification():
"Range endpoints map to head/middle/tail/full roles.\n\nTags: node, boundary"
assert role_for_range(0, 2, 6) is ShardRole.HEAD
assert role_for_range(2, 3, 6) is ShardRole.MIDDLE
assert role_for_range(4, 5, 6) is ShardRole.TAIL
assert role_for_range(0, 5, 6) is ShardRole.FULL
assert ShardRole.HEAD.owns_embedding and not ShardRole.HEAD.owns_final_head
assert ShardRole.TAIL.owns_final_head and not ShardRole.TAIL.owns_embedding
# --------------------------------------------------------------------------- #
# Input-side contract.
# --------------------------------------------------------------------------- #
def test_head_accepts_token_ids_and_owns_embedding():
"The head embeds token IDs and refuses an upstream boundary bundle.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
head = BoundaryAdapter(_ReferenceShard(model, 0, 2))
out = head.forward(token_ids=[1, 2, 3])
assert isinstance(out, BoundaryBundle)
# Head owns embedding: a residual bundle from upstream is a contract error.
bundle = out
with pytest.raises(BoundaryContractError, match="head owns token embedding"):
head.forward(boundary=bundle)
def test_middle_and_tail_bypass_embedding_and_require_the_bundle():
"Middle/tail Shards reject token IDs and demand the named boundary bundle.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
tail = BoundaryAdapter(_ReferenceShard(model, 3, 5))
with pytest.raises(BoundaryContractError, match="bypass token embedding"):
tail.forward(token_ids=[1, 2, 3])
with pytest.raises(BoundaryContractError, match="must receive the named boundary bundle"):
tail.forward()
def test_boundary_seam_layer_mismatch_is_rejected():
"A bundle handed to the wrong range (seam layer mismatch) is rejected.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
head = BoundaryAdapter(_ReferenceShard(model, 0, 2))
bundle = head.forward(token_ids=[1, 2, 3])
assert isinstance(bundle, BoundaryBundle)
assert bundle.next_layer == 3
# A range that starts at layer 4 must not accept a bundle cut at layer 3.
wrong = BoundaryAdapter(_ReferenceShard(model, 4, 5))
with pytest.raises(BoundaryContractError, match="starts at layer 4"):
wrong.forward(boundary=bundle)
def test_normalized_bundle_is_rejected():
"A normalized residual is not the architecture-defined boundary.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
head = BoundaryAdapter(_ReferenceShard(model, 0, 2))
bundle = head.forward(token_ids=[1, 2, 3])
assert isinstance(bundle, BoundaryBundle)
normalized = BoundaryBundle(
architecture_adapter=bundle.architecture_adapter,
schema_version=bundle.schema_version,
tensor_name=bundle.tensor_name,
residual=bundle.residual,
positions=bundle.positions,
next_layer=bundle.next_layer,
normalized=True,
)
tail = BoundaryAdapter(_ReferenceShard(model, 3, 5))
with pytest.raises(BoundaryContractError, match="UNNORMALIZED"):
tail.forward(boundary=normalized)
# --------------------------------------------------------------------------- #
# Output-side contract.
# --------------------------------------------------------------------------- #
def test_non_tail_emits_unnormalized_full_row_boundary():
"A non-tail Shard emits the unnormalized residual with every position row.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
tokens = [3, 7, 1, 9, 2]
head = BoundaryAdapter(_ReferenceShard(model, 0, 2))
bundle = head.forward(token_ids=tokens)
assert isinstance(bundle, BoundaryBundle)
assert bundle.normalized is False
assert bundle.tensor_name == "residual_stream"
assert bundle.schema_version == BOUNDARY_SCHEMA_VERSION
assert bundle.next_layer == 3
# No tail-only row pruning: all sequence positions are forwarded.
assert bundle.residual.shape == (1, len(tokens), model.hidden)
assert bundle.positions.shape == (1, len(tokens))
# The emitted residual must be exactly the whole model's residual after layer 2
# (i.e. before any final norm) — prove it is NOT normalized.
positions = np.arange(len(tokens))[None, :]
hidden = model.embed[np.asarray(tokens)][None, :]
for idx in range(0, 3):
hidden = model._run_layer(hidden, model.layers[idx], positions)
assert np.allclose(bundle.residual, hidden, atol=0)
assert not np.allclose(bundle.residual, model._rmsnorm(hidden, model.final_ln))
def test_tail_emits_pruned_logits_through_the_sampling_contract():
"The tail prunes to the final row and samples through an explicit contract.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
out = _whole_model_next_token(model, [4, 8, 15, 16, 23])
assert isinstance(out, TailOutput)
assert out.logits.shape == (1, model.vocab) # tail-only row pruning to last row
assert out.sampling.mode == "greedy"
assert 0 <= out.token_id < model.vocab
assert out.token_id == int(np.argmax(out.logits[0]))
def test_sampling_contract_rejects_uncertified_modes():
"Only the certified greedy sampling mode is accepted.\n\nTags: node, boundary"
with pytest.raises(BoundaryContractError):
SamplingContract(mode="top_p")
# --------------------------------------------------------------------------- #
# The core parity gate.
# --------------------------------------------------------------------------- #
def test_two_range_prefill_parity_matches_whole_model():
"Whole-model vs two-range prefill produce the same next-token logits and token.\n\nTags: node, boundary, parity"
model = _ReferenceDenseLlama()
prompt = [5, 12, 3, 41, 7, 19, 2, 33]
whole = _whole_model_next_token(model, prompt)
split = _split_next_token(model, prompt, cut_points=[2])
assert np.allclose(whole.logits, split.logits, atol=PARITY_ATOL)
assert whole.token_id == split.token_id
def test_three_range_prefill_parity_exercises_the_middle_role():
"A head/middle/tail split reproduces whole-model prefill through two seams.\n\nTags: node, boundary, parity"
model = _ReferenceDenseLlama()
prompt = [9, 1, 44, 6, 30, 11]
whole = _whole_model_next_token(model, prompt)
split = _split_next_token(model, prompt, cut_points=[1, 3])
assert np.allclose(whole.logits, split.logits, atol=PARITY_ATOL)
assert whole.token_id == split.token_id
def test_two_range_greedy_decode_parity_matches_whole_model():
"Whole-model vs two-range greedy decode produce identical token sequences.\n\nTags: node, boundary, parity"
model = _ReferenceDenseLlama()
prompt = [2, 17, 8, 25]
n_new = 12
whole_tokens = _greedy_generate(
lambda toks: _whole_model_next_token(model, toks), prompt, n_new
)
split_tokens = _greedy_generate(
lambda toks: _split_next_token(model, toks, cut_points=[2]), prompt, n_new
)
assert whole_tokens == split_tokens
assert len(whole_tokens) == n_new
def test_boundary_bundle_wire_round_trip_is_exact():
"Packing and unpacking the boundary bundle reconstructs the exact arrays.\n\nTags: node, boundary"
model = _ReferenceDenseLlama()
head = BoundaryAdapter(_ReferenceShard(model, 0, 2))
bundle = head.forward(token_ids=[1, 2, 3, 4])
assert isinstance(bundle, BoundaryBundle)
restored = BoundaryBundle.unpack(bundle.pack())
assert np.array_equal(restored.residual, bundle.residual)
assert np.array_equal(restored.positions, bundle.positions)
assert restored.next_layer == bundle.next_layer
assert restored.architecture_adapter == bundle.architecture_adapter
fields = bundle.named_tensor_fields()
assert fields["name"] == "residual_stream"
assert fields["shape"] == [1, 4, model.hidden]
assert fields["byte_order"] in ("little", "big")
def test_alias_architecture_still_parity_matches():
"A Shard advertised as 'llama' interoperates with the canonical adapter.\n\nTags: node, boundary, parity"
model = _ReferenceDenseLlama()
prompt = [7, 3, 22, 5]
whole = _whole_model_next_token(model, prompt)
# Head advertises 'LlamaForCausalLM', tail advertises 'llama'; both certify to
# the same canonical adapter, so the seam contract still matches.
head = BoundaryAdapter(_ReferenceShard(model, 0, 2, architecture_adapter="LlamaForCausalLM"))
bundle = head.forward(token_ids=np.asarray(prompt)[None, :])
assert isinstance(bundle, BoundaryBundle)
tail = BoundaryAdapter(_ReferenceShard(model, 3, 5, architecture_adapter="llama"))
split = tail.forward(boundary=BoundaryBundle.unpack(bundle.pack()))
assert isinstance(split, TailOutput)
assert np.allclose(whole.logits, split.logits, atol=PARITY_ATOL)
assert whole.token_id == split.token_id

View File

@@ -39,14 +39,9 @@ def test_dashboard_served_with_all_panels():
assert "resolveModelGroup" in html assert "resolveModelGroup" in html
assert "buildModelAliasMap" in html assert "buildModelAliasMap" in html
assert "modelAliasKey(raw)" in html assert "modelAliasKey(raw)" in html
assert "@media (min-width:900px)" in html assert "main { display:grid; grid-template-columns:repeat(auto-fit,minmax(340px,1fr));" in html
assert "grid-template-columns:repeat(4,minmax(0,1fr));" in html
assert ".wide { grid-column:span 2; }" in html
assert 'onclick="clearConsole()"' in html assert 'onclick="clearConsole()"' in html
assert "let consoleClearedAt = 0;" in html assert "let consoleClearedAt = 0;" in html
assert "max-height:520px; overflow-y:auto; overflow-x:auto;" in html
assert "const CONSOLE_MAX_LINES = 1000;" in html
assert "events.slice(-CONSOLE_MAX_LINES)" in html
finally: finally:
tracker.stop() tracker.stop()
@@ -105,39 +100,6 @@ def test_dashboard_allows_admin_to_request_selected_model_load():
assert '$("request-model-load").style.display = enabled ? "" : "none"' in html assert '$("request-model-load").style.display = enabled ? "" : "none"' in html
def test_dashboard_exposes_admin_model_inventory_and_release_controls():
"Admin placement controls show the full model inventory and can release capacity."
html = _dashboard_html()
assert 'id="admin-model-placement"' in html
assert "renderAdminModelPlacement" in html
assert '"/v1/models/release"' in html
assert "requestAdminModelLoad" in html
assert "releaseAdminModel" in html
assert 'data-admin-model-load=' in html
assert 'data-admin-model-release=' in html
assert "admin-model-placement-status" in html
assert 'id="admin-node-pool"' in html
assert "renderAdminNodePool" in html
assert "model drive" in html
# RAM and VRAM live in the network-map capacity object, not at node top level.
assert "node.ram_bytes = cap.ram_bytes" in html
assert "node.vram_bytes = cap.vram_bytes" in html
assert 'id="model-placement-dialog"' in html
assert "chooseModelPlacementNode" in html
assert "node_id: nodeId" in html
assert "modelAliasKey(node.model)" in html
assert 'id="model-placement-replace"' in html
assert 'id="model-placement-confirm"' in html
assert 'id="model-placement-replace-error"' in html
assert "force: replacing" in html
assert "Tick the box to confirm" in html
assert "releaseAllNodeModels" in html
assert '"/v1/nodes/release-all"' in html
assert "model RAM" in html
assert "loaded_model_bytes" in html
def test_network_map_includes_node_friendly_name(): def test_network_map_includes_node_friendly_name():
"Network map includes node friendly name\n\nTags: dashboard, http" "Network map includes node friendly name\n\nTags: dashboard, http"
tracker = TrackerServer() tracker = TrackerServer()

View File

@@ -355,75 +355,6 @@ def test_admin_model_load_request_queues_directive_on_joined_node():
assert heartbeat["directives"][0]["model"] == "Qwen/Qwen2.5-0.5B-Instruct" assert heartbeat["directives"][0]["model"] == "Qwen/Qwen2.5-0.5B-Instruct"
def test_admin_can_replace_a_served_model_and_release_it():
"Forced admin placement replaces a served shard; release queues DROP_SHARD."
tracker = TrackerServer(enable_billing=False, validator_service_token="test-admin")
port = tracker.start()
try:
node = _post_json(
f"http://127.0.0.1:{port}/v1/nodes/register",
{"endpoint": "http://127.0.0.1:9912", "model": "stub-model",
"shard_start": 0, "shard_end": 3, "managed_assignment": True,
"max_loaded_shards": 1, "memory_mb": 1,
"hardware_profile": {"host_id": "full-host"}},
)
headers = {"Content-Type": "application/json", "Authorization": "Bearer test-admin"}
load = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/models/load",
data=json.dumps({
"model": "qwen2.5-0.5b-instruct",
"node_id": node["node_id"],
"force": True,
}).encode(),
headers=headers, method="POST")
with urllib.request.urlopen(load) as response:
assert json.loads(response.read())["assignment"]["node_id"] == node["node_id"]
heartbeat = _post_json(f"http://127.0.0.1:{port}/v1/nodes/{node['node_id']}/heartbeat", {})
_post_json(
f"http://127.0.0.1:{port}/v1/nodes/{node['node_id']}/heartbeat",
{"completed_directives": [{"action": "DROP_SHARD", "model": "Qwen/Qwen2.5-0.5B-Instruct"}]},
)
network = _get_json(f"http://127.0.0.1:{port}/v1/network/map")
assert heartbeat["directives"][0]["action"] == "LOAD_SHARD"
release = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/models/release",
data=json.dumps({"model": "qwen2.5-0.5b-instruct"}).encode(), headers=headers, method="POST")
with urllib.request.urlopen(release) as response:
assert json.loads(response.read())["released"] == 1
heartbeat = _post_json(f"http://127.0.0.1:{port}/v1/nodes/{node['node_id']}/heartbeat", {})
finally:
tracker.stop()
assert heartbeat["directives"][0]["action"] == "DROP_SHARD"
released_node = next(item for item in network["nodes"] if item["node_id"] == node["node_id"])
assert released_node["shard_start"] is None
assert released_node["shard_end"] is None
def test_models_list_does_not_duplicate_a_preset_registered_by_hf_repo():
"""A preset and its canonical repository are one selectable model."""
tracker = TrackerServer(enable_billing=False)
port = tracker.start()
try:
_post_json(
f"http://127.0.0.1:{port}/v1/nodes/register",
{
"endpoint": "http://127.0.0.1:9913",
"model": "Qwen2.5-0.5B-Instruct",
"hf_repo": "Qwen/Qwen2.5-0.5B-Instruct",
"num_layers": 24,
"shard_start": 0,
"shard_end": 23,
},
)
models = _get_json(f"http://127.0.0.1:{port}/v1/models")["data"]
finally:
tracker.stop()
assert [model["id"] for model in models].count("qwen2.5-0.5b-instruct") == 1
assert not any(model["id"] == "Qwen/Qwen2.5-0.5B-Instruct" for model in models)
def test_endpoint_key_distinguishes_same_port_different_hosts(): def test_endpoint_key_distinguishes_same_port_different_hosts():
"Endpoint key distinguishes same port different hosts\n\nTags: http, performance, routing, tracker" "Endpoint key distinguishes same port different hosts\n\nTags: http, performance, routing, tracker"
from meshnet_node.torch_server import _clamp_downstream_hops, _endpoint_key from meshnet_node.torch_server import _clamp_downstream_hops, _endpoint_key

View File

@@ -1,186 +0,0 @@
"""Tests for the GGUF backend adapter and recipe-gated startup seam."""
from __future__ import annotations
from types import SimpleNamespace
from meshnet_node.gguf_backend import GgufNodeBackend, build_gguf_backend
from meshnet_node.model_backend import TailTokenResult, TensorPayload
from meshnet_node.recipe_manifest import DEFAULT_RECIPE_ID, load_recipe_manifest
from meshnet_node.startup import _gguf_backend_for_recipe
class _RecordingTransport:
def __init__(self) -> None:
self.calls: list[tuple[str, tuple, dict]] = []
def encode_prompt(self, prompt: str, session_id: str | None = None):
self.calls.append(("encode_prompt", (prompt, session_id), {}))
return TensorPayload(
body=b"\x00" * 16,
shape=[1, 2, 4],
attention_mask_header=None,
position_ids_header=None,
)
def encode_next_token(self, token_id: int, session_id: str):
self.calls.append(("encode_next_token", (token_id, session_id), {}))
return TensorPayload(
body=b"\x00" * 8,
shape=[1, 1, 4],
attention_mask_header=None,
position_ids_header=None,
past_len=2,
)
def forward_bytes(
self,
body: bytes,
shape: list[int],
attention_mask_header: str | None,
position_ids_header: str | None,
*,
start_layer: int | None = None,
session_id: str | None = None,
cache_mode: str | None = None,
past_len: int | None = None,
):
self.calls.append(
(
"forward_bytes",
(body, tuple(shape), attention_mask_header, position_ids_header),
{
"start_layer": start_layer,
"session_id": session_id,
"cache_mode": cache_mode,
"past_len": past_len,
},
)
)
if cache_mode == "decode":
return TailTokenResult(text=" done", token_id=17)
return TensorPayload(
body=b"\x00" * 16,
shape=[1, 2, 4],
attention_mask_header=attention_mask_header,
position_ids_header=position_ids_header,
past_len=past_len,
)
def decode_tail_token(self, hidden_states):
self.calls.append(("decode_tail_token", (hidden_states.shape,), {}))
return TailTokenResult(text=" tail", token_id=19)
def generate_text(self, messages, max_new_tokens=5120, temperature=1.0, top_p=1.0):
self.calls.append(("generate_text", (tuple(messages), max_new_tokens, temperature, top_p), {}))
return "ok"
def generate_text_streaming(self, messages, max_new_tokens=5120, temperature=1.0, top_p=1.0):
self.calls.append(("generate_text_streaming", (tuple(messages), max_new_tokens, temperature, top_p), {}))
yield "ok"
def count_prompt_tokens(self, messages):
self.calls.append(("count_prompt_tokens", (tuple(messages),), {}))
return 3
def count_text_tokens(self, text):
self.calls.append(("count_text_tokens", (text,), {}))
return 2
def eos_token_ids(self):
self.calls.append(("eos_token_ids", (), {}))
return [19]
def release_session(self, session_id: str) -> None:
self.calls.append(("release_session", (session_id,), {}))
def test_build_gguf_backend_delegates_to_transport():
transport = _RecordingTransport()
backend = build_gguf_backend(
model_id="meshnet/native-model",
shard_start=0,
shard_end=1,
quantization="bfloat16",
transport=transport,
total_layers=2,
device_type="cpu",
)
assert isinstance(backend, GgufNodeBackend)
assert backend.backend_id == "llama.cpp"
assert backend.is_head is True
assert backend.is_tail is True
assert backend.model.config.to_dict()["architecture_adapter"] == "dense-llama"
assert backend.loaded_tensor_names[0] == "blk.0.weight"
prompt = backend.encode_prompt("hello", session_id="session-1")
assert prompt.shape == [1, 2, 4]
decode = backend.forward_bytes(
b"\x00" * 16,
[1, 2, 4],
None,
None,
session_id="session-1",
cache_mode="decode",
past_len=2,
)
assert isinstance(decode, TailTokenResult)
assert decode.token_id == 17
backend.release_session("session-1")
assert [call[0] for call in transport.calls] == [
"encode_prompt",
"forward_bytes",
"release_session",
]
assert transport.calls[0][1] == ("hello", "session-1")
assert transport.calls[1][2]["cache_mode"] == "decode"
assert transport.calls[1][2]["past_len"] == 2
def test_recipe_gates_native_backend_selection(monkeypatch):
manifest = load_recipe_manifest()
torch_recipe = manifest.require(DEFAULT_RECIPE_ID)
native_recipe = manifest.require("llama-cpp-native")
sentinel_backend = object()
calls: list[dict] = []
def fake_build_gguf_backend(**kwargs):
calls.append(kwargs)
return sentinel_backend
monkeypatch.setattr(
"meshnet_node.startup.build_gguf_backend",
fake_build_gguf_backend,
)
assert _gguf_backend_for_recipe(
torch_recipe,
model_id="meshnet/native-model",
shard_start=0,
shard_end=1,
quantization="bfloat16",
total_layers=2,
device="cpu",
) is None
backend = _gguf_backend_for_recipe(
native_recipe,
model_id="meshnet/native-model",
shard_start=0,
shard_end=1,
quantization="bfloat16",
total_layers=2,
device="cpu",
)
assert backend is sentinel_backend
assert calls[0]["model_id"] == "meshnet/native-model"
assert calls[0]["shard_start"] == 0
assert calls[0]["shard_end"] == 1
assert calls[0]["quantization"] == "bfloat16"
assert calls[0]["total_layers"] == 2

View File

@@ -1,88 +0,0 @@
"""Dense-Llama GGUF ownership selection and introspection tests."""
from __future__ import annotations
import pytest
from meshnet_node.gguf_ownership import (
DenseLlamaShardOwnership,
authoritative_dense_llama_ownership,
infer_dense_llama_ownership,
select_dense_llama_tensor_names,
)
def test_dense_llama_selection_only_picks_block_range_and_endpoints():
"Dense-Llama selection keeps only the owned blocks plus the correct endpoints.\n\nTags: node, GGUF"
tensor_inventory = {
"token_embd.weight": 10_000,
"blk.0.attn_q.weight": 1_000,
"blk.0.ffn_down.weight": 1_000,
"blk.1.attn_q.weight": 2_000,
"blk.1.ffn_down.weight": 2_000,
"blk.2.attn_q.weight": 3_000,
"blk.2.ffn_down.weight": 3_000,
"output_norm.weight": 256,
"output.weight": 10_000,
"rope.freqs": 128,
}
selected = select_dense_llama_tensor_names(
tensor_inventory,
1,
2,
total_layers=3,
)
assert selected == {
"blk.1.attn_q.weight",
"blk.1.ffn_down.weight",
"blk.2.attn_q.weight",
"blk.2.ffn_down.weight",
"output_norm.weight",
"output.weight",
}
selected_bytes = sum(tensor_inventory[name] for name in selected)
full_bytes = sum(tensor_inventory.values())
assert selected_bytes == 20_256
assert selected_bytes < full_bytes
def test_dense_llama_loaded_range_is_authoritative_from_tensor_inventory():
"The backend's loaded tensor inventory is the source of truth for range and ownership.\n\nTags: node, GGUF"
class Backend:
loaded_tensor_names = (
"token_embd.weight",
"blk.4.attn_q.weight",
"blk.5.ffn_down.weight",
"output_norm.weight",
"output.weight",
)
ownership = authoritative_dense_llama_ownership(Backend(), selection=None)
assert isinstance(ownership, DenseLlamaShardOwnership)
assert ownership.range == (4, 5)
assert ownership.owns_embedding is True
assert ownership.owns_final_head is True
def test_derivative_slice_requires_source_and_slice_hashes():
"Temporary derivative GGUF slices must carry hashes and cannot claim final semantics.\n\nTags: node, GGUF"
with pytest.raises(ValueError, match="source and slice hashes"):
infer_dense_llama_ownership(
["blk.1.attn_q.weight"],
derivative_slice=True,
final_artifact_semantics=False,
)
with pytest.raises(ValueError, match="final artifacts"):
infer_dense_llama_ownership(
["blk.1.attn_q.weight"],
source_artifact_hash="sha256:source",
slice_artifact_hash="sha256:slice",
derivative_slice=True,
final_artifact_semantics=True,
)

View File

@@ -1,769 +0,0 @@
"""Isolated concurrent local Hot KV State (DGR-007).
These tests prove the KV/session manager with a *pure-numpy* KV-cached dense-Llama
reference: no download, no GPU, no torch, no API credit. The reference implements
the DGR-006 ``ShardComputation`` duck type plus ``run_layers_cached`` so cached
prefill/decode over a per-session KV context reproduces the stateless whole-model
tokens bit-for-bit. On top of that correctness core, the tests exercise the
manager's lifecycle: owned-layer allocation, prefill/decode append, truncate,
release, TTL/LRU eviction, explicit cache-miss responses, stale-epoch and
incompatible-recipe rejection, four concurrent cross-talk-free sessions, and
budget-bounded cancellation.
"""
from __future__ import annotations
import threading
import numpy as np
import pytest
from meshnet_node.boundary_adapter import BoundaryBundle, TailOutput
from meshnet_node.hot_kv_state import (
CacheMiss,
CacheMissReason,
HotKvStateConfig,
HotKvStateManager,
IncompatibleCacheRecipeError,
KvBoundaryAdapter,
KvBudgetExceededError,
KvCacheMissError,
KvCacheRecipe,
LayerKvCache,
StaleRouteEpochError,
kv_recipe_for,
)
PARITY_ATOL = 1e-6
# --------------------------------------------------------------------------- #
# Pure-numpy KV-cached dense-Llama reference (test fixture, not production).
# --------------------------------------------------------------------------- #
class _KvDenseLlama:
"""A tiny deterministic dense-Llama with both stateless and cached runners."""
architecture_adapter = "dense-llama"
def __init__(
self,
*,
vocab: int = 48,
hidden: int = 32,
n_layers: int = 6,
n_heads: int = 4,
intermediate: int = 64,
rms_eps: float = 1e-6,
rope_theta: float = 10000.0,
seed: int = 20260716,
) -> None:
assert hidden % n_heads == 0
self.vocab = vocab
self.hidden = hidden
self.n_layers = n_layers
self.n_heads = n_heads
self.head_dim = hidden // n_heads
assert self.head_dim % 2 == 0
self.rms_eps = rms_eps
self.rope_theta = rope_theta
rng = np.random.default_rng(seed)
def w(*shape: int) -> np.ndarray:
return (rng.standard_normal(shape) * 0.08).astype(np.float32)
self.embed = w(vocab, hidden)
self.layers = []
for _ in range(n_layers):
self.layers.append(
{
"in_ln": (1.0 + rng.standard_normal(hidden) * 0.02).astype(np.float32),
"q": w(hidden, hidden),
"k": w(hidden, hidden),
"v": w(hidden, hidden),
"o": w(hidden, hidden),
"post_ln": (1.0 + rng.standard_normal(hidden) * 0.02).astype(np.float32),
"gate": w(intermediate, hidden),
"up": w(intermediate, hidden),
"down": w(hidden, intermediate),
}
)
self.final_ln = (1.0 + rng.standard_normal(hidden) * 0.02).astype(np.float32)
self.lm_head_w = w(vocab, hidden)
inv_freq = 1.0 / (
rope_theta ** (np.arange(0, self.head_dim, 2, dtype=np.float32) / self.head_dim)
)
self.inv_freq = inv_freq.astype(np.float32)
# -- primitive ops -----------------------------------------------------
def _rmsnorm(self, x: np.ndarray, weight: np.ndarray) -> np.ndarray:
variance = np.mean(x.astype(np.float32) ** 2, axis=-1, keepdims=True)
normed = x / np.sqrt(variance + self.rms_eps)
return (normed * weight).astype(np.float32)
def _rope(self, positions: np.ndarray):
angles = positions[..., None].astype(np.float32) * self.inv_freq[None, None, :]
emb = np.concatenate([angles, angles], axis=-1)
return np.cos(emb).astype(np.float32), np.sin(emb).astype(np.float32)
@staticmethod
def _rotate_half(x: np.ndarray) -> np.ndarray:
half = x.shape[-1] // 2
return np.concatenate([-x[..., half:], x[..., :half]], axis=-1)
def _apply_rope(self, t: np.ndarray, cos: np.ndarray, sin: np.ndarray) -> np.ndarray:
cos = cos[:, None, :, :]
sin = sin[:, None, :, :]
return t * cos + self._rotate_half(t) * sin
def _project_qkv(self, normed: np.ndarray, layer: dict, positions: np.ndarray):
batch, seq, _ = normed.shape
q = (normed @ layer["q"].T).reshape(batch, seq, self.n_heads, self.head_dim)
k = (normed @ layer["k"].T).reshape(batch, seq, self.n_heads, self.head_dim)
v = (normed @ layer["v"].T).reshape(batch, seq, self.n_heads, self.head_dim)
q = q.transpose(0, 2, 1, 3)
k = k.transpose(0, 2, 1, 3)
v = v.transpose(0, 2, 1, 3)
cos, sin = self._rope(positions)
q = self._apply_rope(q, cos, sin)
k = self._apply_rope(k, cos, sin)
return q, k, v
def _attend(
self,
q: np.ndarray,
k_all: np.ndarray,
v_all: np.ndarray,
layer: dict,
q_positions: np.ndarray,
) -> np.ndarray:
batch, _, seq_new, _ = q.shape
total = k_all.shape[2]
scores = (q @ k_all.transpose(0, 1, 3, 2)) / np.sqrt(self.head_dim)
# Causal mask by absolute position: keys are stored in absolute order
# 0..total-1; query row i lives at absolute position q_positions[i].
key_abs = np.arange(total, dtype=np.int64)
q_abs = np.asarray(q_positions).reshape(seq_new).astype(np.int64)
mask = np.where(key_abs[None, :] <= q_abs[:, None], 0.0, -1e30).astype(np.float32)
scores = scores + mask[None, None, :, :]
scores = scores - scores.max(axis=-1, keepdims=True)
weights = np.exp(scores)
weights = weights / weights.sum(axis=-1, keepdims=True)
out = weights @ v_all
out = out.transpose(0, 2, 1, 3).reshape(batch, seq_new, self.hidden)
return (out @ layer["o"].T).astype(np.float32)
def _mlp(self, x: np.ndarray, layer: dict) -> np.ndarray:
gate = x @ layer["gate"].T
up = x @ layer["up"].T
silu = gate * (1.0 / (1.0 + np.exp(-gate)))
return ((silu * up) @ layer["down"].T).astype(np.float32)
# -- stateless whole-sequence layer (ground truth) ---------------------
def _run_layer_stateless(self, x: np.ndarray, layer: dict, positions: np.ndarray) -> np.ndarray:
normed = self._rmsnorm(x, layer["in_ln"])
q, k, v = self._project_qkv(normed, layer, positions)
attn = self._attend(q, k, v, layer, positions[0])
h = x + attn
h = h + self._mlp(self._rmsnorm(h, layer["post_ln"]), layer)
return h.astype(np.float32)
def whole_model_next_token(self, token_ids: list[int]) -> int:
positions = np.arange(len(token_ids))[None, :]
h = self.embed[np.asarray(token_ids)][None, :]
for idx in range(self.n_layers):
h = self._run_layer_stateless(h, self.layers[idx], positions)
h = self._rmsnorm(h[:, -1:, :], self.final_ln)
logits = h @ self.lm_head_w.T
return int(np.argmax(logits[0, -1]))
def stateless_greedy(self, prompt: list[int], n_new: int) -> list[int]:
tokens = list(prompt)
out: list[int] = []
for _ in range(n_new):
tok = self.whole_model_next_token(tokens)
tokens.append(tok)
out.append(tok)
return out
class _KvReferenceShard:
"""A contiguous inclusive layer range with a KV-cached runner.
Satisfies the KV-aware ``ShardComputation`` duck type used by
``KvBoundaryAdapter``: DGR-006 methods plus ``run_layers_cached`` and the KV
geometry (``n_kv_heads`` / ``head_dim`` / ``kv_dtype``).
"""
kv_dtype = "float32"
def __init__(
self,
model: _KvDenseLlama,
start_layer: int,
end_layer: int,
*,
architecture_adapter: str | None = None,
) -> None:
self._model = model
self.start_layer = start_layer
self.end_layer = end_layer
self.total_layers = model.n_layers
self.n_kv_heads = model.n_heads
self.head_dim = model.head_dim
self.architecture_adapter = architecture_adapter or model.architecture_adapter
def embed_tokens(self, token_ids: np.ndarray) -> np.ndarray:
return self._model.embed[np.asarray(token_ids)]
def final_norm(self, hidden: np.ndarray) -> np.ndarray:
return self._model._rmsnorm(np.asarray(hidden, dtype=np.float32), self._model.final_ln)
def lm_head(self, hidden: np.ndarray) -> np.ndarray:
return np.asarray(hidden, dtype=np.float32) @ self._model.lm_head_w.T
def run_layers_cached(self, hidden, *, positions, past_kv):
m = self._model
x = np.asarray(hidden, dtype=np.float32)
positions = np.asarray(positions)
new_kv: dict[int, tuple[np.ndarray, np.ndarray]] = {}
for idx in range(self.start_layer, self.end_layer + 1):
layer = m.layers[idx]
normed = m._rmsnorm(x, layer["in_ln"])
q, k, v = m._project_qkv(normed, layer, positions)
# Post-RoPE new K/V stored as (seq_new, n_heads, head_dim).
new_k = k[0].transpose(1, 0, 2).copy()
new_v = v[0].transpose(1, 0, 2).copy()
cache = past_kv.get(idx)
if cache is not None and cache.length > 0:
past_k = cache.keys[None].transpose(0, 2, 1, 3)
past_v = cache.values[None].transpose(0, 2, 1, 3)
k_all = np.concatenate([past_k, k], axis=2)
v_all = np.concatenate([past_v, v], axis=2)
else:
k_all, v_all = k, v
attn = m._attend(q, k_all, v_all, layer, positions[0])
h = x + attn
x = h + m._mlp(m._rmsnorm(h, layer["post_ln"]), layer)
x = x.astype(np.float32)
new_kv[idx] = (new_k, new_v)
return x, new_kv
# --------------------------------------------------------------------------- #
# Helpers.
# --------------------------------------------------------------------------- #
class _FakeClock:
def __init__(self) -> None:
self.now = 0.0
def __call__(self) -> float:
return self.now
def advance(self, delta: float) -> None:
self.now += delta
def _full_shard(model: _KvDenseLlama):
return _KvReferenceShard(model, 0, model.n_layers - 1)
def _manager_for(shard, config: HotKvStateConfig | None = None, clock=None) -> HotKvStateManager:
return HotKvStateManager(kv_recipe_for(shard), config=config, clock=clock)
def _cached_greedy(
adapter: KvBoundaryAdapter,
manager: HotKvStateManager,
session_id: str,
epoch: int,
prompt: list[int],
n_new: int,
) -> list[int]:
"""Greedy decode one full-model session through the KV manager."""
out = adapter.prefill(session_id, epoch, token_ids=np.asarray(prompt))
assert isinstance(out, TailOutput)
tokens = [out.token_id]
for _ in range(n_new - 1):
step = adapter.decode(session_id, epoch, token_ids=[out.token_id])
assert isinstance(step, TailOutput)
out = step
tokens.append(out.token_id)
return tokens
# --------------------------------------------------------------------------- #
# Recipe identity.
# --------------------------------------------------------------------------- #
def test_recipe_owned_layers_and_fingerprint_aliasing():
"The KV recipe covers only owned layers and canonicalizes architecture aliases.\n\nTags: node, kv"
recipe = KvCacheRecipe(
architecture_adapter="LlamaForCausalLM",
kv_dtype="float32",
n_kv_heads=4,
head_dim=8,
total_layers=6,
start_layer=2,
end_layer=3,
)
assert recipe.owned_layers == (2, 3)
alias = KvCacheRecipe(
architecture_adapter="llama",
kv_dtype="float32",
n_kv_heads=4,
head_dim=8,
total_layers=6,
start_layer=2,
end_layer=3,
)
assert recipe.is_compatible(alias)
# A different owned range is not compatible.
other = KvCacheRecipe(
architecture_adapter="llama",
kv_dtype="float32",
n_kv_heads=4,
head_dim=8,
total_layers=6,
start_layer=0,
end_layer=1,
)
assert not recipe.is_compatible(other)
def test_recipe_bytes_per_token_scales_with_owned_layers():
"KV bytes-per-token counts keys+values across owned layers only.\n\nTags: node, kv"
base = dict(
architecture_adapter="dense-llama",
kv_dtype="float32",
n_kv_heads=4,
head_dim=8,
total_layers=6,
)
one = KvCacheRecipe(**base, start_layer=0, end_layer=0)
two = KvCacheRecipe(**base, start_layer=0, end_layer=1)
# 2 (k+v) * heads * dim * 4 bytes per layer.
assert one.bytes_per_token() == 2 * 4 * 8 * 4
assert two.bytes_per_token() == 2 * one.bytes_per_token()
# --------------------------------------------------------------------------- #
# Owned-layer allocation.
# --------------------------------------------------------------------------- #
def test_manager_allocates_kv_only_for_owned_layers():
"A middle shard allocates KV state only for its owned layer range.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _KvReferenceShard(model, 2, 3)
manager = _manager_for(shard)
session = manager.open("sess-mid", 0)
assert session.owned_layers == (2, 3)
assert set(session.layers) == {2, 3}
with pytest.raises(KeyError):
session.layer(0)
# --------------------------------------------------------------------------- #
# Prefill / decode / truncate.
# --------------------------------------------------------------------------- #
def test_prefill_then_decode_append_grows_owned_layers():
"Prefill and decode append advance every owned layer in lockstep.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
prompt = [5, 12, 3, 41]
out = adapter.prefill("s", 0, token_ids=np.asarray(prompt))
assert isinstance(out, TailOutput)
session = manager.get("s", 0)
assert session.seq_len == len(prompt)
for cache in session.layers.values():
assert cache.length == len(prompt)
step = adapter.decode("s", 0, token_ids=[out.token_id])
assert isinstance(step, TailOutput)
assert manager.get("s", 0).seq_len == len(prompt) + 1
def test_truncate_rolls_back_all_owned_layers():
"Truncate drops cached positions beyond a length across owned layers.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
adapter.prefill("s", 0, token_ids=np.asarray([1, 2, 3, 4, 5]))
assert manager.get("s", 0).seq_len == 5
manager.truncate("s", 0, 2)
session = manager.get("s", 0)
assert session.seq_len == 2
for cache in session.layers.values():
assert cache.length == 2
def test_layer_kv_cache_rejects_wrong_shape():
"LayerKvCache rejects K/V that do not match its head geometry.\n\nTags: node, kv"
cache = LayerKvCache(0, n_kv_heads=4, head_dim=8, dtype="float32")
with pytest.raises(ValueError):
cache.append(np.zeros((1, 3, 8), dtype=np.float32), np.zeros((1, 3, 8), dtype=np.float32))
cache.append(np.zeros((2, 4, 8), dtype=np.float32), np.zeros((2, 4, 8), dtype=np.float32))
assert cache.length == 2
# --------------------------------------------------------------------------- #
# Cached vs stateless parity (correctness core).
# --------------------------------------------------------------------------- #
def test_cached_full_shard_decode_matches_stateless_whole_model():
"Cached full-model greedy decode reproduces stateless whole-model tokens.\n\nTags: node, kv, parity"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
prompt = [2, 17, 8, 25, 6]
n_new = 12
reference = model.stateless_greedy(prompt, n_new)
cached = _cached_greedy(adapter, manager, "s", 0, prompt, n_new)
assert cached == reference
assert len(cached) == n_new
def test_cached_prefill_next_token_matches_whole_model_logits():
"Cached prefill produces the same next-token logits as the whole model.\n\nTags: node, kv, parity"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
prompt = [9, 1, 44, 6, 30, 11]
out = adapter.prefill("s", 0, token_ids=np.asarray(prompt))
assert isinstance(out, TailOutput)
assert out.token_id == model.whole_model_next_token(prompt)
def test_multi_range_cached_decode_parity_across_a_seam():
"A head/tail split with independent per-range KV reproduces whole-model decode.\n\nTags: node, kv, parity"
model = _KvDenseLlama()
head_shard = _KvReferenceShard(model, 0, 2)
tail_shard = _KvReferenceShard(model, 3, 5)
head_mgr = _manager_for(head_shard)
tail_mgr = _manager_for(tail_shard)
head = KvBoundaryAdapter(head_shard, head_mgr)
tail = KvBoundaryAdapter(tail_shard, tail_mgr)
prompt = [7, 3, 22, 5, 9]
n_new = 8
# Each range only allocates its owned layers.
def step(token_ids, is_prefill):
if is_prefill:
bundle = head.prefill("s", 0, token_ids=np.asarray(token_ids))
out = tail.prefill("s", 0, boundary=bundle)
else:
bundle = head.decode("s", 0, token_ids=[token_ids])
assert isinstance(bundle, BoundaryBundle)
out = tail.decode("s", 0, boundary=bundle)
assert isinstance(out, TailOutput)
return out.token_id
tokens = [step(prompt, True)]
for _ in range(n_new - 1):
tokens.append(step(tokens[-1], False))
assert head_mgr.get("s", 0).owned_layers == (0, 1, 2)
assert tail_mgr.get("s", 0).owned_layers == (3, 4, 5)
assert tokens == model.stateless_greedy(prompt, n_new)
# --------------------------------------------------------------------------- #
# Four concurrent sessions with no cross-talk.
# --------------------------------------------------------------------------- #
def test_four_interleaved_sessions_have_no_kv_cross_talk():
"Four interleaved sessions each decode their own tokens without cross-talk.\n\nTags: node, kv, concurrency"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
prompts = {
"alpha": [1, 2, 3, 4],
"bravo": [40, 39, 2, 15],
"charlie": [7, 7, 7, 7],
"delta": [31, 5, 18, 22],
}
n_new = 10
references = {sid: model.stateless_greedy(p, n_new) for sid, p in prompts.items()}
# The four prompts must actually diverge, else "no cross-talk" is vacuous.
assert len({tuple(v) for v in references.values()}) == 4
generated: dict[str, list[int]] = {}
for sid, prompt in prompts.items():
out = adapter.prefill(sid, 0, token_ids=np.asarray(prompt))
assert isinstance(out, TailOutput)
generated[sid] = [out.token_id]
# Round-robin decode: every session takes one step per round, interleaved.
for _ in range(n_new - 1):
for sid in prompts:
step = adapter.decode(sid, 0, token_ids=[generated[sid][-1]])
assert isinstance(step, TailOutput)
generated[sid].append(step.token_id)
for sid in prompts:
assert generated[sid] == references[sid], sid
assert manager.session_count == 4
def test_four_sessions_on_real_threads_stay_isolated():
"Four sessions decoding on real threads produce their own reference tokens.\n\nTags: node, kv, concurrency"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard, HotKvStateConfig(max_sessions=8))
adapter = KvBoundaryAdapter(shard, manager)
prompts = {
"t-alpha": [3, 14, 1, 5],
"t-bravo": [2, 27, 18, 4],
"t-charlie": [9, 9, 1, 2],
"t-delta": [44, 6, 30, 11],
}
n_new = 8
references = {sid: model.stateless_greedy(p, n_new) for sid, p in prompts.items()}
results: dict[str, list[int]] = {}
errors: list[Exception] = []
def run(sid: str, prompt: list[int]) -> None:
try:
results[sid] = _cached_greedy(adapter, manager, sid, 0, prompt, n_new)
except Exception as exc: # pragma: no cover - surfaced via assert below
errors.append(exc)
threads = [threading.Thread(target=run, args=(sid, p)) for sid, p in prompts.items()]
for t in threads:
t.start()
for t in threads:
t.join()
assert not errors
for sid in prompts:
assert results[sid] == references[sid], sid
def test_release_one_session_leaves_others_intact_and_returns_memory():
"Releasing one session frees its budget and does not disturb the others.\n\nTags: node, kv, concurrency"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
prompts = {"keep-1": [1, 2, 3], "drop": [10, 11, 12, 13], "keep-2": [5, 6, 7]}
n_new = 6
references = {sid: model.stateless_greedy(p, n_new) for sid, p in prompts.items()}
gen: dict[str, list[int]] = {}
for sid, prompt in prompts.items():
out = adapter.prefill(sid, 0, token_ids=np.asarray(prompt))
gen[sid] = [out.token_id]
bytes_before = manager.total_bytes
assert manager.release("drop", 0) is True
assert manager.total_bytes < bytes_before
# A decode on the released session is an explicit cache miss, not corruption.
miss = adapter.decode("drop", 0, token_ids=[gen["drop"][-1]])
assert isinstance(miss, CacheMiss)
assert miss.reason is CacheMissReason.RELEASED
# The survivors keep decoding to their own references.
for _ in range(n_new - 1):
for sid in ("keep-1", "keep-2"):
step = adapter.decode(sid, 0, token_ids=[gen[sid][-1]])
assert isinstance(step, TailOutput)
gen[sid].append(step.token_id)
for sid in ("keep-1", "keep-2"):
assert gen[sid] == references[sid], sid
# --------------------------------------------------------------------------- #
# Stale epoch / incompatible recipe rejection.
# --------------------------------------------------------------------------- #
def test_stale_route_epoch_is_rejected():
"A request for an older route epoch than the current one is rejected.\n\nTags: node, kv"
model = _KvDenseLlama()
manager = _manager_for(_full_shard(model))
manager.open("s", 5)
with pytest.raises(StaleRouteEpochError):
manager.open("s", 4)
with pytest.raises(StaleRouteEpochError):
manager.resolve("s", 4)
with pytest.raises(StaleRouteEpochError):
manager.append("s", 4, {})
def test_new_route_epoch_supersedes_and_frees_old_epoch():
"A newer route epoch supersedes the old one, freeing its KV and reporting a miss.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
adapter.prefill("s", 1, token_ids=np.asarray([1, 2, 3, 4]))
bytes_epoch1 = manager.total_bytes
assert bytes_epoch1 > 0
# Re-planned route: epoch 2 starts a fresh isolated context.
adapter.prefill("s", 2, token_ids=np.asarray([9, 8]))
assert manager.session_keys() == [("s", 2)]
# Old epoch is gone; a lookup for it is now stale (epoch < current).
with pytest.raises(StaleRouteEpochError):
manager.resolve("s", 1)
def test_incompatible_cache_recipe_is_rejected():
"A request carrying a different KV recipe is rejected, not silently reused.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
manager.open("s", 0)
incompatible = KvCacheRecipe(
architecture_adapter="dense-llama",
kv_dtype="float16", # different KV dtype
n_kv_heads=model.n_heads,
head_dim=model.head_dim,
total_layers=model.n_layers,
start_layer=0,
end_layer=model.n_layers - 1,
)
with pytest.raises(IncompatibleCacheRecipeError):
manager.resolve("s", 0, recipe=incompatible)
with pytest.raises(IncompatibleCacheRecipeError):
manager.open("s2", 0, recipe=incompatible)
def test_uncertified_architecture_recipe_fails_closed():
"A KV recipe for an uncertified architecture fails closed at construction.\n\nTags: node, kv"
from meshnet_node.boundary_adapter import UncertifiedArchitectureError
with pytest.raises(UncertifiedArchitectureError):
KvCacheRecipe(
architecture_adapter="qwen3-moe",
kv_dtype="float32",
n_kv_heads=4,
head_dim=8,
total_layers=6,
start_layer=0,
end_layer=5,
)
# --------------------------------------------------------------------------- #
# Explicit cache-miss responses.
# --------------------------------------------------------------------------- #
def test_unknown_session_is_an_explicit_cache_miss():
"Resolving an unknown session returns an explicit unknown-session miss.\n\nTags: node, kv"
manager = _manager_for(_full_shard(_KvDenseLlama()))
miss = manager.resolve("nope", 0)
assert isinstance(miss, CacheMiss)
assert miss.reason is CacheMissReason.UNKNOWN_SESSION
with pytest.raises(KvCacheMissError):
manager.get("nope", 0)
def test_seq_len_mismatch_is_an_explicit_cache_miss():
"A decode whose expected length disagrees with the cache is an explicit miss.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard)
adapter = KvBoundaryAdapter(shard, manager)
out = adapter.prefill("s", 0, token_ids=np.asarray([1, 2, 3]))
# Cache holds 3 tokens; claim it holds 99.
miss = adapter.decode("s", 0, token_ids=[out.token_id], expected_seq_len=99)
assert isinstance(miss, CacheMiss)
assert miss.reason is CacheMissReason.SEQ_LEN_MISMATCH
def test_ttl_eviction_yields_an_explicit_cache_miss():
"A session idle past its TTL is evicted and reported as a TTL cache miss.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
clock = _FakeClock()
manager = _manager_for(shard, HotKvStateConfig(ttl_seconds=10.0), clock=clock)
adapter = KvBoundaryAdapter(shard, manager)
adapter.prefill("s", 0, token_ids=np.asarray([1, 2, 3]))
clock.advance(11.0)
miss = manager.resolve("s", 0)
assert isinstance(miss, CacheMiss)
assert miss.reason is CacheMissReason.EVICTED_TTL
assert manager.total_bytes == 0
# --------------------------------------------------------------------------- #
# Eviction and budget.
# --------------------------------------------------------------------------- #
def test_lru_eviction_by_session_cap_reports_a_miss():
"Exceeding the session cap evicts the least-recently-used session.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
manager = _manager_for(shard, HotKvStateConfig(max_sessions=2))
adapter = KvBoundaryAdapter(shard, manager)
adapter.prefill("a", 0, token_ids=np.asarray([1, 2]))
adapter.prefill("b", 0, token_ids=np.asarray([3, 4]))
# Touch 'a' so 'b' becomes the LRU victim.
adapter.decode("a", 0, token_ids=[1])
adapter.prefill("c", 0, token_ids=np.asarray([5, 6]))
miss = manager.resolve("b", 0)
assert isinstance(miss, CacheMiss)
assert miss.reason is CacheMissReason.EVICTED_LRU
assert set(k[0] for k in manager.session_keys()) == {"a", "c"}
def test_budget_eviction_keeps_total_within_budget():
"Byte-budget pressure evicts LRU sessions so the store stays within budget.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
recipe = kv_recipe_for(shard)
# Budget for ~5 tokens of one session; a second big session forces eviction.
budget = recipe.bytes_per_token() * 5
manager = _manager_for(shard, HotKvStateConfig(budget_bytes=budget, max_sessions=8))
adapter = KvBoundaryAdapter(shard, manager)
adapter.prefill("a", 0, token_ids=np.asarray([1, 2, 3]))
adapter.prefill("b", 0, token_ids=np.asarray([4, 5, 6, 7]))
assert manager.total_bytes <= budget
# 'a' (older, LRU) was evicted to make room for 'b'.
miss = manager.resolve("a", 0)
assert isinstance(miss, CacheMiss)
assert miss.reason is CacheMissReason.EVICTED_LRU
assert manager.get("b", 0).seq_len == 4
def test_single_session_exceeding_budget_raises():
"A single session that cannot fit the budget raises instead of evicting itself.\n\nTags: node, kv"
model = _KvDenseLlama()
shard = _full_shard(model)
recipe = kv_recipe_for(shard)
budget = recipe.bytes_per_token() * 2 # only 2 tokens fit
manager = _manager_for(shard, HotKvStateConfig(budget_bytes=budget))
adapter = KvBoundaryAdapter(shard, manager)
with pytest.raises(KvBudgetExceededError):
adapter.prefill("a", 0, token_ids=np.asarray([1, 2, 3, 4, 5]))

View File

@@ -1,78 +0,0 @@
from __future__ import annotations
import os
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
SCRIPT = ROOT / "packages" / "node" / "native" / "scripts" / "build_llama_worker.sh"
PIN_FILE = ROOT / "packages" / "node" / "native" / "llama" / "UPSTREAM_COMMIT"
@pytest.mark.skipif(not SCRIPT.exists(), reason="llama worker build script is missing")
def test_llama_worker_build_smoke_rebuild(tmp_path: Path) -> None:
if not shutil_which("git"):
pytest.skip("git is unavailable")
if not (shutil_which("g++") or shutil_which("c++") or shutil_which("clang++")):
pytest.skip("no C++ compiler is unavailable")
source_dir = tmp_path / "llama.cpp"
build_one = tmp_path / "build-1"
build_two = tmp_path / "build-2"
pin = PIN_FILE.read_text(encoding="utf-8").strip()
source_dir.mkdir()
_write_fake_upstream_tree(source_dir, pin)
_git_init(source_dir)
_run_build(source_dir, build_one)
_run_build(source_dir, build_two)
binary = build_two / "meshnet_worker"
assert binary.exists()
output = subprocess.run(
[str(binary), "--smoke"],
cwd=ROOT,
check=True,
capture_output=True,
text=True,
)
assert "meshnet worker scaffold ok" in output.stdout
assert pin in output.stdout
def _run_build(source_dir: Path, build_dir: Path) -> None:
env = os.environ.copy()
env.setdefault("PATH", os.environ.get("PATH", ""))
subprocess.run(
[str(SCRIPT), "--source-dir", str(source_dir), "--build-dir", str(build_dir)],
cwd=ROOT,
check=True,
env=env,
capture_output=True,
text=True,
)
def _write_fake_upstream_tree(source_dir: Path, pin: str) -> None:
(source_dir / "LICENSE").write_text("MIT License placeholder\n", encoding="utf-8")
(source_dir / "AUTHORS").write_text("Georgi Gerganov\nMeshnet maintainers\n", encoding="utf-8")
(source_dir / "CMakeLists.txt").write_text("# upstream placeholder\n", encoding="utf-8")
(source_dir / ".meshnet-upstream-commit").write_text(f"{pin}\n", encoding="utf-8")
(source_dir / ".meshnet-upstream-repository").write_text(
"https://github.com/ggml-org/llama.cpp.git\n",
encoding="utf-8",
)
def _git_init(source_dir: Path) -> None:
subprocess.run(["git", "init", "-q"], cwd=source_dir, check=True)
def shutil_which(name: str) -> str | None:
from shutil import which
return which(name)

View File

@@ -1,508 +0,0 @@
"""DGR-002: generated-schema round-trip and compatibility tests.
Covers the versioned gRPC Shard protocol (``packages/node/native/proto``):
* Python round-trip across the full envelope, tensor bundle, and every service.
* Proto3 forward/backward compatibility (unknown-field preservation, defaults).
* Bounded-fragment tensor bundle framing + checksums.
* Cross-language Python<->C++ round-trip when the C++ toolchain is available;
otherwise the C++ test skips with an explicit reason (deterministic, GPU-free,
model-download-free, API-credit-free by construction).
"""
from __future__ import annotations
import shutil
import subprocess
import pytest
# grpc_tools (grpcio-tools) is required to generate the stubs. It is present in
# the project .venv; skip cleanly elsewhere rather than error.
native_protocol = pytest.importorskip(
"meshnet_node.native_protocol",
reason="meshnet_node.native_protocol import failed",
)
try:
native_protocol.generate()
_GEN_ERROR = None
except native_protocol.ProtocGenerationError as exc: # pragma: no cover
_GEN_ERROR = str(exc)
pytestmark = pytest.mark.skipif(
_GEN_ERROR is not None,
reason=f"protobuf stubs unavailable: {_GEN_ERROR}",
)
@pytest.fixture(scope="module")
def pb2():
return native_protocol.load()
# ---------------------------------------------------------------------------
# Envelope / header round-trip and field coverage
# ---------------------------------------------------------------------------
def _full_header(pb2):
return pb2.MessageHeader(
schema_version=pb2.SCHEMA_VERSION_1,
work_id="work-42",
route_session_id="rs-7",
route_epoch=9,
fingerprint=pb2.ArtifactFingerprint(
model_id="meta-llama/Llama-3.1-8B",
revision="main",
artifact_hash="sha256:deadbeef",
quantization="Q4_K_M",
runtime_recipe_fingerprint="recipe-123",
),
shard_range=pb2.ShardRange(
start_layer=8,
end_layer=16,
effective_start_layer=9,
owns_embedding=False,
owns_final_head=False,
),
phase=pb2.PHASE_PREFILL,
position=pb2.Position(start_position=0, token_count=12, sequence_length=12),
idempotency_step=3,
cache_expectation=pb2.CACHE_REUSE,
compression=pb2.COMPRESSION_ZSTD,
checksum=pb2.Checksum(algorithm=pb2.CHECKSUM_CRC32C, value=b"\x00\x01\x02\x03"),
)
def test_message_header_carries_every_required_field(pb2):
"""The header carries every identifier the transport contract demands.
Tags: protocol
"""
header = _full_header(pb2)
raw = header.SerializeToString()
back = pb2.MessageHeader()
back.ParseFromString(raw)
assert back.schema_version == pb2.SCHEMA_VERSION_1
assert back.work_id == "work-42"
assert back.route_session_id == "rs-7"
assert back.route_epoch == 9
assert back.fingerprint.artifact_hash == "sha256:deadbeef"
assert back.fingerprint.runtime_recipe_fingerprint == "recipe-123"
assert back.shard_range.effective_start_layer == 9
assert back.phase == pb2.PHASE_PREFILL
assert back.position.token_count == 12
assert back.idempotency_step == 3
assert back.cache_expectation == pb2.CACHE_REUSE
assert back.compression == pb2.COMPRESSION_ZSTD
assert back.checksum.algorithm == pb2.CHECKSUM_CRC32C
assert back.checksum.value == b"\x00\x01\x02\x03"
def test_named_tensor_bundle_describes_shape_dtype_byteorder_and_fragments(pb2):
"""A tensor bundle round-trips name, shape, dtype, byte order and fragments.
Tags: protocol
"""
bundle = pb2.TensorBundle(
bundle_version=1,
tensors=[
pb2.NamedTensor(
name="hidden_states",
shape=[2, 3, 4096],
dtype=pb2.DTYPE_BF16,
byte_order=pb2.BYTE_ORDER_LITTLE_ENDIAN,
total_byte_length=16,
compression=pb2.COMPRESSION_NONE,
fragments=[
pb2.TensorFragment(
fragment_index=0,
fragment_count=2,
byte_offset=0,
data=b"\x00" * 8,
),
pb2.TensorFragment(
fragment_index=1,
fragment_count=2,
byte_offset=8,
data=b"\x01" * 8,
),
],
)
],
)
back = pb2.TensorBundle()
back.ParseFromString(bundle.SerializeToString())
tensor = back.tensors[0]
assert tensor.name == "hidden_states"
assert list(tensor.shape) == [2, 3, 4096]
assert tensor.dtype == pb2.DTYPE_BF16
assert tensor.byte_order == pb2.BYTE_ORDER_LITTLE_ENDIAN
assert [f.byte_offset for f in tensor.fragments] == [0, 8]
def test_session_stream_carries_open_prefill_decode_release_cancel(pb2):
"""The bidi stream oneof expresses every seam operation.
Tags: protocol
"""
header = _full_header(pb2)
frames = {
"open": pb2.SessionActivation(
open=pb2.SessionOpen(
header=header,
deadline_unix_nanos=1_000_000,
max_prefill_tokens_per_chunk=256,
max_fragment_bytes=1 << 20,
initial_credit=pb2.FlowControl(credits=8, max_in_flight_bytes=1 << 24),
)
),
"prefill": pb2.SessionActivation(
prefill=pb2.PrefillChunk(
header=header, chunk_index=0, chunk_count=2, final_chunk=False
)
),
"decode": pb2.SessionActivation(decode=pb2.DecodeStep(header=header)),
"release": pb2.SessionActivation(
release=pb2.ReleaseRequest(header=header, reason="done")
),
"cancel": pb2.SessionActivation(
cancel=pb2.CancelRequest(header=header, reason="client abort")
),
"flow_control": pb2.SessionActivation(
flow_control=pb2.FlowControl(credits=4)
),
}
for name, frame in frames.items():
back = pb2.SessionActivation()
back.ParseFromString(frame.SerializeToString())
assert back.WhichOneof("payload") == name
def test_session_response_carries_structured_status_and_results(pb2):
"""Server frames carry accepted/result/status/acks with structured Status.
Tags: protocol
"""
status = pb2.Status(
code=8,
message="resource exhausted",
retry_class=pb2.RETRY_CLASS_RETRYABLE,
details={"queue_depth": "128"},
)
resp = pb2.SessionResponse(
result=pb2.ActivationResult(
header=_full_header(pb2),
outputs=pb2.TensorBundle(bundle_version=1),
cache_result=pb2.CACHE_WRITTEN,
status=status,
)
)
back = pb2.SessionResponse()
back.ParseFromString(resp.SerializeToString())
assert back.WhichOneof("payload") == "result"
assert back.result.cache_result == pb2.CACHE_WRITTEN
assert back.result.status.retry_class == pb2.RETRY_CLASS_RETRYABLE
assert back.result.status.details["queue_depth"] == "128"
def test_capability_and_health_round_trip(pb2):
"""Capability and health messages round-trip their admission fields.
Tags: protocol
"""
cap = pb2.CapabilityResponse(
schema_version=pb2.SCHEMA_VERSION_1,
supported_schema_versions=[pb2.SCHEMA_VERSION_1],
supported_architectures=["llama"],
supported_quantizations=["Q4_K_M", "F16"],
servable_range=pb2.ShardRange(start_layer=0, end_layer=16),
budget=pb2.ResourceBudget(
weight_bytes=1 << 32, kv_bytes=1 << 30, max_concurrent_sessions=4
),
supported_compression=[pb2.COMPRESSION_NONE, pb2.COMPRESSION_ZSTD],
supported_checksums=[pb2.CHECKSUM_CRC32C, pb2.CHECKSUM_SHA256],
)
cap_back = pb2.CapabilityResponse()
cap_back.ParseFromString(cap.SerializeToString())
assert cap_back.budget.max_concurrent_sessions == 4
assert list(cap_back.supported_quantizations) == ["Q4_K_M", "F16"]
health = pb2.HealthResponse(
status=pb2.SERVING, active_sessions=2, queued_requests=1, kv_pressure=0.5
)
health_back = pb2.HealthResponse()
health_back.ParseFromString(health.SerializeToString())
assert health_back.status == pb2.SERVING
assert health_back.kv_pressure == pytest.approx(0.5)
# ---------------------------------------------------------------------------
# Compatibility
# ---------------------------------------------------------------------------
def test_unknown_fields_are_preserved_for_forward_compatibility(pb2):
"""An older reader tolerates and preserves fields it does not know.
A newer sender may add a field; parsing into the current schema must not
fail and must round-trip the unknown bytes.
Tags: protocol, compatibility
"""
header = _full_header(pb2)
raw = bytearray(header.SerializeToString())
# Append an unknown field: number 5000, wire type 2 (length-delimited).
tag = (5000 << 3) | 2
raw += _encode_varint(tag)
payload = b"future-field"
raw += _encode_varint(len(payload))
raw += payload
parsed = pb2.MessageHeader()
# Parsing must not raise on the unknown field.
parsed.ParseFromString(bytes(raw))
# Known fields survive intact.
assert parsed.work_id == "work-42"
assert parsed.route_epoch == 9
# The unknown bytes are preserved and re-emitted on re-serialization. This is
# the behavioural compatibility guarantee; the introspection accessor
# (UnknownFields()) is not implemented by the upb backend, so we assert the
# observable outcome rather than the accessor.
reserialized = parsed.SerializeToString()
assert payload in reserialized
assert _encode_varint(tag) in reserialized
def test_defaults_are_stable_for_backward_compatibility(pb2):
"""A message from an older sender (missing new fields) reads as enum zero.
Tags: protocol, compatibility
"""
empty = pb2.MessageHeader()
back = pb2.MessageHeader()
back.ParseFromString(empty.SerializeToString())
assert back.schema_version == pb2.SCHEMA_VERSION_UNSPECIFIED
assert back.phase == pb2.PHASE_UNSPECIFIED
assert back.cache_expectation == pb2.CACHE_EXPECTATION_UNSPECIFIED
assert back.work_id == ""
assert back.route_epoch == 0
# ---------------------------------------------------------------------------
# Bounded-fragment helpers
# ---------------------------------------------------------------------------
def test_fragment_and_reassemble_round_trip_with_checksums(pb2):
"""Bounded fragmentation reassembles exactly and validates checksums.
Tags: protocol
"""
payload = bytes((i * 7) % 256 for i in range(10_000))
tensor = native_protocol.fragment_tensor(
name="hidden",
shape=[1, 4096],
dtype=pb2.DTYPE_F16,
payload=payload,
max_fragment_bytes=4096,
checksum_algorithm=pb2.CHECKSUM_CRC32C,
)
assert len(tensor.fragments) == 3
assert all(len(f.data) <= 4096 for f in tensor.fragments)
# Survives a serialization round-trip before reassembly.
back = pb2.NamedTensor()
back.ParseFromString(tensor.SerializeToString())
assert native_protocol.reassemble_tensor(back) == payload
def test_reassemble_detects_fragment_corruption(pb2):
"""A flipped fragment byte fails checksum verification.
Tags: protocol
"""
payload = b"abcdefabcdef" * 100
tensor = native_protocol.fragment_tensor(
name="t",
shape=[len(payload)],
dtype=pb2.DTYPE_U8,
payload=payload,
max_fragment_bytes=256,
checksum_algorithm=pb2.CHECKSUM_SHA256,
)
tensor.fragments[1].data = tensor.fragments[1].data[:-1] + b"\x00"
with pytest.raises(ValueError, match="checksum mismatch"):
native_protocol.reassemble_tensor(tensor)
def test_checksum_algorithms_verify(pb2):
"""CRC32C, CRC32 and SHA256 all verify their own payloads.
Tags: protocol
"""
data = b"the quick brown fox"
for algo in (pb2.CHECKSUM_CRC32C, pb2.CHECKSUM_CRC32, pb2.CHECKSUM_SHA256):
checksum = native_protocol.compute_checksum(algo, data)
assert native_protocol.verify_checksum(checksum, data)
assert not native_protocol.verify_checksum(checksum, data + b"!")
def test_service_descriptor_exposes_all_operations(pb2):
"""The generated service defines capability/health/session/release/cancel.
Requires the grpc runtime; skips cleanly without it.
Tags: protocol
"""
grpc = pytest.importorskip("grpc", reason="grpc runtime not installed")
assert grpc is not None
grpc_mod = native_protocol.load_grpc()
assert hasattr(grpc_mod, "ShardRuntimeStub")
assert hasattr(grpc_mod, "ShardRuntimeServicer")
# Confirm the streaming seam and unary ops exist on the servicer.
servicer = grpc_mod.ShardRuntimeServicer
for op in ("GetCapability", "Health", "ActivateSession", "Release", "Cancel"):
assert hasattr(servicer, op), op
# ---------------------------------------------------------------------------
# Cross-language Python <-> C++ compatibility
# ---------------------------------------------------------------------------
def _cpp_toolchain_reason() -> str | None:
"""Return a skip reason if the C++ build toolchain is unavailable."""
for tool in ("cmake", "protoc"):
if shutil.which(tool) is None:
return f"{tool} not found on PATH"
return None
def _build_cpp_compatible_sample(pb2):
"""Python message matching what roundtrip_test.cpp CheckSample expects."""
header = pb2.MessageHeader(
schema_version=pb2.SCHEMA_VERSION_1,
work_id="w1",
route_session_id="s1",
route_epoch=3,
phase=pb2.PHASE_PREFILL,
idempotency_step=7,
cache_expectation=pb2.CACHE_FRESH,
compression=pb2.COMPRESSION_NONE,
fingerprint=pb2.ArtifactFingerprint(
model_id="meta-llama/Llama-3.1-8B",
quantization="Q4_K_M",
runtime_recipe_fingerprint="recipe-abc",
),
shard_range=pb2.ShardRange(
start_layer=0, end_layer=16, effective_start_layer=0, owns_embedding=True
),
position=pb2.Position(start_position=0, token_count=5, sequence_length=5),
)
return pb2.SessionActivation(
prefill=pb2.PrefillChunk(
header=header,
chunk_index=0,
chunk_count=1,
final_chunk=True,
activations=pb2.TensorBundle(
bundle_version=1,
tensors=[
pb2.NamedTensor(
name="hidden",
shape=[1, 4096],
dtype=pb2.DTYPE_F16,
byte_order=pb2.BYTE_ORDER_LITTLE_ENDIAN,
total_byte_length=8,
compression=pb2.COMPRESSION_NONE,
fragments=[
pb2.TensorFragment(
fragment_index=0,
fragment_count=1,
byte_offset=0,
data=bytes(range(1, 9)),
)
],
)
],
),
)
)
def test_cross_language_roundtrip_python_and_cpp(pb2, tmp_path):
"""Python and C++ parse each other's serialized frames (both directions).
Builds the C++ round-trip binary via CMake, feeds it a Python-serialized
fixture (C++ must parse it), and parses the C++-serialized output back in
Python. Skips with an explicit reason when the C++ toolchain is absent.
Tags: protocol, compatibility, cpp
"""
reason = _cpp_toolchain_reason()
if reason is not None:
pytest.skip(f"C++ toolchain unavailable: {reason}")
native_root = native_protocol.PROTO_DIR.parent
build_dir = tmp_path / "cpp-build"
configure = subprocess.run(
["cmake", "-S", str(native_root), "-B", str(build_dir)],
capture_output=True,
text=True,
)
if configure.returncode != 0:
pytest.skip(
"cmake configure failed (protobuf C++ dev likely missing):\n"
+ configure.stderr[-2000:]
)
build = subprocess.run(
["cmake", "--build", str(build_dir), "--target",
"shard_protocol_roundtrip_test"],
capture_output=True,
text=True,
)
assert build.returncode == 0, f"C++ build failed:\n{build.stderr[-2000:]}"
binary = build_dir / "shard_protocol_roundtrip_test"
assert binary.exists(), "C++ test binary not produced"
py_fixture = tmp_path / "py_sample.bin"
cpp_out = tmp_path / "cpp_sample.bin"
py_fixture.write_bytes(_build_cpp_compatible_sample(pb2).SerializeToString())
run = subprocess.run(
[str(binary), "--selftest", "--read", str(py_fixture),
"--write", str(cpp_out)],
capture_output=True,
text=True,
)
assert run.returncode == 0, f"C++ round-trip failed:\n{run.stdout}\n{run.stderr}"
# C++ parsed our bytes; now Python parses C++'s bytes and checks known fields.
parsed = pb2.SessionActivation()
parsed.ParseFromString(cpp_out.read_bytes())
assert parsed.WhichOneof("payload") == "prefill"
assert parsed.prefill.header.work_id == "w1"
assert parsed.prefill.header.route_epoch == 3
assert parsed.prefill.activations.tensors[0].name == "hidden"
assert parsed.prefill.activations.tensors[0].dtype == pb2.DTYPE_F16
# ---------------------------------------------------------------------------
# Local helpers
# ---------------------------------------------------------------------------
def _encode_varint(value: int) -> bytes:
out = bytearray()
while True:
byte = value & 0x7F
value >>= 7
if value:
out.append(byte | 0x80)
else:
out.append(byte)
return bytes(out)

View File

@@ -22,7 +22,6 @@ import pytest
from meshnet_node.admission import ( from meshnet_node.admission import (
REASON_BACKEND_MISMATCH, REASON_BACKEND_MISMATCH,
REASON_COMPATIBILITY_MISMATCH,
REASON_MODEL_MISMATCH, REASON_MODEL_MISMATCH,
REASON_NO_REPORT, REASON_NO_REPORT,
REASON_NOT_PASSED, REASON_NOT_PASSED,
@@ -69,26 +68,11 @@ class _FakeBackend:
total_layers = 24 total_layers = 24
hidden_size = 8 hidden_size = 8
def __init__( def __init__(self, *, shard_start=0, shard_end=23, device="cpu", forward_error=None):
self,
*,
shard_start=0,
shard_end=23,
device="cpu",
forward_error=None,
loaded_shard_start=None,
loaded_shard_end=None,
owns_embedding=None,
owns_final_head=None,
):
self.shard_start = shard_start self.shard_start = shard_start
self.shard_end = shard_end self.shard_end = shard_end
self.is_head = shard_start == 0 self.is_head = shard_start == 0
self.is_tail = shard_end == self.total_layers - 1 self.is_tail = shard_end == self.total_layers - 1
self.loaded_shard_start = shard_start if loaded_shard_start is None else loaded_shard_start
self.loaded_shard_end = shard_end if loaded_shard_end is None else loaded_shard_end
self.owns_embedding = self.is_head if owns_embedding is None else owns_embedding
self.owns_final_head = self.is_tail if owns_final_head is None else owns_final_head
self.device = _FakeDevice(device) self.device = _FakeDevice(device)
self.model_id = MODEL self.model_id = MODEL
self._forward_error = forward_error self._forward_error = forward_error
@@ -208,17 +192,6 @@ def test_a_passing_report_from_another_backend_or_device_is_refused():
assert exc.value.reason == REASON_BACKEND_MISMATCH assert exc.value.reason == REASON_BACKEND_MISMATCH
def test_a_passing_report_with_the_wrong_cache_layout_is_refused():
"The compatibility fingerprint fails closed when cache layout changes.\n\nTags: node, admission"
ctx = _context()
report = capability_report_for(ctx, cache_layout="local-hot-kv")
with pytest.raises(CapabilityAdmissionError) as exc:
admit(AdmissionRequirement.for_context(ctx), report)
assert exc.value.reason == REASON_COMPATIBILITY_MISMATCH
def test_a_report_older_than_the_freshness_window_is_refused(): def test_a_report_older_than_the_freshness_window_is_refused():
"Hardware, drivers and weights move; an old proof is not a current one.\n\nTags: node, admission" "Hardware, drivers and weights move; an old proof is not a current one.\n\nTags: node, admission"
ctx = _context() ctx = _context()
@@ -385,73 +358,6 @@ def test_a_stale_report_cannot_be_reused_to_register(startup_env):
assert startup_env == [] assert startup_env == []
# ---------------------------------------------------------------------------
# Re-registration: the proof presented is fresh, never the one captured at boot
# ---------------------------------------------------------------------------
def test_run_startup_hands_the_heartbeat_a_refresher_for_the_current_shard(startup_env, monkeypatch):
"The tracker refuses aged proofs, so the heartbeat must be able to re-prove what the node serves now.\n\nTags: node, admission, startup"
import meshnet_node.startup as startup_mod
captured: dict = {}
monkeypatch.setattr(
startup_mod, "_start_heartbeat", lambda *a, **kw: captured.update(kw)
)
_start(capability_validator=capability_stub())
refresh = captured.get("refresh_capability")
assert callable(refresh), "run_startup no longer wires a capability refresher"
fresh = refresh({"hf_repo": MODEL, "model": MODEL.split("/")[-1]})
assert fresh is not None
assert fresh["model"]["model_id"] == MODEL
assert (fresh["shard"]["start"], fresh["shard"]["end"]) == (0, 23)
assert fresh["validated_at"] > time.time() - 60
def test_a_reregistration_presents_a_refreshed_proof(monkeypatch):
"Replaying the boot-time report after an outage re-registers the node unroutable; the re-register path must present a fresh proof.\n\nTags: node, admission, startup"
import json
import meshnet_node.startup as startup_mod
model = "acme/refresh-model-7b"
boot_report = {"validated_at": 1.0, "marker": "boot"}
fresh_report = {"validated_at": 2.0, "marker": "fresh"}
posted: list[dict] = []
def _record(url, payload, timeout=10.0):
if url.endswith("/v1/nodes/register") and payload.get("hf_repo") == model:
posted.append(json.loads(json.dumps(payload)))
return {"node_id": "node-refresh"}
raise SystemExit # first heartbeat POST ends the daemon loop
monkeypatch.setattr(startup_mod, "_post_json", _record)
payload = {
"hf_repo": model,
"model": model.split("/")[-1],
"capability_report": dict(boot_report),
}
thread = startup_mod._start_heartbeat(
"http://tracker.invalid",
startup_mod._PENDING_NODE_ID, # forces a re-registration on the first tick
payload,
interval=0.02,
refresh_capability=lambda _payload: dict(fresh_report),
)
# The loop must be dead before this test returns: once monkeypatch restores
# `_post_json`, a surviving thread would re-register through whatever the
# *next* test patches in and corrupt its call counts.
thread.join(timeout=5.0)
assert not thread.is_alive(), "the heartbeat loop outlived the test"
assert posted, "the heartbeat never re-registered"
assert posted[0]["capability_report"] == fresh_report
def test_a_matching_passing_report_registers_and_travels_with_the_payload(startup_env): def test_a_matching_passing_report_registers_and_travels_with_the_payload(startup_env):
"Registration carries the proof for exactly the model/shard/recipe it advertises.\n\nTags: node, admission, startup" "Registration carries the proof for exactly the model/shard/recipe it advertises.\n\nTags: node, admission, startup"
node = _start() # production validator against a working fake backend node = _start() # production validator against a working fake backend
@@ -465,31 +371,10 @@ def test_a_matching_passing_report_registers_and_travels_with_the_payload(startu
assert report["status"] == "passed" assert report["status"] == "passed"
assert report["model"]["model_id"] == MODEL assert report["model"]["model_id"] == MODEL
assert (report["shard"]["start"], report["shard"]["end"]) == (0, 23) assert (report["shard"]["start"], report["shard"]["end"]) == (0, 23)
assert report["shard"]["owns_embedding"] is True
assert report["shard"]["owns_final_head"] is True
assert report["recipe"]["recipe_id"] == DEFAULT_RECIPE_ID assert report["recipe"]["recipe_id"] == DEFAULT_RECIPE_ID
assert report["backend"]["device"] == "cpu" assert report["backend"]["device"] == "cpu"
def test_capability_report_prefers_backend_loaded_range_over_cli_claims():
"The proof reports the model's loaded range, not the CLI's requested range.\n\nTags: node, admission"
backend = _FakeBackend(
shard_start=0,
shard_end=23,
loaded_shard_start=8,
loaded_shard_end=15,
owns_embedding=False,
owns_final_head=True,
)
report = capability_report_for(
_context(backend=backend, shard_start=0, shard_end=23),
)
assert (report.shard.start, report.shard.end) == (8, 15)
assert report.shard.owns_embedding is False
assert report.shard.owns_final_head is True
def test_the_served_backend_is_loaded_with_the_recipe_that_was_validated(startup_env): def test_the_served_backend_is_loaded_with_the_recipe_that_was_validated(startup_env):
"The recipe named in the report is the one the serving backend actually ran.\n\nTags: node, admission, startup" "The recipe named in the report is the one the serving backend actually ran.\n\nTags: node, admission, startup"
node = _start(recipe_id="eager-attention") node = _start(recipe_id="eager-attention")

View File

@@ -42,12 +42,9 @@ def _report(**overrides):
status="passed", status="passed",
duration_ms=142, duration_ms=142,
validated_at=1_760_000_000.0, validated_at=1_760_000_000.0,
owns_embedding=True,
owns_final_head=False,
) )
kwargs.update(overrides) kwargs.update(overrides)
report = build_capability_report(**kwargs) return build_capability_report(**kwargs)
return report
# --- model-agnostic identity ------------------------------------------------ # --- model-agnostic identity ------------------------------------------------
@@ -117,9 +114,6 @@ def test_report_dict_has_the_stable_documented_key_set():
"shard", "shard",
"recipe", "recipe",
"backend", "backend",
"artifact",
"runtime_recipe",
"compatibility_fingerprint",
"status", "status",
"validated_at", "validated_at",
"duration_ms", "duration_ms",
@@ -127,38 +121,12 @@ def test_report_dict_has_the_stable_documented_key_set():
} }
assert payload["schema_version"] == CAPABILITY_SCHEMA_VERSION assert payload["schema_version"] == CAPABILITY_SCHEMA_VERSION
assert set(payload["model"]) == {"model_id", "revision", "config_fingerprint"} assert set(payload["model"]) == {"model_id", "revision", "config_fingerprint"}
assert set(payload["shard"]) == { assert set(payload["shard"]) == {"start", "end"}
"start",
"end",
"owns_embedding",
"owns_final_head",
}
assert set(payload["recipe"]) == { assert set(payload["recipe"]) == {
"recipe_id", "recipe_id",
"recipe_version", "recipe_version",
"catalogue_version", "catalogue_version",
} }
assert set(payload["artifact"]) == {
"model_id",
"revision",
"artifact_hash",
"shard_start",
"shard_end",
}
assert set(payload["runtime_recipe"]) == {
"weight_quantization",
"activation_dtype",
"compute_dtype",
"kv_dtype",
"kv_layout",
"tokenizer_revision",
"architecture_adapter",
"backend_id",
"runtime_version",
"boundary_schema_version",
"cache_layout",
"fingerprint",
}
assert set(payload["backend"]) == { assert set(payload["backend"]) == {
"backend_id", "backend_id",
"device", "device",
@@ -166,19 +134,10 @@ def test_report_dict_has_the_stable_documented_key_set():
"quantization", "quantization",
"runtime", "runtime",
} }
assert payload["compatibility_fingerprint"].startswith("sha256:")
# JSON-serializable end to end. # JSON-serializable end to end.
assert json.loads(json.dumps(payload)) == payload assert json.loads(json.dumps(payload)) == payload
def test_report_carries_endpoint_ownership():
"Endpoint ownership is recorded alongside the shard range.\n\nTags: node, startup"
payload = _report().to_dict()
assert payload["shard"]["owns_embedding"] is True
assert payload["shard"]["owns_final_head"] is False
def test_identity_key_pins_model_shard_recipe_and_backend(): def test_identity_key_pins_model_shard_recipe_and_backend():
"Identity key pins model shard recipe and backend\n\nTags: node, startup" "Identity key pins model shard recipe and backend\n\nTags: node, startup"
base = _report() base = _report()
@@ -197,15 +156,6 @@ def test_identity_key_pins_model_shard_recipe_and_backend():
assert _report(device="other-device").identity_key() != base.identity_key() assert _report(device="other-device").identity_key() != base.identity_key()
def test_compatibility_fingerprint_changes_when_the_runtime_recipe_changes():
"The compatibility fingerprint changes when the runtime recipe changes.\n\nTags: node, startup"
base = _report()
altered = _report(cache_layout="stateless")
assert base.compatibility_fingerprint != altered.compatibility_fingerprint
assert base.runtime_recipe.fingerprint != altered.runtime_recipe.fingerprint
def test_config_fingerprint_is_stable_under_key_order_and_detects_change(): def test_config_fingerprint_is_stable_under_key_order_and_detects_change():
"Config fingerprint is stable under key order and detects change\n\nTags: node, startup" "Config fingerprint is stable under key order and detects change\n\nTags: node, startup"
a = config_fingerprint({"num_hidden_layers": 8, "hidden_size": 512}) a = config_fingerprint({"num_hidden_layers": 8, "hidden_size": 512})

View File

@@ -287,47 +287,6 @@ def test_configure_torch_threads_applies_explicit_settings(monkeypatch):
assert active == {"torch_threads": 12, "torch_interop_threads": 2} assert active == {"torch_threads": 12, "torch_interop_threads": 2}
def test_heartbeat_applies_release_without_reregistering(monkeypatch):
"""DROP_SHARD has no replacement range and must not look like an outage."""
import meshnet_node.startup as startup_mod
released = threading.Event()
requests: list[tuple[str, dict]] = []
class FakeNode:
def apply_tracker_directives(self, directives):
assert directives == [{"action": "DROP_SHARD", "model": "Qwen/Qwen2.5-0.5B-Instruct"}]
return {"action": "DROP_SHARD", "model": "Qwen/Qwen2.5-0.5B-Instruct"}
def fake_post(url, payload, timeout=10.0):
requests.append((url, dict(payload)))
released.set()
return {"directives": [{"action": "DROP_SHARD", "model": "Qwen/Qwen2.5-0.5B-Instruct"}]}
sleep_calls = 0
def one_heartbeat(_seconds):
nonlocal sleep_calls
sleep_calls += 1
if sleep_calls > 1:
raise SystemExit
monkeypatch.setattr(startup_mod, "_post_json", fake_post)
monkeypatch.setattr(startup_mod.time, "sleep", one_heartbeat)
payload = {
"model": "Qwen2.5-0.5B-Instruct",
"hf_repo": "Qwen/Qwen2.5-0.5B-Instruct",
"shard_start": 0,
"shard_end": 23,
}
startup_mod._start_heartbeat("http://tracker", "node-1", payload, interval=0, node_ref=FakeNode())
assert released.wait(1), "heartbeat did not receive the queued release"
assert len(requests) == 1, "release must not trigger a re-registration"
assert payload["shard_start"] == 0
assert payload["shard_end"] == 23
def test_benchmark_throughput_is_registered_in_payload(monkeypatch, tmp_path): def test_benchmark_throughput_is_registered_in_payload(monkeypatch, tmp_path):
"benchmark_tokens_per_sec from the benchmark is included in the tracker registration.\n\nTags: node, performance, startup" "benchmark_tokens_per_sec from the benchmark is included in the tracker registration.\n\nTags: node, performance, startup"
import meshnet_node.startup as startup_mod import meshnet_node.startup as startup_mod

View File

@@ -1,286 +0,0 @@
"""Tests for the DGR-001 performance contract metadata."""
from __future__ import annotations
import json
from unittest.mock import MagicMock, patch
import pytest
from meshnet_node.performance_contract import (
BENCHMARK_SCHEMA_VERSION,
DEFAULT_CONTRACT,
SCHEMA_VERSION,
main,
run_performance_benchmark,
run_real_model_endpoint_benchmark,
)
def test_default_contract_is_architecture_aligned_and_small():
"""The baseline stays on DeepSeek2 and uses the smallest DeepSeek-family GGUF.
Tags: performance, model, gguf
"""
payload = DEFAULT_CONTRACT.to_dict()
assert payload["schema_version"] == SCHEMA_VERSION
assert payload["story_id"] == "DGR-001"
assert payload["model_target"] == {
"name": "DeepSeek-V2-Lite-Chat",
"architecture": "deepseek2",
"safetensors_repo": "deepseek-ai/DeepSeek-V2-Lite-Chat",
"safetensors_precision": "bfloat16",
"gguf_repo": "second-state/DeepSeek-V2-Lite-Chat-GGUF",
"gguf_quant": "Q2_K",
"gguf_size_gb": 6.43,
"comparison_policy": (
"same model/revision, closest practical low-footprint precision pair: "
"BF16 safetensors versus Q2_K GGUF"
),
"rationale": (
"Smallest DeepSeek-family benchmark anchor that still points toward "
"DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead "
"of falling back to a tiny but architecture-mismatched smoke model."
),
}
assert payload["benchmark_lanes"] == [
{
"id": "transformers-safetensors-cpu",
"runtime": "transformers",
"device": "cpu",
"recipe": "current safetensors recipe",
"concurrency_levels": [1, 4],
},
{
"id": "llama-cpp-gguf-cpu",
"runtime": "llama.cpp",
"device": "cpu",
"recipe": "whole-model GGUF recipe",
"concurrency_levels": [1, 4],
},
{
"id": "transformers-safetensors-gpu",
"runtime": "transformers",
"device": "gpu",
"recipe": "current safetensors recipe",
"concurrency_levels": [1, 4],
},
{
"id": "llama-cpp-gguf-gpu",
"runtime": "llama.cpp",
"device": "gpu",
"recipe": "whole-model GGUF recipe",
"concurrency_levels": [1, 4],
},
]
assert "ttft_ms" in payload["metrics"]
assert "output_drift" in payload["metrics"]
assert "meaningful speed or fit benefit" in payload["stop_condition"]
assert any("mounted drive" in note for note in payload["notes"])
def test_contract_cli_writes_json(tmp_path, capsys):
"""The contract can be emitted as a machine-readable artifact.
Tags: performance, artifact
"""
output = tmp_path / "performance-contract.json"
assert main(["--json-out", str(output)]) == 0
written = json.loads(output.read_text(encoding="utf-8"))
assert written == DEFAULT_CONTRACT.to_dict()
assert str(output) in capsys.readouterr().out
def test_stub_benchmark_covers_every_lane_concurrency_and_metric():
"""The runner exercises all four CPU/GPU lanes with the full metric set.
Tags: performance, benchmark, gguf
"""
report = run_performance_benchmark()
assert report["schema_version"] == BENCHMARK_SCHEMA_VERSION
assert report["story_id"] == "DGR-001"
assert report["source"] == "stub-backend"
assert report["model_target"] == DEFAULT_CONTRACT.model_target.to_dict()
assert [lane["id"] for lane in report["lanes"]] == [
lane.id for lane in DEFAULT_CONTRACT.benchmark_lanes
]
for lane in report["lanes"]:
assert [result["concurrency"] for result in lane["results"]] == [1, 4]
for result in lane["results"]:
assert set(result["metrics"]) == set(DEFAULT_CONTRACT.metrics)
assert result["metrics"]["failure_count"] == 0
assert result["metrics"]["decode_tok_per_sec"] > 0
def test_stub_benchmark_is_deterministic():
"""Two runs produce byte-identical reports; no clocks or randomness leak in.
Tags: performance, benchmark, deterministic
"""
first = run_performance_benchmark()
second = run_performance_benchmark()
assert first == second
assert json.dumps(first, sort_keys=True) == json.dumps(second, sort_keys=True)
def test_stub_benchmark_compares_gguf_against_safetensors_per_device():
"""Each device gets a GGUF-vs-safetensors comparison and a stop-condition verdict.
Tags: performance, benchmark, gguf
"""
report = run_performance_benchmark()
assert set(report["comparisons"]) == {"cpu", "gpu"}
cpu, gpu = report["comparisons"]["cpu"], report["comparisons"]["gpu"]
assert cpu["safetensors_lane"] == "transformers-safetensors-cpu"
assert cpu["gguf_lane"] == "llama-cpp-gguf-cpu"
assert cpu["memory_metric"] == "rss_bytes"
assert gpu["safetensors_lane"] == "transformers-safetensors-gpu"
assert gpu["gguf_lane"] == "llama-cpp-gguf-gpu"
assert gpu["memory_metric"] == "vram_bytes"
for comparison in (cpu, gpu):
assert comparison["decode_speedup"] > 1.0
assert comparison["artifact_bytes_ratio"] < 0.5
assert comparison["memory_bytes_ratio"] < 1.0
assert comparison["output_drift"] == 0.0
assert comparison["gguf_benefit"] is True
assert report["stop_condition"]["gguf_benefit"] is True
assert report["stop_condition"]["triggered"] is False
assert report["stop_condition"]["text"] == DEFAULT_CONTRACT.stop_condition
def test_contract_cli_writes_benchmark_report(tmp_path, capsys):
"""--benchmark-out emits the stub benchmark report next to the contract.
Tags: performance, benchmark, artifact
"""
contract_out = tmp_path / "performance-contract.json"
benchmark_out = tmp_path / "artifacts" / "stub-benchmark-report.json"
assert main(["--json-out", str(contract_out), "--benchmark-out", str(benchmark_out)]) == 0
report = json.loads(benchmark_out.read_text(encoding="utf-8"))
assert report == run_performance_benchmark()
output = capsys.readouterr().out
assert str(contract_out) in output
assert str(benchmark_out) in output
def test_real_model_endpoint_benchmark_uses_lane_specific_endpoints_and_shared_schema():
"""The live client path fans out to one endpoint per CPU/GPU lane.
Tags: performance, benchmark, live
"""
response = MagicMock()
response.read.return_value = json.dumps({"choices": [{"message": {"content": "mesh activation"}}]}).encode()
response.headers.get.return_value = "lane-session"
response.__enter__.return_value = response
endpoints = {
"transformers-safetensors-cpu": "http://cpu-safetensors",
"llama-cpp-gguf-cpu": "http://cpu-gguf",
"transformers-safetensors-gpu": "http://gpu-safetensors",
"llama-cpp-gguf-gpu": "http://gpu-gguf",
}
with patch("meshnet_node.performance_contract.urllib.request.urlopen", return_value=response) as urlopen:
report = run_real_model_endpoint_benchmark(endpoints=endpoints, model="deepseek-ai/DeepSeek-V2-Lite-Chat")
assert report["source"] == "real-model-endpoints"
assert report["model_target"] == DEFAULT_CONTRACT.model_target.to_dict()
assert set(report["comparisons"]) == {"cpu", "gpu"}
assert urlopen.call_count == len(endpoints)
called_urls = [call.args[0].full_url for call in urlopen.call_args_list]
assert called_urls == [f"{url}/v1/chat/completions" for url in endpoints.values()]
for lane in report["lanes"]:
assert lane["results"][0]["metrics"]["decode_tok_per_sec"] > 0
assert lane["results"][0]["metrics"]["ttft_ms"] > 0
assert lane["output_tokens"] == ["mesh", "activation"]
assert report["comparisons"]["cpu"]["gguf_lane"] == "llama-cpp-gguf-cpu"
assert report["comparisons"]["gpu"]["gguf_lane"] == "llama-cpp-gguf-gpu"
def test_contract_cli_runs_live_endpoint_benchmark(tmp_path, capsys):
"""--live-endpoint mappings drive the live runner and write its report.
Tags: performance, benchmark, live, artifact
"""
contract_out = tmp_path / "performance-contract.json"
live_out = tmp_path / "artifacts" / "live-benchmark-report.json"
endpoints = {
"transformers-safetensors-cpu": "http://cpu-safetensors",
"llama-cpp-gguf-cpu": "http://cpu-gguf",
"transformers-safetensors-gpu": "http://gpu-safetensors",
"llama-cpp-gguf-gpu": "http://gpu-gguf",
}
fake_report = {"schema_version": BENCHMARK_SCHEMA_VERSION, "source": "real-model-endpoints"}
argv = ["--json-out", str(contract_out), "--live-benchmark-out", str(live_out)]
for lane_id, url in endpoints.items():
argv += ["--live-endpoint", f"{lane_id}={url}"]
with patch(
"meshnet_node.performance_contract.run_real_model_endpoint_benchmark",
return_value=fake_report,
) as runner:
assert main(argv) == 0
runner.assert_called_once_with(
endpoints,
model=DEFAULT_CONTRACT.model_target.safetensors_repo,
contract=DEFAULT_CONTRACT,
)
assert json.loads(live_out.read_text(encoding="utf-8")) == fake_report
output = capsys.readouterr().out
assert str(contract_out) in output
assert str(live_out) in output
def test_contract_cli_passes_explicit_live_model(tmp_path):
"""--live-model overrides the contract's safetensors repo default.
Tags: performance, benchmark, live
"""
live_out = tmp_path / "live-benchmark-report.json"
argv = [
"--json-out", str(tmp_path / "performance-contract.json"),
"--live-benchmark-out", str(live_out),
"--live-endpoint", "transformers-safetensors-cpu=http://cpu-safetensors",
"--live-model", "local/DeepSeek-V2-Lite-Chat-Q2_K",
]
with patch(
"meshnet_node.performance_contract.run_real_model_endpoint_benchmark",
return_value={},
) as runner:
assert main(argv) == 0
assert runner.call_args.kwargs["model"] == "local/DeepSeek-V2-Lite-Chat-Q2_K"
@pytest.mark.parametrize(
"argv",
[
["--live-endpoint", "transformers-safetensors-cpu=http://cpu"],
["--live-benchmark-out", "live-report.json"],
[
"--live-endpoint", "not-a-mapping",
"--live-benchmark-out", "live-report.json",
],
],
ids=["endpoint-without-out", "out-without-endpoint", "malformed-mapping"],
)
def test_contract_cli_rejects_incomplete_live_arguments(tmp_path, argv, capsys):
"""Live flags must arrive as a consistent LANE_ID=URL + output-path set.
Tags: performance, benchmark, live, cli
"""
with pytest.raises(SystemExit) as excinfo:
main(["--json-out", str(tmp_path / "performance-contract.json"), *argv])
assert excinfo.value.code == 2
assert "--live-" in capsys.readouterr().err

View File

@@ -32,18 +32,12 @@ def test_matrix_reports_direct_relay_prefill_decode_and_machine_readable_metrics
assert {"p50_latency_ms", "p95_latency_ms", "payload_bytes", "compression_ratio", assert {"p50_latency_ms", "p95_latency_ms", "payload_bytes", "compression_ratio",
"connection_attempts", "p95_queue_wait_ms"} <= set(run["phases"]["decode"]) "connection_attempts", "p95_queue_wait_ms"} <= set(run["phases"]["decode"])
sample = run["samples"][0] sample = run["samples"][0]
assert sample["model_ms"] > 0
assert sample["encode_ms"] > 0
assert sample["activation_decode_ms"] > 0
assert sample["framing_ms"] > 0 assert sample["framing_ms"] > 0
assert sample["metadata_ms"] > 0 assert sample["metadata_ms"] > 0
assert sample["copy_allocation_ms"] > 0 assert sample["copy_allocation_ms"] > 0
assert sample["copy_allocation_bytes"] >= sample["payload_bytes"] assert sample["copy_allocation_bytes"] >= sample["payload_bytes"]
assert sample["local_http_forwarding_ms"] > 0
assert len(run["samples"]) == 1 + len(run["output_tokens"]) assert len(run["samples"]) == 1 + len(run["output_tokens"])
assert {"tokens_per_sec", "bytes_per_token", "compression_cpu_ms", "peak_buffered_bytes", assert {"tokens_per_sec", "bytes_per_token", "compression_cpu_ms", "peak_buffered_bytes"} <= set(run["phases"]["decode"])
"model_execution_ms", "activation_encoding_ms", "activation_decoding_ms",
"local_http_forwarding_ms"} <= set(run["phases"]["decode"])
def test_cached_sessions_reuse_one_connection_and_preserve_stub_tokens(): def test_cached_sessions_reuse_one_connection_and_preserve_stub_tokens():
@@ -80,10 +74,7 @@ def test_cli_writes_json_artifact_and_human_summary(tmp_path, capsys):
report = json.loads(output.read_text()) report = json.loads(output.read_text())
assert report["schema_version"] == 1 assert report["schema_version"] == 1
assert "Route Session benchmark" in capsys.readouterr().out assert "Route Session benchmark" in capsys.readouterr().out
summary = format_summary(report) assert "relay" in format_summary(report)
assert "relay" in summary
assert "model/encode/decode" in summary
assert "HTTP" in summary
def test_performance_gate_checks_comparison_identity_session_and_cleanup(): def test_performance_gate_checks_comparison_identity_session_and_cleanup():

View File

@@ -5,7 +5,6 @@ Model ids here are arbitrary and made up on purpose: nothing in the admission or
routing path may branch on a vendor, model or kernel name. routing path may branch on a vendor, model or kernel name.
""" """
import hashlib
import json import json
import time import time
import urllib.error import urllib.error
@@ -19,7 +18,6 @@ from meshnet_tracker.capability import (
POLICY_ENFORCE, POLICY_ENFORCE,
STATE_ABSENT, STATE_ABSENT,
STATE_ADMITTED, STATE_ADMITTED,
STATE_COMPATIBILITY_MISMATCH,
STATE_CATALOGUE_INCOMPATIBLE, STATE_CATALOGUE_INCOMPATIBLE,
STATE_FAILED, STATE_FAILED,
STATE_INVALID, STATE_INVALID,
@@ -43,14 +41,6 @@ SHORT = "oracle-9b"
LAYERS = 32 LAYERS = 32
def _stable_json(data: dict) -> str:
return json.dumps(data, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
def _sha256_text(data: dict) -> str:
return "sha256:" + hashlib.sha256(_stable_json(data).encode("utf-8")).hexdigest()
def _post_json(url: str, payload: dict) -> dict: def _post_json(url: str, payload: dict) -> dict:
data = json.dumps(payload).encode() data = json.dumps(payload).encode()
req = urllib.request.Request( req = urllib.request.Request(
@@ -70,8 +60,6 @@ def _report(
model_id: str = MODEL, model_id: str = MODEL,
start: int = 0, start: int = 0,
end: int = 15, end: int = 15,
owns_embedding: bool | None = None,
owns_final_head: bool | None = None,
status: str = "passed", status: str = "passed",
validated_at: float | None = None, validated_at: float | None = None,
recipe_id: str = "baseline", recipe_id: str = "baseline",
@@ -82,48 +70,10 @@ def _report(
diagnostics: list | None = None, diagnostics: list | None = None,
) -> dict: ) -> dict:
"""A capability report shaped exactly as `meshnet_node.capability` emits it.""" """A capability report shaped exactly as `meshnet_node.capability` emits it."""
if owns_embedding is None: return {
owns_embedding = start == 0
if owns_final_head is None:
owns_final_head = end >= LAYERS - 1
artifact = {
"model_id": model_id,
"revision": None,
"artifact_hash": _sha256_text(
{
"model_id": model_id,
"shard_start": start,
"shard_end": end,
"recipe_id": recipe_id,
"recipe_version": recipe_version,
}
),
"shard_start": start,
"shard_end": end,
}
runtime_recipe = {
"weight_quantization": "bfloat16",
"activation_dtype": "bfloat16",
"compute_dtype": "bfloat16",
"kv_dtype": "bfloat16",
"kv_layout": "session-cache",
"tokenizer_revision": model_id,
"architecture_adapter": "unknown",
"backend_id": "torch-transformers",
"runtime_version": "0.1.0",
"boundary_schema_version": 1,
"cache_layout": "local-hot-kv",
}
runtime_recipe["fingerprint"] = _sha256_text(runtime_recipe)
payload = {
"schema_version": schema_version, "schema_version": schema_version,
"model": {"model_id": model_id, "revision": None, "config_fingerprint": None}, "model": {"model_id": model_id, "revision": None, "config_fingerprint": None},
"shard": { "shard": {"start": start, "end": end},
"start": start,
"end": end,
"owns_embedding": owns_embedding,
"owns_final_head": owns_final_head,
},
"recipe": { "recipe": {
"recipe_id": recipe_id, "recipe_id": recipe_id,
"recipe_version": recipe_version, "recipe_version": recipe_version,
@@ -136,24 +86,11 @@ def _report(
"quantization": "bfloat16", "quantization": "bfloat16",
"runtime": {}, "runtime": {},
}, },
"artifact": artifact,
"runtime_recipe": runtime_recipe,
"status": status, "status": status,
"validated_at": time.time() if validated_at is None else validated_at, "validated_at": time.time() if validated_at is None else validated_at,
"duration_ms": 42, "duration_ms": 42,
"diagnostics": list(diagnostics or []), "diagnostics": list(diagnostics or []),
} }
payload["compatibility_fingerprint"] = _sha256_text(
{
"model": payload["model"],
"shard": payload["shard"],
"recipe": payload["recipe"],
"backend": payload["backend"],
"artifact": payload["artifact"],
"runtime_recipe": payload["runtime_recipe"],
}
)
return payload
def _registration( def _registration(
@@ -182,7 +119,6 @@ def _registration(
report = _report(start=start, end=end) report = _report(start=start, end=end)
if report is not None: if report is not None:
payload["capability_report"] = report payload["capability_report"] = report
payload["compatibility_fingerprint"] = report["compatibility_fingerprint"]
if recipe_id is not None: if recipe_id is not None:
payload["recipe_id"] = recipe_id payload["recipe_id"] = recipe_id
if recipe_version is not None: if recipe_version is not None:
@@ -260,15 +196,6 @@ def test_a_report_for_a_different_recipe_than_the_node_declares_is_a_recipe_mism
assert versioned.state == STATE_RECIPE_MISMATCH assert versioned.state == STATE_RECIPE_MISMATCH
def test_a_report_for_a_different_compatibility_fingerprint_is_a_compatibility_mismatch():
"The exact artifact/runtime recipe fingerprint gates admission.\n\nTags: routing, tracker"
state = _evaluate(
_report(),
declared_compatibility_fingerprint="sha256:deadbeef",
)
assert state.state == STATE_COMPATIBILITY_MISMATCH
def test_an_older_recipe_catalogue_is_incompatible(): def test_an_older_recipe_catalogue_is_incompatible():
"Recipe ids from a catalogue older than the tracker's minimum cannot be matched.\n\nTags: routing, tracker" "Recipe ids from a catalogue older than the tracker's minimum cannot be matched.\n\nTags: routing, tracker"
state = _evaluate(_report(catalogue_version="2025.01.1")) state = _evaluate(_report(catalogue_version="2025.01.1"))

View File

@@ -2869,43 +2869,6 @@ def test_same_endpoint_can_register_multiple_models():
tracker.stop() tracker.stop()
def test_explicit_model_placement_targets_only_the_selected_node():
"An admin can add and release a model on one chosen multi-model node.\n\nTags: http, routing, tracker"
from meshnet_tracker.server import _release_model_locked, _request_model_load_locked
tracker = _tracker(model_presets={
"model-a": {"total_layers": 4, "bytes_per_layer": {"bfloat16": 1_000}, "hf_repo": "org/ModelA"},
"model-b": {"total_layers": 4, "bytes_per_layer": {"bfloat16": 1_000}, "hf_repo": "org/ModelB"},
})
tracker_port = tracker.start()
try:
registrations = []
for port in (9062, 9063):
registrations.append(_post_json(
f"http://127.0.0.1:{tracker_port}/v1/nodes/register",
{"endpoint": f"http://127.0.0.1:{port}", "model": "model-a", "hf_repo": "org/ModelA",
"num_layers": 4, "shard_start": 0, "shard_end": 3, "max_loaded_shards": 2,
"vram_bytes": 20_000, "ram_bytes": 20_000, "quantizations": ["bfloat16"],
"benchmark_tokens_per_sec": 1.0, "hardware_profile": {}, "score": 1.0},
))
selected, other = (item["node_id"] for item in registrations)
with tracker._lock:
assignment = _request_model_load_locked(tracker._server, "model-b", selected) # type: ignore[arg-type]
assert assignment is not None
assert assignment["node_id"] == selected
assert tracker._registry[selected].pending_new_assignment is not None
assert tracker._registry[other].pending_new_assignment is None
with tracker._lock:
released = _release_model_locked(tracker._server, "model-a", selected) # type: ignore[arg-type]
assert released == 1
assert len(tracker._registry[selected].pending_directives) == 2
assert tracker._registry[other].pending_directives == []
finally:
tracker.stop()
def test_scale_demanded_models_queues_add_shard_on_spare_host(): def test_scale_demanded_models_queues_add_shard_on_spare_host():
"Scale demanded models queues add shard on spare host\n\nTags: http, routing, tracker" "Scale demanded models queues add shard on spare host\n\nTags: http, routing, tracker"
tracker = _tracker(model_presets={ tracker = _tracker(model_presets={
@@ -3042,13 +3005,6 @@ def test_a_node_declaring_an_unsupported_quantization_is_never_routed():
assert status == 503 assert status == 503
def test_a_node_declaring_auto_quantization_serves_a_default_precision_request():
"'auto' is the CLI default that delegates the choice — it is not a refusal, so the node must resolve to its best advertised precision and route.\n\nTags: http, routing, tracker"
status, response = _proxy_chat_status(POLICY_COMPAT, quantization="auto")
assert status == 200
assert response["choices"][0]["message"]["content"] == "ok"
def test_a_node_declaring_a_null_quantization_is_never_routed(): def test_a_node_declaring_a_null_quantization_is_never_routed():
"An explicit null states 'no usable precision' -- only an absent field is legacy.\n\nTags: http, routing, tracker" "An explicit null states 'no usable precision' -- only an absent field is legacy.\n\nTags: http, routing, tracker"
node = http.server.HTTPServer(("127.0.0.1", 0), _EchoChatHandler) node = http.server.HTTPServer(("127.0.0.1", 0), _EchoChatHandler)