feat: DGR-017 - Lock the GLM-5.2 Max target and alpha contract
This commit is contained in:
266
.scratch/distributed-gguf-runtime/evidence/DGR-017/README.md
Normal file
266
.scratch/distributed-gguf-runtime/evidence/DGR-017/README.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# DGR-017 — Lock the GLM-5.2 Max target and alpha contract
|
||||
|
||||
Status: **done**. Every acceptance criterion is met with real command output.
|
||||
|
||||
Evidence class: **real upstream metadata + deterministic arithmetic**. No weight
|
||||
payload was downloaded, no model was loaded, no GPU was used, and no benchmark was
|
||||
run — and none is claimed. This story makes the target *reviewable before* the
|
||||
216.7 GB download, which is exactly its job.
|
||||
|
||||
## 1. Summary
|
||||
|
||||
The alpha target is now pinned, planned, and sealed:
|
||||
|
||||
- **Identity.** `zai-org/GLM-5.2` @ `b4734de4facf877f85769a911abafc5283eab3d9` and
|
||||
`unsloth/GLM-5.2-GGUF` @ `abc55e72527792c6e77069c99b4cb7de16fa9f23`, quantization
|
||||
`UD-IQ1_S`, six shards, 216,715,360,960 bytes, every shard's LFS SHA-256 resolved.
|
||||
- **Architecture.** The config/tokenizer/chat-template metadata the runtime cannot
|
||||
shard without, hashed at the pinned revision.
|
||||
- **Resources.** A deterministic planner that counts unified memory once, applies the
|
||||
`max(20% , 8 GiB)` reserve, and reports the arithmetic minimum and the recommended
|
||||
node count as two different numbers.
|
||||
- **Contract.** The roadmap's section-5 acceptance matrix as a machine-readable,
|
||||
digest-sealed document, locked before the target ever runs and cross-bound to the
|
||||
exact manifest and architecture-snapshot digests.
|
||||
- **Upstream.** A refreshed llama.cpp/donor status report.
|
||||
|
||||
Three findings are worth a reader's attention.
|
||||
|
||||
**Every number in the roadmap reproduced from primary sources.** The 216,715,360,960
|
||||
byte total, the 201.832 GiB figure, the whole KV table (0.73 / 0.77 / 0.89 / 1.68 GiB
|
||||
at 16K, through 46.62 / 49.41 / 56.98 / 107.25 GiB at 1M), and the whole tier table
|
||||
(9 / 6 / 4 / 3 / 2 arithmetic minimum nodes) fall out of the exact config and the
|
||||
exact shard bytes. The roadmap was not approximating. The planner is written as a
|
||||
*reproduction* of those tables, so if the arithmetic ever stops matching, a test says
|
||||
which numbers moved.
|
||||
|
||||
**The roadmap's "recommended" column is an imbalance factor of exactly 1.10.** Nodes
|
||||
= `ceil(total x 1.10 / budget)` yields 10 / 6 / 5 / 3 / 3 for the 32 / 48 / 64 / 96 /
|
||||
128 GiB tiers — precisely the roadmap's recommendations. That constant is now named
|
||||
(`PLACEMENT_IMBALANCE_FACTOR`) and documented as a placeholder for measured
|
||||
per-tensor placement, not a fudge factor to be tuned once results are in.
|
||||
|
||||
**224 GiB aggregate does not actually fit.** Two 112 GiB nodes hit the 224 GiB
|
||||
"hard-fit floor" exactly, and still come up **23.5 GiB short** once each node honours
|
||||
its reserve. That is what makes 224 GiB an *experimental floor* rather than an
|
||||
envelope, and it is now a test, not a caveat in prose. Relatedly, the 2×128 and 4×64
|
||||
"fit probe" topologies fit with only **2.08 GiB of headroom across the entire route** —
|
||||
which is why they require measured placement evidence and are not the recommendation.
|
||||
|
||||
## 2. Files changed
|
||||
|
||||
New — runtime-loadable package (single source of truth):
|
||||
|
||||
| Path | What |
|
||||
|---|---|
|
||||
| `packages/node/meshnet_node/glm_alpha/__init__.py` | Public surface |
|
||||
| `packages/node/meshnet_node/glm_alpha/manifest.py` | Target manifest + architecture snapshot; fail-closed identity |
|
||||
| `packages/node/meshnet_node/glm_alpha/planner.py` | Memory / KV / seam planner; unified-memory de-duplication |
|
||||
| `packages/node/meshnet_node/glm_alpha/contract.py` | Immutable, digest-sealed alpha acceptance contract |
|
||||
| `packages/node/meshnet_node/glm_alpha/data/target-manifest.json` | The six pinned shards, sizes, SHA-256, URLs, licenses |
|
||||
| `packages/node/meshnet_node/glm_alpha/data/architecture-snapshot.json` | Pinned architecture + config/template hashes |
|
||||
| `packages/node/meshnet_node/glm_alpha/data/alpha-contract.json` | Sealed acceptance thresholds (`aab23220…`) |
|
||||
| `scripts/refresh_glm_target_manifest.py` | Re-resolve/verify pins from upstream metadata (`--check` / `--write`) |
|
||||
| `tests/test_glm_alpha_target.py` | 97 deterministic offline tests |
|
||||
|
||||
New — evidence:
|
||||
|
||||
- `.scratch/distributed-gguf-runtime/evidence/DGR-017/README.md` (this file)
|
||||
- `.../commands.txt` — exact commands and real results
|
||||
- `.../resource-plan.json` — generated tier/route/seam/KV plan
|
||||
- `.../upstream-status.json` — refreshed llama.cpp and donor status
|
||||
|
||||
Modified:
|
||||
|
||||
- `.scratch/distributed-gguf-runtime/issues/17-...md` — `Status: done`
|
||||
- `.scratch/distributed-gguf-runtime/prd.json` — DGR-017 `passes: true` (this story only)
|
||||
- `.ralph-tui/progress.md` — learnings
|
||||
|
||||
The data files live **in the package**, not in evidence, because the runtime must load
|
||||
them (DGR-018 verifies downloads against these digests; DGR-003 folds the manifest
|
||||
digest into the recipe fingerprint). Duplicating them into evidence would create two
|
||||
sources of truth that could drift.
|
||||
|
||||
## 3. Acceptance criteria
|
||||
|
||||
| Criterion | Where it is proven |
|
||||
|---|---|
|
||||
| Pin both repos by exact observed revision; `UD-IQ1_S` is the alpha quant | `target-manifest.json`; `test_manifest_pins_both_repositories_by_exact_revision` |
|
||||
| Six filenames, exact bytes, LFS SHA-256, aggregate GB/GiB, license, URLs, no payload download | HF `paths-info` API (LFS pointer metadata); `test_manifest_resolves_all_six_shards…`, `test_manifest_aggregate_bytes_are_exact_and_self_consistent` |
|
||||
| Snapshot + hash architecture-critical config/tokenizer/chat-template metadata | `architecture-snapshot.json`; `test_snapshot_captures_the_architecture_critical_metadata`, `test_snapshot_hashes_the_config_and_chat_template_bytes` |
|
||||
| Deterministic minimum-node calc from exact bytes, Q8_0 KV @16K/c1, imbalance, reserve | `planner.plan_topology`; `test_topology_planner_reproduces_the_published_tier_table` |
|
||||
| 224 GiB is a hard-fit floor, not an envelope; recommend 5×64 or 3×96/128 | `test_224_gib_aggregate_is_a_hard_fit_floor_not_an_operational_envelope`, `test_the_recommended_topologies_are_five_by_64_or_three_by_96_or_128` |
|
||||
| Unified memory counted once; additive RAM+VRAM rejected | `NodeMemory.from_host`; `test_adding_integrated_gpu_memory_to_system_ram_is_rejected`, `test_unified_memory_is_counted_once` |
|
||||
| 2.5 GbE minimum / 10 GbE recommended; serial latency modelled apart from bandwidth | `planner.plan_seams`; `test_2_5_gbe_is_the_alpha_minimum_and_10_gbe_is_recommended`, `test_serial_seam_latency_is_modelled_separately_from_bandwidth` |
|
||||
| Identity/semantic/target-run/performance/reliability/storage criteria locked before execution | `alpha-contract.json` (sealed, `locked_before_target_execution: true`); `test_the_contract_locks_every_roadmap_acceptance_section` |
|
||||
| Refresh upstream llama.cpp + donor status; no broad fork/scheduler | `upstream-status.json`; `adoption_state: none adopted` |
|
||||
| Tests reject changed revisions, missing shards, coordinated digest/config substitutions, inconsistent bytes, duplicate unified memory, malformed telemetry, and post-result threshold mutation | 97 tests; see §5 |
|
||||
| Targeted pytest passes | `97 passed` |
|
||||
| Installed wheel includes and loads all locked JSON resources | Real wheel build/install plus `load_locked_target()` outside the source tree |
|
||||
| `compileall packages tests` | exit 0 |
|
||||
| `git diff --check` | exit 0 |
|
||||
| Default tests deterministic, download-free, credit-free, GPU-free | Pure JSON + arithmetic; the only network code is an opt-in script excluded from the suite |
|
||||
| Full deterministic `pytest -q` | **852 passed, 13 skipped** on final rerun |
|
||||
|
||||
## 4. Real results
|
||||
|
||||
```
|
||||
scripts/refresh_glm_target_manifest.py --check -> match upstream (exit 0)
|
||||
pytest -q tests/test_glm_alpha_target.py -> 97 passed
|
||||
build + install wheel; load_locked_target() -> INSTALLED_WHEEL_PASS
|
||||
compileall -q packages tests -> exit 0
|
||||
git diff --check -> exit 0
|
||||
pytest -q -> 852 passed, 13 skipped (253.30s)
|
||||
```
|
||||
|
||||
Controller review found and fixed four gaps before the commit was accepted:
|
||||
|
||||
1. the initial wheel omitted `glm_alpha/data/*.json`, despite source-tree tests passing;
|
||||
2. the self-sealed contract did not bind the manifest/snapshot digests, so coordinated
|
||||
shard-hash or architecture substitutions could be accepted;
|
||||
3. `--check` followed moving repository HEAD instead of validating immutable pins;
|
||||
4. non-finite resource telemetry could bypass ordinary range checks.
|
||||
|
||||
Each failure now has either an adversarial regression test or a real installed-wheel /
|
||||
live-metadata gate. None of the provisional agent results were accepted on trust.
|
||||
|
||||
The intermittent tracker cancellation race that DGR-001 and DGR-002 both recorded as
|
||||
flaky on a clean tree failed once in the final validation (`404` after the request
|
||||
completed), then passed **5/5** in isolation and passed in the integrated full-suite
|
||||
rerun above. This story touches no tracker code; the failed run is retained in
|
||||
`commands.txt` rather than hidden.
|
||||
|
||||
Planner output (`resource-plan.json`):
|
||||
|
||||
| Route | Fits | Headroom |
|
||||
|---|---|---:|
|
||||
| 5×64 GiB unified (recommended) | yes | +53.28 GiB |
|
||||
| 3×96 GiB unified (recommended) | yes | +27.68 GiB |
|
||||
| 3×128 GiB unified (recommended) | yes | +104.48 GiB |
|
||||
| 4×64 GiB (fit probe) | yes | **+2.08 GiB** |
|
||||
| 2×128 GiB (fit probe) | yes | **+2.08 GiB** |
|
||||
| 2×112 GiB (= 224 GiB floor) | **no** | −23.52 GiB |
|
||||
| 3×64 GiB | no | −49.12 GiB |
|
||||
|
||||
## 5. How the "no silent swap" claim is earned
|
||||
|
||||
The story's whole purpose is to stop a later agent from changing the target after
|
||||
seeing a result. Each of those moves now has a test that names it:
|
||||
|
||||
- swap the artifact → `test_a_changed_gguf_revision_is_rejected`
|
||||
- pin a branch instead of a commit → `test_a_branch_name_is_not_an_acceptable_revision_pin`
|
||||
- drop a shard → `test_a_missing_shard_is_rejected`
|
||||
- shrink a shard so it "fits" → `test_a_shard_size_edited_to_make_the_model_look_smaller_is_rejected`
|
||||
- change a valid-looking shard SHA without changing bytes → `test_coordinated_shard_hash_substitution_is_rejected_by_contract`
|
||||
- change internally consistent architecture metadata → `test_internally_consistent_architecture_substitution_is_rejected_by_contract`
|
||||
- take the bigger quant quietly → `test_swapping_in_a_different_quantization_is_rejected`
|
||||
- add iGPU "VRAM" to system RAM → `test_adding_integrated_gpu_memory_to_system_ram_is_rejected`
|
||||
- count one machine twice → `test_the_same_machine_counted_twice_in_a_route_is_rejected`
|
||||
- lower the speed floor → `test_lowering_the_speed_floor_after_seeing_a_result_is_rejected`
|
||||
- call a slow pass an alpha → `test_relabelling_a_speed_failure_as_a_pass_is_rejected`
|
||||
- admit the dense fallback → `test_admitting_the_dense_attention_fallback_after_the_fact_is_rejected`
|
||||
- shrink the reserve → `test_relaxing_the_per_node_reserve_after_the_fact_is_rejected`
|
||||
|
||||
**Be precise about what the seal does.** `contract_sha256` is tamper-*evidence*, not
|
||||
tamper-proofing. Nothing checked into a repo can stop an agent that rewrites the
|
||||
threshold *and* re-seals the digest — `test_resealing_a_mutated_contract_changes_its_digest`
|
||||
asserts that path openly. What the seal removes is the *silent* mutation: the digest
|
||||
moves, and the change becomes a visible diff on a file whose entire purpose is to not
|
||||
change, still claiming `contract_id: glm-5.2-max-alpha/v1`. Reviewers, not hashes, are
|
||||
the enforcement; the hash makes sure there is something to review.
|
||||
|
||||
## 6. Upstream status — the gating risk for DGR-004/DGR-018
|
||||
|
||||
Refreshed against live GitHub on 2026-07-13. One item **changed** since the roadmap:
|
||||
|
||||
- **#24231 is now MERGED** (2026-07-11) — a generic `GGML_OP_LIGHTNING_INDEXER` exists.
|
||||
- #24770 MERGED (2026-06-20) — GLM-5.2 loads via a **dense-MLA compatibility path**.
|
||||
- **#25407 still OPEN** (updated today) — the real GLM DSA/IndexShare wiring.
|
||||
- #24730 still OPEN — the umbrella GLM-5.2 support request.
|
||||
|
||||
**No released upstream llama.cpp performs native GLM-5.2 DSA + IndexShare today.** A
|
||||
stock pin taken now would load the artifact and emit text through the dense fallback —
|
||||
which the alpha contract explicitly refuses (`dense_attention_fallback_satisfies_alpha:
|
||||
false`). DGR-018 must therefore prove those paths are *active*, not that output appeared.
|
||||
|
||||
Donor policy holds, and the evidence now supports it more strongly than before: PR
|
||||
#25407 is **12 files, +414/−7**. The semantics alpha needs are small enough to track
|
||||
and reproduce upstream. That is the argument against adopting Mesh-LLM's 261-patch
|
||||
fork — recorded as a donor (Apache-2.0, branch head `9bd18f15`, 2026-07-12), nothing
|
||||
adopted here.
|
||||
|
||||
## 7. Limitations and deferred work
|
||||
|
||||
- **No artifact was downloaded or loaded.** Sizes and SHA-256 come from Hugging Face
|
||||
LFS pointer metadata. DGR-018 must verify the digests against the real files on
|
||||
mounted storage before route admission. A matching size with a wrong hash is exactly
|
||||
the failure this manifest exists to catch, and only a local verify can catch it.
|
||||
- **`PLACEMENT_IMBALANCE_FACTOR = 1.10` is a planning assumption, not a measurement.**
|
||||
It reproduces the roadmap's recommendations, but the real per-node share depends on
|
||||
exact tensor bytes (embeddings, output head, dense vs MoE layers, shared experts,
|
||||
indexer tensors, quant block alignment). DGR-019 must replace it with measured
|
||||
placement. Until then, arithmetic-minimum topologies (2×128, 4×64) stay fit probes.
|
||||
- **KV numbers are planning estimates, not admission truth.** The planner deliberately
|
||||
budgets the *conservative* indexer layout (keys across all 78 layers, not just the 21
|
||||
Full ones) so a route admitted here cannot be surprised by the implementation it
|
||||
actually gets. The runtime must still report measured allocated/resident MLA and
|
||||
indexer cache per shard.
|
||||
- **Peak scratch is unmodelled.** The reserve exists precisely because backend
|
||||
workspaces and graph scratch are not predictable from the artifact; measured peak
|
||||
must land inside the reserve, and the contract requires that evidence.
|
||||
- **Upstream is moving fast.** #25407 was updated the same day it was observed. Refresh
|
||||
`upstream-status.json` before DGR-004 picks a llama.cpp pin. The manifest script's
|
||||
`--check` deliberately validates the immutable Hugging Face pins, not moving HEAD.
|
||||
|
||||
## 8. Compatibility and migration notes
|
||||
|
||||
- Purely additive. No existing module, wire format, or test changed. Nothing in this
|
||||
story is on a live request path.
|
||||
- `meshnet_node.glm_alpha` has **no heavy imports** — no torch, no transformers, no
|
||||
network at import time — so a tracker or planner can read the target contract without
|
||||
paying for a model runtime.
|
||||
- Re-pinning is deliberately awkward: `--write` follows current HEAD and leaves the
|
||||
existing contract binding invalid until a new contract is reviewed and sealed.
|
||||
`--check` uses revision-specific APIs and exits non-zero rather than healing any
|
||||
integrity drift in the already locked target.
|
||||
|
||||
## 9. Handoff to dependent stories
|
||||
|
||||
**DGR-003 (recipe identity):** fold `TargetManifest.digest`
|
||||
(`0b6aed04479d204902bb64c0203f1a46cab26a47b378ecccf85237b63f6c1962`) and
|
||||
`ArchitectureSnapshot.digest` (`253fbd94…`) into the runtime recipe fingerprint. The
|
||||
GLM fields the roadmap asks you to add (DSA/IndexShare metadata, context max, expert
|
||||
counts) are already resolved in `architecture-snapshot.json` — read them, do not
|
||||
re-derive them by hand. Populate the DGR-002 `Fingerprint` message; do not invent a
|
||||
second identity struct.
|
||||
|
||||
**DGR-004 (llama.cpp pin):** read `upstream-status.json` first. Any pin taken before
|
||||
#25407 merges gives you the dense-MLA fallback, which cannot satisfy alpha. Track
|
||||
#25407 (12 files) as a numbered patch; do not adopt the Mesh-LLM fork.
|
||||
|
||||
**DGR-018 (whole-model oracle):** the six digests in `target-manifest.json` are what you
|
||||
verify the download against. Your host needs ≥224 GiB runtime-accessible memory — and
|
||||
note that 224 GiB is the *floor*, not a comfortable target (see §1). Prove DSA,
|
||||
IndexShare, shared expert, and the Max template are **active**; the contract's
|
||||
`require_rendered_reasoning_effort_marker` is `<|system|>Reasoning Effort: Max`. Assert
|
||||
the rendered marker, not the request field: the template's only non-max level is
|
||||
`'high'`, so *every other value — including an absent one — renders Max*, and "the
|
||||
request said max" proves nothing.
|
||||
|
||||
**DGR-019 (GLM semantics):** the IndexShare split is **21 Full producer layers and 57
|
||||
Shared consumers**, in a `[full, full, full] + repeating [shared, shared, shared, full]`
|
||||
pattern. Prefer shard boundaries that keep an ownership group whole; the 8 KiB
|
||||
(2048 × int32) top-k sideband is the cost when you cannot. Replace
|
||||
`PLACEMENT_IMBALANCE_FACTOR` with measured per-tensor placement.
|
||||
|
||||
**DGR-020 (alpha verdict):** load the target with `load_locked_target()`. It verifies
|
||||
the contract seal and cross-binds the manifest and architecture snapshot before
|
||||
returning them. Judge against
|
||||
`contract.threshold(section, key)` — an unlocked threshold raises rather than
|
||||
defaulting, so a criterion cannot be invented at read time. The verdict is `alpha` or
|
||||
`stop`; there is no third outcome, and a quality pass with a speed failure is `stop`.
|
||||
|
||||
**Everyone:** unified system RAM and integrated-GPU memory are one pool. Build nodes
|
||||
with `NodeMemory.from_host(..., unified=True)` and it is impossible to write the
|
||||
double-count; pass a GPU size alongside `unified=True` and it raises rather than
|
||||
silently ignoring the argument.
|
||||
100
.scratch/distributed-gguf-runtime/evidence/DGR-017/commands.txt
Normal file
100
.scratch/distributed-gguf-runtime/evidence/DGR-017/commands.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
# DGR-017 — exact commands and real results (2026-07-13)
|
||||
# Project venv is used explicitly. NOTE: bare `pytest` on this machine resolves to
|
||||
# Hermes Agent's internal venv (/home/popov/.hermes/...), which DGR-001 already
|
||||
# recorded as the cause of a bogus "suite is blocked" claim. Always use $VP.
|
||||
VP=/run/media/popov/d/DEV/repos/d-popov.com/AI/.venv/bin/python # Python 3.14.6
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Resolve the target from upstream metadata ONLY. No weight payload downloaded.
|
||||
# Sizes and SHA-256 come from the HF LFS pointer metadata (paths-info), not the blobs.
|
||||
# ---------------------------------------------------------------------------
|
||||
curl -sS "https://huggingface.co/api/models/zai-org/GLM-5.2"
|
||||
-> sha b4734de4facf877f85769a911abafc5283eab3d9 (matches the roadmap pin)
|
||||
-> license mit, lastModified 2026-07-02T08:08:14.000Z
|
||||
|
||||
curl -sS "https://huggingface.co/api/models/unsloth/GLM-5.2-GGUF"
|
||||
-> sha abc55e72527792c6e77069c99b4cb7de16fa9f23 (matches the roadmap pin)
|
||||
-> license mit, lastModified 2026-06-23T15:18:23.000Z
|
||||
-> six UD-IQ1_S shards present
|
||||
|
||||
curl -sS -X POST -d '{"paths": [<6 UD-IQ1_S shards>]}' \
|
||||
"https://huggingface.co/api/models/unsloth/GLM-5.2-GGUF/paths-info/abc55e7..."
|
||||
-> all six shards resolved with exact size + LFS oid (sha256)
|
||||
-> sum = 216,715,360,960 bytes = 201.832 GiB = 216.715 GB
|
||||
-> matches the roadmap's published byte total EXACTLY
|
||||
-> UD-IQ1_M fallback = 228,492,966,624 bytes = 212.801 GiB (also matches)
|
||||
|
||||
curl -sS ".../resolve/b4734de4.../{config.json,chat_template.jinja,
|
||||
generation_config.json,tokenizer_config.json}"
|
||||
-> config.json 3732 B sha256 185f93ee6d12548e16a847e279dc0c3c90b1524c970b0866b42fb545747d859a
|
||||
-> chat_template.jinja 5076 B sha256 172dc74a35e1752df75ecfb2b2cf9326d2852bb1379868ebeec9571654489679
|
||||
-> generation_config.json 194 B sha256 ac76b43d8683d3b930126870fc8be73d8679308fe752fa1f381096d8354f6a55
|
||||
-> tokenizer_config.json 761 B sha256 98b1271574f41abf89427ae2dda030d94dc9478f0edc5a8bd240db213c6fd5fc
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Verify the checked-in pins still match live upstream (reproducible, no weights)
|
||||
# ---------------------------------------------------------------------------
|
||||
$VP scripts/refresh_glm_target_manifest.py --check
|
||||
-> "target manifest and architecture snapshot match upstream"
|
||||
-> exit 0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Upstream llama.cpp / donor status refresh (GitHub REST API, read-only)
|
||||
# ---------------------------------------------------------------------------
|
||||
curl -sS "https://api.github.com/repos/ggml-org/llama.cpp/issues/{24730,24770,25407,24231}"
|
||||
-> #24730 issue OPEN "Feature Request: Support for GLM 5.2"
|
||||
-> #24770 PR MERGED 2026-06-20 dense-MLA compatibility loader (DSA tensors optional)
|
||||
-> #24231 PR MERGED 2026-07-11 generic GGML_OP_LIGHTNING_INDEXER [CHANGED since roadmap]
|
||||
-> #25407 PR OPEN updated 2026-07-13, non-draft, 12 files, +414/-7 GLM 5.2 Indexer support
|
||||
curl -sS "https://api.github.com/repos/Mesh-LLM/mesh-llm{,/branches/feat%2Fjianyang-glm-52}"
|
||||
-> Apache-2.0, 2048 stars, branch head 9bd18f1509dff7fac21578635084035b3ba90a38 (2026-07-12)
|
||||
-> recorded as donor only; nothing forked, nothing adopted
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Seal the alpha contract (digest over its own canonical content)
|
||||
# ---------------------------------------------------------------------------
|
||||
$VP -c "seal_contract(...)" -> contract_sha256 aab23220280c053a3c14ff559df3cb5c9e1bf7f0f7188c6519e2e9d9ad036ed9
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. Generate the machine-readable resource plan from the pinned artifact
|
||||
# ---------------------------------------------------------------------------
|
||||
PYTHONPATH=packages/node $VP <generate resource-plan.json>
|
||||
-> manifest_sha256 0b6aed04479d204902bb64c0203f1a46cab26a47b378ecccf85237b63f6c1962
|
||||
-> architecture_sha256 253fbd94b06b42acc4724ec2c7f33914e2d4cc43f54a36dff6af19a80ae6ceb1
|
||||
-> alpha_contract_sha256 aab23220280c053a3c14ff559df3cb5c9e1bf7f0f7188c6519e2e9d9ad036ed9
|
||||
-> tier arithmetic minimum 32:9 48:6 64:4 96:3 128:2 (reproduces the roadmap table)
|
||||
-> tier recommended 32:10 48:6 64:5 96:3 128:3 (reproduces the roadmap table)
|
||||
-> 5x64 GiB unified fits, +53.28 GiB headroom
|
||||
-> 3x96 GiB unified fits, +27.68 GiB headroom
|
||||
-> 2x128 / 4x64 (fit probes) fit with only +2.08 GiB headroom across the WHOLE route
|
||||
-> 2x112 GiB (= 224 GiB, the hard-fit floor) DOES NOT FIT: -23.52 GiB
|
||||
-> 3x64 GiB does not fit: -49.12 GiB
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. Quality gates (project .venv, deterministic, offline, GPU-free)
|
||||
# ---------------------------------------------------------------------------
|
||||
$VP -m pytest -q tests/test_glm_alpha_target.py
|
||||
-> 97 passed in 0.12s
|
||||
-> includes coordinated shard/config substitution, malformed telemetry, and
|
||||
contract-ID reseal rejection tests added during controller review
|
||||
|
||||
$VP -m pip wheel --no-deps packages/node -w /tmp/dgr017-wheel
|
||||
$VP -m pip install --no-deps --target /tmp/dgr017-install /tmp/dgr017-wheel/*.whl
|
||||
$VP -I -c "... from meshnet_node.glm_alpha import load_locked_target ..."
|
||||
-> INSTALLED_WHEEL_PASS
|
||||
-> packaged alpha-contract.json, target-manifest.json, and architecture-snapshot.json
|
||||
load and cross-bind successfully outside the source tree
|
||||
|
||||
$VP -m compileall -q packages tests
|
||||
-> exit 0
|
||||
|
||||
git diff --check
|
||||
-> exit 0
|
||||
|
||||
$VP -m pytest -q # full deterministic suite
|
||||
-> first final run: 1 failed, 851 passed, 13 skipped; only the tracker cancellation
|
||||
race already documented by DGR-001/DGR-002 failed
|
||||
$VP -m pytest -q tests/test_tracker_routing.py::test_tracker_dashboard_can_cancel_inflight_proxy
|
||||
-> 1 passed, repeated 5/5 in isolation
|
||||
$VP -m pytest -q # integrated rerun
|
||||
-> 852 passed, 13 skipped in 253.30s (0:04:13)
|
||||
@@ -0,0 +1,255 @@
|
||||
{
|
||||
"generated_by": "DGR-017 meshnet_node.glm_alpha.planner",
|
||||
"target": {
|
||||
"gguf_repo_id": "unsloth/GLM-5.2-GGUF",
|
||||
"gguf_revision": "abc55e72527792c6e77069c99b4cb7de16fa9f23",
|
||||
"quantization": "UD-IQ1_S",
|
||||
"total_bytes": 216715360960,
|
||||
"total_gib": 201.832,
|
||||
"total_gb": 216.715
|
||||
},
|
||||
"manifest_sha256": "0b6aed04479d204902bb64c0203f1a46cab26a47b378ecccf85237b63f6c1962",
|
||||
"architecture_snapshot_sha256": "253fbd94b06b42acc4724ec2c7f33914e2d4cc43f54a36dff6af19a80ae6ceb1",
|
||||
"alpha_contract_sha256": "aab23220280c053a3c14ff559df3cb5c9e1bf7f0f7188c6519e2e9d9ad036ed9",
|
||||
"kv_assumptions": {
|
||||
"dtype": "Q8_0",
|
||||
"bytes_per_value": 1.0625,
|
||||
"context_tokens": 16384,
|
||||
"concurrency": 1,
|
||||
"indexer_layout": "conservative",
|
||||
"mla_values_per_token_per_layer": 576,
|
||||
"backbone_layers": 78,
|
||||
"indexer_full_layers": 21,
|
||||
"note": "Alpha budgets indexer keys across all 78 layers (current experimental DSA layout), not only the 21 Full layers."
|
||||
},
|
||||
"kv_table_gib": {
|
||||
"16384": {
|
||||
"mla_only_q8_gib": 0.73,
|
||||
"optimized_dsa_q8_gib": 0.77,
|
||||
"conservative_dsa_q8_gib": 0.89,
|
||||
"conservative_dsa_f16_gib": 1.68
|
||||
},
|
||||
"131072": {
|
||||
"mla_only_q8_gib": 5.83,
|
||||
"optimized_dsa_q8_gib": 6.18,
|
||||
"conservative_dsa_q8_gib": 7.12,
|
||||
"conservative_dsa_f16_gib": 13.41
|
||||
},
|
||||
"1048576": {
|
||||
"mla_only_q8_gib": 46.62,
|
||||
"optimized_dsa_q8_gib": 49.41,
|
||||
"conservative_dsa_q8_gib": 56.98,
|
||||
"conservative_dsa_f16_gib": 107.25
|
||||
}
|
||||
},
|
||||
"aggregate_hard_fit_floor_gib": 224.0,
|
||||
"aggregate_floor_class": "experimental_hard_fit_floor",
|
||||
"placement_imbalance_factor": 1.1,
|
||||
"tier_table": {
|
||||
"32": {
|
||||
"physical_usable_gib": 32.0,
|
||||
"reserve_gib": 8.0,
|
||||
"placement_budget_gib": 24.0,
|
||||
"weight_gib": 201.832,
|
||||
"kv_gib": 0.89,
|
||||
"total_placement_gib": 202.722,
|
||||
"arithmetic_minimum_nodes": 9,
|
||||
"recommended_nodes": 10,
|
||||
"imbalance_factor": 1.1
|
||||
},
|
||||
"48": {
|
||||
"physical_usable_gib": 48.0,
|
||||
"reserve_gib": 9.6,
|
||||
"placement_budget_gib": 38.4,
|
||||
"weight_gib": 201.832,
|
||||
"kv_gib": 0.89,
|
||||
"total_placement_gib": 202.722,
|
||||
"arithmetic_minimum_nodes": 6,
|
||||
"recommended_nodes": 6,
|
||||
"imbalance_factor": 1.1
|
||||
},
|
||||
"64": {
|
||||
"physical_usable_gib": 64.0,
|
||||
"reserve_gib": 12.8,
|
||||
"placement_budget_gib": 51.2,
|
||||
"weight_gib": 201.832,
|
||||
"kv_gib": 0.89,
|
||||
"total_placement_gib": 202.722,
|
||||
"arithmetic_minimum_nodes": 4,
|
||||
"recommended_nodes": 5,
|
||||
"imbalance_factor": 1.1
|
||||
},
|
||||
"96": {
|
||||
"physical_usable_gib": 96.0,
|
||||
"reserve_gib": 19.2,
|
||||
"placement_budget_gib": 76.8,
|
||||
"weight_gib": 201.832,
|
||||
"kv_gib": 0.89,
|
||||
"total_placement_gib": 202.722,
|
||||
"arithmetic_minimum_nodes": 3,
|
||||
"recommended_nodes": 3,
|
||||
"imbalance_factor": 1.1
|
||||
},
|
||||
"128": {
|
||||
"physical_usable_gib": 128.0,
|
||||
"reserve_gib": 25.6,
|
||||
"placement_budget_gib": 102.4,
|
||||
"weight_gib": 201.832,
|
||||
"kv_gib": 0.89,
|
||||
"total_placement_gib": 202.722,
|
||||
"arithmetic_minimum_nodes": 2,
|
||||
"recommended_nodes": 3,
|
||||
"imbalance_factor": 1.1
|
||||
}
|
||||
},
|
||||
"routes": {
|
||||
"recommended_5x64_unified": {
|
||||
"node_count": 5,
|
||||
"aggregate_usable_gib": 320.0,
|
||||
"aggregate_placement_budget_gib": 256.0,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": true,
|
||||
"meets_hard_fit_floor": true,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": 53.278,
|
||||
"reasons": []
|
||||
},
|
||||
"recommended_3x96_unified": {
|
||||
"node_count": 3,
|
||||
"aggregate_usable_gib": 288.0,
|
||||
"aggregate_placement_budget_gib": 230.4,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": true,
|
||||
"meets_hard_fit_floor": true,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": 27.678,
|
||||
"reasons": []
|
||||
},
|
||||
"recommended_3x128_unified": {
|
||||
"node_count": 3,
|
||||
"aggregate_usable_gib": 384.0,
|
||||
"aggregate_placement_budget_gib": 307.2,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": true,
|
||||
"meets_hard_fit_floor": true,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": 104.478,
|
||||
"reasons": []
|
||||
},
|
||||
"fit_probe_2x128_unified": {
|
||||
"node_count": 2,
|
||||
"aggregate_usable_gib": 256.0,
|
||||
"aggregate_placement_budget_gib": 204.8,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": true,
|
||||
"meets_hard_fit_floor": true,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": 2.078,
|
||||
"reasons": []
|
||||
},
|
||||
"fit_probe_4x64_unified": {
|
||||
"node_count": 4,
|
||||
"aggregate_usable_gib": 256.0,
|
||||
"aggregate_placement_budget_gib": 204.8,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": true,
|
||||
"meets_hard_fit_floor": true,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": 2.078,
|
||||
"reasons": []
|
||||
},
|
||||
"hard_fit_floor_2x112_unified": {
|
||||
"node_count": 2,
|
||||
"aggregate_usable_gib": 224.0,
|
||||
"aggregate_placement_budget_gib": 179.2,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": false,
|
||||
"meets_hard_fit_floor": true,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": -23.522,
|
||||
"reasons": [
|
||||
"aggregate placement budget 179.2 GiB is below the 202.7 GiB the target needs after each node's reserve"
|
||||
]
|
||||
},
|
||||
"insufficient_3x64_unified": {
|
||||
"node_count": 3,
|
||||
"aggregate_usable_gib": 192.0,
|
||||
"aggregate_placement_budget_gib": 153.6,
|
||||
"required_placement_gib": 202.722,
|
||||
"fits": false,
|
||||
"meets_hard_fit_floor": false,
|
||||
"no_single_node_can_admit_target": true,
|
||||
"headroom_gib": -49.122,
|
||||
"reasons": [
|
||||
"aggregate placement budget 153.6 GiB is below the 202.7 GiB the target needs after each node's reserve",
|
||||
"aggregate usable memory 192.0 GiB is below the 224 GiB experimental hard-fit floor"
|
||||
]
|
||||
}
|
||||
},
|
||||
"seams": {
|
||||
"3_nodes_2.5gbe": {
|
||||
"node_count": 3,
|
||||
"seam_count": 2,
|
||||
"hidden_size": 6144,
|
||||
"bytes_per_token_per_seam": 12288,
|
||||
"prefill_bytes_per_seam": 201326592,
|
||||
"decode_bytes_per_seam_per_token": 12288,
|
||||
"dsa_sideband_bytes_per_query": 8192,
|
||||
"link_rate_gbps": 2.5,
|
||||
"meets_alpha_minimum": true,
|
||||
"is_recommended_link": false,
|
||||
"decode_serialization_ms_per_token": 0.0786,
|
||||
"decode_latency_ms_per_token": 1.0,
|
||||
"decode_bandwidth_share_ms_per_token": 0.0786,
|
||||
"prefill_serialization_ms": 1288.49
|
||||
},
|
||||
"3_nodes_10.0gbe": {
|
||||
"node_count": 3,
|
||||
"seam_count": 2,
|
||||
"hidden_size": 6144,
|
||||
"bytes_per_token_per_seam": 12288,
|
||||
"prefill_bytes_per_seam": 201326592,
|
||||
"decode_bytes_per_seam_per_token": 12288,
|
||||
"dsa_sideband_bytes_per_query": 8192,
|
||||
"link_rate_gbps": 10.0,
|
||||
"meets_alpha_minimum": true,
|
||||
"is_recommended_link": true,
|
||||
"decode_serialization_ms_per_token": 0.0197,
|
||||
"decode_latency_ms_per_token": 1.0,
|
||||
"decode_bandwidth_share_ms_per_token": 0.0197,
|
||||
"prefill_serialization_ms": 322.123
|
||||
},
|
||||
"5_nodes_2.5gbe": {
|
||||
"node_count": 5,
|
||||
"seam_count": 4,
|
||||
"hidden_size": 6144,
|
||||
"bytes_per_token_per_seam": 12288,
|
||||
"prefill_bytes_per_seam": 201326592,
|
||||
"decode_bytes_per_seam_per_token": 12288,
|
||||
"dsa_sideband_bytes_per_query": 8192,
|
||||
"link_rate_gbps": 2.5,
|
||||
"meets_alpha_minimum": true,
|
||||
"is_recommended_link": false,
|
||||
"decode_serialization_ms_per_token": 0.1573,
|
||||
"decode_latency_ms_per_token": 2.0,
|
||||
"decode_bandwidth_share_ms_per_token": 0.1573,
|
||||
"prefill_serialization_ms": 2576.98
|
||||
},
|
||||
"5_nodes_10.0gbe": {
|
||||
"node_count": 5,
|
||||
"seam_count": 4,
|
||||
"hidden_size": 6144,
|
||||
"bytes_per_token_per_seam": 12288,
|
||||
"prefill_bytes_per_seam": 201326592,
|
||||
"decode_bytes_per_seam_per_token": 12288,
|
||||
"dsa_sideband_bytes_per_query": 8192,
|
||||
"link_rate_gbps": 10.0,
|
||||
"meets_alpha_minimum": true,
|
||||
"is_recommended_link": true,
|
||||
"decode_serialization_ms_per_token": 0.0393,
|
||||
"decode_latency_ms_per_token": 2.0,
|
||||
"decode_bandwidth_share_ms_per_token": 0.0393,
|
||||
"prefill_serialization_ms": 644.245
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"observed_at": "2026-07-13",
|
||||
"observed_by": "DGR-017",
|
||||
"method": "GitHub REST API (api.github.com), read-only; no fork, no clone, no patch adopted",
|
||||
"refresh_note": "The roadmap's 2026-07-13 observations were re-verified against live upstream. One item changed: PR #24231 is now MERGED (2026-07-11), which the roadmap already anticipated as 'generic CPU lightning-indexer support is merged'.",
|
||||
"llama_cpp": {
|
||||
"repo": "ggml-org/llama.cpp",
|
||||
"items": [
|
||||
{
|
||||
"ref": "issue #24730",
|
||||
"url": "https://github.com/ggml-org/llama.cpp/issues/24730",
|
||||
"title": "Feature Request: Support for GLM 5.2",
|
||||
"type": "issue",
|
||||
"state": "open",
|
||||
"updated_at": "2026-07-03T22:02:15Z",
|
||||
"meaning": "The umbrella GLM-5.2 support request is still open. GLM-5.2 is not fully supported upstream."
|
||||
},
|
||||
{
|
||||
"ref": "PR #24770",
|
||||
"url": "https://github.com/ggml-org/llama.cpp/pull/24770",
|
||||
"title": "model : glm-dsa load DSA indexer tensors as optional",
|
||||
"type": "pull_request",
|
||||
"state": "closed",
|
||||
"merged_at": "2026-06-20T10:48:24Z",
|
||||
"meaning": "MERGED. GLM-5.2 loads, but through a dense-MLA compatibility path with DSA indexer tensors treated as optional. This is the fallback the alpha contract explicitly refuses: it can produce text without performing DSA/IndexShare computation."
|
||||
},
|
||||
{
|
||||
"ref": "PR #24231",
|
||||
"url": "https://github.com/ggml-org/llama.cpp/pull/24231",
|
||||
"title": "New GGML_OP_LIGHTNING_INDEXER that implements DeepSeek V3.2/V4 lightning indexer",
|
||||
"type": "pull_request",
|
||||
"state": "closed",
|
||||
"merged_at": "2026-07-11T09:39:07Z",
|
||||
"meaning": "MERGED since the roadmap was written. A generic lightning-indexer op now exists in GGML. Backend coverage beyond CPU remains uneven and must be verified per backend by DGR-018, not assumed."
|
||||
},
|
||||
{
|
||||
"ref": "PR #25407",
|
||||
"url": "https://github.com/ggml-org/llama.cpp/pull/25407",
|
||||
"title": "GLM 5.2 Indexer support",
|
||||
"type": "pull_request",
|
||||
"state": "open",
|
||||
"draft": false,
|
||||
"mergeable_state": "unstable",
|
||||
"head_sha": "8dedd06415f36f10fc6091241a39b23c1bf0ee11",
|
||||
"base": "master",
|
||||
"commits": 6,
|
||||
"changed_files": 12,
|
||||
"additions": 414,
|
||||
"deletions": 7,
|
||||
"updated_at": "2026-07-13T15:28:51Z",
|
||||
"meaning": "OPEN and actively moving (updated today). This is the real DSA/IndexShare implementation alpha needs. It is narrow — 12 files, +414/-7 — which is the single most important finding for donor policy: the semantics alpha requires are reviewable and trackable upstream, not a 261-patch fork."
|
||||
}
|
||||
]
|
||||
},
|
||||
"capability_status_for_alpha": {
|
||||
"gguf_load_of_UD-IQ1_S": "expected via merged #24770, unverified by this project; DGR-018 must prove it against the exact pinned artifact",
|
||||
"moe_routing_and_shared_expert": "expected supported; unverified here",
|
||||
"compressed_mla_kv": "supported via the dense-MLA compatibility path",
|
||||
"dsa_lightning_indexer": "generic GGML op merged (#24231); GLM-5.2 wiring still open (#25407)",
|
||||
"indexshare_full_shared_roles": "NOT upstream; only in open PR #25407",
|
||||
"mtp_nextn": "not required for alpha; NextN tensors must be explicitly loaded or excluded, never silently reinterpreted",
|
||||
"conclusion": "As of 2026-07-13 no released upstream llama.cpp performs native GLM-5.2 DSA + IndexShare. A stock pin today would satisfy 'it emits text' via the dense fallback and would FAIL the alpha semantic-correctness contract. This is the gating technical risk for DGR-004 and DGR-018."
|
||||
},
|
||||
"donor": {
|
||||
"repo": "Mesh-LLM/mesh-llm",
|
||||
"url": "https://github.com/Mesh-LLM/mesh-llm",
|
||||
"license": "Apache-2.0",
|
||||
"stars_observed": 2048,
|
||||
"pushed_at": "2026-07-13T06:45:51Z",
|
||||
"glm_branch": "feat/jianyang-glm-52",
|
||||
"glm_branch_head": "9bd18f1509dff7fac21578635084035b3ba90a38",
|
||||
"glm_branch_head_date": "2026-07-12T06:37:43Z",
|
||||
"policy": "TEST AND PATCH DONOR ONLY. Do not adopt the fork, its scheduler, discovery, routing, public mesh, or package manager. Meshnet remains the sole control plane (RALPH-CONTEXT runtime decision, ADR-0020).",
|
||||
"focused_candidates": [
|
||||
"GLM DSA graph semantics",
|
||||
"lightning indexer and sparse-attention tests",
|
||||
"IndexShare metadata and Full/Shared role validation",
|
||||
"top-k sideband shape and lifecycle",
|
||||
"stage-local KV filtering",
|
||||
"target parity and performance fixtures"
|
||||
],
|
||||
"adoption_state": "none adopted in DGR-017. This story reads and records upstream state; it takes no patch and forks nothing."
|
||||
},
|
||||
"recommendation_for_dgr_004_and_dgr_018": [
|
||||
"Track upstream PR #25407 rather than forking Mesh-LLM. At 12 files and +414/-7 it is small enough to review, reproduce, and carry as a numbered patch in the project's own pinned stack.",
|
||||
"Any pin chosen before #25407 merges will load GLM-5.2 through the dense-MLA compatibility path. DGR-018 must therefore prove DSA/IndexShare are ACTIVE, not merely that the model emits text — the alpha contract already forbids the fallback.",
|
||||
"Verify lightning-indexer backend coverage (#24231) on the specific backend the route will use. CPU support being merged says nothing about ROCm/HIP."
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# 17 — Lock the GLM-5.2 Max target and alpha contract
|
||||
|
||||
Status: ready-for-agent
|
||||
Status: done
|
||||
|
||||
## Mandatory fresh-session context
|
||||
|
||||
|
||||
@@ -537,7 +537,7 @@
|
||||
"Update only this story issue to `Status: done` after every acceptance criterion and quality gate passes."
|
||||
],
|
||||
"priority": 3,
|
||||
"passes": false,
|
||||
"passes": true,
|
||||
"notes": "Source issue: .scratch/distributed-gguf-runtime/issues/17-lock-glm-5-2-max-target-and-alpha-contract.md",
|
||||
"dependsOn": [
|
||||
"DGR-001",
|
||||
|
||||
123
packages/node/meshnet_node/glm_alpha/__init__.py
Normal file
123
packages/node/meshnet_node/glm_alpha/__init__.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""The locked GLM-5.2 Max alpha target: identity, resource plan, and acceptance contract.
|
||||
|
||||
Three files, three jobs:
|
||||
|
||||
- :mod:`~meshnet_node.glm_alpha.manifest` — *is this the exact artifact?* Pinned
|
||||
repository revisions, six shard digests, and the architecture-critical config
|
||||
snapshot they must agree with.
|
||||
- :mod:`~meshnet_node.glm_alpha.planner` — *can this route hold it?* Deterministic
|
||||
memory, KV, and seam arithmetic over the exact artifact bytes, counting unified
|
||||
memory once.
|
||||
- :mod:`~meshnet_node.glm_alpha.contract` — *what would have counted as success?*
|
||||
The acceptance thresholds, locked before the target runs and digest-bound so a
|
||||
later change cannot be silent.
|
||||
|
||||
Nothing here downloads, loads, or executes a model. This package is the contract
|
||||
DGR-018, DGR-019, and DGR-020 are judged against.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .contract import (
|
||||
ALPHA_CONTRACT_ID,
|
||||
ALPHA_CONTRACT_SCHEMA_VERSION,
|
||||
VERDICT_ALPHA,
|
||||
VERDICT_STOP,
|
||||
AlphaContract,
|
||||
AlphaContractError,
|
||||
compute_contract_digest,
|
||||
load_alpha_contract,
|
||||
parse_alpha_contract,
|
||||
require_contract_target,
|
||||
seal_contract,
|
||||
)
|
||||
from .manifest import (
|
||||
ALPHA_QUANTIZATION,
|
||||
ALPHA_SHARD_COUNT,
|
||||
ArchitectureSnapshot,
|
||||
GlmTargetError,
|
||||
Shard,
|
||||
TargetManifest,
|
||||
canonical_sha256,
|
||||
load_architecture_snapshot,
|
||||
load_target_manifest,
|
||||
parse_architecture_snapshot,
|
||||
parse_target_manifest,
|
||||
require_pinned_target,
|
||||
)
|
||||
from .planner import (
|
||||
AGGREGATE_HARD_FIT_FLOOR_GIB,
|
||||
ALPHA_CONTEXT_TOKENS,
|
||||
ALPHA_KV_DTYPE,
|
||||
MIN_LINK_RATE_GBPS,
|
||||
PLACEMENT_IMBALANCE_FACTOR,
|
||||
RECOMMENDED_LINK_RATE_GBPS,
|
||||
RESERVE_FLOOR_GIB,
|
||||
RESERVE_FRACTION,
|
||||
NodeMemory,
|
||||
ResourcePlanError,
|
||||
RouteFit,
|
||||
SeamPlan,
|
||||
TopologyPlan,
|
||||
kv_bytes,
|
||||
plan_all_tiers,
|
||||
plan_route,
|
||||
plan_seams,
|
||||
plan_topology,
|
||||
)
|
||||
|
||||
|
||||
def load_locked_target() -> tuple[AlphaContract, TargetManifest, ArchitectureSnapshot]:
|
||||
"""Load and cross-bind the packaged alpha contract, manifest, and snapshot."""
|
||||
|
||||
contract = load_alpha_contract()
|
||||
manifest = load_target_manifest()
|
||||
snapshot = load_architecture_snapshot()
|
||||
require_contract_target(contract, manifest, snapshot)
|
||||
return contract, manifest, snapshot
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AGGREGATE_HARD_FIT_FLOOR_GIB",
|
||||
"ALPHA_CONTEXT_TOKENS",
|
||||
"ALPHA_CONTRACT_ID",
|
||||
"ALPHA_CONTRACT_SCHEMA_VERSION",
|
||||
"ALPHA_KV_DTYPE",
|
||||
"ALPHA_QUANTIZATION",
|
||||
"ALPHA_SHARD_COUNT",
|
||||
"MIN_LINK_RATE_GBPS",
|
||||
"PLACEMENT_IMBALANCE_FACTOR",
|
||||
"RECOMMENDED_LINK_RATE_GBPS",
|
||||
"RESERVE_FLOOR_GIB",
|
||||
"RESERVE_FRACTION",
|
||||
"VERDICT_ALPHA",
|
||||
"VERDICT_STOP",
|
||||
"AlphaContract",
|
||||
"AlphaContractError",
|
||||
"ArchitectureSnapshot",
|
||||
"GlmTargetError",
|
||||
"NodeMemory",
|
||||
"ResourcePlanError",
|
||||
"RouteFit",
|
||||
"SeamPlan",
|
||||
"Shard",
|
||||
"TargetManifest",
|
||||
"TopologyPlan",
|
||||
"canonical_sha256",
|
||||
"compute_contract_digest",
|
||||
"kv_bytes",
|
||||
"load_alpha_contract",
|
||||
"load_architecture_snapshot",
|
||||
"load_locked_target",
|
||||
"load_target_manifest",
|
||||
"parse_alpha_contract",
|
||||
"parse_architecture_snapshot",
|
||||
"parse_target_manifest",
|
||||
"plan_all_tiers",
|
||||
"plan_route",
|
||||
"plan_seams",
|
||||
"plan_topology",
|
||||
"require_contract_target",
|
||||
"require_pinned_target",
|
||||
"seal_contract",
|
||||
]
|
||||
332
packages/node/meshnet_node/glm_alpha/contract.py
Normal file
332
packages/node/meshnet_node/glm_alpha/contract.py
Normal file
@@ -0,0 +1,332 @@
|
||||
"""The immutable GLM-5.2 Max alpha acceptance contract.
|
||||
|
||||
The contract exists to answer one question that cannot be answered honestly after
|
||||
the fact: *what would have counted as success?*
|
||||
|
||||
Its thresholds are locked before the target ever runs (DGR-017), and DGR-020 reads
|
||||
them back to publish an ``alpha`` or ``stop`` verdict. The whole point is that the
|
||||
gap between those two moments is where a threshold quietly becomes "0.1 tokens/sec
|
||||
was always the goal". So the document carries ``contract_sha256`` over its own
|
||||
canonical content, and :func:`load_alpha_contract` recomputes it on every load. An
|
||||
agent that edits a threshold and forgets the digest is rejected; an agent that
|
||||
edits both has left a diff on a file whose whole purpose is to not change.
|
||||
|
||||
This is a tamper-*evidence* mechanism, not tamper-proofing. It cannot stop a
|
||||
determined rewrite of the file and the digest together — nothing in-repo can. What
|
||||
it does is remove the possibility of a silent one, which is the failure mode that
|
||||
actually happens: a number nudged mid-run, with no reviewer ever seeing that it
|
||||
moved.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from importlib.resources import files
|
||||
from pathlib import Path
|
||||
from typing import Any, Mapping
|
||||
|
||||
from .manifest import (
|
||||
ALPHA_QUANTIZATION,
|
||||
ALPHA_SHARD_COUNT,
|
||||
ArchitectureSnapshot,
|
||||
GlmTargetError,
|
||||
TargetManifest,
|
||||
canonical_sha256,
|
||||
)
|
||||
|
||||
ALPHA_CONTRACT_SCHEMA_VERSION = 1
|
||||
ALPHA_CONTRACT_VERSION = 1
|
||||
ALPHA_CONTRACT_ID = "glm-5.2-max-alpha/v1"
|
||||
|
||||
_CONTRACT_RESOURCE = "alpha-contract.json"
|
||||
|
||||
DIGEST_FIELD = "contract_sha256"
|
||||
|
||||
VERDICT_ALPHA = "alpha"
|
||||
VERDICT_STOP = "stop"
|
||||
|
||||
# Every section the roadmap's acceptance matrix (section 5) locks. A contract that
|
||||
# omits one is not a weaker contract, it is an unreviewable one.
|
||||
REQUIRED_SECTIONS: tuple[str, ...] = (
|
||||
"identity_and_fit",
|
||||
"semantic_correctness",
|
||||
"target_run",
|
||||
"performance",
|
||||
"reliability",
|
||||
"storage",
|
||||
)
|
||||
|
||||
|
||||
class AlphaContractError(GlmTargetError):
|
||||
"""Raised when the alpha contract is missing, malformed, or has been mutated."""
|
||||
|
||||
|
||||
def contract_signing_payload(document: Mapping[str, Any]) -> dict:
|
||||
"""The contract content the digest covers: everything except the digest itself."""
|
||||
unsigned = dict(document)
|
||||
unsigned.pop(DIGEST_FIELD, None)
|
||||
return unsigned
|
||||
|
||||
|
||||
def compute_contract_digest(document: Mapping[str, Any]) -> str:
|
||||
"""SHA-256 over the canonical contract content."""
|
||||
return canonical_sha256(contract_signing_payload(document))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AlphaContract:
|
||||
"""A locked, digest-bound alpha acceptance contract."""
|
||||
|
||||
schema_version: int
|
||||
contract_version: int
|
||||
contract_id: str
|
||||
locked_at: str
|
||||
locked_by: str
|
||||
target: Mapping[str, Any]
|
||||
sections: Mapping[str, Mapping[str, Any]]
|
||||
verdicts: tuple[str, ...]
|
||||
amendment_policy: str
|
||||
digest: str
|
||||
raw: Mapping[str, Any]
|
||||
source: str = "<memory>"
|
||||
|
||||
def section(self, name: str) -> Mapping[str, Any]:
|
||||
if name not in self.sections:
|
||||
raise AlphaContractError(f"contract section {name!r} is missing from {self.source}")
|
||||
return self.sections[name]
|
||||
|
||||
def threshold(self, section: str, key: str) -> Any:
|
||||
block = self.section(section)
|
||||
if key not in block:
|
||||
raise AlphaContractError(
|
||||
f"threshold {section}.{key} is not locked in {self.source}; an unlocked "
|
||||
"threshold cannot be used to judge a result"
|
||||
)
|
||||
return block[key]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return dict(self.raw)
|
||||
|
||||
|
||||
def parse_alpha_contract(data: Any, source: str = "<memory>") -> AlphaContract:
|
||||
"""Validate a contract document and verify it has not been mutated since locking."""
|
||||
if not isinstance(data, Mapping):
|
||||
raise AlphaContractError(f"contract root in {source} must be a JSON object")
|
||||
|
||||
schema_version = data.get("schema_version")
|
||||
if (
|
||||
not isinstance(schema_version, int)
|
||||
or isinstance(schema_version, bool)
|
||||
or schema_version != ALPHA_CONTRACT_SCHEMA_VERSION
|
||||
):
|
||||
raise AlphaContractError(
|
||||
f"{source} declares alpha-contract schema version {schema_version!r}, but this "
|
||||
f"node reads version {ALPHA_CONTRACT_SCHEMA_VERSION}"
|
||||
)
|
||||
|
||||
contract_version = data.get("contract_version")
|
||||
if (
|
||||
not isinstance(contract_version, int)
|
||||
or isinstance(contract_version, bool)
|
||||
or contract_version != ALPHA_CONTRACT_VERSION
|
||||
):
|
||||
raise AlphaContractError(
|
||||
f"{source} declares contract version {contract_version!r}, but this node "
|
||||
f"reads version {ALPHA_CONTRACT_VERSION}"
|
||||
)
|
||||
|
||||
contract_id = data.get("contract_id")
|
||||
if contract_id != ALPHA_CONTRACT_ID:
|
||||
raise AlphaContractError(
|
||||
f"{source} declares contract_id {contract_id!r}, but this node is locked "
|
||||
f"to {ALPHA_CONTRACT_ID!r}"
|
||||
)
|
||||
|
||||
for field in ("locked_at", "locked_by"):
|
||||
value = data.get(field)
|
||||
if not isinstance(value, str) or not value.strip():
|
||||
raise AlphaContractError(f"{source} must carry a non-empty {field}")
|
||||
|
||||
declared = data.get(DIGEST_FIELD)
|
||||
if not isinstance(declared, str) or not declared:
|
||||
raise AlphaContractError(
|
||||
f"{source} carries no {DIGEST_FIELD}; an unsealed contract cannot prove it "
|
||||
"predates the results it judges"
|
||||
)
|
||||
|
||||
computed = compute_contract_digest(data)
|
||||
if computed != declared:
|
||||
raise AlphaContractError(
|
||||
f"{source} has been modified since it was locked: its content hashes to "
|
||||
f"{computed}, but it declares {declared}. Alpha thresholds are locked before "
|
||||
"target execution and may not be weakened afterwards. To change them, open a "
|
||||
"new contract_id under human review; do not edit this one."
|
||||
)
|
||||
|
||||
if not data.get("locked_before_target_execution"):
|
||||
raise AlphaContractError(
|
||||
f"{source} does not assert locked_before_target_execution; a contract written "
|
||||
"after the results are known is not a contract"
|
||||
)
|
||||
|
||||
missing = [name for name in REQUIRED_SECTIONS if not isinstance(data.get(name), Mapping)]
|
||||
if missing:
|
||||
raise AlphaContractError(
|
||||
f"{source} is missing locked acceptance section(s) {missing}"
|
||||
)
|
||||
|
||||
verdicts = data.get("verdicts")
|
||||
if not isinstance(verdicts, list) or sorted(verdicts) != sorted([VERDICT_ALPHA, VERDICT_STOP]):
|
||||
raise AlphaContractError(
|
||||
f"{source} must offer exactly the verdicts {[VERDICT_ALPHA, VERDICT_STOP]}; a "
|
||||
"third outcome is how 'it loaded' becomes a pass"
|
||||
)
|
||||
|
||||
target = data.get("target")
|
||||
if not isinstance(target, Mapping):
|
||||
raise AlphaContractError(f"{source} is missing its 'target' block")
|
||||
for field in (
|
||||
"source_repo_id",
|
||||
"source_revision",
|
||||
"gguf_repo_id",
|
||||
"gguf_revision",
|
||||
"quantization",
|
||||
"target_manifest_sha256",
|
||||
"architecture_snapshot_sha256",
|
||||
"reasoning_effort",
|
||||
):
|
||||
if not target.get(field):
|
||||
raise AlphaContractError(f"{source} target block is missing {field!r}")
|
||||
for field in ("source_revision", "gguf_revision"):
|
||||
if not re.fullmatch(r"[0-9a-f]{40}", str(target[field])):
|
||||
raise AlphaContractError(f"{source} target.{field} is not a full commit revision")
|
||||
for field in ("target_manifest_sha256", "architecture_snapshot_sha256"):
|
||||
if not re.fullmatch(r"[0-9a-f]{64}", str(target[field])):
|
||||
raise AlphaContractError(f"{source} target.{field} is not a SHA-256 digest")
|
||||
if target["quantization"] != ALPHA_QUANTIZATION:
|
||||
raise AlphaContractError(
|
||||
f"{source} targets {target['quantization']!r}, not locked alpha quantization "
|
||||
f"{ALPHA_QUANTIZATION!r}"
|
||||
)
|
||||
if target["reasoning_effort"] != "max":
|
||||
raise AlphaContractError(f"{source} must lock reasoning_effort='max'")
|
||||
shard_count = target.get("shard_count")
|
||||
if (
|
||||
not isinstance(shard_count, int)
|
||||
or isinstance(shard_count, bool)
|
||||
or shard_count != ALPHA_SHARD_COUNT
|
||||
):
|
||||
raise AlphaContractError(
|
||||
f"{source} target.shard_count must be exactly {ALPHA_SHARD_COUNT}"
|
||||
)
|
||||
total_bytes = target.get("total_bytes")
|
||||
if not isinstance(total_bytes, int) or isinstance(total_bytes, bool) or total_bytes <= 0:
|
||||
raise AlphaContractError(f"{source} target.total_bytes must be a positive integer")
|
||||
|
||||
amendment_policy = data.get("amendment_policy")
|
||||
if not isinstance(amendment_policy, str) or not amendment_policy.strip():
|
||||
raise AlphaContractError(f"{source} must state its amendment policy")
|
||||
|
||||
return AlphaContract(
|
||||
schema_version=schema_version,
|
||||
contract_version=contract_version,
|
||||
contract_id=contract_id,
|
||||
locked_at=str(data["locked_at"]),
|
||||
locked_by=str(data["locked_by"]),
|
||||
target=target,
|
||||
sections={name: data[name] for name in REQUIRED_SECTIONS},
|
||||
verdicts=tuple(verdicts),
|
||||
amendment_policy=amendment_policy,
|
||||
digest=declared,
|
||||
raw=data,
|
||||
source=source,
|
||||
)
|
||||
|
||||
|
||||
def require_contract_target(
|
||||
contract: AlphaContract,
|
||||
manifest: TargetManifest,
|
||||
snapshot: ArchitectureSnapshot,
|
||||
) -> None:
|
||||
"""Bind the sealed contract to the exact manifest and architecture snapshot.
|
||||
|
||||
Repository revisions alone do not bind shard LFS objects or derived architecture
|
||||
semantics. Call this before planning, admission, download, or execution.
|
||||
"""
|
||||
|
||||
expected = contract.target
|
||||
actual = {
|
||||
"source_repo_id": manifest.source_repo_id,
|
||||
"source_revision": manifest.source_revision,
|
||||
"gguf_repo_id": manifest.gguf_repo_id,
|
||||
"gguf_revision": manifest.gguf_revision,
|
||||
"quantization": manifest.quantization,
|
||||
"shard_count": len(manifest.shards),
|
||||
"total_bytes": manifest.total_bytes,
|
||||
"target_manifest_sha256": manifest.digest,
|
||||
"architecture_snapshot_sha256": snapshot.digest,
|
||||
}
|
||||
if snapshot.source_repo_id != manifest.source_repo_id:
|
||||
raise AlphaContractError(
|
||||
"architecture snapshot repository does not match the target manifest repository"
|
||||
)
|
||||
if snapshot.source_revision != manifest.source_revision:
|
||||
raise AlphaContractError(
|
||||
"architecture snapshot revision does not match the target manifest revision"
|
||||
)
|
||||
mismatches = {
|
||||
key: (expected.get(key), value)
|
||||
for key, value in actual.items()
|
||||
if expected.get(key) != value
|
||||
}
|
||||
if mismatches:
|
||||
details = ", ".join(
|
||||
f"{key}: locked={locked!r}, actual={value!r}"
|
||||
for key, (locked, value) in sorted(mismatches.items())
|
||||
)
|
||||
raise AlphaContractError(f"target documents do not match the sealed contract: {details}")
|
||||
|
||||
|
||||
def load_alpha_contract(path: Path | None = None) -> AlphaContract:
|
||||
"""Load the packaged alpha contract, or one at ``path``."""
|
||||
if path is not None:
|
||||
source = str(path)
|
||||
try:
|
||||
raw = path.read_text(encoding="utf-8")
|
||||
except OSError as exc:
|
||||
raise AlphaContractError(f"cannot read {source}: {exc.strerror or exc}") from exc
|
||||
else:
|
||||
source = f"packaged {_CONTRACT_RESOURCE}"
|
||||
try:
|
||||
raw = (
|
||||
files("meshnet_node.glm_alpha")
|
||||
.joinpath("data", _CONTRACT_RESOURCE)
|
||||
.read_text(encoding="utf-8")
|
||||
)
|
||||
except (OSError, FileNotFoundError, ModuleNotFoundError) as exc:
|
||||
raise AlphaContractError(
|
||||
f"{source} is missing from this node installation ({type(exc).__name__})"
|
||||
) from exc
|
||||
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise AlphaContractError(
|
||||
f"{source} is not valid JSON: {exc.msg} at line {exc.lineno} column {exc.colno}"
|
||||
) from exc
|
||||
|
||||
return parse_alpha_contract(data, source=source)
|
||||
|
||||
|
||||
def seal_contract(document: Mapping[str, Any]) -> dict:
|
||||
"""Return the document with a freshly computed digest.
|
||||
|
||||
This is the only supported way to produce a contract file. It is deliberately
|
||||
*not* called at load time: sealing on load would turn every mutation into a
|
||||
valid contract, which is precisely the property the digest exists to deny.
|
||||
"""
|
||||
sealed = dict(document)
|
||||
sealed[DIGEST_FIELD] = compute_contract_digest(document)
|
||||
return sealed
|
||||
122
packages/node/meshnet_node/glm_alpha/data/alpha-contract.json
Normal file
122
packages/node/meshnet_node/glm_alpha/data/alpha-contract.json
Normal file
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"contract_version": 1,
|
||||
"contract_id": "glm-5.2-max-alpha/v1",
|
||||
"locked_at": "2026-07-13",
|
||||
"locked_by": "DGR-017",
|
||||
"locked_before_target_execution": true,
|
||||
"target": {
|
||||
"source_repo_id": "zai-org/GLM-5.2",
|
||||
"source_revision": "b4734de4facf877f85769a911abafc5283eab3d9",
|
||||
"gguf_repo_id": "unsloth/GLM-5.2-GGUF",
|
||||
"gguf_revision": "abc55e72527792c6e77069c99b4cb7de16fa9f23",
|
||||
"quantization": "UD-IQ1_S",
|
||||
"shard_count": 6,
|
||||
"total_bytes": 216715360960,
|
||||
"target_manifest_sha256": "0b6aed04479d204902bb64c0203f1a46cab26a47b378ecccf85237b63f6c1962",
|
||||
"architecture_snapshot_sha256": "253fbd94b06b42acc4724ec2c7f33914e2d4cc43f54a36dff6af19a80ae6ceb1",
|
||||
"reasoning_effort": "max"
|
||||
},
|
||||
"identity_and_fit": {
|
||||
"require_exact_revisions": true,
|
||||
"require_all_shard_sha256": true,
|
||||
"require_per_node_owned_tensor_report": true,
|
||||
"require_owned_tensor_union_equals_inventory": true,
|
||||
"max_unintended_tensor_overlap": 0,
|
||||
"require_no_single_node_can_admit_complete_recipe": true,
|
||||
"min_node_reserve_fraction": 0.2,
|
||||
"min_node_reserve_gib": 8.0,
|
||||
"require_measured_peak_scratch_inside_reserve": true,
|
||||
"forbid_swap": true,
|
||||
"forbid_overcommit": true,
|
||||
"forbid_mmap_only_fit_claim": true,
|
||||
"forbid_double_counted_unified_memory": true,
|
||||
"aggregate_hard_fit_floor_gib": 224.0,
|
||||
"aggregate_floor_class": "experimental_hard_fit_floor",
|
||||
"recommended_topologies": [
|
||||
"5x64GiB",
|
||||
"3x96GiB",
|
||||
"3x128GiB"
|
||||
],
|
||||
"arithmetic_minimum_requires_measured_placement_evidence": true
|
||||
},
|
||||
"semantic_correctness": {
|
||||
"require_active_moe_routing": true,
|
||||
"require_active_shared_expert": true,
|
||||
"require_active_dsa_lightning_indexer": true,
|
||||
"require_active_sparse_attention": true,
|
||||
"require_active_indexshare_full_and_shared": true,
|
||||
"dense_attention_fallback_satisfies_alpha": false,
|
||||
"require_rendered_reasoning_effort_marker": "<|system|>Reasoning Effort: Max",
|
||||
"f32_seam_fixture_exact_match_tokens": 32,
|
||||
"f32_seam_fixture_requires_exact_match": true,
|
||||
"min_greedy_token_agreement": 0.9,
|
||||
"min_mean_state_cosine_similarity": 0.999,
|
||||
"forbid_nonfinite_tensors": true,
|
||||
"require_fail_closed_on_fingerprint_mismatch": true
|
||||
},
|
||||
"target_run": {
|
||||
"context_tokens": 16384,
|
||||
"kv_dtype": "Q8_0",
|
||||
"concurrency": 1,
|
||||
"prompt_lane_tokens": 4096,
|
||||
"min_output_tokens": 512,
|
||||
"min_output_tokens_with_natural_eos": 128,
|
||||
"require_same_switch_wired_network": true,
|
||||
"min_link_rate_gbps": 2.5,
|
||||
"recommended_link_rate_gbps": 10.0,
|
||||
"require_sentinels": [
|
||||
"coding",
|
||||
"structured_tool_call_json",
|
||||
"multi_step_reasoning"
|
||||
],
|
||||
"require_openai_compatible_response_fields": [
|
||||
"model",
|
||||
"finish_reason",
|
||||
"usage"
|
||||
]
|
||||
},
|
||||
"performance": {
|
||||
"min_median_decode_tokens_per_second": 0.5,
|
||||
"max_ttft_seconds_at_4096_prompt": 600,
|
||||
"max_unexplained_stall_seconds": 60,
|
||||
"warmups": 1,
|
||||
"require_per_stage_telemetry": [
|
||||
"compute",
|
||||
"queue",
|
||||
"kv",
|
||||
"seam_bytes",
|
||||
"seam_latency",
|
||||
"rss",
|
||||
"vram",
|
||||
"backend_timing"
|
||||
],
|
||||
"quality_pass_with_speed_fail_verdict": "stop",
|
||||
"forbid_generalising_results_to_other_hardware": true
|
||||
},
|
||||
"reliability": {
|
||||
"consecutive_clean_cold_starts": 2,
|
||||
"require_cancellation_releases_buffers_and_kv": true,
|
||||
"require_worker_loss_aborts_route": true,
|
||||
"retry_policy": "from_token_zero_on_new_compatible_route",
|
||||
"forbid_silent_kv_migration": true,
|
||||
"require_reject_stale_epoch": true,
|
||||
"require_reject_duplicate_step_id": true,
|
||||
"synthetic_workers_satisfy_alpha": false,
|
||||
"layer_reduced_fixtures_satisfy_alpha": false
|
||||
},
|
||||
"storage": {
|
||||
"mounted_storage_only": true,
|
||||
"forbidden_path_prefixes": [
|
||||
"/home"
|
||||
],
|
||||
"forbid_secrets_in_logs": true,
|
||||
"forbid_unrestricted_prompt_payloads_in_logs": true
|
||||
},
|
||||
"verdicts": [
|
||||
"alpha",
|
||||
"stop"
|
||||
],
|
||||
"amendment_policy": "Thresholds are locked before target execution. They may not be weakened, moved, or reinterpreted after results are known. A change requires a new contract_id and contract_version under human review, and the superseded contract is retained.",
|
||||
"contract_sha256": "aab23220280c053a3c14ff559df3cb5c9e1bf7f0f7188c6519e2e9d9ad036ed9"
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"observed_at": "2026-07-13",
|
||||
"source_repo_id": "zai-org/GLM-5.2",
|
||||
"source_revision": "b4734de4facf877f85769a911abafc5283eab3d9",
|
||||
"source_files": [
|
||||
{
|
||||
"path": "config.json",
|
||||
"size_bytes": 3732,
|
||||
"sha256": "185f93ee6d12548e16a847e279dc0c3c90b1524c970b0866b42fb545747d859a",
|
||||
"url": "https://huggingface.co/zai-org/GLM-5.2/resolve/b4734de4facf877f85769a911abafc5283eab3d9/config.json"
|
||||
},
|
||||
{
|
||||
"path": "chat_template.jinja",
|
||||
"size_bytes": 5076,
|
||||
"sha256": "172dc74a35e1752df75ecfb2b2cf9326d2852bb1379868ebeec9571654489679",
|
||||
"url": "https://huggingface.co/zai-org/GLM-5.2/resolve/b4734de4facf877f85769a911abafc5283eab3d9/chat_template.jinja"
|
||||
},
|
||||
{
|
||||
"path": "generation_config.json",
|
||||
"size_bytes": 194,
|
||||
"sha256": "ac76b43d8683d3b930126870fc8be73d8679308fe752fa1f381096d8354f6a55",
|
||||
"url": "https://huggingface.co/zai-org/GLM-5.2/resolve/b4734de4facf877f85769a911abafc5283eab3d9/generation_config.json"
|
||||
},
|
||||
{
|
||||
"path": "tokenizer_config.json",
|
||||
"size_bytes": 761,
|
||||
"sha256": "98b1271574f41abf89427ae2dda030d94dc9478f0edc5a8bd240db213c6fd5fc",
|
||||
"url": "https://huggingface.co/zai-org/GLM-5.2/resolve/b4734de4facf877f85769a911abafc5283eab3d9/tokenizer_config.json"
|
||||
}
|
||||
],
|
||||
"architecture": {
|
||||
"architectures": [
|
||||
"GlmMoeDsaForCausalLM"
|
||||
],
|
||||
"model_type": "glm_moe_dsa",
|
||||
"num_hidden_layers": 78,
|
||||
"num_nextn_predict_layers": 1,
|
||||
"total_artifact_layers": 79,
|
||||
"first_k_dense_replace": 3,
|
||||
"dense_layers": 3,
|
||||
"sparse_moe_layers": 75,
|
||||
"hidden_size": 6144,
|
||||
"intermediate_size": 12288,
|
||||
"moe_intermediate_size": 2048,
|
||||
"n_routed_experts": 256,
|
||||
"num_experts_per_tok": 8,
|
||||
"n_shared_experts": 1,
|
||||
"scoring_func": "sigmoid",
|
||||
"topk_method": "noaux_tc",
|
||||
"norm_topk_prob": true,
|
||||
"routed_scaling_factor": 2.5,
|
||||
"num_attention_heads": 64,
|
||||
"head_dim": 192,
|
||||
"qk_nope_head_dim": 192,
|
||||
"qk_rope_head_dim": 64,
|
||||
"qk_head_dim": 256,
|
||||
"v_head_dim": 256,
|
||||
"kv_lora_rank": 512,
|
||||
"q_lora_rank": 2048,
|
||||
"mla_cached_values_per_token_per_layer": 576,
|
||||
"index_topk": 2048,
|
||||
"index_head_dim": 128,
|
||||
"index_n_heads": 32,
|
||||
"index_topk_freq": 4,
|
||||
"index_skip_topk_offset": 3,
|
||||
"index_share_for_mtp_iteration": true,
|
||||
"indexer_full_layers": 21,
|
||||
"indexer_shared_layers": 57,
|
||||
"indexer_types_sha256": "ec3b4927af83cf02baf37fb10454c40176ec8bf501ae89334b27a9df5fa17025",
|
||||
"max_position_embeddings": 1048576,
|
||||
"vocab_size": 154880,
|
||||
"rope_theta": 8000000,
|
||||
"dtype": "bfloat16",
|
||||
"tie_word_embeddings": false
|
||||
},
|
||||
"reasoning_effort": {
|
||||
"alpha_mode": "max",
|
||||
"rendered_marker": "<|system|>Reasoning Effort: Max",
|
||||
"template_rule": "effective_reasoning_effort = 'high' if reasoning_effort == 'high' else 'max'",
|
||||
"default_is_max": true,
|
||||
"suppressed_when": "enable_thinking is defined and false",
|
||||
"note": "The template recognises exactly one non-max level ('high'); every other value, including an absent reasoning_effort, renders Max. Alpha therefore asserts the rendered 'Reasoning Effort: Max' marker, not merely the presence of a request field."
|
||||
},
|
||||
"notes": [
|
||||
"indexer_types has 78 entries: layers 0-2 are 'full', then a repeating [shared, shared, shared, full] pattern, giving 21 Full producer layers and 57 Shared consumer layers.",
|
||||
"MLA caches kv_lora_rank (512) + qk_rope_head_dim (64) = 576 values per token per backbone layer.",
|
||||
"num_nextn_predict_layers=1 is the NextN/MTP layer present in the artifact. Alpha does not run MTP; the tensors are loaded or explicitly excluded by a certified recipe and must never be silently reinterpreted as a 79th backbone layer.",
|
||||
"Values are derived from the pinned config.json. The runtime must re-derive them from the artifact and fail closed on contradictory metadata; marketing names are not compatibility identity."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"manifest_version": 1,
|
||||
"observed_at": "2026-07-13",
|
||||
"observed_by": "DGR-017",
|
||||
"alpha_quantization": "UD-IQ1_S",
|
||||
"source_model": {
|
||||
"repo_id": "zai-org/GLM-5.2",
|
||||
"revision": "b4734de4facf877f85769a911abafc5283eab3d9",
|
||||
"last_modified": "2026-07-02T08:08:14.000Z",
|
||||
"weight_license": "mit",
|
||||
"code_documentation_license": "apache-2.0",
|
||||
"url": "https://huggingface.co/zai-org/GLM-5.2",
|
||||
"revision_url": "https://huggingface.co/zai-org/GLM-5.2/tree/b4734de4facf877f85769a911abafc5283eab3d9",
|
||||
"api_url": "https://huggingface.co/api/models/zai-org/GLM-5.2"
|
||||
},
|
||||
"gguf_artifact": {
|
||||
"repo_id": "unsloth/GLM-5.2-GGUF",
|
||||
"revision": "abc55e72527792c6e77069c99b4cb7de16fa9f23",
|
||||
"last_modified": "2026-06-23T15:18:23.000Z",
|
||||
"license": "mit",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF",
|
||||
"revision_url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/tree/abc55e72527792c6e77069c99b4cb7de16fa9f23",
|
||||
"api_url": "https://huggingface.co/api/models/unsloth/GLM-5.2-GGUF",
|
||||
"quantization": "UD-IQ1_S",
|
||||
"shard_count": 6,
|
||||
"total_bytes": 216715360960,
|
||||
"total_gib": 201.832,
|
||||
"total_gb": 216.715,
|
||||
"shards": [
|
||||
{
|
||||
"index": 1,
|
||||
"path": "UD-IQ1_S/GLM-5.2-UD-IQ1_S-00001-of-00006.gguf",
|
||||
"size_bytes": 9423744,
|
||||
"sha256": "46b6148389219ae45167cb8124fbb18ef7d432daf619b4faf9e06ea80d3f4777",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/resolve/abc55e72527792c6e77069c99b4cb7de16fa9f23/UD-IQ1_S/GLM-5.2-UD-IQ1_S-00001-of-00006.gguf"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"path": "UD-IQ1_S/GLM-5.2-UD-IQ1_S-00002-of-00006.gguf",
|
||||
"size_bytes": 49208128256,
|
||||
"sha256": "f2180207285e04fcaa5b8c53ba6e77ad5cc58666b6e7c6b04a5eded3fe8bef09",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/resolve/abc55e72527792c6e77069c99b4cb7de16fa9f23/UD-IQ1_S/GLM-5.2-UD-IQ1_S-00002-of-00006.gguf"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"path": "UD-IQ1_S/GLM-5.2-UD-IQ1_S-00003-of-00006.gguf",
|
||||
"size_bytes": 49684417024,
|
||||
"sha256": "b1c0c5a302cc8d5d9ea0bcd4467c01db72c26839f820f7e882079582ea0a8d2b",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/resolve/abc55e72527792c6e77069c99b4cb7de16fa9f23/UD-IQ1_S/GLM-5.2-UD-IQ1_S-00003-of-00006.gguf"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"path": "UD-IQ1_S/GLM-5.2-UD-IQ1_S-00004-of-00006.gguf",
|
||||
"size_bytes": 49396052864,
|
||||
"sha256": "a6a42da6975e29f89866dcde2956e9e50e6ea26635fb5063b74f3973f4f863b6",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/resolve/abc55e72527792c6e77069c99b4cb7de16fa9f23/UD-IQ1_S/GLM-5.2-UD-IQ1_S-00004-of-00006.gguf"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"path": "UD-IQ1_S/GLM-5.2-UD-IQ1_S-00005-of-00006.gguf",
|
||||
"size_bytes": 49246275936,
|
||||
"sha256": "a4a9851a50db533f21ef824e5d8038f04e6782e7d602d18e5fdd6643f68ccccb",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/resolve/abc55e72527792c6e77069c99b4cb7de16fa9f23/UD-IQ1_S/GLM-5.2-UD-IQ1_S-00005-of-00006.gguf"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"path": "UD-IQ1_S/GLM-5.2-UD-IQ1_S-00006-of-00006.gguf",
|
||||
"size_bytes": 19171063136,
|
||||
"sha256": "3b767f55df64e0432d52fcf1a14eb47a1ef3bbc91339e2ae220f38602237d7d7",
|
||||
"url": "https://huggingface.co/unsloth/GLM-5.2-GGUF/resolve/abc55e72527792c6e77069c99b4cb7de16fa9f23/UD-IQ1_S/GLM-5.2-UD-IQ1_S-00006-of-00006.gguf"
|
||||
}
|
||||
]
|
||||
},
|
||||
"diagnostic_fallback": {
|
||||
"quantization": "UD-IQ1_M",
|
||||
"shard_count": 6,
|
||||
"total_bytes": 228492966624,
|
||||
"total_gib": 212.801,
|
||||
"total_gb": 228.493,
|
||||
"policy": "First diagnostic fallback only if UD-IQ1_S exposes a runtime or quality defect. It does not satisfy the alpha 'lowest published quantization' target unless human review changes the target contract."
|
||||
},
|
||||
"storage": {
|
||||
"mounted_storage_only": true,
|
||||
"forbidden_path_prefixes": [
|
||||
"/home"
|
||||
],
|
||||
"note": "Model artifacts resolve through the machine-specific .env.<hostname> mounted-drive configuration. A path under /home fails admission closed."
|
||||
}
|
||||
}
|
||||
490
packages/node/meshnet_node/glm_alpha/manifest.py
Normal file
490
packages/node/meshnet_node/glm_alpha/manifest.py
Normal file
@@ -0,0 +1,490 @@
|
||||
"""The pinned GLM-5.2 Max target manifest and architecture snapshot.
|
||||
|
||||
This module is the *identity* half of the alpha target contract. It answers one
|
||||
question: is the artifact on this disk the exact artifact alpha was locked
|
||||
against?
|
||||
|
||||
Identity is pinned by repository revision **and** by every shard's LFS SHA-256.
|
||||
A revision alone is not enough — a repository can be force-pushed, and a tag can
|
||||
be moved — and a size alone is not enough, because two different quantizations of
|
||||
the same model land within a rounding error of each other. The manifest therefore
|
||||
carries both, plus the aggregate byte total, and cross-checks the aggregate
|
||||
against the sum of the shards. A manifest whose declared total disagrees with its
|
||||
own shards is rejected rather than trusted, because that is the exact shape a
|
||||
hand-edited "it fits now" manifest takes.
|
||||
|
||||
Nothing here downloads a weight payload. Sizes and hashes come from the Hugging
|
||||
Face metadata API (see ``scripts/refresh_glm_target_manifest.py``); verification
|
||||
against a local file is DGR-018's job, using the digests locked here.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from importlib.resources import files
|
||||
from pathlib import Path
|
||||
from typing import Any, Mapping
|
||||
|
||||
TARGET_MANIFEST_SCHEMA_VERSION = 1
|
||||
ARCHITECTURE_SNAPSHOT_SCHEMA_VERSION = 1
|
||||
|
||||
ALPHA_QUANTIZATION = "UD-IQ1_S"
|
||||
ALPHA_SHARD_COUNT = 6
|
||||
|
||||
_SHA256_RE = re.compile(r"\A[0-9a-f]{64}\Z")
|
||||
|
||||
_MANIFEST_RESOURCE = "target-manifest.json"
|
||||
_ARCHITECTURE_RESOURCE = "architecture-snapshot.json"
|
||||
|
||||
GIB = 1024**3
|
||||
GB = 1000**3
|
||||
|
||||
|
||||
class GlmTargetError(ValueError):
|
||||
"""Raised when the target manifest or architecture snapshot is not the pinned target."""
|
||||
|
||||
|
||||
def canonical_sha256(value: Any) -> str:
|
||||
"""SHA-256 over canonical JSON — the repository's digest convention."""
|
||||
payload = json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
|
||||
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def _require_mapping(value: Any, what: str) -> Mapping[str, Any]:
|
||||
if not isinstance(value, Mapping):
|
||||
raise GlmTargetError(f"{what} must be a JSON object, got {type(value).__name__}")
|
||||
return value
|
||||
|
||||
|
||||
def _require_text(value: Any, what: str) -> str:
|
||||
if not isinstance(value, str) or not value.strip():
|
||||
raise GlmTargetError(f"{what} must be a non-empty string")
|
||||
return value
|
||||
|
||||
|
||||
def _require_int(value: Any, what: str) -> int:
|
||||
if not isinstance(value, int) or isinstance(value, bool):
|
||||
raise GlmTargetError(f"{what} must be an integer, got {type(value).__name__}")
|
||||
return value
|
||||
|
||||
|
||||
def _require_sha256(value: Any, what: str) -> str:
|
||||
text = _require_text(value, what)
|
||||
if not _SHA256_RE.match(text):
|
||||
raise GlmTargetError(
|
||||
f"{what} must be a lowercase 64-character hex SHA-256, got {text!r}"
|
||||
)
|
||||
return text
|
||||
|
||||
|
||||
def _require_revision(value: Any, what: str) -> str:
|
||||
text = _require_text(value, what)
|
||||
if not re.fullmatch(r"[0-9a-f]{40}", text):
|
||||
raise GlmTargetError(
|
||||
f"{what} must be a full 40-character commit revision, got {text!r}; "
|
||||
"a branch name or short SHA is not an immutable pin"
|
||||
)
|
||||
return text
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Shard:
|
||||
"""One GGUF shard of the alpha artifact."""
|
||||
|
||||
index: int
|
||||
path: str
|
||||
size_bytes: int
|
||||
sha256: str
|
||||
url: str
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"index": self.index,
|
||||
"path": self.path,
|
||||
"size_bytes": self.size_bytes,
|
||||
"sha256": self.sha256,
|
||||
"url": self.url,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TargetManifest:
|
||||
"""The pinned, self-consistent GLM-5.2 ``UD-IQ1_S`` target."""
|
||||
|
||||
schema_version: int
|
||||
manifest_version: int
|
||||
observed_at: str
|
||||
quantization: str
|
||||
source_repo_id: str
|
||||
source_revision: str
|
||||
source_license: str
|
||||
gguf_repo_id: str
|
||||
gguf_revision: str
|
||||
gguf_license: str
|
||||
total_bytes: int
|
||||
shards: tuple[Shard, ...]
|
||||
raw: Mapping[str, Any]
|
||||
source: str = "<memory>"
|
||||
|
||||
@property
|
||||
def total_gib(self) -> float:
|
||||
return self.total_bytes / GIB
|
||||
|
||||
@property
|
||||
def total_gb(self) -> float:
|
||||
return self.total_bytes / GB
|
||||
|
||||
def shard(self, index: int) -> Shard:
|
||||
for shard in self.shards:
|
||||
if shard.index == index:
|
||||
return shard
|
||||
raise GlmTargetError(f"shard {index} is not in {self.source}")
|
||||
|
||||
@property
|
||||
def digest(self) -> str:
|
||||
"""Stable identity of this manifest, for the DGR-003 runtime recipe."""
|
||||
return canonical_sha256(self.raw)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return dict(self.raw)
|
||||
|
||||
|
||||
def _parse_shards(raw: Any, expected_count: int, expected_total: int) -> tuple[Shard, ...]:
|
||||
if not isinstance(raw, list):
|
||||
raise GlmTargetError("gguf_artifact.shards must be a JSON array")
|
||||
if len(raw) != expected_count:
|
||||
raise GlmTargetError(
|
||||
f"the alpha artifact has exactly {expected_count} shards, "
|
||||
f"but the manifest lists {len(raw)}"
|
||||
)
|
||||
|
||||
shards: list[Shard] = []
|
||||
seen_index: set[int] = set()
|
||||
seen_sha: set[str] = set()
|
||||
for position, entry in enumerate(raw):
|
||||
item = _require_mapping(entry, f"shards[{position}]")
|
||||
index = _require_int(item.get("index"), f"shards[{position}].index")
|
||||
if index in seen_index:
|
||||
raise GlmTargetError(f"duplicate shard index {index} in the manifest")
|
||||
seen_index.add(index)
|
||||
size_bytes = _require_int(item.get("size_bytes"), f"shards[{index}].size_bytes")
|
||||
if size_bytes <= 0:
|
||||
raise GlmTargetError(f"shards[{index}].size_bytes must be positive")
|
||||
sha256 = _require_sha256(item.get("sha256"), f"shards[{index}].sha256")
|
||||
if sha256 in seen_sha:
|
||||
raise GlmTargetError(
|
||||
f"shard {index} repeats SHA-256 {sha256}; two distinct shards cannot "
|
||||
"have the same content digest"
|
||||
)
|
||||
seen_sha.add(sha256)
|
||||
shards.append(
|
||||
Shard(
|
||||
index=index,
|
||||
path=_require_text(item.get("path"), f"shards[{index}].path"),
|
||||
size_bytes=size_bytes,
|
||||
sha256=sha256,
|
||||
url=_require_text(item.get("url"), f"shards[{index}].url"),
|
||||
)
|
||||
)
|
||||
|
||||
expected_indices = set(range(1, expected_count + 1))
|
||||
if seen_index != expected_indices:
|
||||
missing = sorted(expected_indices - seen_index)
|
||||
raise GlmTargetError(
|
||||
f"the manifest is missing shard(s) {missing}; all {expected_count} "
|
||||
"shards of the alpha artifact must be pinned"
|
||||
)
|
||||
|
||||
summed = sum(shard.size_bytes for shard in shards)
|
||||
if summed != expected_total:
|
||||
raise GlmTargetError(
|
||||
f"declared total_bytes {expected_total} does not equal the sum of the "
|
||||
f"shard sizes {summed}; the manifest is not self-consistent"
|
||||
)
|
||||
|
||||
return tuple(sorted(shards, key=lambda shard: shard.index))
|
||||
|
||||
|
||||
def parse_target_manifest(data: Any, source: str = "<memory>") -> TargetManifest:
|
||||
"""Validate an already-decoded target manifest, failing closed."""
|
||||
doc = _require_mapping(data, f"manifest root in {source}")
|
||||
|
||||
schema_version = _require_int(doc.get("schema_version"), f"'schema_version' in {source}")
|
||||
if schema_version != TARGET_MANIFEST_SCHEMA_VERSION:
|
||||
raise GlmTargetError(
|
||||
f"{source} declares target-manifest schema version {schema_version}, "
|
||||
f"but this node reads version {TARGET_MANIFEST_SCHEMA_VERSION}"
|
||||
)
|
||||
|
||||
quantization = _require_text(doc.get("alpha_quantization"), f"'alpha_quantization' in {source}")
|
||||
if quantization != ALPHA_QUANTIZATION:
|
||||
raise GlmTargetError(
|
||||
f"{source} pins quantization {quantization!r}, but the locked alpha "
|
||||
f"quantization is {ALPHA_QUANTIZATION!r}; a different quantization is a "
|
||||
"different target and requires a human contract change"
|
||||
)
|
||||
|
||||
source_model = _require_mapping(doc.get("source_model"), f"'source_model' in {source}")
|
||||
gguf = _require_mapping(doc.get("gguf_artifact"), f"'gguf_artifact' in {source}")
|
||||
|
||||
gguf_quant = _require_text(gguf.get("quantization"), f"gguf_artifact.quantization in {source}")
|
||||
if gguf_quant != quantization:
|
||||
raise GlmTargetError(
|
||||
f"{source} declares alpha_quantization {quantization!r} but the GGUF "
|
||||
f"artifact block says {gguf_quant!r}"
|
||||
)
|
||||
|
||||
shard_count = _require_int(gguf.get("shard_count"), f"gguf_artifact.shard_count in {source}")
|
||||
if shard_count != ALPHA_SHARD_COUNT:
|
||||
raise GlmTargetError(
|
||||
f"{source} declares {shard_count} shards; the pinned alpha artifact has "
|
||||
f"exactly {ALPHA_SHARD_COUNT}"
|
||||
)
|
||||
|
||||
total_bytes = _require_int(gguf.get("total_bytes"), f"gguf_artifact.total_bytes in {source}")
|
||||
shards = _parse_shards(gguf.get("shards"), shard_count, total_bytes)
|
||||
|
||||
return TargetManifest(
|
||||
schema_version=schema_version,
|
||||
manifest_version=_require_int(doc.get("manifest_version"), f"'manifest_version' in {source}"),
|
||||
observed_at=_require_text(doc.get("observed_at"), f"'observed_at' in {source}"),
|
||||
quantization=quantization,
|
||||
source_repo_id=_require_text(source_model.get("repo_id"), "source_model.repo_id"),
|
||||
source_revision=_require_revision(source_model.get("revision"), "source_model.revision"),
|
||||
source_license=_require_text(source_model.get("weight_license"), "source_model.weight_license"),
|
||||
gguf_repo_id=_require_text(gguf.get("repo_id"), "gguf_artifact.repo_id"),
|
||||
gguf_revision=_require_revision(gguf.get("revision"), "gguf_artifact.revision"),
|
||||
gguf_license=_require_text(gguf.get("license"), "gguf_artifact.license"),
|
||||
total_bytes=total_bytes,
|
||||
shards=shards,
|
||||
raw=doc,
|
||||
source=source,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArchitectureSnapshot:
|
||||
"""Architecture-critical metadata derived from the pinned ``config.json``."""
|
||||
|
||||
schema_version: int
|
||||
source_repo_id: str
|
||||
source_revision: str
|
||||
architecture: Mapping[str, Any]
|
||||
reasoning_effort: Mapping[str, Any]
|
||||
source_files: Mapping[str, Mapping[str, Any]]
|
||||
raw: Mapping[str, Any]
|
||||
source: str = "<memory>"
|
||||
|
||||
def __getitem__(self, key: str) -> Any:
|
||||
if key not in self.architecture:
|
||||
raise GlmTargetError(f"architecture field {key!r} is missing from {self.source}")
|
||||
return self.architecture[key]
|
||||
|
||||
@property
|
||||
def digest(self) -> str:
|
||||
return canonical_sha256(self.raw)
|
||||
|
||||
def file_sha256(self, path: str) -> str:
|
||||
entry = self.source_files.get(path)
|
||||
if entry is None:
|
||||
raise GlmTargetError(f"{path!r} is not pinned in {self.source}")
|
||||
return str(entry["sha256"])
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return dict(self.raw)
|
||||
|
||||
|
||||
# Fields the distributed runtime cannot plan or shard without. Absent or
|
||||
# contradictory values fail closed rather than defaulting.
|
||||
REQUIRED_ARCHITECTURE_FIELDS: tuple[str, ...] = (
|
||||
"model_type",
|
||||
"num_hidden_layers",
|
||||
"num_nextn_predict_layers",
|
||||
"total_artifact_layers",
|
||||
"first_k_dense_replace",
|
||||
"dense_layers",
|
||||
"sparse_moe_layers",
|
||||
"hidden_size",
|
||||
"n_routed_experts",
|
||||
"num_experts_per_tok",
|
||||
"n_shared_experts",
|
||||
"kv_lora_rank",
|
||||
"qk_rope_head_dim",
|
||||
"mla_cached_values_per_token_per_layer",
|
||||
"index_topk",
|
||||
"index_head_dim",
|
||||
"indexer_full_layers",
|
||||
"indexer_shared_layers",
|
||||
"max_position_embeddings",
|
||||
"vocab_size",
|
||||
)
|
||||
|
||||
|
||||
def parse_architecture_snapshot(data: Any, source: str = "<memory>") -> ArchitectureSnapshot:
|
||||
"""Validate an architecture snapshot and its internal arithmetic."""
|
||||
doc = _require_mapping(data, f"snapshot root in {source}")
|
||||
|
||||
schema_version = _require_int(doc.get("schema_version"), f"'schema_version' in {source}")
|
||||
if schema_version != ARCHITECTURE_SNAPSHOT_SCHEMA_VERSION:
|
||||
raise GlmTargetError(
|
||||
f"{source} declares architecture-snapshot schema version {schema_version}, "
|
||||
f"but this node reads version {ARCHITECTURE_SNAPSHOT_SCHEMA_VERSION}"
|
||||
)
|
||||
|
||||
arch = _require_mapping(doc.get("architecture"), f"'architecture' in {source}")
|
||||
missing = [field for field in REQUIRED_ARCHITECTURE_FIELDS if field not in arch]
|
||||
if missing:
|
||||
raise GlmTargetError(
|
||||
f"{source} is missing architecture-critical field(s) {missing}; the "
|
||||
"runtime cannot shard or plan an architecture it cannot fully describe"
|
||||
)
|
||||
|
||||
layers = _require_int(arch["num_hidden_layers"], "num_hidden_layers")
|
||||
nextn = _require_int(arch["num_nextn_predict_layers"], "num_nextn_predict_layers")
|
||||
total_layers = _require_int(arch["total_artifact_layers"], "total_artifact_layers")
|
||||
if total_layers != layers + nextn:
|
||||
raise GlmTargetError(
|
||||
f"total_artifact_layers {total_layers} != num_hidden_layers {layers} + "
|
||||
f"num_nextn_predict_layers {nextn}; the NextN layer must be counted "
|
||||
"explicitly, never folded into the backbone"
|
||||
)
|
||||
|
||||
dense = _require_int(arch["dense_layers"], "dense_layers")
|
||||
sparse = _require_int(arch["sparse_moe_layers"], "sparse_moe_layers")
|
||||
if dense != _require_int(arch["first_k_dense_replace"], "first_k_dense_replace"):
|
||||
raise GlmTargetError("dense_layers must equal first_k_dense_replace")
|
||||
if dense + sparse != layers:
|
||||
raise GlmTargetError(
|
||||
f"dense_layers {dense} + sparse_moe_layers {sparse} != num_hidden_layers {layers}"
|
||||
)
|
||||
|
||||
full = _require_int(arch["indexer_full_layers"], "indexer_full_layers")
|
||||
shared = _require_int(arch["indexer_shared_layers"], "indexer_shared_layers")
|
||||
if full + shared != layers:
|
||||
raise GlmTargetError(
|
||||
f"indexer_full_layers {full} + indexer_shared_layers {shared} != "
|
||||
f"num_hidden_layers {layers}; every layer holds exactly one IndexShare role"
|
||||
)
|
||||
if full <= 0:
|
||||
raise GlmTargetError(
|
||||
"indexer_full_layers must be positive; a route with no Full producer layer "
|
||||
"has no index for its Shared consumers to reuse"
|
||||
)
|
||||
|
||||
mla = _require_int(
|
||||
arch["mla_cached_values_per_token_per_layer"], "mla_cached_values_per_token_per_layer"
|
||||
)
|
||||
expected_mla = _require_int(arch["kv_lora_rank"], "kv_lora_rank") + _require_int(
|
||||
arch["qk_rope_head_dim"], "qk_rope_head_dim"
|
||||
)
|
||||
if mla != expected_mla:
|
||||
raise GlmTargetError(
|
||||
f"mla_cached_values_per_token_per_layer {mla} != kv_lora_rank + "
|
||||
f"qk_rope_head_dim ({expected_mla})"
|
||||
)
|
||||
|
||||
reasoning = _require_mapping(doc.get("reasoning_effort"), f"'reasoning_effort' in {source}")
|
||||
if reasoning.get("alpha_mode") != "max":
|
||||
raise GlmTargetError(
|
||||
f"{source} does not lock reasoning_effort=max; alpha is defined as the "
|
||||
"Max reasoning mode of this exact checkpoint"
|
||||
)
|
||||
_require_text(reasoning.get("rendered_marker"), "reasoning_effort.rendered_marker")
|
||||
|
||||
files_raw = doc.get("source_files")
|
||||
if not isinstance(files_raw, list) or not files_raw:
|
||||
raise GlmTargetError(f"'source_files' in {source} must be a non-empty JSON array")
|
||||
source_files: dict[str, Mapping[str, Any]] = {}
|
||||
for position, entry in enumerate(files_raw):
|
||||
item = _require_mapping(entry, f"source_files[{position}]")
|
||||
path = _require_text(item.get("path"), f"source_files[{position}].path")
|
||||
_require_sha256(item.get("sha256"), f"source_files[{path}].sha256")
|
||||
source_files[path] = item
|
||||
for required in ("config.json", "chat_template.jinja"):
|
||||
if required not in source_files:
|
||||
raise GlmTargetError(
|
||||
f"{source} does not pin {required!r}; config and chat-template drift "
|
||||
"silently changes runtime semantics"
|
||||
)
|
||||
|
||||
return ArchitectureSnapshot(
|
||||
schema_version=schema_version,
|
||||
source_repo_id=_require_text(doc.get("source_repo_id"), "source_repo_id"),
|
||||
source_revision=_require_revision(doc.get("source_revision"), "source_revision"),
|
||||
architecture=arch,
|
||||
reasoning_effort=reasoning,
|
||||
source_files=source_files,
|
||||
raw=doc,
|
||||
source=source,
|
||||
)
|
||||
|
||||
|
||||
def _read_resource(resource: str, path: Path | None) -> tuple[str, str]:
|
||||
if path is not None:
|
||||
try:
|
||||
return str(path), path.read_text(encoding="utf-8")
|
||||
except OSError as exc:
|
||||
raise GlmTargetError(f"cannot read {path}: {exc.strerror or exc}") from exc
|
||||
source = f"packaged {resource}"
|
||||
try:
|
||||
raw = files("meshnet_node.glm_alpha").joinpath("data", resource).read_text(encoding="utf-8")
|
||||
except (OSError, FileNotFoundError, ModuleNotFoundError) as exc:
|
||||
raise GlmTargetError(
|
||||
f"{source} is missing from this node installation ({type(exc).__name__})"
|
||||
) from exc
|
||||
return source, raw
|
||||
|
||||
|
||||
def _load_json(resource: str, path: Path | None) -> tuple[str, Any]:
|
||||
source, raw = _read_resource(resource, path)
|
||||
try:
|
||||
return source, json.loads(raw)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise GlmTargetError(
|
||||
f"{source} is not valid JSON: {exc.msg} at line {exc.lineno} column {exc.colno}"
|
||||
) from exc
|
||||
|
||||
|
||||
def load_target_manifest(path: Path | None = None) -> TargetManifest:
|
||||
"""Load the packaged target manifest, or one at ``path``."""
|
||||
source, data = _load_json(_MANIFEST_RESOURCE, path)
|
||||
return parse_target_manifest(data, source=source)
|
||||
|
||||
|
||||
def load_architecture_snapshot(path: Path | None = None) -> ArchitectureSnapshot:
|
||||
"""Load the packaged architecture snapshot, or one at ``path``."""
|
||||
source, data = _load_json(_ARCHITECTURE_RESOURCE, path)
|
||||
return parse_architecture_snapshot(data, source=source)
|
||||
|
||||
|
||||
def require_pinned_target(
|
||||
manifest: TargetManifest,
|
||||
snapshot: ArchitectureSnapshot,
|
||||
*,
|
||||
expected_source_revision: str,
|
||||
expected_gguf_revision: str,
|
||||
) -> None:
|
||||
"""Reject any target whose revisions are not the ones alpha was locked against.
|
||||
|
||||
Callers pass the revisions from the locked alpha contract, so a swapped
|
||||
manifest cannot quietly re-point the target at a different upstream commit.
|
||||
"""
|
||||
if manifest.source_revision != expected_source_revision:
|
||||
raise GlmTargetError(
|
||||
f"source revision {manifest.source_revision} does not match the locked "
|
||||
f"alpha revision {expected_source_revision}"
|
||||
)
|
||||
if manifest.gguf_revision != expected_gguf_revision:
|
||||
raise GlmTargetError(
|
||||
f"GGUF revision {manifest.gguf_revision} does not match the locked alpha "
|
||||
f"revision {expected_gguf_revision}"
|
||||
)
|
||||
if snapshot.source_revision != manifest.source_revision:
|
||||
raise GlmTargetError(
|
||||
f"the architecture snapshot was taken at {snapshot.source_revision} but the "
|
||||
f"manifest pins {manifest.source_revision}; config metadata and weights must "
|
||||
"come from one revision"
|
||||
)
|
||||
522
packages/node/meshnet_node/glm_alpha/planner.py
Normal file
522
packages/node/meshnet_node/glm_alpha/planner.py
Normal file
@@ -0,0 +1,522 @@
|
||||
"""Deterministic memory, KV, and network planner for the GLM-5.2 Max alpha route.
|
||||
|
||||
Everything here is arithmetic over the exact pinned artifact bytes and the exact
|
||||
pinned architecture. There is no measurement, no probing, and no heuristic tuned
|
||||
to a result — the planner is written *before* the target runs so that a later
|
||||
story cannot discover a topology that "works" and then rationalise it.
|
||||
|
||||
Three ideas do the real work.
|
||||
|
||||
**Unified memory is one pool.** On an integrated-GPU machine the "VRAM" the driver
|
||||
reports is carved out of the same physical DRAM the OS is already counting. Adding
|
||||
them produces a node that appears to hold twice what it holds, and the failure mode
|
||||
is not a clean admission rejection — it is an OOM or a swap-thrash halfway through
|
||||
a 200 GiB load. :class:`NodeMemory` therefore refuses to be constructed from an
|
||||
additive claim about one shared pool.
|
||||
|
||||
**The reserve is not optional headroom.** Weights plus KV are not the whole
|
||||
resident cost: backend workspaces, quantization scratch, the graph plan, the
|
||||
process, and the OS all live outside them, and the largest of those scale with the
|
||||
backend rather than with the shard. Alpha reserves ``max(20% of physically usable
|
||||
memory, 8 GiB)`` per node, and the *remainder* is the placement budget.
|
||||
|
||||
**Equal layer counts are not equal bytes.** Embeddings and the output head are
|
||||
endpoint-only; three layers are dense and 75 are MoE; shared experts, indexer
|
||||
tensors, and quant block alignment all skew the per-node share. Until DGR-018/019
|
||||
report measured per-tensor placement, the planner carries an explicit
|
||||
:data:`PLACEMENT_IMBALANCE_FACTOR` and reports the arithmetic minimum and the
|
||||
recommended count as two separate numbers. The arithmetic minimum is a fit probe;
|
||||
it is admissible only with exact measured placement evidence behind it.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
from .manifest import GIB, ArchitectureSnapshot, TargetManifest
|
||||
|
||||
# Q8_0 stores 32 int8 quants plus one fp16 scale per block: 34 bytes / 32 values.
|
||||
Q8_0_BYTES_PER_VALUE = 34 / 32
|
||||
F16_BYTES_PER_VALUE = 2.0
|
||||
|
||||
KV_DTYPES: dict[str, float] = {
|
||||
"Q8_0": Q8_0_BYTES_PER_VALUE,
|
||||
"F16": F16_BYTES_PER_VALUE,
|
||||
}
|
||||
|
||||
# The alpha KV configuration, locked by the roadmap.
|
||||
ALPHA_KV_DTYPE = "Q8_0"
|
||||
ALPHA_CONTEXT_TOKENS = 16384
|
||||
ALPHA_CONCURRENCY = 1
|
||||
|
||||
# The reserve every node holds outside its weight-plus-KV placement budget.
|
||||
RESERVE_FRACTION = 0.20
|
||||
RESERVE_FLOOR_GIB = 8.0
|
||||
|
||||
# The aggregate runtime-accessible memory at which the artifact *just* fits.
|
||||
# This is an experimental hard-fit floor, not an operational envelope: it has no
|
||||
# room for a backend that allocates more scratch than another, and none for the
|
||||
# imbalance below.
|
||||
AGGREGATE_HARD_FIT_FLOOR_GIB = 224.0
|
||||
|
||||
# How much more than an equal share the worst-placed node is expected to hold.
|
||||
# 1.10 is the roadmap's recommended-topology column expressed as arithmetic: it
|
||||
# reproduces 10 / 6 / 5 / 3 / 3 nodes for the 32 / 48 / 64 / 96 / 128 GiB tiers.
|
||||
# DGR-019 must replace it with measured per-tensor placement.
|
||||
PLACEMENT_IMBALANCE_FACTOR = 1.10
|
||||
|
||||
# Alpha network floor. A link rate is a bandwidth claim, never a speed claim.
|
||||
MIN_LINK_RATE_GBPS = 2.5
|
||||
RECOMMENDED_LINK_RATE_GBPS = 10.0
|
||||
|
||||
BF16_BYTES = 2
|
||||
DSA_SIDEBAND_INT32_BYTES = 4
|
||||
|
||||
IndexerLayout = Literal["optimized", "conservative"]
|
||||
|
||||
|
||||
class ResourcePlanError(ValueError):
|
||||
"""Raised when a node or route cannot be accounted for honestly."""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NodeMemory:
|
||||
"""One node's physically usable memory, counted once.
|
||||
|
||||
``physical_usable_gib`` is what the node can actually place bytes into after
|
||||
firmware and fixed carve-outs — not the marketing capacity, and not a sum of
|
||||
two views of the same DRAM.
|
||||
"""
|
||||
|
||||
name: str
|
||||
physical_usable_gib: float
|
||||
unified: bool
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not isinstance(self.name, str) or not self.name.strip():
|
||||
raise ResourcePlanError("node name must be a non-empty physical-host identity")
|
||||
if (
|
||||
isinstance(self.physical_usable_gib, bool)
|
||||
or not isinstance(self.physical_usable_gib, (int, float))
|
||||
or not math.isfinite(self.physical_usable_gib)
|
||||
or self.physical_usable_gib <= 0
|
||||
):
|
||||
raise ResourcePlanError(
|
||||
f"node {self.name!r} must declare finite positive usable memory"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_host(
|
||||
cls,
|
||||
name: str,
|
||||
*,
|
||||
system_ram_gib: float,
|
||||
gpu_memory_gib: float = 0.0,
|
||||
unified: bool,
|
||||
) -> "NodeMemory":
|
||||
"""Build a node from a host's reported RAM and GPU memory.
|
||||
|
||||
On a unified machine the GPU memory *is* system RAM, so it is counted once
|
||||
and never added. Passing a non-zero ``gpu_memory_gib`` alongside
|
||||
``unified=True`` is the double-count this project has already decided is a
|
||||
bug (RALPH-CONTEXT runtime decision 16), so it is rejected rather than
|
||||
silently discarded: a caller who believes an integrated GPU adds memory has
|
||||
a wrong model of the machine, and quietly ignoring the argument would let
|
||||
that belief survive.
|
||||
"""
|
||||
if not isinstance(unified, bool):
|
||||
raise ResourcePlanError(f"node {name!r} unified flag must be boolean")
|
||||
for value, label, allow_zero in (
|
||||
(system_ram_gib, "system RAM", False),
|
||||
(gpu_memory_gib, "GPU memory", True),
|
||||
):
|
||||
if (
|
||||
isinstance(value, bool)
|
||||
or not isinstance(value, (int, float))
|
||||
or not math.isfinite(value)
|
||||
or value < 0
|
||||
or (not allow_zero and value == 0)
|
||||
):
|
||||
qualifier = "finite non-negative" if allow_zero else "finite positive"
|
||||
raise ResourcePlanError(f"node {name!r} must declare {qualifier} {label}")
|
||||
if unified:
|
||||
if gpu_memory_gib:
|
||||
raise ResourcePlanError(
|
||||
f"node {name!r} declares unified memory and {gpu_memory_gib} GiB of "
|
||||
"separate GPU memory. Integrated-GPU memory is carved out of the same "
|
||||
"physical DRAM as system RAM; adding them double-counts one pool. "
|
||||
"Pass unified=True with system_ram_gib only."
|
||||
)
|
||||
usable = system_ram_gib
|
||||
else:
|
||||
usable = system_ram_gib + gpu_memory_gib
|
||||
return cls(name=name, physical_usable_gib=usable, unified=unified)
|
||||
|
||||
@property
|
||||
def reserve_gib(self) -> float:
|
||||
"""``max(20% of physically usable memory, 8 GiB)``."""
|
||||
return max(RESERVE_FRACTION * self.physical_usable_gib, RESERVE_FLOOR_GIB)
|
||||
|
||||
@property
|
||||
def placement_budget_gib(self) -> float:
|
||||
"""What remains for weights plus KV after the reserve."""
|
||||
return self.physical_usable_gib - self.reserve_gib
|
||||
|
||||
|
||||
def kv_bytes(
|
||||
snapshot: ArchitectureSnapshot,
|
||||
*,
|
||||
context_tokens: int = ALPHA_CONTEXT_TOKENS,
|
||||
concurrency: int = ALPHA_CONCURRENCY,
|
||||
dtype: str = ALPHA_KV_DTYPE,
|
||||
indexer_layout: IndexerLayout = "conservative",
|
||||
include_indexer: bool = True,
|
||||
) -> int:
|
||||
"""Bytes of MLA (and DSA indexer) KV cache for the whole model.
|
||||
|
||||
``indexer_layout`` is the honest part. Correct DSA only needs indexer keys for
|
||||
the Full producer layers, but the current experimental implementation may
|
||||
allocate them across every backbone layer. Alpha budgets ``conservative``
|
||||
(all 78) so that a route admitted by this planner cannot be surprised by the
|
||||
implementation it actually gets.
|
||||
"""
|
||||
if (
|
||||
not isinstance(context_tokens, int)
|
||||
or isinstance(context_tokens, bool)
|
||||
or context_tokens <= 0
|
||||
or not isinstance(concurrency, int)
|
||||
or isinstance(concurrency, bool)
|
||||
or concurrency <= 0
|
||||
):
|
||||
raise ResourcePlanError("context_tokens and concurrency must be positive integers")
|
||||
if dtype not in KV_DTYPES:
|
||||
raise ResourcePlanError(
|
||||
f"unsupported KV dtype {dtype!r}; alpha locks {ALPHA_KV_DTYPE} "
|
||||
f"(known: {', '.join(sorted(KV_DTYPES))})"
|
||||
)
|
||||
bytes_per_value = KV_DTYPES[dtype]
|
||||
|
||||
layers = int(snapshot["num_hidden_layers"])
|
||||
mla_values = int(snapshot["mla_cached_values_per_token_per_layer"])
|
||||
total_values = mla_values * layers
|
||||
|
||||
if include_indexer:
|
||||
if indexer_layout == "optimized":
|
||||
indexer_layers = int(snapshot["indexer_full_layers"])
|
||||
elif indexer_layout == "conservative":
|
||||
indexer_layers = layers
|
||||
else: # pragma: no cover - Literal keeps this unreachable from typed callers
|
||||
raise ResourcePlanError(f"unknown indexer_layout {indexer_layout!r}")
|
||||
total_values += int(snapshot["index_head_dim"]) * indexer_layers
|
||||
|
||||
return int(total_values * context_tokens * concurrency * bytes_per_value)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TopologyPlan:
|
||||
"""The node count a homogeneous tier needs, and how it was reached."""
|
||||
|
||||
physical_usable_gib: float
|
||||
reserve_gib: float
|
||||
placement_budget_gib: float
|
||||
weight_gib: float
|
||||
kv_gib: float
|
||||
total_placement_gib: float
|
||||
arithmetic_minimum_nodes: int
|
||||
recommended_nodes: int
|
||||
imbalance_factor: float
|
||||
|
||||
@property
|
||||
def is_arithmetic_minimum_topology(self) -> bool:
|
||||
"""True when the recommendation offers no imbalance headroom at all."""
|
||||
return self.recommended_nodes == self.arithmetic_minimum_nodes
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"physical_usable_gib": round(self.physical_usable_gib, 3),
|
||||
"reserve_gib": round(self.reserve_gib, 3),
|
||||
"placement_budget_gib": round(self.placement_budget_gib, 3),
|
||||
"weight_gib": round(self.weight_gib, 3),
|
||||
"kv_gib": round(self.kv_gib, 3),
|
||||
"total_placement_gib": round(self.total_placement_gib, 3),
|
||||
"arithmetic_minimum_nodes": self.arithmetic_minimum_nodes,
|
||||
"recommended_nodes": self.recommended_nodes,
|
||||
"imbalance_factor": self.imbalance_factor,
|
||||
}
|
||||
|
||||
|
||||
def plan_topology(
|
||||
manifest: TargetManifest,
|
||||
snapshot: ArchitectureSnapshot,
|
||||
*,
|
||||
physical_usable_gib: float,
|
||||
context_tokens: int = ALPHA_CONTEXT_TOKENS,
|
||||
concurrency: int = ALPHA_CONCURRENCY,
|
||||
kv_dtype: str = ALPHA_KV_DTYPE,
|
||||
indexer_layout: IndexerLayout = "conservative",
|
||||
imbalance_factor: float = PLACEMENT_IMBALANCE_FACTOR,
|
||||
) -> TopologyPlan:
|
||||
"""Minimum and recommended node count for a homogeneous tier of this size."""
|
||||
if (
|
||||
isinstance(imbalance_factor, bool)
|
||||
or not isinstance(imbalance_factor, (int, float))
|
||||
or not math.isfinite(imbalance_factor)
|
||||
or imbalance_factor < 1.0
|
||||
):
|
||||
raise ResourcePlanError(
|
||||
"imbalance_factor must be finite and at least 1.0; a lower value would "
|
||||
"assume the worst-placed node holds less than an equal share"
|
||||
)
|
||||
|
||||
node = NodeMemory(
|
||||
name=f"{physical_usable_gib:g}GiB-tier",
|
||||
physical_usable_gib=physical_usable_gib,
|
||||
unified=False,
|
||||
)
|
||||
budget = node.placement_budget_gib
|
||||
if budget <= 0:
|
||||
raise ResourcePlanError(
|
||||
f"a {physical_usable_gib:g} GiB node has no placement budget after its "
|
||||
f"{node.reserve_gib:.1f} GiB reserve"
|
||||
)
|
||||
|
||||
weight_gib = manifest.total_bytes / GIB
|
||||
kv_gib = (
|
||||
kv_bytes(
|
||||
snapshot,
|
||||
context_tokens=context_tokens,
|
||||
concurrency=concurrency,
|
||||
dtype=kv_dtype,
|
||||
indexer_layout=indexer_layout,
|
||||
)
|
||||
/ GIB
|
||||
)
|
||||
total = weight_gib + kv_gib
|
||||
|
||||
return TopologyPlan(
|
||||
physical_usable_gib=physical_usable_gib,
|
||||
reserve_gib=node.reserve_gib,
|
||||
placement_budget_gib=budget,
|
||||
weight_gib=weight_gib,
|
||||
kv_gib=kv_gib,
|
||||
total_placement_gib=total,
|
||||
arithmetic_minimum_nodes=math.ceil(total / budget),
|
||||
recommended_nodes=math.ceil(total * imbalance_factor / budget),
|
||||
imbalance_factor=imbalance_factor,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RouteFit:
|
||||
"""Whether a concrete, possibly heterogeneous set of nodes can hold the target."""
|
||||
|
||||
node_count: int
|
||||
aggregate_usable_gib: float
|
||||
aggregate_placement_budget_gib: float
|
||||
required_placement_gib: float
|
||||
fits: bool
|
||||
meets_hard_fit_floor: bool
|
||||
no_single_node_can_admit_target: bool
|
||||
headroom_gib: float
|
||||
reasons: tuple[str, ...]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"node_count": self.node_count,
|
||||
"aggregate_usable_gib": round(self.aggregate_usable_gib, 3),
|
||||
"aggregate_placement_budget_gib": round(self.aggregate_placement_budget_gib, 3),
|
||||
"required_placement_gib": round(self.required_placement_gib, 3),
|
||||
"fits": self.fits,
|
||||
"meets_hard_fit_floor": self.meets_hard_fit_floor,
|
||||
"no_single_node_can_admit_target": self.no_single_node_can_admit_target,
|
||||
"headroom_gib": round(self.headroom_gib, 3),
|
||||
"reasons": list(self.reasons),
|
||||
}
|
||||
|
||||
|
||||
def plan_route(
|
||||
manifest: TargetManifest,
|
||||
snapshot: ArchitectureSnapshot,
|
||||
nodes: list[NodeMemory],
|
||||
*,
|
||||
context_tokens: int = ALPHA_CONTEXT_TOKENS,
|
||||
concurrency: int = ALPHA_CONCURRENCY,
|
||||
kv_dtype: str = ALPHA_KV_DTYPE,
|
||||
indexer_layout: IndexerLayout = "conservative",
|
||||
) -> RouteFit:
|
||||
"""Evaluate a concrete route. Every node's memory is already counted once."""
|
||||
if len(nodes) < 2:
|
||||
raise ResourcePlanError(
|
||||
"the alpha target is distributed by definition; a route needs at least two "
|
||||
"physical nodes"
|
||||
)
|
||||
names = [node.name for node in nodes]
|
||||
if len(set(names)) != len(names):
|
||||
raise ResourcePlanError(
|
||||
"duplicate node names in the route; one physical machine counted twice is "
|
||||
"the same double-count as adding integrated-GPU memory to system RAM"
|
||||
)
|
||||
|
||||
weight_gib = manifest.total_bytes / GIB
|
||||
kv_gib = (
|
||||
kv_bytes(
|
||||
snapshot,
|
||||
context_tokens=context_tokens,
|
||||
concurrency=concurrency,
|
||||
dtype=kv_dtype,
|
||||
indexer_layout=indexer_layout,
|
||||
)
|
||||
/ GIB
|
||||
)
|
||||
required = weight_gib + kv_gib
|
||||
|
||||
aggregate_usable = sum(node.physical_usable_gib for node in nodes)
|
||||
aggregate_budget = sum(node.placement_budget_gib for node in nodes)
|
||||
fits = aggregate_budget >= required
|
||||
largest_budget = max(node.placement_budget_gib for node in nodes)
|
||||
no_single_node = largest_budget < required
|
||||
|
||||
reasons: list[str] = []
|
||||
if not fits:
|
||||
reasons.append(
|
||||
f"aggregate placement budget {aggregate_budget:.1f} GiB is below the "
|
||||
f"{required:.1f} GiB the target needs after each node's reserve"
|
||||
)
|
||||
if not no_single_node:
|
||||
reasons.append(
|
||||
"at least one node could admit the complete target alone; that is a "
|
||||
"single-host run, not distributed alpha"
|
||||
)
|
||||
if aggregate_usable < AGGREGATE_HARD_FIT_FLOOR_GIB:
|
||||
reasons.append(
|
||||
f"aggregate usable memory {aggregate_usable:.1f} GiB is below the "
|
||||
f"{AGGREGATE_HARD_FIT_FLOOR_GIB:g} GiB experimental hard-fit floor"
|
||||
)
|
||||
|
||||
return RouteFit(
|
||||
node_count=len(nodes),
|
||||
aggregate_usable_gib=aggregate_usable,
|
||||
aggregate_placement_budget_gib=aggregate_budget,
|
||||
required_placement_gib=required,
|
||||
fits=fits,
|
||||
meets_hard_fit_floor=aggregate_usable >= AGGREGATE_HARD_FIT_FLOOR_GIB,
|
||||
no_single_node_can_admit_target=no_single_node,
|
||||
headroom_gib=aggregate_budget - required,
|
||||
reasons=tuple(reasons),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SeamPlan:
|
||||
"""Bytes and latency across the activation seams of a route.
|
||||
|
||||
Bandwidth and latency are reported separately on purpose. Decode moves almost
|
||||
nothing — 12 KiB per token per seam — so a faster link barely helps it. What
|
||||
decode pays is *serial*: every generated token crosses every seam in order, so
|
||||
the cost that matters is ``seams x per-hop latency``. A route that claims to be
|
||||
fast because it is on 10 GbE has confused the two.
|
||||
"""
|
||||
|
||||
node_count: int
|
||||
seam_count: int
|
||||
hidden_size: int
|
||||
bytes_per_token_per_seam: int
|
||||
prefill_bytes_per_seam: int
|
||||
decode_bytes_per_seam_per_token: int
|
||||
dsa_sideband_bytes_per_query: int
|
||||
link_rate_gbps: float
|
||||
meets_alpha_minimum: bool
|
||||
is_recommended_link: bool
|
||||
decode_serialization_ms_per_token: float
|
||||
decode_latency_ms_per_token: float
|
||||
decode_bandwidth_share_ms_per_token: float
|
||||
prefill_serialization_ms: float
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"node_count": self.node_count,
|
||||
"seam_count": self.seam_count,
|
||||
"hidden_size": self.hidden_size,
|
||||
"bytes_per_token_per_seam": self.bytes_per_token_per_seam,
|
||||
"prefill_bytes_per_seam": self.prefill_bytes_per_seam,
|
||||
"decode_bytes_per_seam_per_token": self.decode_bytes_per_seam_per_token,
|
||||
"dsa_sideband_bytes_per_query": self.dsa_sideband_bytes_per_query,
|
||||
"link_rate_gbps": self.link_rate_gbps,
|
||||
"meets_alpha_minimum": self.meets_alpha_minimum,
|
||||
"is_recommended_link": self.is_recommended_link,
|
||||
"decode_serialization_ms_per_token": round(self.decode_serialization_ms_per_token, 4),
|
||||
"decode_latency_ms_per_token": round(self.decode_latency_ms_per_token, 4),
|
||||
"decode_bandwidth_share_ms_per_token": round(
|
||||
self.decode_bandwidth_share_ms_per_token, 4
|
||||
),
|
||||
"prefill_serialization_ms": round(self.prefill_serialization_ms, 3),
|
||||
}
|
||||
|
||||
|
||||
def plan_seams(
|
||||
snapshot: ArchitectureSnapshot,
|
||||
*,
|
||||
node_count: int,
|
||||
context_tokens: int = ALPHA_CONTEXT_TOKENS,
|
||||
link_rate_gbps: float = MIN_LINK_RATE_GBPS,
|
||||
per_hop_latency_ms: float = 0.5,
|
||||
) -> SeamPlan:
|
||||
"""Model seam bytes, wire serialization, and serial per-hop latency separately."""
|
||||
if not isinstance(node_count, int) or isinstance(node_count, bool) or node_count < 2:
|
||||
raise ResourcePlanError("a seam exists only between two nodes")
|
||||
if not isinstance(context_tokens, int) or isinstance(context_tokens, bool) or context_tokens <= 0:
|
||||
raise ResourcePlanError("context_tokens must be a positive integer")
|
||||
if (
|
||||
isinstance(link_rate_gbps, bool)
|
||||
or not isinstance(link_rate_gbps, (int, float))
|
||||
or not math.isfinite(link_rate_gbps)
|
||||
or link_rate_gbps <= 0
|
||||
):
|
||||
raise ResourcePlanError("link_rate_gbps must be finite and positive")
|
||||
if (
|
||||
isinstance(per_hop_latency_ms, bool)
|
||||
or not isinstance(per_hop_latency_ms, (int, float))
|
||||
or not math.isfinite(per_hop_latency_ms)
|
||||
or per_hop_latency_ms < 0
|
||||
):
|
||||
raise ResourcePlanError("per_hop_latency_ms must be finite and non-negative")
|
||||
|
||||
hidden = int(snapshot["hidden_size"])
|
||||
bytes_per_token = hidden * BF16_BYTES
|
||||
seams = node_count - 1
|
||||
|
||||
bits_per_ms = link_rate_gbps * 1e9 / 1e3
|
||||
decode_serialization_ms = (bytes_per_token * 8) / bits_per_ms
|
||||
prefill_serialization_ms = (bytes_per_token * context_tokens * 8) / bits_per_ms
|
||||
|
||||
return SeamPlan(
|
||||
node_count=node_count,
|
||||
seam_count=seams,
|
||||
hidden_size=hidden,
|
||||
bytes_per_token_per_seam=bytes_per_token,
|
||||
prefill_bytes_per_seam=bytes_per_token * context_tokens,
|
||||
decode_bytes_per_seam_per_token=bytes_per_token,
|
||||
dsa_sideband_bytes_per_query=int(snapshot["index_topk"]) * DSA_SIDEBAND_INT32_BYTES,
|
||||
link_rate_gbps=link_rate_gbps,
|
||||
meets_alpha_minimum=link_rate_gbps >= MIN_LINK_RATE_GBPS,
|
||||
is_recommended_link=link_rate_gbps >= RECOMMENDED_LINK_RATE_GBPS,
|
||||
decode_serialization_ms_per_token=decode_serialization_ms * seams,
|
||||
decode_latency_ms_per_token=per_hop_latency_ms * seams,
|
||||
decode_bandwidth_share_ms_per_token=decode_serialization_ms * seams,
|
||||
prefill_serialization_ms=prefill_serialization_ms * seams,
|
||||
)
|
||||
|
||||
|
||||
ALPHA_TIERS_GIB: tuple[float, ...] = (32.0, 48.0, 64.0, 96.0, 128.0)
|
||||
|
||||
|
||||
def plan_all_tiers(
|
||||
manifest: TargetManifest, snapshot: ArchitectureSnapshot
|
||||
) -> dict[str, TopologyPlan]:
|
||||
"""The alpha tier table, recomputed from the pinned artifact and architecture."""
|
||||
return {
|
||||
f"{tier:g}": plan_topology(manifest, snapshot, physical_usable_gib=tier)
|
||||
for tier in ALPHA_TIERS_GIB
|
||||
}
|
||||
@@ -42,3 +42,4 @@ include = ["meshnet_node*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
meshnet_node = ["*.json"]
|
||||
"meshnet_node.glm_alpha" = ["data/*.json"]
|
||||
|
||||
254
scripts/refresh_glm_target_manifest.py
Normal file
254
scripts/refresh_glm_target_manifest.py
Normal file
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Refresh (or check) the pinned GLM-5.2 target manifest and architecture snapshot.
|
||||
|
||||
Resolves revisions, shard sizes, and LFS SHA-256 digests from the Hugging Face
|
||||
metadata API. It never downloads a weight payload: sizes and digests come from
|
||||
``/api/models/.../paths-info``, which returns the LFS pointer metadata, and the only
|
||||
files fetched in full are the small config/tokenizer/chat-template documents whose
|
||||
bytes the snapshot hashes.
|
||||
|
||||
Usage::
|
||||
|
||||
python scripts/refresh_glm_target_manifest.py --check # CI: pinned bytes still resolve?
|
||||
python scripts/refresh_glm_target_manifest.py --write # re-pin HEAD after human review
|
||||
|
||||
``--check`` validates the already locked revisions through Hugging Face's
|
||||
revision-specific API. A normal new upstream commit does not mutate the target.
|
||||
``--write`` intentionally follows moving HEAD and is therefore a reviewed target
|
||||
change, never an automatic refresh.
|
||||
|
||||
This script requires network access and is not part of the default test suite.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
DATA_DIR = Path(__file__).resolve().parent.parent / "packages/node/meshnet_node/glm_alpha/data"
|
||||
MANIFEST_PATH = DATA_DIR / "target-manifest.json"
|
||||
SNAPSHOT_PATH = DATA_DIR / "architecture-snapshot.json"
|
||||
|
||||
SOURCE_REPO = "zai-org/GLM-5.2"
|
||||
GGUF_REPO = "unsloth/GLM-5.2-GGUF"
|
||||
QUANT = "UD-IQ1_S"
|
||||
FALLBACK_QUANT = "UD-IQ1_M"
|
||||
SHARD_COUNT = 6
|
||||
|
||||
SNAPSHOT_FILES = (
|
||||
"config.json",
|
||||
"chat_template.jinja",
|
||||
"generation_config.json",
|
||||
"tokenizer_config.json",
|
||||
)
|
||||
|
||||
TIMEOUT = 60
|
||||
|
||||
|
||||
def _get(url: str) -> bytes:
|
||||
with urllib.request.urlopen(url, timeout=TIMEOUT) as response: # noqa: S310 - fixed HTTPS host
|
||||
return response.read()
|
||||
|
||||
|
||||
def _get_json(url: str) -> Any:
|
||||
return json.loads(_get(url))
|
||||
|
||||
|
||||
def _post_json(url: str, payload: dict) -> Any:
|
||||
request = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode("utf-8"),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib.request.urlopen(request, timeout=TIMEOUT) as response: # noqa: S310
|
||||
return json.loads(response.read())
|
||||
|
||||
|
||||
def _shard_paths(quant: str) -> list[str]:
|
||||
return [
|
||||
f"{quant}/GLM-5.2-{quant}-{index:05d}-of-{SHARD_COUNT:05d}.gguf"
|
||||
for index in range(1, SHARD_COUNT + 1)
|
||||
]
|
||||
|
||||
|
||||
def _resolve_shards(revision: str, quant: str) -> list[dict]:
|
||||
info = _post_json(
|
||||
f"https://huggingface.co/api/models/{GGUF_REPO}/paths-info/{revision}",
|
||||
{"paths": _shard_paths(quant)},
|
||||
)
|
||||
by_path = {entry["path"]: entry for entry in info}
|
||||
shards = []
|
||||
for index, path in enumerate(_shard_paths(quant), start=1):
|
||||
entry = by_path.get(path)
|
||||
if entry is None:
|
||||
raise SystemExit(f"upstream is missing shard {path} at revision {revision}")
|
||||
lfs = entry.get("lfs") or {}
|
||||
oid = lfs.get("oid")
|
||||
if not oid:
|
||||
raise SystemExit(
|
||||
f"{path} has no LFS oid; a non-LFS shard is not the published artifact"
|
||||
)
|
||||
shards.append(
|
||||
{
|
||||
"index": index,
|
||||
"path": path,
|
||||
"size_bytes": int(entry["size"]),
|
||||
"sha256": oid,
|
||||
"url": f"https://huggingface.co/{GGUF_REPO}/resolve/{revision}/{path}",
|
||||
}
|
||||
)
|
||||
return shards
|
||||
|
||||
|
||||
def build_documents(
|
||||
*,
|
||||
source_revision: str | None = None,
|
||||
gguf_revision: str | None = None,
|
||||
) -> tuple[dict, dict]:
|
||||
"""Resolve documents at explicit pins, or at current HEAD for reviewed re-pinning."""
|
||||
|
||||
source_api = f"https://huggingface.co/api/models/{SOURCE_REPO}"
|
||||
gguf_api = f"https://huggingface.co/api/models/{GGUF_REPO}"
|
||||
if source_revision is not None:
|
||||
source_api += f"/revision/{source_revision}"
|
||||
if gguf_revision is not None:
|
||||
gguf_api += f"/revision/{gguf_revision}"
|
||||
source_info = _get_json(source_api)
|
||||
gguf_info = _get_json(gguf_api)
|
||||
source_rev = source_info["sha"]
|
||||
gguf_rev = gguf_info["sha"]
|
||||
if source_revision is not None and source_rev != source_revision:
|
||||
raise SystemExit(
|
||||
f"source revision endpoint returned {source_rev}, expected {source_revision}"
|
||||
)
|
||||
if gguf_revision is not None and gguf_rev != gguf_revision:
|
||||
raise SystemExit(f"GGUF revision endpoint returned {gguf_rev}, expected {gguf_revision}")
|
||||
|
||||
shards = _resolve_shards(gguf_rev, QUANT)
|
||||
total = sum(shard["size_bytes"] for shard in shards)
|
||||
fallback = _resolve_shards(gguf_rev, FALLBACK_QUANT)
|
||||
fallback_total = sum(shard["size_bytes"] for shard in fallback)
|
||||
|
||||
manifest = json.loads(MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||
manifest["source_model"]["revision"] = source_rev
|
||||
manifest["source_model"]["last_modified"] = source_info.get("lastModified")
|
||||
manifest["source_model"]["revision_url"] = (
|
||||
f"https://huggingface.co/{SOURCE_REPO}/tree/{source_rev}"
|
||||
)
|
||||
manifest["gguf_artifact"]["revision"] = gguf_rev
|
||||
manifest["gguf_artifact"]["last_modified"] = gguf_info.get("lastModified")
|
||||
manifest["gguf_artifact"]["revision_url"] = (
|
||||
f"https://huggingface.co/{GGUF_REPO}/tree/{gguf_rev}"
|
||||
)
|
||||
manifest["gguf_artifact"]["shards"] = shards
|
||||
manifest["gguf_artifact"]["total_bytes"] = total
|
||||
manifest["gguf_artifact"]["total_gib"] = round(total / 1024**3, 3)
|
||||
manifest["gguf_artifact"]["total_gb"] = round(total / 1000**3, 3)
|
||||
manifest["diagnostic_fallback"]["total_bytes"] = fallback_total
|
||||
manifest["diagnostic_fallback"]["total_gib"] = round(fallback_total / 1024**3, 3)
|
||||
manifest["diagnostic_fallback"]["total_gb"] = round(fallback_total / 1000**3, 3)
|
||||
|
||||
snapshot = json.loads(SNAPSHOT_PATH.read_text(encoding="utf-8"))
|
||||
snapshot["source_revision"] = source_rev
|
||||
source_files = []
|
||||
config: dict[str, Any] = {}
|
||||
for name in SNAPSHOT_FILES:
|
||||
url = f"https://huggingface.co/{SOURCE_REPO}/resolve/{source_rev}/{name}"
|
||||
body = _get(url)
|
||||
source_files.append(
|
||||
{
|
||||
"path": name,
|
||||
"size_bytes": len(body),
|
||||
"sha256": hashlib.sha256(body).hexdigest(),
|
||||
"url": url,
|
||||
}
|
||||
)
|
||||
if name == "config.json":
|
||||
config = json.loads(body)
|
||||
snapshot["source_files"] = source_files
|
||||
|
||||
indexer_types = config["indexer_types"]
|
||||
arch = snapshot["architecture"]
|
||||
arch["num_hidden_layers"] = config["num_hidden_layers"]
|
||||
arch["num_nextn_predict_layers"] = config["num_nextn_predict_layers"]
|
||||
arch["total_artifact_layers"] = config["num_hidden_layers"] + config["num_nextn_predict_layers"]
|
||||
arch["hidden_size"] = config["hidden_size"]
|
||||
arch["n_routed_experts"] = config["n_routed_experts"]
|
||||
arch["num_experts_per_tok"] = config["num_experts_per_tok"]
|
||||
arch["n_shared_experts"] = config["n_shared_experts"]
|
||||
arch["index_topk"] = config["index_topk"]
|
||||
arch["index_head_dim"] = config["index_head_dim"]
|
||||
arch["kv_lora_rank"] = config["kv_lora_rank"]
|
||||
arch["qk_rope_head_dim"] = config["qk_rope_head_dim"]
|
||||
arch["mla_cached_values_per_token_per_layer"] = (
|
||||
config["kv_lora_rank"] + config["qk_rope_head_dim"]
|
||||
)
|
||||
arch["indexer_full_layers"] = sum(1 for role in indexer_types if role == "full")
|
||||
arch["indexer_shared_layers"] = sum(1 for role in indexer_types if role == "shared")
|
||||
arch["indexer_types_sha256"] = hashlib.sha256(
|
||||
json.dumps(indexer_types, separators=(",", ":")).encode("utf-8")
|
||||
).hexdigest()
|
||||
arch["max_position_embeddings"] = config["max_position_embeddings"]
|
||||
arch["vocab_size"] = config["vocab_size"]
|
||||
arch["first_k_dense_replace"] = config["first_k_dense_replace"]
|
||||
arch["dense_layers"] = config["first_k_dense_replace"]
|
||||
arch["sparse_moe_layers"] = config["num_hidden_layers"] - config["first_k_dense_replace"]
|
||||
|
||||
return manifest, snapshot
|
||||
|
||||
|
||||
def _dump(document: dict) -> str:
|
||||
return json.dumps(document, indent=2, ensure_ascii=False) + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument("--check", action="store_true", help="fail if the pins have drifted")
|
||||
group.add_argument("--write", action="store_true", help="re-pin from upstream")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.check:
|
||||
pinned = json.loads(MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||
manifest, snapshot = build_documents(
|
||||
source_revision=pinned["source_model"]["revision"],
|
||||
gguf_revision=pinned["gguf_artifact"]["revision"],
|
||||
)
|
||||
else:
|
||||
# --write intentionally follows current HEAD and therefore requires review.
|
||||
manifest, snapshot = build_documents()
|
||||
|
||||
if args.write:
|
||||
MANIFEST_PATH.write_text(_dump(manifest), encoding="utf-8")
|
||||
SNAPSHOT_PATH.write_text(_dump(snapshot), encoding="utf-8")
|
||||
print(f"wrote {MANIFEST_PATH}")
|
||||
print(f"wrote {SNAPSHOT_PATH}")
|
||||
print("Re-pinning changes the alpha target. Update the alpha contract under review.")
|
||||
return 0
|
||||
|
||||
drifted = False
|
||||
for path, fresh in ((MANIFEST_PATH, manifest), (SNAPSHOT_PATH, snapshot)):
|
||||
current = json.loads(path.read_text(encoding="utf-8"))
|
||||
if current != fresh:
|
||||
drifted = True
|
||||
print(f"DRIFT: {path.name} no longer matches upstream", file=sys.stderr)
|
||||
if drifted:
|
||||
print(
|
||||
"\nPinned revision metadata no longer matches the locked files. Treat this as "
|
||||
"artifact-integrity drift; do not heal or re-pin without human review.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
print("target manifest and architecture snapshot match upstream")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
851
tests/test_glm_alpha_target.py
Normal file
851
tests/test_glm_alpha_target.py
Normal file
@@ -0,0 +1,851 @@
|
||||
"""DGR-017 — the locked GLM-5.2 Max target, resource plan, and alpha contract.
|
||||
|
||||
These tests are deterministic, offline, GPU-free, and download-free. They assert
|
||||
against the *pinned* manifest, so they fail if a later agent swaps the artifact,
|
||||
loosens the memory accounting, or moves a threshold after seeing a result.
|
||||
|
||||
The planner tests are written as a reproduction of the roadmap's published tables.
|
||||
That is the point: if the arithmetic here ever stops reproducing them, either the
|
||||
roadmap or the planner is lying, and the test says which numbers changed.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from meshnet_node.glm_alpha import (
|
||||
AGGREGATE_HARD_FIT_FLOOR_GIB,
|
||||
ALPHA_CONTRACT_ID,
|
||||
ALPHA_QUANTIZATION,
|
||||
ALPHA_SHARD_COUNT,
|
||||
MIN_LINK_RATE_GBPS,
|
||||
RECOMMENDED_LINK_RATE_GBPS,
|
||||
RESERVE_FLOOR_GIB,
|
||||
AlphaContractError,
|
||||
GlmTargetError,
|
||||
NodeMemory,
|
||||
ResourcePlanError,
|
||||
compute_contract_digest,
|
||||
kv_bytes,
|
||||
load_alpha_contract,
|
||||
load_architecture_snapshot,
|
||||
load_locked_target,
|
||||
load_target_manifest,
|
||||
parse_alpha_contract,
|
||||
parse_architecture_snapshot,
|
||||
parse_target_manifest,
|
||||
plan_route,
|
||||
plan_seams,
|
||||
plan_topology,
|
||||
require_contract_target,
|
||||
require_pinned_target,
|
||||
seal_contract,
|
||||
)
|
||||
from meshnet_node.glm_alpha.manifest import GIB
|
||||
|
||||
# The revisions observed and pinned by DGR-017 on 2026-07-13.
|
||||
SOURCE_REVISION = "b4734de4facf877f85769a911abafc5283eab3d9"
|
||||
GGUF_REVISION = "abc55e72527792c6e77069c99b4cb7de16fa9f23"
|
||||
TOTAL_BYTES = 216_715_360_960
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def manifest():
|
||||
return load_target_manifest()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def snapshot():
|
||||
return load_architecture_snapshot()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def contract():
|
||||
return load_alpha_contract()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def manifest_doc(manifest):
|
||||
return copy.deepcopy(dict(manifest.raw))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def snapshot_doc(snapshot):
|
||||
return copy.deepcopy(dict(snapshot.raw))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def contract_doc(contract):
|
||||
return copy.deepcopy(dict(contract.raw))
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Identity: the exact artifact, pinned
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_manifest_pins_both_repositories_by_exact_revision(manifest):
|
||||
assert manifest.source_repo_id == "zai-org/GLM-5.2"
|
||||
assert manifest.source_revision == SOURCE_REVISION
|
||||
assert manifest.gguf_repo_id == "unsloth/GLM-5.2-GGUF"
|
||||
assert manifest.gguf_revision == GGUF_REVISION
|
||||
assert manifest.quantization == ALPHA_QUANTIZATION == "UD-IQ1_S"
|
||||
assert manifest.source_license == "mit"
|
||||
assert manifest.gguf_license == "mit"
|
||||
|
||||
|
||||
def test_manifest_resolves_all_six_shards_with_sizes_hashes_and_urls(manifest):
|
||||
assert len(manifest.shards) == ALPHA_SHARD_COUNT == 6
|
||||
assert [shard.index for shard in manifest.shards] == [1, 2, 3, 4, 5, 6]
|
||||
|
||||
for shard in manifest.shards:
|
||||
assert shard.size_bytes > 0
|
||||
assert len(shard.sha256) == 64
|
||||
assert shard.url.startswith(f"https://huggingface.co/{manifest.gguf_repo_id}/resolve/")
|
||||
assert GGUF_REVISION in shard.url, "a shard URL must resolve at the pinned revision"
|
||||
|
||||
digests = {shard.sha256 for shard in manifest.shards}
|
||||
assert len(digests) == 6, "six distinct shards must have six distinct content digests"
|
||||
|
||||
|
||||
def test_manifest_aggregate_bytes_are_exact_and_self_consistent(manifest):
|
||||
assert manifest.total_bytes == TOTAL_BYTES
|
||||
assert sum(shard.size_bytes for shard in manifest.shards) == TOTAL_BYTES
|
||||
assert round(manifest.total_gib, 3) == 201.832
|
||||
assert round(manifest.total_gb, 3) == 216.715
|
||||
|
||||
|
||||
def test_manifest_records_the_iq1_m_diagnostic_fallback_without_promoting_it(manifest):
|
||||
fallback = manifest.raw["diagnostic_fallback"]
|
||||
assert fallback["quantization"] == "UD-IQ1_M"
|
||||
assert fallback["total_bytes"] == 228_492_966_624
|
||||
assert fallback["total_bytes"] > manifest.total_bytes
|
||||
assert "does not satisfy" in fallback["policy"]
|
||||
|
||||
|
||||
def test_manifest_forbids_home_storage(manifest):
|
||||
assert manifest.raw["storage"]["mounted_storage_only"] is True
|
||||
assert "/home" in manifest.raw["storage"]["forbidden_path_prefixes"]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Identity: what the manifest must reject
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_a_changed_source_revision_is_rejected(manifest, snapshot, manifest_doc):
|
||||
manifest_doc["source_model"]["revision"] = "0" * 40
|
||||
swapped = parse_target_manifest(manifest_doc)
|
||||
|
||||
with pytest.raises(GlmTargetError, match="does not match the locked alpha revision"):
|
||||
require_pinned_target(
|
||||
swapped,
|
||||
snapshot,
|
||||
expected_source_revision=SOURCE_REVISION,
|
||||
expected_gguf_revision=GGUF_REVISION,
|
||||
)
|
||||
|
||||
|
||||
def test_a_changed_gguf_revision_is_rejected(manifest, snapshot, manifest_doc):
|
||||
manifest_doc["gguf_artifact"]["revision"] = "1" * 40
|
||||
swapped = parse_target_manifest(manifest_doc)
|
||||
|
||||
with pytest.raises(GlmTargetError, match="does not match the locked alpha revision"):
|
||||
require_pinned_target(
|
||||
swapped,
|
||||
snapshot,
|
||||
expected_source_revision=SOURCE_REVISION,
|
||||
expected_gguf_revision=GGUF_REVISION,
|
||||
)
|
||||
|
||||
|
||||
def test_the_pinned_target_passes_its_own_revision_check(manifest, snapshot):
|
||||
require_pinned_target(
|
||||
manifest,
|
||||
snapshot,
|
||||
expected_source_revision=SOURCE_REVISION,
|
||||
expected_gguf_revision=GGUF_REVISION,
|
||||
)
|
||||
|
||||
|
||||
def test_config_metadata_from_a_different_revision_than_the_weights_is_rejected(
|
||||
manifest, snapshot_doc
|
||||
):
|
||||
snapshot_doc["source_revision"] = "2" * 40
|
||||
drifted = parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
with pytest.raises(GlmTargetError, match="must come from one revision"):
|
||||
require_pinned_target(
|
||||
manifest,
|
||||
drifted,
|
||||
expected_source_revision=SOURCE_REVISION,
|
||||
expected_gguf_revision=GGUF_REVISION,
|
||||
)
|
||||
|
||||
|
||||
def test_a_branch_name_is_not_an_acceptable_revision_pin(manifest_doc):
|
||||
manifest_doc["gguf_artifact"]["revision"] = "main"
|
||||
|
||||
with pytest.raises(GlmTargetError, match="not an immutable pin"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_a_missing_shard_is_rejected(manifest_doc):
|
||||
manifest_doc["gguf_artifact"]["shards"].pop()
|
||||
|
||||
with pytest.raises(GlmTargetError, match="exactly 6 shards"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_a_shard_replaced_by_a_duplicate_of_another_is_rejected(manifest_doc):
|
||||
shards = manifest_doc["gguf_artifact"]["shards"]
|
||||
# Keep the count at six and the byte total consistent, but drop shard 6's
|
||||
# identity — the shape a lazy "just re-download it" repair takes.
|
||||
shards[5]["index"] = 5
|
||||
|
||||
with pytest.raises(GlmTargetError, match="duplicate shard index"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_two_shards_claiming_the_same_content_digest_are_rejected(manifest_doc):
|
||||
shards = manifest_doc["gguf_artifact"]["shards"]
|
||||
shards[5]["sha256"] = shards[4]["sha256"]
|
||||
|
||||
with pytest.raises(GlmTargetError, match="same content digest"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_an_inconsistent_aggregate_byte_total_is_rejected(manifest_doc):
|
||||
manifest_doc["gguf_artifact"]["total_bytes"] = TOTAL_BYTES - 1
|
||||
|
||||
with pytest.raises(GlmTargetError, match="not self-consistent"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_a_shard_size_edited_to_make_the_model_look_smaller_is_rejected(manifest_doc):
|
||||
# The aggregate is now internally inconsistent, which is exactly the tell.
|
||||
manifest_doc["gguf_artifact"]["shards"][2]["size_bytes"] = 1_000_000
|
||||
|
||||
with pytest.raises(GlmTargetError, match="not self-consistent"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_swapping_in_a_different_quantization_is_rejected(manifest_doc):
|
||||
manifest_doc["alpha_quantization"] = "UD-IQ1_M"
|
||||
|
||||
with pytest.raises(GlmTargetError, match="requires a human contract change"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
def test_a_truncated_sha256_is_rejected(manifest_doc):
|
||||
manifest_doc["gguf_artifact"]["shards"][0]["sha256"] = "abc123"
|
||||
|
||||
with pytest.raises(GlmTargetError, match="64-character hex SHA-256"):
|
||||
parse_target_manifest(manifest_doc)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Architecture snapshot
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_snapshot_captures_the_architecture_critical_metadata(snapshot):
|
||||
assert snapshot["model_type"] == "glm_moe_dsa"
|
||||
assert snapshot["num_hidden_layers"] == 78
|
||||
assert snapshot["num_nextn_predict_layers"] == 1
|
||||
assert snapshot["total_artifact_layers"] == 79
|
||||
assert snapshot["dense_layers"] == 3
|
||||
assert snapshot["sparse_moe_layers"] == 75
|
||||
assert snapshot["hidden_size"] == 6144
|
||||
assert snapshot["n_routed_experts"] == 256
|
||||
assert snapshot["num_experts_per_tok"] == 8
|
||||
assert snapshot["n_shared_experts"] == 1
|
||||
assert snapshot["index_topk"] == 2048
|
||||
assert snapshot["index_head_dim"] == 128
|
||||
assert snapshot["max_position_embeddings"] == 1_048_576
|
||||
assert snapshot["vocab_size"] == 154_880
|
||||
|
||||
|
||||
def test_snapshot_records_indexshare_roles_for_every_layer(snapshot):
|
||||
assert snapshot["indexer_full_layers"] == 21
|
||||
assert snapshot["indexer_shared_layers"] == 57
|
||||
assert snapshot["indexer_full_layers"] + snapshot["indexer_shared_layers"] == 78
|
||||
|
||||
|
||||
def test_mla_cache_width_is_derived_not_asserted(snapshot):
|
||||
assert snapshot["kv_lora_rank"] == 512
|
||||
assert snapshot["qk_rope_head_dim"] == 64
|
||||
assert snapshot["mla_cached_values_per_token_per_layer"] == 576
|
||||
|
||||
|
||||
def test_snapshot_hashes_the_config_and_chat_template_bytes(snapshot):
|
||||
assert len(snapshot.file_sha256("config.json")) == 64
|
||||
assert len(snapshot.file_sha256("chat_template.jinja")) == 64
|
||||
assert len(snapshot.file_sha256("tokenizer_config.json")) == 64
|
||||
assert len(snapshot["indexer_types_sha256"]) == 64
|
||||
assert len(snapshot.digest) == 64
|
||||
|
||||
|
||||
def test_reasoning_effort_max_is_locked_as_an_observable_rendered_marker(snapshot):
|
||||
reasoning = snapshot.reasoning_effort
|
||||
assert reasoning["alpha_mode"] == "max"
|
||||
assert reasoning["rendered_marker"] == "<|system|>Reasoning Effort: Max"
|
||||
# The template's only non-max level is 'high'; everything else renders Max. So
|
||||
# "the request carried reasoning_effort=max" proves nothing on its own.
|
||||
assert reasoning["default_is_max"] is True
|
||||
|
||||
|
||||
def test_folding_the_nextn_layer_into_the_backbone_is_rejected(snapshot_doc):
|
||||
snapshot_doc["architecture"]["total_artifact_layers"] = 78
|
||||
|
||||
with pytest.raises(GlmTargetError, match="NextN layer must be counted"):
|
||||
parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
|
||||
def test_indexshare_roles_that_do_not_cover_every_layer_are_rejected(snapshot_doc):
|
||||
snapshot_doc["architecture"]["indexer_full_layers"] = 20
|
||||
|
||||
with pytest.raises(GlmTargetError, match="exactly one IndexShare role"):
|
||||
parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
|
||||
def test_a_route_with_no_full_indexer_producer_is_rejected(snapshot_doc):
|
||||
snapshot_doc["architecture"]["indexer_full_layers"] = 0
|
||||
snapshot_doc["architecture"]["indexer_shared_layers"] = 78
|
||||
|
||||
with pytest.raises(GlmTargetError, match="no index for its Shared consumers"):
|
||||
parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
|
||||
def test_a_contradictory_mla_width_is_rejected(snapshot_doc):
|
||||
snapshot_doc["architecture"]["mla_cached_values_per_token_per_layer"] = 512
|
||||
|
||||
with pytest.raises(GlmTargetError, match="kv_lora_rank"):
|
||||
parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
|
||||
def test_a_snapshot_missing_an_architecture_critical_field_is_rejected(snapshot_doc):
|
||||
del snapshot_doc["architecture"]["n_routed_experts"]
|
||||
|
||||
with pytest.raises(GlmTargetError, match="architecture-critical field"):
|
||||
parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
|
||||
def test_a_snapshot_that_drops_reasoning_effort_max_is_rejected(snapshot_doc):
|
||||
snapshot_doc["reasoning_effort"]["alpha_mode"] = "high"
|
||||
|
||||
with pytest.raises(GlmTargetError, match="does not lock reasoning_effort=max"):
|
||||
parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# KV planning
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("context", "mla_only", "optimized", "conservative", "conservative_f16"),
|
||||
[
|
||||
(16_384, 0.73, 0.77, 0.89, 1.68),
|
||||
(131_072, 5.83, 6.18, 7.12, 13.41),
|
||||
(1_048_576, 46.62, 49.41, 56.98, 107.25),
|
||||
],
|
||||
)
|
||||
def test_kv_planner_reproduces_the_published_roadmap_table(
|
||||
snapshot, context, mla_only, optimized, conservative, conservative_f16
|
||||
):
|
||||
def gib(**kwargs):
|
||||
return kv_bytes(snapshot, context_tokens=context, concurrency=1, **kwargs) / GIB
|
||||
|
||||
assert round(gib(include_indexer=False), 2) == mla_only
|
||||
assert round(gib(indexer_layout="optimized"), 2) == optimized
|
||||
assert round(gib(indexer_layout="conservative"), 2) == conservative
|
||||
assert round(gib(indexer_layout="conservative", dtype="F16"), 2) == conservative_f16
|
||||
|
||||
|
||||
def test_alpha_budgets_the_conservative_indexer_layout(snapshot):
|
||||
"""Alpha must budget the implementation it may actually get, not the ideal one."""
|
||||
optimized = kv_bytes(snapshot, indexer_layout="optimized")
|
||||
conservative = kv_bytes(snapshot, indexer_layout="conservative")
|
||||
|
||||
assert conservative > optimized
|
||||
assert kv_bytes(snapshot) == conservative, "the default must be the conservative layout"
|
||||
|
||||
|
||||
def test_kv_scales_with_concurrency(snapshot):
|
||||
assert kv_bytes(snapshot, concurrency=2) == 2 * kv_bytes(snapshot, concurrency=1)
|
||||
|
||||
|
||||
def test_an_unlocked_kv_dtype_is_rejected(snapshot):
|
||||
with pytest.raises(ResourcePlanError, match="alpha locks Q8_0"):
|
||||
kv_bytes(snapshot, dtype="Q4_0")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", [0, -1, True, 1.5])
|
||||
def test_kv_rejects_non_positive_or_non_integer_dimensions(snapshot, bad):
|
||||
with pytest.raises(ResourcePlanError, match="positive integers"):
|
||||
kv_bytes(snapshot, context_tokens=bad)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Memory accounting: unified memory is one pool
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_unified_memory_is_counted_once():
|
||||
node = NodeMemory.from_host("strix-halo", system_ram_gib=128.0, unified=True)
|
||||
|
||||
assert node.physical_usable_gib == 128.0, "integrated-GPU memory is not extra memory"
|
||||
|
||||
|
||||
def test_adding_integrated_gpu_memory_to_system_ram_is_rejected():
|
||||
with pytest.raises(ResourcePlanError, match="double-counts one pool"):
|
||||
NodeMemory.from_host(
|
||||
"strix-halo",
|
||||
system_ram_gib=128.0,
|
||||
gpu_memory_gib=96.0,
|
||||
unified=True,
|
||||
)
|
||||
|
||||
|
||||
def test_a_discrete_gpu_does_add_its_own_memory():
|
||||
node = NodeMemory.from_host(
|
||||
"workstation", system_ram_gib=64.0, gpu_memory_gib=24.0, unified=False
|
||||
)
|
||||
|
||||
assert node.physical_usable_gib == 88.0
|
||||
|
||||
|
||||
def test_the_same_machine_counted_twice_in_a_route_is_rejected(manifest, snapshot):
|
||||
twin = [
|
||||
NodeMemory.from_host("box-a", system_ram_gib=128.0, unified=True),
|
||||
NodeMemory.from_host("box-a", system_ram_gib=128.0, unified=True),
|
||||
]
|
||||
|
||||
with pytest.raises(ResourcePlanError, match="counted twice"):
|
||||
plan_route(manifest, snapshot, twin)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", [float("nan"), float("inf"), -1.0, True])
|
||||
def test_node_memory_rejects_non_finite_or_invalid_capacity(bad):
|
||||
with pytest.raises(ResourcePlanError, match="finite positive"):
|
||||
NodeMemory(name="bad-host", physical_usable_gib=bad, unified=True)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Reserve and topology
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_reserve_floor_binds_on_small_nodes():
|
||||
small = NodeMemory(name="32", physical_usable_gib=32.0, unified=True)
|
||||
|
||||
assert small.reserve_gib == RESERVE_FLOOR_GIB == 8.0 # 20% of 32 is only 6.4
|
||||
assert small.placement_budget_gib == 24.0
|
||||
|
||||
|
||||
def test_the_reserve_fraction_binds_on_large_nodes():
|
||||
large = NodeMemory(name="128", physical_usable_gib=128.0, unified=True)
|
||||
|
||||
assert large.reserve_gib == 25.6 # 20% of 128 clears the 8 GiB floor
|
||||
assert large.placement_budget_gib == 102.4
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("tier", "reserve", "budget", "arithmetic_minimum", "recommended"),
|
||||
[
|
||||
(32.0, 8.0, 24.0, 9, 10),
|
||||
(48.0, 9.6, 38.4, 6, 6),
|
||||
(64.0, 12.8, 51.2, 4, 5),
|
||||
(96.0, 19.2, 76.8, 3, 3),
|
||||
(128.0, 25.6, 102.4, 2, 3),
|
||||
],
|
||||
)
|
||||
def test_topology_planner_reproduces_the_published_tier_table(
|
||||
manifest, snapshot, tier, reserve, budget, arithmetic_minimum, recommended
|
||||
):
|
||||
plan = plan_topology(manifest, snapshot, physical_usable_gib=tier)
|
||||
|
||||
assert round(plan.reserve_gib, 2) == reserve
|
||||
assert round(plan.placement_budget_gib, 2) == budget
|
||||
assert plan.arithmetic_minimum_nodes == arithmetic_minimum
|
||||
assert plan.recommended_nodes == recommended
|
||||
assert round(plan.weight_gib, 3) == 201.832
|
||||
assert round(plan.kv_gib, 2) == 0.89 # 16K, concurrency 1, Q8_0, conservative DSA
|
||||
|
||||
|
||||
def test_the_recommended_topologies_are_five_by_64_or_three_by_96_or_128(manifest, snapshot):
|
||||
assert plan_topology(manifest, snapshot, physical_usable_gib=64.0).recommended_nodes == 5
|
||||
assert plan_topology(manifest, snapshot, physical_usable_gib=96.0).recommended_nodes == 3
|
||||
assert plan_topology(manifest, snapshot, physical_usable_gib=128.0).recommended_nodes == 3
|
||||
|
||||
|
||||
def test_two_by_128_is_an_arithmetic_minimum_not_a_recommendation(manifest, snapshot):
|
||||
plan = plan_topology(manifest, snapshot, physical_usable_gib=128.0)
|
||||
|
||||
assert plan.arithmetic_minimum_nodes == 2
|
||||
assert plan.recommended_nodes == 3
|
||||
assert not plan.is_arithmetic_minimum_topology, (
|
||||
"2x128 GiB leaves no room for endpoint/tensor imbalance; it is a fit probe that "
|
||||
"requires measured placement evidence, not the alpha recommendation"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", [0.9, float("nan"), float("inf"), True])
|
||||
def test_an_invalid_placement_imbalance_is_rejected(manifest, snapshot, bad):
|
||||
with pytest.raises(ResourcePlanError, match="less than an equal share"):
|
||||
plan_topology(manifest, snapshot, physical_usable_gib=64.0, imbalance_factor=bad)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Route fit
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_recommended_five_by_64_route_fits(manifest, snapshot):
|
||||
nodes = [
|
||||
NodeMemory.from_host(f"node-{i}", system_ram_gib=64.0, unified=True) for i in range(5)
|
||||
]
|
||||
|
||||
fit = plan_route(manifest, snapshot, nodes)
|
||||
|
||||
assert fit.fits
|
||||
assert fit.meets_hard_fit_floor
|
||||
assert fit.no_single_node_can_admit_target
|
||||
assert fit.reasons == ()
|
||||
|
||||
|
||||
def test_224_gib_aggregate_is_a_hard_fit_floor_not_an_operational_envelope(manifest, snapshot):
|
||||
"""Exactly 224 GiB of aggregate memory clears the floor and still does not fit.
|
||||
|
||||
This is the whole reason the roadmap calls 224 GiB an *experimental hard-fit
|
||||
floor*. It is the number you get by ignoring the per-node reserve — and once
|
||||
the reserve is applied, the weights alone no longer have anywhere to go.
|
||||
"""
|
||||
nodes = [
|
||||
NodeMemory.from_host(f"node-{i}", system_ram_gib=112.0, unified=True) for i in range(2)
|
||||
]
|
||||
|
||||
fit = plan_route(manifest, snapshot, nodes)
|
||||
|
||||
assert fit.aggregate_usable_gib == AGGREGATE_HARD_FIT_FLOOR_GIB == 224.0
|
||||
assert fit.meets_hard_fit_floor
|
||||
assert not fit.fits, "224 GiB aggregate does not fit the target once reserves are honoured"
|
||||
assert any("below the" in reason for reason in fit.reasons)
|
||||
|
||||
|
||||
def test_a_route_too_small_for_the_target_does_not_fit(manifest, snapshot):
|
||||
nodes = [
|
||||
NodeMemory.from_host(f"node-{i}", system_ram_gib=64.0, unified=True) for i in range(3)
|
||||
]
|
||||
|
||||
fit = plan_route(manifest, snapshot, nodes)
|
||||
|
||||
assert not fit.fits
|
||||
assert not fit.meets_hard_fit_floor
|
||||
|
||||
|
||||
def test_a_route_where_one_node_could_hold_everything_is_not_distributed_alpha(
|
||||
manifest, snapshot
|
||||
):
|
||||
nodes = [
|
||||
NodeMemory.from_host(f"node-{i}", system_ram_gib=512.0, unified=True) for i in range(2)
|
||||
]
|
||||
|
||||
fit = plan_route(manifest, snapshot, nodes)
|
||||
|
||||
assert fit.fits
|
||||
assert not fit.no_single_node_can_admit_target
|
||||
assert any("single-host run" in reason for reason in fit.reasons)
|
||||
|
||||
|
||||
def test_a_single_node_is_not_a_route(manifest, snapshot):
|
||||
with pytest.raises(ResourcePlanError, match="at least two physical nodes"):
|
||||
plan_route(
|
||||
manifest,
|
||||
snapshot,
|
||||
[NodeMemory.from_host("solo", system_ram_gib=512.0, unified=True)],
|
||||
)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Seams and network
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_seam_bytes_match_the_published_activation_arithmetic(snapshot):
|
||||
plan = plan_seams(snapshot, node_count=4, context_tokens=16_384)
|
||||
|
||||
assert plan.seam_count == 3, "four nodes imply three serial seams"
|
||||
assert plan.bytes_per_token_per_seam == 12_288 # 6144 x bf16
|
||||
assert plan.prefill_bytes_per_seam == 192 * 1024**2 # 192 MiB
|
||||
assert plan.decode_bytes_per_seam_per_token == 12 * 1024 # 12 KiB
|
||||
assert plan.dsa_sideband_bytes_per_query == 8 * 1024 # 2048 int32 = 8 KiB
|
||||
|
||||
|
||||
def test_2_5_gbe_is_the_alpha_minimum_and_10_gbe_is_recommended(snapshot):
|
||||
gigabit = plan_seams(snapshot, node_count=3, link_rate_gbps=1.0)
|
||||
minimum = plan_seams(snapshot, node_count=3, link_rate_gbps=MIN_LINK_RATE_GBPS)
|
||||
recommended = plan_seams(snapshot, node_count=3, link_rate_gbps=RECOMMENDED_LINK_RATE_GBPS)
|
||||
|
||||
assert not gigabit.meets_alpha_minimum, "1 GbE is fit-only evidence, not an alpha route"
|
||||
assert minimum.meets_alpha_minimum
|
||||
assert not minimum.is_recommended_link
|
||||
assert recommended.meets_alpha_minimum
|
||||
assert recommended.is_recommended_link
|
||||
|
||||
|
||||
def test_serial_seam_latency_is_modelled_separately_from_bandwidth(snapshot):
|
||||
"""Decode moves 12 KiB a token. What it pays is hops, not bytes."""
|
||||
fast_link = plan_seams(snapshot, node_count=5, link_rate_gbps=10.0, per_hop_latency_ms=2.0)
|
||||
slow_link = plan_seams(snapshot, node_count=5, link_rate_gbps=2.5, per_hop_latency_ms=2.0)
|
||||
|
||||
# Quadrupling the link rate barely touches decode: the payload is tiny.
|
||||
assert fast_link.decode_bandwidth_share_ms_per_token < 0.05
|
||||
assert slow_link.decode_bandwidth_share_ms_per_token < 0.2
|
||||
|
||||
# Latency is unchanged by link rate and scales with the number of serial seams.
|
||||
assert fast_link.decode_latency_ms_per_token == slow_link.decode_latency_ms_per_token == 8.0
|
||||
|
||||
# A 10 GbE claim cannot buy back a hop.
|
||||
assert fast_link.decode_latency_ms_per_token > fast_link.decode_bandwidth_share_ms_per_token
|
||||
|
||||
|
||||
def test_adding_a_node_adds_a_serial_seam_to_every_decoded_token(snapshot):
|
||||
three = plan_seams(snapshot, node_count=3, per_hop_latency_ms=1.0)
|
||||
five = plan_seams(snapshot, node_count=5, per_hop_latency_ms=1.0)
|
||||
|
||||
assert three.decode_latency_ms_per_token == 2.0
|
||||
assert five.decode_latency_ms_per_token == 4.0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", [float("nan"), float("inf"), 0.0, True])
|
||||
def test_seam_planner_rejects_invalid_link_telemetry(snapshot, bad):
|
||||
with pytest.raises(ResourcePlanError, match="finite and positive"):
|
||||
plan_seams(snapshot, node_count=3, link_rate_gbps=bad)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# The immutable alpha contract
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_packaged_contract_is_sealed_and_verifies(contract):
|
||||
assert contract.contract_id == ALPHA_CONTRACT_ID
|
||||
assert contract.contract_version == 1
|
||||
assert contract.locked_by == "DGR-017"
|
||||
assert contract.raw["locked_before_target_execution"] is True
|
||||
assert contract.digest == compute_contract_digest(contract.raw)
|
||||
|
||||
|
||||
def test_the_contract_locks_the_same_target_as_the_manifest(contract, manifest, snapshot):
|
||||
assert contract.target["source_revision"] == manifest.source_revision
|
||||
assert contract.target["gguf_revision"] == manifest.gguf_revision
|
||||
assert contract.target["quantization"] == manifest.quantization
|
||||
assert contract.target["total_bytes"] == manifest.total_bytes
|
||||
assert contract.target["target_manifest_sha256"] == manifest.digest
|
||||
assert contract.target["architecture_snapshot_sha256"] == snapshot.digest
|
||||
assert contract.target["reasoning_effort"] == "max"
|
||||
|
||||
|
||||
def test_the_packaged_target_documents_are_cross_bound_to_the_contract():
|
||||
contract, manifest, snapshot = load_locked_target()
|
||||
assert contract.target["target_manifest_sha256"] == manifest.digest
|
||||
assert contract.target["architecture_snapshot_sha256"] == snapshot.digest
|
||||
|
||||
|
||||
def test_coordinated_shard_hash_substitution_is_rejected_by_contract(
|
||||
contract, manifest_doc, snapshot
|
||||
):
|
||||
manifest_doc["gguf_artifact"]["shards"][0]["sha256"] = "0" * 64
|
||||
substituted = parse_target_manifest(manifest_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="target_manifest_sha256"):
|
||||
require_contract_target(contract, substituted, snapshot)
|
||||
|
||||
|
||||
def test_internally_consistent_architecture_substitution_is_rejected_by_contract(
|
||||
contract, manifest, snapshot_doc
|
||||
):
|
||||
snapshot_doc["architecture"]["hidden_size"] = 8192
|
||||
substituted = parse_architecture_snapshot(snapshot_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="architecture_snapshot_sha256"):
|
||||
require_contract_target(contract, manifest, substituted)
|
||||
|
||||
|
||||
def test_contract_id_cannot_be_changed_even_when_resealed(contract_doc):
|
||||
contract_doc["contract_id"] = "glm-5.2-max-alpha/v2"
|
||||
contract_doc = seal_contract(contract_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="contract_id"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_max_reasoning_mode_cannot_be_changed_even_when_resealed(contract_doc):
|
||||
contract_doc["target"]["reasoning_effort"] = "high"
|
||||
contract_doc = seal_contract(contract_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="reasoning_effort='max'"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("field", ["schema_version", "contract_version"])
|
||||
def test_boolean_contract_versions_are_rejected_even_when_resealed(contract_doc, field):
|
||||
contract_doc[field] = True
|
||||
contract_doc = seal_contract(contract_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="version"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_wheel_metadata_includes_nested_glm_alpha_json_resources():
|
||||
pyproject = Path(__file__).parents[1] / "packages/node/pyproject.toml"
|
||||
text = pyproject.read_text(encoding="utf-8")
|
||||
assert '"meshnet_node.glm_alpha" = ["data/*.json"]' in text
|
||||
|
||||
|
||||
def test_the_contract_locks_every_roadmap_acceptance_section(contract):
|
||||
for section in (
|
||||
"identity_and_fit",
|
||||
"semantic_correctness",
|
||||
"target_run",
|
||||
"performance",
|
||||
"reliability",
|
||||
"storage",
|
||||
):
|
||||
assert contract.section(section)
|
||||
|
||||
|
||||
def test_the_contract_locks_the_roadmap_thresholds(contract):
|
||||
assert contract.threshold("identity_and_fit", "min_node_reserve_fraction") == 0.20
|
||||
assert contract.threshold("identity_and_fit", "min_node_reserve_gib") == 8.0
|
||||
assert contract.threshold("identity_and_fit", "aggregate_hard_fit_floor_gib") == 224.0
|
||||
assert (
|
||||
contract.threshold("identity_and_fit", "aggregate_floor_class")
|
||||
== "experimental_hard_fit_floor"
|
||||
)
|
||||
assert contract.threshold("identity_and_fit", "forbid_double_counted_unified_memory") is True
|
||||
|
||||
assert contract.threshold("semantic_correctness", "min_greedy_token_agreement") == 0.90
|
||||
assert contract.threshold("semantic_correctness", "min_mean_state_cosine_similarity") == 0.999
|
||||
assert contract.threshold("semantic_correctness", "dense_attention_fallback_satisfies_alpha") is False
|
||||
|
||||
assert contract.threshold("target_run", "context_tokens") == 16_384
|
||||
assert contract.threshold("target_run", "kv_dtype") == "Q8_0"
|
||||
assert contract.threshold("target_run", "min_link_rate_gbps") == MIN_LINK_RATE_GBPS
|
||||
assert contract.threshold("target_run", "recommended_link_rate_gbps") == RECOMMENDED_LINK_RATE_GBPS
|
||||
assert contract.threshold("target_run", "min_output_tokens") == 512
|
||||
|
||||
assert contract.threshold("performance", "min_median_decode_tokens_per_second") == 0.5
|
||||
assert contract.threshold("performance", "max_ttft_seconds_at_4096_prompt") == 600
|
||||
assert contract.threshold("performance", "quality_pass_with_speed_fail_verdict") == "stop"
|
||||
|
||||
assert contract.threshold("reliability", "synthetic_workers_satisfy_alpha") is False
|
||||
assert contract.threshold("storage", "forbidden_path_prefixes") == ["/home"]
|
||||
|
||||
|
||||
def test_the_contract_offers_only_alpha_or_stop(contract):
|
||||
assert sorted(contract.verdicts) == ["alpha", "stop"]
|
||||
|
||||
|
||||
def test_lowering_the_speed_floor_after_seeing_a_result_is_rejected(contract_doc):
|
||||
"""The exact move the contract exists to prevent."""
|
||||
contract_doc["performance"]["min_median_decode_tokens_per_second"] = 0.05
|
||||
|
||||
with pytest.raises(AlphaContractError, match="modified since it was locked"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_relabelling_a_speed_failure_as_a_pass_is_rejected(contract_doc):
|
||||
contract_doc["performance"]["quality_pass_with_speed_fail_verdict"] = "alpha"
|
||||
|
||||
with pytest.raises(AlphaContractError, match="modified since it was locked"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_admitting_the_dense_attention_fallback_after_the_fact_is_rejected(contract_doc):
|
||||
contract_doc["semantic_correctness"]["dense_attention_fallback_satisfies_alpha"] = True
|
||||
|
||||
with pytest.raises(AlphaContractError, match="modified since it was locked"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_relaxing_the_per_node_reserve_after_the_fact_is_rejected(contract_doc):
|
||||
contract_doc["identity_and_fit"]["min_node_reserve_gib"] = 1.0
|
||||
|
||||
with pytest.raises(AlphaContractError, match="modified since it was locked"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_re_pointing_the_contract_at_a_different_artifact_is_rejected(contract_doc):
|
||||
contract_doc["target"]["gguf_revision"] = "9" * 40
|
||||
|
||||
with pytest.raises(AlphaContractError, match="modified since it was locked"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_an_unsealed_contract_is_rejected(contract_doc):
|
||||
del contract_doc["contract_sha256"]
|
||||
|
||||
with pytest.raises(AlphaContractError, match="cannot prove it predates"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_a_contract_not_locked_before_execution_is_rejected(contract_doc):
|
||||
contract_doc["locked_before_target_execution"] = False
|
||||
contract_doc = seal_contract(contract_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="not a contract"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_a_third_verdict_is_rejected(contract_doc):
|
||||
contract_doc["verdicts"] = ["alpha", "stop", "partial"]
|
||||
contract_doc = seal_contract(contract_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="third outcome"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_a_dropped_acceptance_section_is_rejected(contract_doc):
|
||||
del contract_doc["reliability"]
|
||||
contract_doc = seal_contract(contract_doc)
|
||||
|
||||
with pytest.raises(AlphaContractError, match="missing locked acceptance section"):
|
||||
parse_alpha_contract(contract_doc)
|
||||
|
||||
|
||||
def test_resealing_a_mutated_contract_changes_its_digest(contract, contract_doc):
|
||||
"""Tamper-evidence, not tamper-proofing: a rewrite is legal but never silent."""
|
||||
contract_doc["performance"]["min_median_decode_tokens_per_second"] = 0.05
|
||||
resealed = seal_contract(contract_doc)
|
||||
|
||||
# It parses — nothing in-repo can stop a determined rewrite of file plus digest.
|
||||
reparsed = parse_alpha_contract(resealed)
|
||||
|
||||
# But the digest moved, so the change is a visible diff on a file whose entire
|
||||
# purpose is to not change, and the contract_id still claims to be v1.
|
||||
assert reparsed.digest != contract.digest
|
||||
|
||||
|
||||
def test_an_unknown_threshold_cannot_be_invented_at_read_time(contract):
|
||||
with pytest.raises(AlphaContractError, match="is not locked"):
|
||||
contract.threshold("performance", "min_decode_tokens_per_second_v2")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# The tests themselves stay offline
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_packaged_data_files_are_valid_json_and_load_offline(manifest, snapshot, contract):
|
||||
"""No network, no model, no GPU: the whole target contract is reviewable offline."""
|
||||
assert json.dumps(manifest.to_dict())
|
||||
assert json.dumps(snapshot.to_dict())
|
||||
assert json.dumps(contract.to_dict())
|
||||
assert len(manifest.digest) == 64
|
||||
Reference in New Issue
Block a user