Skip to content

Throughput-aware scheduling + ring-plan service + signed model registry & generic ModelRuntime adapter#6

Open
onlyzhynx wants to merge 10 commits into
leyten:masterfrom
onlyzhynx:prod-improvements
Open

Throughput-aware scheduling + ring-plan service + signed model registry & generic ModelRuntime adapter#6
onlyzhynx wants to merge 10 commits into
leyten:masterfrom
onlyzhynx:prod-improvements

Conversation

@onlyzhynx

@onlyzhynx onlyzhynx commented Jun 27, 2026

Copy link
Copy Markdown

Rebased onto current master (the ModelRuntime / one-engine-every-model commit). origin/master is an ancestor — conflict-free; the only file overlap is phase0/confidence.py, byte-identical on both sides.

Heads-up on scope + honesty: this branch grew past its original title. It now carries two things: (1) the in-house moat work (throughput scheduling, ring-plan service, receipt export, confidence gate) and (2) a model-onboarding layer (signed registry + a GenericHFRuntime impl of your ModelRuntime + an add-model tool). The runtime piece is interface-complete and unit-green but NOT GPU-validated — I did not run your step-2 spike. Happy to split this into two PRs, hold the runtime half for VllmRuntime first, or have you take the runtime adapters — your call. Flagging before you invest review time.

Moat layer (in-house; orthogonal to the ModelRuntime sprint)

  • Throughput-aware ring selection (shard/throughput.py, shard/perf_store.py): picks the ring maximizing estimated tok/s, not the first feasible one (WAN + per-layer compute + draft + accept; exact subset enumeration for small rings). PerfStore learns fleet behavior via EWMA, cold-starts on 3090/4090 priors; atomic writes; largest-remainder conserves exactly. Default plan stays latency-only for byte-compat; objective:"tok_s" opts in.
  • Ring-plan HTTP service (phase0/scheduler_svc.py): the bridge c0mpute calls for a plan (subset + order + per-stage blocks) from live VRAM+RTT, plus /telemetry to learn. Stdlib only.
  • Auto-planned demo ring (phase0/plan_ring.py): plans the libp2p ring from live VRAM+RTT.
  • Verified per-stage receipt export (phase0/specpipe.py --receipts-out): writes verified receipts as JSON for the c0mpute payout path. Only fires under --pipe + --receipts.
  • Confidence-scheduled depth (phase0/specpipe.py, confidence.py): adapts pipeline depth from the acceptance EMA so a bad draft streak doesn't waste WAN traversals. K stays fixed (CUDA-graph shape K+1); only depth changes → lossless (output bit-identical). Result dict gains mean_conf_depth / final_confidence for A/B.
  • Layer-count correction (plan_ring.py, launch_swarm.py): gpt-oss reconciled to its real 36 layers; NLAYERS no longer a GLM-78 holdover applied globally.
  • GLM-path drafting (research, behind flags): MLA-latent KV merge + an MTP drafter scaffold. MTP is GLM-5.2-specific (NEXTN head), behind a flag, n-gram default; K>1 rollout is scaffold-only, not validated past k=1.

Model-onboarding layer (needs your ack — see heads-up)

  • Single signed model registry — shard-models/1 (shard/registry.py, phase0/publish_registry.py, registry/models.json): a model defined once, both repos read it; layer count / bytes-per-layer / quant / engine path / adapter / tokenizer stop living in three places that drift (the gpt-oss 120-vs-36 bug). Signed with the publisher Ed25519 key (reuses manifest.py's canonical+sign path); consumers pin the pubkey and fail closed on bad sig, pinned-pubkey mismatch, unknown adapter, duplicate id, non-positive layerCount. plan_ring.py resolves from the registry; the old MODEL_LAYERS dict is deleted.
  • Generic HF ModelRuntime adapter (phase0/hf_runtime.py): GenericHFRuntime implements your shard/node.py over the proven pipeline.load_stage/run_block — the universal HF fallback, any arch transformers can load (incl. gpt-oss) with no new engine code. make_runtime(adapter, …) maps the registry adapter field to an impl; generic-vllm falls back here until VllmRuntime lands. One adapter behind the firewall — coordinate_pipe rides on it unchanged. Not a competing interface; implements yours.
  • add-model tooling + runbook (phase0/add_model.py, docs/runbooks/add-a-model.md): config → fit math (gbPerLayer/kvGbPerLayer, dense and MoE) → emit+merge+sign the registry row (version bumped). Prints the operator steps it can't do — quantize+host+CID, tokenizer round-trip, the 3-stage smoke.

Tests (all offline, no GPU)

scheduler_svc (6), plan_ring (6), throughput (29), registry (11, incl. a post-sign layerCount tamper rejected by the signature — the gpt-oss-drift guard), hf_runtime (22, conformance via a torch-free fake), add_model (16, incl. a new MoE model → signed verifiable row with zero engine code), cross-repo agreement (29, drives both repos + asserts identical KNOWN_ADAPTERS), plus confidence.py / mtp_draft.py self-tests.

What "green" does NOT cover (stated plainly)

  • No GPU validation of GenericHFRuntime — a sliced layer block running on hardware and matching a full-model reference is your step-2 spike, not done here. This PR is the torch-only reference for it.
  • MLA-latent / MTP not proven on-box; quantize + 3-stage smoke in the add-model flow are the irreducible/metered remainder (only the data-emission half is tested).

Out of scope (follow-up)

  • VllmRuntime behind ModelRuntime + the GPU spike that gates it (MODEL_RUNTIME.md 2-3).
  • Deriving weight keys from the manifest weight_map in shard/fetch.py (step 4) — flagged, not grabbed.
  • Batch-aware plan_ring sizing now that the engine serves B streams.

@joelovestech

Copy link
Copy Markdown

Hey — went through the prod-improvements branch, solid work. The throughput-aware ring selection is the right call and it's model-agnostic — the order-independence insight (reuse the latency loop, let compute drive selection) is clean, and your 3090/4090 priors match the fleet you're targeting, so cold-start should be decent until the perf store learns real numbers.

One thing on the drafting side, for the M2.5 target: the MTP drafter you scaffolded is GLM-5.2-specific — it leans on GLM's native NEXTN head (layer 78), which only exists because 5.2 was trained with it. You can't add an MTP head to a model that wasn't trained with one, so it won't port to MiniMax M2.5 unless M2.5 actually exposes a NEXTN/num_mtp head — which your m25_config_probe was checking for (num_nextn_predict_layers / num_mtp_modules). If that came back empty, M2.5 has no MTP head and the draft path stays n-gram, which is what launch_ngram already does. So for the M2.5 target the real draft lever is n-gram / prompt-lookup acceptance, not the MTP rollout.

If you're keeping a parallel GLM-5.2 path (since you pulled the ring_mtp work), one heads-up: you nailed the single-step convention (post-model.norm hidden, [enorm(emb); hnorm(h)] — the one that costs 0.86→0.51 on pre-norm). But the K>1 autoregressive rollout invents two conventions that aren't validated — it re-applies model.norm to the MTP block's own output to chain steps (model.norm is the main trunk's final norm, not part of the MTP recurrence), and it runs the block at start_pos 0,1,2… instead of the true sequence offsets (wrong RoPE on an attention layer). Neither breaks correctness — the ring verifies every token — but both silently tank acceptance, the whole reason to run MTP. ring_mtp only validated k=1; worth sweeping the K>1 conventions before trusting a multi-token number.

Smaller and model-agnostic: acceptance isn't really a per-model scalar — it climbs with context — so the tok/s estimate drifts long. Non-blocking. Nice branch overall.

onlyzhynx added 10 commits June 28, 2026 21:30
…after scaffold

shard/research:
- glm_swarm_nvfp4_kv.py: full replace from shardv2 (MLA-latent cache,
  tree verify par/dep, GraphVerify, GLM_MAXPOS)
- mla_latent.py: offline MLA absorb equivalence proof (1e-13 errors)
- ring_mtp.py, ring_long.py, draft_accept_bench.py: MTP + long-ctx research

shard/phase0:
- confidence.py: ConfidenceScheduler (EMA-based depth/K adaptation,
  DSpark-inspired), self-test passes
- mtp_draft.py: MtpDrafter scaffold matching NgramDrafter interface,
  post-norm convention, lazy-loads Layer 78, degrades without torch
- specpipe.py: confidence-scheduled depth in coordinate_pipe (K stays
  fixed for CUDA graph, depth adapts from acceptance EMA)
the orchestrator owns ring assembly + payments but must not re-implement the
VRAM-fit + min-latency topology solver (tested python in shard/scheduler.py).
POST /plan {model,total_layers,gb_per_layer,nodes:[{node_id,vram_gb,rtt_ms}]}
-> {coordinator, ring_order, stages:[{stage,node_id,lo,hi,n_layers}]}.

coordinator is co-located on the head stage (matches launch_libp2p.py): ring =
[coord] + topology(coord), blocks re-tiled contiguous in ring order so each
stage's --lo/--hi is a clean local 0-based window. auto-picks lowest-mean-rtt
depot when unpinned. stdlib only, no deps. boundary law: knows layers/vram/rtt,
nothing about accounts/pay.

6 offline tests ($0): even/heterogeneous fit, fat-node-first, coord pin+auto,
insufficient-vram raise, 0-layer node dropped. all pass + live HTTP smoke.
the working demo is hand-tuned: operator guesses --stages order + --layers
split. plan_ring queries each box's REAL vram (nvidia-smi) + the measured rtt
mesh (reuses launch_swarm.mesh_rtt), calls the scheduler, prints the exact
launch_libp2p.py invocation (--stages in ring order, --layers as the vram fit).

non-invasive: launcher untouched, operator pastes the printed command. fleet
imports (launch_oss/launch_swarm, which read ~/.shard_psk + pull vastai) are
lazy so the pure planning logic stays importable + testable offline.

6 offline tests ($0): vram parse (single/multi-gpu/units/garbage), node
assembly, full pipeline with stubbed vram (fat-node-biggest, [0:78] coverage),
coord pin. all pass.
the shard side of the c0mpute receipts bridge. on a --pipe --receipts coordinator
run, after the post-gen ring sweep verifies every signature + full layer coverage,
dump {ok, receipts:[...]} to this path. the c0mpute shard-worker reads it and
forwards the receipts to the orchestrator on job:complete, which re-verifies
(signer-bound) and pays each stage. complements --dump (output) with the receipts.
…learn from real runs

The latency-only planner (topology.py) can't see GPU compute — it'd hand a slow
fat-VRAM card a big layer block and tank throughput. Score the whole speculative
round instead (WAN loop + per-GPU layers*ms/layer + accept-rate) and choose the
subset+order that maximizes predicted tok/s.

- shard/throughput.py: best_ring searches feasible node subsets, fits+orders each
  (reusing optimal_loop — order is still the min-latency loop for a fixed set), scores
  est_tok_s, returns the winner. round_ms/est_tok_s with accept-cap + zero guards.
- shard/perf_store.py: EWMA store of per-GPU ms/layer, edge RTT, per-model accept_rate,
  learned from completed runs; GPU-class priors when cold; atomic JSON persistence.
- scheduler_svc: POST /plan {objective:tok_s} -> throughput plan (+est_tok_s/round_ms);
  POST /telemetry folds a completed run into the store; --perf-store persists it.
  Default /plan unchanged (latency-only) — fully backward-compatible.
- specpipe --dump: add rounds (mean_accept/K already present) so accept_rate is derivable.
- throughput_test.py: 29 tests incl. the headline 'slow fat GPU loses to fast lean pair',
  the learn-then-replan loop (cold 77 tok/s single-fat -> warm 100 tok/s fast-pair), and
  backward-compat. 41 Python tests green.
S1: gpt-oss layer count reconciled to 36 everywhere
  - plan_ring.py: MODEL_LAYERS dict, no global DEFAULT_TOTAL_LAYERS=78
  - launch_swarm.py: NLAYERS 78->36 (matches default model gpt-oss-120B)
S2: FIXME flag in receipt.py verify_coverage (unknown-signer hole)
  leyten's self-check, not payment boundary. Flagged for him to fix.

Python syntax verified.
a model is defined once in registry/models.json (shard-models/1), signed with
the publisher ed25519 key (reuses manifest.py canonical+sign path). both repos
read it. deletes plan_ring MODEL_LAYERS — layer count / bytes-per-layer / quant
now resolve from the verified registry, --total-layers stays an override only.

- shard/registry.py: load/verify/sign + row validation (known adapter, unique
  ids, positive layerCount), fail closed on bad sig / pinned-pubkey mismatch.
- phase0/publish_registry.py: sign a source registry, or --verify a signed one.
- registry_test.py: 11 proofs incl tampered-layerCount rejection (the gpt-oss
  120-vs-36 bug, now caught by the signature).
- tests/registry_cross_repo_test.py: drives BOTH repos, asserts field-for-field
  agreement on every model — the test that would have caught the drift.
implements upstream's ModelRuntime (shard/node.py, MODEL_RUNTIME.md) over the
proven pipeline.load_stage / run_block path: GenericHFRuntime is the universal
HF/Transformers fallback — any arch transformers can load (incl gpt-oss) serves
with no new engine code. make_runtime(adapter,...) maps the signed-registry
adapter field to the impl; generic-vllm falls back here until VllmRuntime lands
(MODEL_RUNTIME.md step 3). NOT a new interface — one adapter behind the in-house
firewall, so coordinate_pipe rides on it unchanged.

registry KNOWN_ADAPTERS gains generic-hf/hf (kept identical to c0mpute's set,
asserted by the cross-repo test). 22 $0 proofs (no torch): subclass+contract,
adapter selection fail-closed, head/tail boundary law, [0:N] tiling. the real
load_shard/forward is the metered GPU spike (MODEL_RUNTIME.md step 2).

supersedes the earlier StageRuntime sketch, which duplicated ModelRuntime; this
conforms to the already-merged upstream interface instead.
add_model.py turns onboarding into data: read config.architectures + dims,
compute gbPerLayer + kvGbPerLayer for the scheduler fit, emit + merge + sign the
registry row (version bumped so consumers refetch). prints the operator steps it
can't do (quantize + host + manifest CID, tokenizer round-trip, 3-stage smoke).

- fit math handles dense AND MoE layers (num_experts*expert_mlp + shared +
  router), conservative bytes/param per quant so the vram fit never over-commits.
- add_model_test.py: 16 $0 proofs incl the acceptance offline half — a new MoE
  model goes nothing -> signed verifiable registry row with ZERO engine code,
  post-sign tamper rejected.
- docs/runbooks/add-a-model.md: one-page runbook (TL;DR, quant recipe, fit math,
  tokenizer silent-failure guard, $0 verify list).

adapter values reference the ModelRuntime impls (generic-hf/generic-vllm/glm-nvfp4).
@onlyzhynx onlyzhynx force-pushed the prod-improvements branch from 9bdc950 to f603786 Compare June 29, 2026 01:00
@onlyzhynx onlyzhynx changed the title prod-readiness: MLA-latent merge, confidence-scheduled verify, MTP dr… Throughput-aware scheduling + ring-plan service + signed model registry & generic ModelRuntime adapter Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants