V2 Model Support — compute graph → working Runtime-V2 demo
This is the GENERIC pipeline for putting ANY model on MPK Runtime-V2. It was distilled from
the campaign that took DeepSeek-V3 decode from a v1-only model to a full-61-layer Runtime-V2
e2e run at TP8 EP2 bs=1 (commit e31b34dd, opt-in --use-v2, default build byte-identical).
DSv3 examples below are clearly labeled worked-example material — the recipe does not depend
on them; the staged plan that drove that campaign is archived at
references/V2_DSV3_DECODE_MASTER_PLAN.md (M0→M5 ladder). A SECOND, smaller worked example
— Qwen3-8B on v2, dense, single-GPU-capable — is in §"Worked example #2" below (it is
the closest starting point for a dense-model campaign).
It is a context+phased-recipe skill: architectures vary, the PHASES and GATES do not.
Read mpk-development-norms FIRST. This skill is the HOW (graph→plan→demo); that one is the WHERE + the PR-shape gate that decides what lands cleanly on mpk when the campaign is done — model code in models/<model>/builder.py + demo/<model>/, only GENERIC ops (never <model>_*) in shared persistent_kernel.py, no experiment env-vars in landed code, runtime fixes as separate PRs. During exploration keep levers env-gated default-OFF (mpk-lever-cleanup); before opening the PR, conform to the norms.
Environment prerequisites (what must exist on the machine)
In-repo (travels with every clone): this skill's references/, the v2 runtime + kernels
(include/mirage/persistent_kernel/, tasks/blackwell_v2/), the harness
(tests/runtime_python/blackwell_v2/), both worked-example demos (demo/deepseek_v3/,
demo/qwen3/), the repo agents (.claude/agents/*.md), and the sibling skills. Machine-local
(keep working without them, as noted):
- Remote multi-GPU box — only for multi-rank gates + verdict configs. The box CLI
(
~/nebius_box.sh) and the machine inventory in references/box-orchestration.md §1-2
are SITE-SPECIFIC (placeholders in-repo; actual IPs/users/keys/paths stay in
operator-local notes — never committed); the structural rules there (§3-8: rsync/build,
session discipline, safety, testing tiers) transfer to any box. No box ⇒ single-GPU phases still run end-to-end
(Qwen3-class models need no box at TP1).
- Local GPU(s) — needed from the first harness gate onward (graph-build/test-mode gates
are 0-GPU). Torch-probe cards before use.
- Model checkpoints — site-specific paths; the input contract below is what matters.
- User-level agents (
~/.claude/agents/: mpk-perf-analyzer, ablation-logic-reviewer,
codex-task-dispatcher) — present only on the same user account. The repo-level roster
(.claude/agents/mpk-*, v2-*, ferret-*) travels with the clone. If
ablation-logic-reviewer is missing, run the review discipline with a general-purpose
subagent given its first-principles brief.
- Codex MCP (
mcp__codex__codex) — the cross-check second engine; .mcp.json is
machine-local (git-ignored). If unconfigured, reviews degrade to subagent-only — say so.
- Personal memory (
~/.claude/projects/-home-muhengl-mirage/memory/) — optional context,
same-account only. The load-bearing lessons are already distilled into this suite's docs.
experiment_history/ — git-ignored, so a FRESH CLONE STARTS EMPTY. That is expected:
create INDEX.md + the journal on first use (contract in Phase d); the anti-loop evidence
that must survive clones lives in v2-kernel-writing/references/m1-decode-evidence.md.
Input contract (what you need before starting)
- Model config — hidden size, layer count/types (dense vs MoE, attention variant),
head geometry, vocab, dtype/quantization (FP8 block-scale? BF16?), norm eps.
- HF checkpoint — safetensors; know which weights need conversion/absorption
(e.g. MLA absorbed q_b_proj) and which need requantization.
- Parallelism plan — TP degree, EP degree (routed_tp_size = world/EP), which
linears are Column vs Row parallel, where the AllReduces land, vocab-parallel or
replicated lm_head.
- The compute graph — a draw.io file (ops as nodes labeled name+shape+dtype,
edges = tensor deps, TP-sharding annotations). Format + parsing:
references/graph-to-plan.md. If none is supplied, derive the graph from the HF
modeling_*.py and WRITE the plan doc as if you had one — the plan doc is the
contract, the drawio is just its serialization.
- Target machine(s) — which box runs the multi-GPU verdict configs
(
references/box-orchestration.md). Single-GPU/local for micro-gates only.
Why phased (the one-sentence history)
DSv3-on-v2 succeeded because it NEVER registered a live-path task without a complete
v2 consumer body (a bodyless consumer silently deadlocks the whole box — see the §1.1
trap below), validated each op bit-exact in isolation BEFORE it entered the graph, and
went e2e at the smallest possible slice (1 MoE layer) before scaling. Every shortcut
attempted around this ladder cost days (9 debug rounds on a missing AllReduce; an
iter-1 hang from re-zeroing a monotonic barrier). Do not reorder the phases.
The pipeline
Phase 0 GRAPH→PLAN drawio → op inventory → classify {reuse|new-kernel|fused-later}
Phase a DEMO builder-first: weights/SHARD_RULES/cache-key/lifetimes; chain of
existing v2 tasks; graph-build + test-mode gates (0-GPU first)
Phase b KERNEL per-op loop for missing/slow ops; M0→M5 staged bring-up
Phase c DEBUG the gate ladder (token-match first, TP-collective blind spot,
nondeterminism protocol, hang triage)
Phase d WORKFLOW the multi-agent perf loop + box orchestration + history contract
Phase 0 — GRAPH→PLAN (read references/graph-to-plan.md)
- Parse the draw.io XML → op list. Each op row:
name | op kind | input/output shapes AT THE CHOSEN TP/EP | dtype(s) | weight source key(s) | conversion/absorption needs | collective (none / AR / reduce-scatter / EP-dispatch) | grid intuition.
- Derive PER-RANK shapes: apply the sharding plan (Column→shard N, Row→shard K +
AllReduce after, EP→local expert slice). The DSv3 worked table is in the reference.
- Classify EVERY op:
- REUSE — an existing v2 task covers it (rmsnorm_v2, silu_mul_v2, linear v2/v3
with its
M<=16 contract, embedding_v2, argmax_partial/reduce_v2,
nvshmem_tile_allreduce_v2(+residual), tensor_init_v2, mul_sum_add_v2 …).
Check runtime_header.h enums 242/243, 326-355 and tasks/blackwell_v2/.
- NEW KERNEL — no v2 variant exists → Phase-b item. Tag its port kind:
leaf (role-split trivial) / collective (v2-safe sync rewrite — HARD) /
megakernel-shape Form-2 (num_tasks==num_workers, in-op GMEM barrier).
- FUSED-BLOCK CANDIDATE — defer; fusion comes only after chain correctness.
- Output = the model plan doc: the op table, the v2-ABSENT set, the milestone ladder,
the risk ranking. Location:
.claude/skills/v2-model-support/references/ V2_<MODEL>_MASTER_PLAN.md if it should travel with the repo, scratch/ (git-ignored)
for throwaway drafts. Mirror the archived DSv3 instance
(references/V2_DSV3_DECODE_MASTER_PLAN.md). This doc is what the phase leads execute
against.
Phase (a) — DEMO: builder-first bring-up (read references/demo-stage.md)
Goal: demo/<model>/demo.py + python/mirage/mpk/models/<model>/builder.py that
BUILD the graph (no GPU needed yet) and pass test-mode with existing tasks.
- CHAIN-FIRST rule: assemble every layer from existing generic v2 tasks even if
slow. Fused megakernels are Phase-b/perf work. A correct chain is your ground truth
for every later diff (
FUSED_KERNEL_DEBUG_METHODOLOGY.md step 2 depends on it).
- Weight mapping: SHARD_RULES live in TWO places — the builder AND the demo's
conversion pass. Update both, always.
- Cache-key contract: the weight cache key hashes config, NOT conversion code. Bump
the format-version string on ANY conversion-logic change (silent stale weights is
the worst failure). Details +
MPK_CONVERT_SEMAPHORE / MPK_BUILD_CACHE_ONLY in
the reference.
- v2 wiring is 90% automatic: pass
use_v2_runtime=args.use_v2 into
PersistentKernel(...); compile() itself runs the v2 queue plan + SMEM plan +
the §1.1 deadlock guard (persistent_kernel.py ~:5619-5640). Builder-side work is
selecting v2 task names (most *_layer wrappers self-switch on
self.use_v2_runtime) and the v2-only allocations (scratch sizing, scale packs).
- Gates before ANY GPU run: (1) graph-build succeeds for the smallest slice;
(2) the §1.1 guard passes —
v2_unsafe_task_types empty (every graph-used task
type has a v2 role variant, else compile() raises instead of wedging the box);
(3) test-mode (0-GPU-graph-build + single-pass CPU-launchable subset) green.
Phase (b) — KERNEL: per-op loop on the M0→M5 ladder
For each NEW KERNEL op, dispatch the sibling skill v2-kernel-writing
(.claude/skills/v2-kernel-writing/ — the per-kernel inner loop this pipeline plugs
into: SPEC→IMPLEMENT→WIRE→VALIDATE→PERF→REVIEW) with the op's spec row from Phase 0
(roles / SMEM regions / sync / correctness reference / validate step — the §3
template in the DSv3 master plan). For pure kernel-PERF rewrites of an op that already
passes correctness, ferret-kernel-system/kda-kernel-agent + mpk-faithful-gate
are the measurement-honest routes. Every new _v2 task touches: runtime_header.h enum +
task_register.cc register_*_v2_task (consumer body MUST begin with
emit_dep_wait_consumer_prefix) + graph.cc dispatch + runtime.cc
task_type_to_name (+ the task_offset = bid.x block for fused megas) + the
.cuh/_spec.h pair in tasks/blackwell_v2/ + the persistent_kernel.py wrapper's
"..._v2" if self.use_v2_runtime switch + the builder call site.
Stage the bring-up on the PROVEN ladder (mirror references/V2_DSV3_DECODE_MASTER_PLAN.md
— DSv3 worked example; a dense single-GPU model collapses M1 to "none" and M4/M5 shrink):
- M0 — leaves + tail wiring. Trivial role-split tasks (tensor_init-class), tail
re-routes (lm_head/argmax path), confirm already-present v2 leaves are reachable
from THIS model's builder. Validate in the
tests/runtime_python/blackwell_v2/
harness (per-op, deterministically-seeded, vs fp32 torch ref AND vs the v1 twin).
- M1 — collectives at TP2 first. The AllReduce-class ports are the highest-risk
items (block-wide
__syncthreads()/256-thread bodies vs the 128-thread consumer
role → deadlock/half-compute if pasted). Validate on a TP2 micrograph (2 ranks,
known vectors, bit-exact sum on both ranks), then TP8. Do this EARLY — it de-risks
everything downstream and is the first multi-rank v2 proof.
- M2 — fused blocks. Megakernel-shape (Form-2) ports: check first whether an
existing v2 mega can be REUSED via a builder re-route (DSv3's FFN was — kernel
already proven, the work was builder-side tensor packing). Each fused mega:
bit-match vs its v1 twin in a TP-shaped harness, THEN a small-slice in-MPK smoke
(the
__align__(1024) extern-smem footgun is only caught in-MPK).
- M3 — FIRST E2E at the smallest real slice (DSv3:
--use-v2 --layers 3-3
TP8 EP2 bs=1, --disable-vocab-parallel-lm-head to stay on present tail tasks).
TWO hard pre-conditions: (1) reachability diff — build the sliced graph in
test-mode and diff the task list vs a full build so no head/tail seed task is
silently dropped; (2) §1.1 guard green. Correctness = the Phase-c protocol.
- M4 — scale layers up (+ restore any deferred tail variant). Expect the
cold-convert OOM class here at full TP —
MPK_CONVERT_SEMAPHORE=K.
- M5 — remaining layer types (DSv3: dense layers 0-2 via one Form-2 task) →
full-model e2e. Deliverable: full-layer coherent decode on v2 + tpot vs v1.
Per-kernel gate: test-mode numeric PASS (cos ≥ 0.999, rel_max ≤ 3e-2, no NaN, and
bit-exact-vs-v1 for elementwise ops) BEFORE the task enters any e2e graph.
Phase (c) — DEBUG (read references/debug-gates.md BEFORE debugging anything)
The distilled ladder — full checklists in the reference:
- Full-layer TOKEN-MATCH first; NEVER judge correctness from few-layer coherence.
- Broken → diff vs the CHAIN stage-by-stage (clean token position, FULL vectors).
- Garbage at TP>1 + gate/TP1 fine ⇒ suspect a MISSING CROSS-RANK COLLECTIVE first —
a single-rank gate is structurally blind to it (6 gate-fidelity classes).
- Token-identity only on DETERMINISTIC configs. The TP8 FFN atomicAdd path is
nondeterministic → use the 3-part gate: deterministic canary + NaN poison-fill +
full-model coherence-in-envelope (with an OFF1-vs-OFF2 control).
- iter-0-fine / iter-1-hang ⇒ a PERSISTENT state got re-initialized (monotonic
barrier +
skip_after_step0 class), not a missing event.
- Hangs: watchdog (names the hung task) > breadcrumb (crash-only; in-flight counts
are base-rate artifacts). Illegal address: compute-sanitizer is ground truth.
- "Dead task / safe to remove" claims: box token-identity A/B is the ONLY ground
truth — static analysis + reviewers have been wrong.
Run the
mpk-correctness-gate agent before trusting any baseline and before every
math-changing commit.
Phase (d) — WORKFLOW orchestration (perf loop, after correctness)
The full v2-updated loop is the sibling skill v2-perf-iteration
(.claude/skills/v2-perf-iteration/) — load it to run this phase; the summary below is
orientation only.
The multi-agent loop, unchanged: profiler → (analyzer) → planner →
iterator → [ablation-logic-reviewer] → implement → correctness-gate → profiler →
commit-reviewer → commit → memory-keeper → decide. Standing disciplines:
- EVERY non-trivial conclusion through
ablation-logic-reviewer + a Codex MCP
cross-check before acting on it (the over-claim guard; defaults params only).
- Every lever lands env-gated default-OFF; DEFAULT BUILD BYTE-IDENTICAL (the whole
v2 wiring itself followed this —
--use-v2 opt-in).
- Verdict metric at the PRODUCTION config (DSv3: bs=1 TP8 e2e tpot); smaller TP is
triage only. Slowest-CTA per-position, never P50/per-kernel aggregates.
experiment_history/ contract: journal + INDEX row after every experiment,
ESPECIALLY NULL/REGRESS (anti-loop) — via mpk-memory-keeper.
- GPU-safety: never crash-loop the megakernel (D-state zombies), memory-cap every
launch, box sessions per
references/box-orchestration.md.
Worked example #2 — Qwen3-8B on v2 (in-tree + upstream; the dense single-GPU shape)
A COMPLETE second instance of this pipeline's endpoint already exists for a dense model, and
it is the natural starting point for any dense/single-GPU v2 campaign (e.g. Qwen3-8B
throughput work):
- In-tree (this branch):
demo/qwen3/demo.py has --use-v2 (argparse :127;
use_v2_runtime=args.use_v2 into PersistentKernel ~:352). The graph is built INLINE in
the demo (the python/mirage/mpk/models/qwen3/builder.py GraphBuilder has NO v2 branches —
a wiring-style difference vs DSv3's builder-side gating). The v2 branches swap exactly the
GEMM-shaped ops to the Channel-based per-tile linear family, tiles_per_task=1:
qkv_proj + gate_up → linear_layer_v3 (:544, :711), o_proj + down_proj →
linear_with_residual_layer_v3 (:637, :744), lm_head → linear_layer_v3 (:795)
(TASK_LINEAR_SM100_V3 = 244 / _WITH_RESIDUAL_ = 245). Everything else keeps its task
name and runs as the v2 role variant: rmsnorm (TASK_RMS_NORM_HOPPER_V2 326), paged
attention (TASK_ATTN_SM100_V2 329, consumer-only), silu_mul, embedding, argmax
partial/reduce. Task-plan wiring is EXPLICIT at demo level (~:850-854):
task_graph["v2_worker_task_queues"] = build_v2_worker_task_queues(...) +
add_v2_region_smem_plan(...) before mpk.compile() — the older of the two wiring
styles (DSv3 relies on compile() doing both internally; see references/demo-stage.md §7).
- Single-GPU capable: yes — the demo runs at
world_size == 1 with a local
--model-path or the HF default Qwen/Qwen3-8B; no NVSHMEM collectives exist at TP1, so
no box is needed. The tracked calibration script
tests/runtime_python/blackwell_v2/e2e_qwen3_check.sh runs v1-vs---use-v2
token+ms/tok on one local GPU (v1 reference ~4.03 ms/tok noted in its header) — NOTE it
hardcodes the original machine's PY=.../mirage/.venv/bin/python and DEMO_DIR; adjust
those two vars on a clone (it is repo code — do not expect it to self-locate).
- Upstream twin:
demo/qwen3/demo.py@mirage-project/runtime_refactor (head 0eadb3fd,
2026-06-11) is the same demo where the Channel-based linear was PROMOTED to be THE v2
(linear_layer_v2/linear_with_residual_layer_v2, ids 244/245; non-linear v2 ids parked
at 224-229). Read it via git show mirage-project/runtime_refactor:demo/qwen3/demo.py
(remote-add note in v2-kernel-writing/references/upstream-kernel-catalog.md, which also
catalogs every upstream v2 kernel the qwen3 path uses).
- What a Qwen3-class campaign reuses from this pipeline: Phase 0 classifies nearly
everything REUSE (all needed v2 tasks exist); Phase (a) is the demo/plan wiring above;
Phase (b) shrinks to perf rewrites (M1 collectives = none at TP1); Phase (c)'s
deterministic token-match applies directly (no TP8 nondeterminism protocol needed);
Phase (d) =
v2-perf-iteration with the verdict config restated for THAT campaign
(e.g. single-GPU bs=1024 throughput instead of TP8 bs=1 tpot — restate it in every
dispatch prompt; the mpk-* defs and this suite default to the DSv3 framing).
Subagent dispatch model
This suite runs as a nested pipeline: the TOP orchestrator (main thread or the
v2-model-support-orchestrator agent) owns phase sequencing and ALL box operations;
it dispatches ONE lead subagent per phase, and a phase lead may dispatch its own
scoped workers (per-op kernel authors, harness writers, reviewers). Hard rules:
- Box ops (start/stop/ssh/rsync/run) stay with the TOP orchestrator ONLY. Phase
leads and workers produce code + local gates; they hand "needs a box run" items up.
(History: a box-touching subagent leaked an idle box for ~55 min; nested watchers
park past their stop step. See
references/box-orchestration.md.)
- Phase gates are blocking: a phase lead reports PASS/FAIL + evidence; the top
orchestrator never starts phase N+1 on a FAIL.
- Reuse the existing roster where it fits:
mpk-correctness-gate, mpk-profiler,
mpk-commit-reviewer, mpk-memory-keeper, ablation-logic-reviewer,
ferret-kernel-agent/kda-kernel-agent for kernel-perf work.
Non-negotiables (the failure modes this suite exists to prevent)
- Never register a live-path v2 task without a COMPLETE consumer body (§1.1: silent
deadlock, D-state box wedge). The build-time guard must stay green.
- Never re-zero monotonic barrier scratch after step 0 (
skip_after_step0=True is
correctness, not perf — iter-1 hang otherwise).
- Never paste a 256-thread/
__syncthreads() body into a 128-thread consumer role.
- New fused-mega task types MUST be added to the
task_offset = bid.x block in
runtime.cc (else garbage CTA index → grid-barrier deadlock).
- Extern-smem regions:
alignment=1024 in the _spec.h, and an in-MPK smoke after
every fused-mega port (the harness cannot catch misalignment of OTHER tasks).
- A rank must never silently skip a collective (epoch alignment = identical-graph
determinism; a skipped AR desyncs the team counter → deadlock/stale).
- Chain first, fuse later; bit-exact per-op before e2e; smallest slice before scale.
- Default build byte-identical; all new paths opt-in.
References
| Doc |
Content |
references/graph-to-plan.md |
drawio convention + parsing, per-rank shape derivation, DSv3 worked op table, classification decision |
references/demo-stage.md |
builder anatomy, SHARD_RULES/cache-key/lifetime footguns, v2 wiring specifics |
references/debug-gates.md |
the phase-c ladder as checklists, 6 gate-fidelity classes, hang triage |
references/box-orchestration.md |
remote-box session playbook (setup/poll split, rsync, retries, safety) — §1-2 site-specific, §3-8 transfer |
references/V2_DSV3_DECODE_MASTER_PLAN.md |
the real M0→M5 plan this skill generalizes (archived worked example) |
FUSED_KERNEL_DEBUG_METHODOLOGY.md (repo root) |
the original debug order-of-operations |
../v2-perf-iteration/SKILL.md + its references/loop-agents.md |
the full multi-agent loop (repo-root WORKFLOW.md is a superseded stub) |
1---2name: v2-model-support3description: End-to-end pipeline for adding or porting a model to MPK Runtime-V2 — from a compute-graph spec (shapes + draw.io graph + HF checkpoint + TP/EP plan) to a working multi-GPU demo. Use when bringing up a NEW model on the v2 (role-split, static-plan) runtime, when porting an existing v1 model to --use-v2, or when handed a compute-graph file and asked to make it run. Covers graph→plan, builder/demo bring-up, per-kernel authoring dispatch, the debug gate ladder, and the multi-agent/box workflow.4---56# V2 Model Support — compute graph → working Runtime-V2 demo78This is the GENERIC pipeline for putting ANY model on MPK Runtime-V2. It was distilled from9the campaign that took DeepSeek-V3 decode from a v1-only model to a full-61-layer Runtime-V210e2e run at TP8 EP2 bs=1 (commit `e31b34dd`, opt-in `--use-v2`, default build byte-identical).11DSv3 examples below are clearly labeled worked-example material — the recipe does not depend12on them; the staged plan that drove that campaign is archived at13`references/V2_DSV3_DECODE_MASTER_PLAN.md` (M0→M5 ladder). A SECOND, smaller worked example14— **Qwen3-8B on v2, dense, single-GPU-capable** — is in §"Worked example #2" below (it is15the closest starting point for a dense-model campaign).16It is a context+phased-recipe skill: architectures vary, the PHASES and GATES do not.1718> **Read `mpk-development-norms` FIRST.** This skill is the HOW (graph→plan→demo); that one is the WHERE + the PR-shape gate that decides what lands cleanly on `mpk` when the campaign is done — model code in `models/<model>/builder.py` + `demo/<model>/`, only GENERIC ops (never `<model>_*`) in shared `persistent_kernel.py`, no experiment env-vars in landed code, runtime fixes as separate PRs. During exploration keep levers env-gated default-OFF (`mpk-lever-cleanup`); before opening the PR, conform to the norms.1920## Environment prerequisites (what must exist on the machine)2122In-repo (travels with every clone): this skill's `references/`, the v2 runtime + kernels23(`include/mirage/persistent_kernel/`, `tasks/blackwell_v2/`), the harness24(`tests/runtime_python/blackwell_v2/`), both worked-example demos (`demo/deepseek_v3/`,25`demo/qwen3/`), the repo agents (`.claude/agents/*.md`), and the sibling skills. Machine-local26(keep working without them, as noted):2728- **Remote multi-GPU box** — only for multi-rank gates + verdict configs. The box CLI29 (`~/nebius_box.sh`) and the machine inventory in `references/box-orchestration.md` §1-230 are SITE-SPECIFIC (placeholders in-repo; actual IPs/users/keys/paths stay in31 operator-local notes — never committed); the structural rules there (§3-8: rsync/build,32 session discipline, safety, testing tiers) transfer to any box. No box ⇒ single-GPU phases still run end-to-end33 (Qwen3-class models need no box at TP1).34- **Local GPU(s)** — needed from the first harness gate onward (graph-build/test-mode gates35 are 0-GPU). Torch-probe cards before use.36- **Model checkpoints** — site-specific paths; the input contract below is what matters.37- **User-level agents** (`~/.claude/agents/`: `mpk-perf-analyzer`, `ablation-logic-reviewer`,38 `codex-task-dispatcher`) — present only on the same user account. The repo-level roster39 (`.claude/agents/mpk-*`, `v2-*`, `ferret-*`) travels with the clone. If40 `ablation-logic-reviewer` is missing, run the review discipline with a general-purpose41 subagent given its first-principles brief.42- **Codex MCP** (`mcp__codex__codex`) — the cross-check second engine; `.mcp.json` is43 machine-local (git-ignored). If unconfigured, reviews degrade to subagent-only — say so.44- **Personal memory** (`~/.claude/projects/-home-muhengl-mirage/memory/`) — optional context,45 same-account only. The load-bearing lessons are already distilled into this suite's docs.46- **`experiment_history/`** — git-ignored, so a FRESH CLONE STARTS EMPTY. That is expected:47 create `INDEX.md` + the journal on first use (contract in Phase d); the anti-loop evidence48 that must survive clones lives in `v2-kernel-writing/references/m1-decode-evidence.md`.4950## Input contract (what you need before starting)51521. **Model config** — hidden size, layer count/types (dense vs MoE, attention variant),53 head geometry, vocab, dtype/quantization (FP8 block-scale? BF16?), norm eps.542. **HF checkpoint** — safetensors; know which weights need conversion/absorption55 (e.g. MLA absorbed q_b_proj) and which need requantization.563. **Parallelism plan** — TP degree, EP degree (routed_tp_size = world/EP), which57 linears are Column vs Row parallel, where the AllReduces land, vocab-parallel or58 replicated lm_head.594. **The compute graph** — a draw.io file (ops as nodes labeled name+shape+dtype,60 edges = tensor deps, TP-sharding annotations). Format + parsing:61 `references/graph-to-plan.md`. If none is supplied, derive the graph from the HF62 `modeling_*.py` and WRITE the plan doc as if you had one — the plan doc is the63 contract, the drawio is just its serialization.645. **Target machine(s)** — which box runs the multi-GPU verdict configs65 (`references/box-orchestration.md`). Single-GPU/local for micro-gates only.6667## Why phased (the one-sentence history)6869DSv3-on-v2 succeeded because it NEVER registered a live-path task without a complete70v2 consumer body (a bodyless consumer silently deadlocks the whole box — see the §1.171trap below), validated each op bit-exact in isolation BEFORE it entered the graph, and72went e2e at the smallest possible slice (1 MoE layer) before scaling. Every shortcut73attempted around this ladder cost days (9 debug rounds on a missing AllReduce; an74iter-1 hang from re-zeroing a monotonic barrier). Do not reorder the phases.7576## The pipeline7778```79Phase 0 GRAPH→PLAN drawio → op inventory → classify {reuse|new-kernel|fused-later}80Phase a DEMO builder-first: weights/SHARD_RULES/cache-key/lifetimes; chain of81 existing v2 tasks; graph-build + test-mode gates (0-GPU first)82Phase b KERNEL per-op loop for missing/slow ops; M0→M5 staged bring-up83Phase c DEBUG the gate ladder (token-match first, TP-collective blind spot,84 nondeterminism protocol, hang triage)85Phase d WORKFLOW the multi-agent perf loop + box orchestration + history contract86```8788## Phase 0 — GRAPH→PLAN (read `references/graph-to-plan.md`)89901. Parse the draw.io XML → op list. Each op row: `name | op kind | input/output shapes91 AT THE CHOSEN TP/EP | dtype(s) | weight source key(s) | conversion/absorption needs92 | collective (none / AR / reduce-scatter / EP-dispatch) | grid intuition`.932. Derive PER-RANK shapes: apply the sharding plan (Column→shard N, Row→shard K +94 AllReduce after, EP→local expert slice). The DSv3 worked table is in the reference.953. Classify EVERY op:96 - **REUSE** — an existing v2 task covers it (rmsnorm_v2, silu_mul_v2, linear v2/v397 with its `M<=16` contract, embedding_v2, argmax_partial/reduce_v2,98 nvshmem_tile_allreduce_v2(+residual), tensor_init_v2, mul_sum_add_v2 …).99 Check `runtime_header.h` enums 242/243, 326-355 and `tasks/blackwell_v2/`.100 - **NEW KERNEL** — no v2 variant exists → Phase-b item. Tag its port kind:101 leaf (role-split trivial) / collective (v2-safe sync rewrite — HARD) /102 megakernel-shape Form-2 (num_tasks==num_workers, in-op GMEM barrier).103 - **FUSED-BLOCK CANDIDATE** — defer; fusion comes only after chain correctness.1044. Output = the model plan doc: the op table, the v2-ABSENT set, the milestone ladder,105 the risk ranking. Location: `.claude/skills/v2-model-support/references/106 V2_<MODEL>_MASTER_PLAN.md` if it should travel with the repo, `scratch/` (git-ignored)107 for throwaway drafts. Mirror the archived DSv3 instance108 (`references/V2_DSV3_DECODE_MASTER_PLAN.md`). This doc is what the phase leads execute109 against.110111## Phase (a) — DEMO: builder-first bring-up (read `references/demo-stage.md`)112113Goal: `demo/<model>/demo.py` + `python/mirage/mpk/models/<model>/builder.py` that114BUILD the graph (no GPU needed yet) and pass test-mode with existing tasks.115116- **CHAIN-FIRST rule**: assemble every layer from existing generic v2 tasks even if117 slow. Fused megakernels are Phase-b/perf work. A correct chain is your ground truth118 for every later diff (`FUSED_KERNEL_DEBUG_METHODOLOGY.md` step 2 depends on it).119- Weight mapping: SHARD_RULES live in TWO places — the builder AND the demo's120 conversion pass. Update both, always.121- Cache-key contract: the weight cache key hashes config, NOT conversion code. Bump122 the format-version string on ANY conversion-logic change (silent stale weights is123 the worst failure). Details + `MPK_CONVERT_SEMAPHORE` / `MPK_BUILD_CACHE_ONLY` in124 the reference.125- v2 wiring is 90% automatic: pass `use_v2_runtime=args.use_v2` into126 `PersistentKernel(...)`; `compile()` itself runs the v2 queue plan + SMEM plan +127 the §1.1 deadlock guard (persistent_kernel.py ~:5619-5640). Builder-side work is128 selecting v2 task names (most `*_layer` wrappers self-switch on129 `self.use_v2_runtime`) and the v2-only allocations (scratch sizing, scale packs).130- **Gates before ANY GPU run**: (1) graph-build succeeds for the smallest slice;131 (2) the §1.1 guard passes — `v2_unsafe_task_types` empty (every graph-used task132 type has a v2 role variant, else `compile()` raises instead of wedging the box);133 (3) test-mode (0-GPU-graph-build + single-pass CPU-launchable subset) green.134135## Phase (b) — KERNEL: per-op loop on the M0→M5 ladder136137For each **NEW KERNEL** op, dispatch the sibling skill **`v2-kernel-writing`**138(`.claude/skills/v2-kernel-writing/` — the per-kernel inner loop this pipeline plugs139into: SPEC→IMPLEMENT→WIRE→VALIDATE→PERF→REVIEW) with the op's spec row from Phase 0140(roles / SMEM regions / sync / correctness reference / validate step — the `§3`141template in the DSv3 master plan). For pure kernel-PERF rewrites of an op that already142passes correctness, `ferret-kernel-system`/`kda-kernel-agent` + `mpk-faithful-gate`143are the measurement-honest routes. Every new `_v2` task touches: `runtime_header.h` enum +144`task_register.cc` `register_*_v2_task` (consumer body MUST begin with145`emit_dep_wait_consumer_prefix`) + `graph.cc` dispatch + `runtime.cc`146`task_type_to_name` (+ the `task_offset = bid.x` block for fused megas) + the147`.cuh`/`_spec.h` pair in `tasks/blackwell_v2/` + the `persistent_kernel.py` wrapper's148`"..._v2" if self.use_v2_runtime` switch + the builder call site.149150Stage the bring-up on the PROVEN ladder (mirror `references/V2_DSV3_DECODE_MASTER_PLAN.md`151— DSv3 worked example; a dense single-GPU model collapses M1 to "none" and M4/M5 shrink):152153- **M0 — leaves + tail wiring.** Trivial role-split tasks (tensor_init-class), tail154 re-routes (lm_head/argmax path), confirm already-present v2 leaves are reachable155 from THIS model's builder. Validate in the `tests/runtime_python/blackwell_v2/`156 harness (per-op, deterministically-seeded, vs fp32 torch ref AND vs the v1 twin).157- **M1 — collectives at TP2 first.** The AllReduce-class ports are the highest-risk158 items (block-wide `__syncthreads()`/256-thread bodies vs the 128-thread consumer159 role → deadlock/half-compute if pasted). Validate on a TP2 micrograph (2 ranks,160 known vectors, bit-exact sum on both ranks), then TP8. Do this EARLY — it de-risks161 everything downstream and is the first multi-rank v2 proof.162- **M2 — fused blocks.** Megakernel-shape (Form-2) ports: check first whether an163 existing v2 mega can be REUSED via a builder re-route (DSv3's FFN was — kernel164 already proven, the work was builder-side tensor packing). Each fused mega:165 bit-match vs its v1 twin in a TP-shaped harness, THEN a small-slice in-MPK smoke166 (the `__align__(1024)` extern-smem footgun is only caught in-MPK).167- **M3 — FIRST E2E** at the smallest real slice (DSv3: `--use-v2 --layers 3-3`168 TP8 EP2 bs=1, `--disable-vocab-parallel-lm-head` to stay on present tail tasks).169 TWO hard pre-conditions: (1) reachability diff — build the sliced graph in170 test-mode and diff the task list vs a full build so no head/tail seed task is171 silently dropped; (2) §1.1 guard green. Correctness = the Phase-c protocol.172- **M4 — scale** layers up (+ restore any deferred tail variant). Expect the173 cold-convert OOM class here at full TP — `MPK_CONVERT_SEMAPHORE=K`.174- **M5 — remaining layer types** (DSv3: dense layers 0-2 via one Form-2 task) →175 full-model e2e. Deliverable: full-layer coherent decode on v2 + tpot vs v1.176177Per-kernel gate: test-mode numeric PASS (cos ≥ 0.999, rel_max ≤ 3e-2, no NaN, and178bit-exact-vs-v1 for elementwise ops) BEFORE the task enters any e2e graph.179180## Phase (c) — DEBUG (read `references/debug-gates.md` BEFORE debugging anything)181182The distilled ladder — full checklists in the reference:1831. Full-layer TOKEN-MATCH first; NEVER judge correctness from few-layer coherence.1842. Broken → diff vs the CHAIN stage-by-stage (clean token position, FULL vectors).1853. Garbage at TP>1 + gate/TP1 fine ⇒ suspect a MISSING CROSS-RANK COLLECTIVE first —186 a single-rank gate is structurally blind to it (6 gate-fidelity classes).1874. Token-identity only on DETERMINISTIC configs. The TP8 FFN atomicAdd path is188 nondeterministic → use the 3-part gate: deterministic canary + NaN poison-fill +189 full-model coherence-in-envelope (with an OFF1-vs-OFF2 control).1905. iter-0-fine / iter-1-hang ⇒ a PERSISTENT state got re-initialized (monotonic191 barrier + `skip_after_step0` class), not a missing event.1926. Hangs: watchdog (names the hung task) > breadcrumb (crash-only; in-flight counts193 are base-rate artifacts). Illegal address: compute-sanitizer is ground truth.1947. "Dead task / safe to remove" claims: box token-identity A/B is the ONLY ground195 truth — static analysis + reviewers have been wrong.196Run the `mpk-correctness-gate` agent before trusting any baseline and before every197math-changing commit.198199## Phase (d) — WORKFLOW orchestration (perf loop, after correctness)200201**The full v2-updated loop is the sibling skill `v2-perf-iteration`202(`.claude/skills/v2-perf-iteration/`) — load it to run this phase; the summary below is203orientation only.**204205The multi-agent loop, unchanged: profiler → (analyzer) → planner →206iterator → [ablation-logic-reviewer] → implement → correctness-gate → profiler →207commit-reviewer → commit → memory-keeper → decide. Standing disciplines:208- EVERY non-trivial conclusion through `ablation-logic-reviewer` + a Codex MCP209 cross-check before acting on it (the over-claim guard; defaults params only).210- Every lever lands env-gated default-OFF; DEFAULT BUILD BYTE-IDENTICAL (the whole211 v2 wiring itself followed this — `--use-v2` opt-in).212- Verdict metric at the PRODUCTION config (DSv3: bs=1 TP8 e2e tpot); smaller TP is213 triage only. Slowest-CTA per-position, never P50/per-kernel aggregates.214- `experiment_history/` contract: journal + INDEX row after every experiment,215 ESPECIALLY NULL/REGRESS (anti-loop) — via `mpk-memory-keeper`.216- GPU-safety: never crash-loop the megakernel (D-state zombies), memory-cap every217 launch, box sessions per `references/box-orchestration.md`.218219## Worked example #2 — Qwen3-8B on v2 (in-tree + upstream; the dense single-GPU shape)220221A COMPLETE second instance of this pipeline's endpoint already exists for a dense model, and222it is the natural starting point for any dense/single-GPU v2 campaign (e.g. Qwen3-8B223throughput work):224225- **In-tree (this branch)**: `demo/qwen3/demo.py` has `--use-v2` (argparse ~:127;226 `use_v2_runtime=args.use_v2` into `PersistentKernel` ~:352). The graph is built INLINE in227 the demo (the `python/mirage/mpk/models/qwen3/builder.py` GraphBuilder has NO v2 branches —228 a wiring-style difference vs DSv3's builder-side gating). The v2 branches swap exactly the229 GEMM-shaped ops to the Channel-based per-tile linear family, `tiles_per_task=1`:230 qkv_proj + gate_up → `linear_layer_v3` (~:544, ~:711), o_proj + down_proj →231 `linear_with_residual_layer_v3` (~:637, ~:744), lm_head → `linear_layer_v3` (~:795)232 (`TASK_LINEAR_SM100_V3` = 244 / `_WITH_RESIDUAL_` = 245). Everything else keeps its task233 name and runs as the v2 role variant: rmsnorm (`TASK_RMS_NORM_HOPPER_V2` 326), paged234 attention (`TASK_ATTN_SM100_V2` 329, consumer-only), silu_mul, embedding, argmax235 partial/reduce. Task-plan wiring is EXPLICIT at demo level (~:850-854):236 `task_graph["v2_worker_task_queues"] = build_v2_worker_task_queues(...)` +237 `add_v2_region_smem_plan(...)` before `mpk.compile()` — the older of the two wiring238 styles (DSv3 relies on `compile()` doing both internally; see `references/demo-stage.md` §7).239- **Single-GPU capable**: yes — the demo runs at `world_size == 1` with a local240 `--model-path` or the HF default `Qwen/Qwen3-8B`; no NVSHMEM collectives exist at TP1, so241 no box is needed. The tracked calibration script242 `tests/runtime_python/blackwell_v2/e2e_qwen3_check.sh` runs v1-vs-`--use-v2`243 token+ms/tok on one local GPU (v1 reference ~4.03 ms/tok noted in its header) — NOTE it244 hardcodes the original machine's `PY=.../mirage/.venv/bin/python` and `DEMO_DIR`; adjust245 those two vars on a clone (it is repo code — do not expect it to self-locate).246- **Upstream twin**: `demo/qwen3/demo.py@mirage-project/runtime_refactor` (head `0eadb3fd`,247 2026-06-11) is the same demo where the Channel-based linear was PROMOTED to be THE v2248 (`linear_layer_v2`/`linear_with_residual_layer_v2`, ids 244/245; non-linear v2 ids parked249 at 224-229). Read it via `git show mirage-project/runtime_refactor:demo/qwen3/demo.py`250 (remote-add note in `v2-kernel-writing/references/upstream-kernel-catalog.md`, which also251 catalogs every upstream v2 kernel the qwen3 path uses).252- **What a Qwen3-class campaign reuses from this pipeline**: Phase 0 classifies nearly253 everything REUSE (all needed v2 tasks exist); Phase (a) is the demo/plan wiring above;254 Phase (b) shrinks to perf rewrites (M1 collectives = none at TP1); Phase (c)'s255 deterministic token-match applies directly (no TP8 nondeterminism protocol needed);256 Phase (d) = `v2-perf-iteration` with the verdict config restated for THAT campaign257 (e.g. single-GPU bs=1024 throughput instead of TP8 bs=1 tpot — restate it in every258 dispatch prompt; the mpk-* defs and this suite default to the DSv3 framing).259260## Subagent dispatch model261262This suite runs as a nested pipeline: the TOP orchestrator (main thread or the263`v2-model-support-orchestrator` agent) owns phase sequencing and ALL box operations;264it dispatches ONE lead subagent per phase, and a phase lead may dispatch its own265scoped workers (per-op kernel authors, harness writers, reviewers). Hard rules:266- **Box ops (start/stop/ssh/rsync/run) stay with the TOP orchestrator ONLY.** Phase267 leads and workers produce code + local gates; they hand "needs a box run" items up.268 (History: a box-touching subagent leaked an idle box for ~55 min; nested watchers269 park past their stop step. See `references/box-orchestration.md`.)270- Phase gates are blocking: a phase lead reports PASS/FAIL + evidence; the top271 orchestrator never starts phase N+1 on a FAIL.272- Reuse the existing roster where it fits: `mpk-correctness-gate`, `mpk-profiler`,273 `mpk-commit-reviewer`, `mpk-memory-keeper`, `ablation-logic-reviewer`,274 `ferret-kernel-agent`/`kda-kernel-agent` for kernel-perf work.275276## Non-negotiables (the failure modes this suite exists to prevent)2772781. Never register a live-path v2 task without a COMPLETE consumer body (§1.1: silent279 deadlock, D-state box wedge). The build-time guard must stay green.2802. Never re-zero monotonic barrier scratch after step 0 (`skip_after_step0=True` is281 correctness, not perf — iter-1 hang otherwise).2823. Never paste a 256-thread/`__syncthreads()` body into a 128-thread consumer role.2834. New fused-mega task types MUST be added to the `task_offset = bid.x` block in284 `runtime.cc` (else garbage CTA index → grid-barrier deadlock).2855. Extern-smem regions: `alignment=1024` in the `_spec.h`, and an in-MPK smoke after286 every fused-mega port (the harness cannot catch misalignment of OTHER tasks).2876. A rank must never silently skip a collective (epoch alignment = identical-graph288 determinism; a skipped AR desyncs the team counter → deadlock/stale).2897. Chain first, fuse later; bit-exact per-op before e2e; smallest slice before scale.2908. Default build byte-identical; all new paths opt-in.291292## References293294| Doc | Content |295|---|---|296| `references/graph-to-plan.md` | drawio convention + parsing, per-rank shape derivation, DSv3 worked op table, classification decision |297| `references/demo-stage.md` | builder anatomy, SHARD_RULES/cache-key/lifetime footguns, v2 wiring specifics |298| `references/debug-gates.md` | the phase-c ladder as checklists, 6 gate-fidelity classes, hang triage |299| `references/box-orchestration.md` | remote-box session playbook (setup/poll split, rsync, retries, safety) — §1-2 site-specific, §3-8 transfer |300| `references/V2_DSV3_DECODE_MASTER_PLAN.md` | the real M0→M5 plan this skill generalizes (archived worked example) |301| `FUSED_KERNEL_DEBUG_METHODOLOGY.md` (repo root) | the original debug order-of-operations |302| `../v2-perf-iteration/SKILL.md` + its `references/loop-agents.md` | the full multi-agent loop (repo-root `WORKFLOW.md` is a superseded stub) |