267 lines
17 KiB
Markdown
267 lines
17 KiB
Markdown
# 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`
|
||
|
||
**Contract continuity is fail-closed.** The document’s `contract_sha256` detects
|
||
accidental edits, and the approved v1 digest is pinned independently in code. A caller
|
||
that changes a threshold and re-seals it under `glm-5.2-max-alpha/v1` is rejected by
|
||
`test_resealing_a_mutated_v1_contract_is_rejected`; amendments require a new supported
|
||
contract identity under human review. Parsed nested state is recursively immutable,
|
||
so thresholds cannot change between validation and use; `to_dict()` returns an isolated
|
||
copy rather than exposing the validated object.
|
||
|
||
## 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.
|