fix(frank-zealot): 2 x 262,144 over unquantized f16 KV

Frank: "shift frank-zealot to 2 parallels of unquantized kv".

Shape: CTX_SIZE 786432 -> 524288, PARALLEL 3 -> 2, CACHE_TYPE_K/V
q8_0 -> f16. The per-slot window is UNCHANGED at 262,144 (the native
trained window, and models.yml contextWindow), so what the exact cache
buys is fidelity and what it pays is one concurrent conversation.

The POOL is the term that had to move: exact KV bills 32,768 B/token at
this geometry (8 full-attention layers x 4 KV heads x 256 dim, 2 B,
K and V), so the old 786,432 pool asks 24,576 MiB against the 24,123 MiB
the driver leaves addressable. 524,288 positions = 16,384 MiB, projected
~21,200 used / ~2,900 free from the 13:19 boot ledger (only the KV pool
and one recurrent-state cell move).

Also corrects a repo-wide arithmetic error: "f16 would bill 26,112 MiB"
doubled the q8_0 ledger figure INCLUDING its 1/32 scale overhead. q8_0 is
1.0625 B/element, f16 exactly 2.0, so the true ratio is 1.882x. The wall
stands; the number was wrong.

And it corrects a false claim about the drafter: this build DOES expose
--spec-draft-type-k / --spec-draft-type-v (verified against
llama-server --help), so the draft cache is quantizable -- the
exact-KV-plus-MTP exclusion is a measurement gap, not a law, and the
1,088 MiB quantized-draft arm is recorded as unmeasured.

Seam: tests/frank_zealot_unit.bats re-pins the shape contract (2 slots,
524,288 pool, 262,144 per slot) and adds a VRAM fit gate that computes
dtype x pool + the measured non-KV ledger terms against 24,123 MiB with
>=1 GiB of slack -- and proves the gate REFUSES exact KV at the old
pool, so passing means something. 18/18 green.
This commit is contained in:
Frank committed 2026-10-18 21:02:37 -07:00
1 parent 100b62ba22
commit 68afc6dbaf
5 files changed
+217 -141

No files matched your search

+57 -49
View File
@@ -3,33 +3,35 @@
# in the file) as frank-zealot on Dankclaw's RTX 3090 via llama.cpp (PrismML
# vendor build 10777, CUDA sm_86).
#
# 2026-10-18 (Frank): Bonsai-2 27B PQ2_0 → the 9B MTP export at THREE
# 262,144-token conversations (--ctx-size 786432 --parallel 3), q8_0 K + q8_0 V.
# The 9B bills 17,408 B/token against the 27B's 34,816 (8 full-attention layers
# instead of 16), and that halved rate is what funds three NATIVE windows where
# the 27B could only afford two cut to 200,704. Verbosity 4 ships so the
# VRAM-fit forensics (KV layout, buffer sizes, graph capture) land in the
# journal.
# 2026-10-18 (Frank): Bonsai-2 27B PQ2_0 → the 9B MTP export, then the same
# evening TWO 262,144-token conversations (--ctx-size 524288 --parallel 2) over
# an UNQUANTIZED f16 KV cache. The 9B bills 8,192 elements per token per cache
# (8 full-attention layers instead of the 27B's 16), so exact K and V costs
# 32,768 B/token — 16,384.00 MiB at the 524,288 pool, which is what a 24,123 MiB
# addressable card can carry beside the trunk. Verbosity 4 ships so the VRAM-fit
# forensics (KV layout, buffer sizes, graph capture) land in the journal.
#
# Architecture (engine ledger, not the marketing page): qwen35 hybrid, 32
# layers with qwen35.full_attention_interval = 4 ⇒ 8 full-attention + 24 Gated
# DeltaNet, 4 KV heads × 256 dim, native 262,144. The KV pool scales with the 8
# full layers (13,056.00 MiB at the 786,432 pool, ledger-exact); the DeltaNet
# layers cost a fixed recurrent state per SLOT — 452.25 MiB for 3 cells, ~151
# MiB each. The runtime is a hard lock, not a preference: custom GGML type 142
# plus prism.hadamard.* metadata, which only the vendor build registers, and
# MTP beside quantized V needs build ≥ b10776 — so the prebuilt moved 10754 →
# 10777 with the payload. Vision comes from the publisher's Q8_0 projector (the
# BF16 one can crash the server on concurrent images, and this endpoint runs
# three slots), so --mmproj is what gives this endpoint eyes; MMPROJ_FILE="" is
# the documented text-only opt-out.
# full layers (16,384.00 MiB of f16 at the 524,288 pool); the DeltaNet layers
# cost a fixed recurrent state per SLOT — ~50.25 MiB a cell, so 100.50 MiB for
# two. The runtime is a hard lock, not a preference: custom GGML type 142 plus
# prism.hadamard.* metadata, which only the vendor build registers (the b10776
# gate that moved the prebuilt 10754 → 10777 was MTP beside quantized V, which
# exact KV now makes moot — the type-142 lock alone keeps the build pinned).
# Vision comes from the publisher's Q8_0 projector (the BF16 one can crash the
# server on concurrent images, and this endpoint runs two slots), so --mmproj is
# what gives this endpoint eyes; MMPROJ_FILE="" is the documented text-only
# opt-out.
#
# Speculative decoding ships OFF, measured: the head loads and accepts well
# (0.798/0.617 per position, mean length 2.41) but the draft context bills its
# own f16 KV over the WHOLE pool — 4,096 B/position × 786,432 = 3,072 MiB plus
# buffers — and at ubatch 2048 that squeeze HALVES decode (167.2 → 109.2 t/s).
# frank-zealot.env carries the six-arm table and the arm that turns it back on
# (--ubatch-size 1024, decode 213.5 t/s) with its price.
# own f16 KV over the WHOLE pool — 4,096 B/position × 524,288 = 2,048 MiB plus
# buffers — and the trunk already projects 21,234 MiB with exact KV. Exact KV
# and MTP cannot share this card; frank-zealot.env carries the q8_0-era arm table
# and the two doors back to the drafter (one window, or KV back to q8_0 at
# --ubatch-size 1024 for 213.5 t/s).
#
# Sampling: the checkpoint carries the publisher's thinking recipe as GGUF
# metadata (general.sampling.* = temp 1.0 / top_p 0.95 / top_k 20 / min_p 0 /
@@ -56,40 +58,46 @@ fi
: "${ALIAS:=frank-zealot}"
: "${BIND_ADDR:=0.0.0.0}"
: "${LISTEN_PORT:=7771}"
# ctx-size is the POOL llama.cpp divides across slots: 786,432 / 3 = 262,144
# per conversation — every slot at the model's trained window. The harness
# ctx-size is the POOL llama.cpp divides across slots: 524,288 / 2 = 262,144
# per conversation — every slot still at the model's trained window. The harness
# contextWindow MUST quote the PER-SLOT number — a longer prompt is answered
# with a 400, never truncated.
: "${CTX_SIZE:=786432}"
: "${PARALLEL:=3}"
# with a 400, never truncated. Under exact KV the pool cannot stay at 786,432:
# 32,768 B/token × 786,432 = 24,576 MiB, more than the card's whole addressable
# 24,123 MiB before a single weight loads.
: "${CTX_SIZE:=524288}"
: "${PARALLEL:=2}"
# Compute-buffer geometry. Ubatch is a prefill knob (decode never moves).
# 2048 is the measured CUDA optimum (MiMo era, same arch/shape: +4.6 % prefill
# at 8.9k depth, decode flat, 616 MiB). The logical batch is VRAM- and
# throughput-neutral at a fixed ubatch. It ALSO sets the compute-buffer size,
# which is the term that decides whether an MTP draft context fits beside a
# 786,432-position pool: 1024 hands back 1,306 MiB and is the arm that runs the
# drafter at three slots (frank-zealot.env carries the table).
# which is the term that decides whether an MTP draft context fits beside a KV
# pool: 1024 hands back 1,306 MiB and was the arm that ran the drafter at three
# q8_0 windows (frank-zealot.env carries the table).
: "${BATCH_SIZE:=4096}"
: "${UBATCH_SIZE:=2048}"
# Quantized KV: q8_0 K + q8_0 V — the only pair that funds 3 × 262,144 on this
# card. 17 KiB/token at this geometry (8 full-attention layers × 4 KV heads ×
# 256 dim); 13,056.00 MiB at the 786,432 pool, ledger-exact. f16 would bill
# 26,112 MiB against a 24,123 MiB card and dies at cudaMalloc; q4_0 is the
# fallback rung. Explicit either way so the contract is visible in the argv,
# and --flash-attn stays required for quantized V (no true fp8 KV dtype exists
# in this build).
: "${CACHE_TYPE_K:=q8_0}"
: "${CACHE_TYPE_V:=q8_0}"
# Exact KV: f16 K + f16 V — no quantization error anywhere in the attention
# state. 32 KiB/token at this geometry (8 full-attention layers × 4 KV heads ×
# 256 dim × 2 B × 2 caches); 16,384.00 MiB at the 524,288 pool. That is the whole
# reason the slot count is 2: the same dtype at the old 786,432 pool is 24,576
# MiB and dies at cudaMalloc. q8_0 K + q8_0 V (17,408 B/token, 13,056.00 MiB at
# 786,432) is the documented fallback rung and funds three windows; CACHE_TYPE_V
# alone is the halfway door. Explicit either way so the contract is visible in
# the argv, and --flash-attn stays pinned because quantized V — the fallback —
# is illegal without it (no true fp8 KV dtype exists in this build).
: "${CACHE_TYPE_K:=f16}"
: "${CACHE_TYPE_V:=f16}"
# Speculative decoding defaults OFF, measured on this card and shape: the head
# IS in the checkpoint (qwen35.nextn_predict_layers = 1 — MTP is a property of
# the FILE, so the plain PQ2_0 sibling could not run it at any flag value), it
# loads, and it accepts well (mean accepted length 2.41) — but the draft context
# bills its own f16 KV over the WHOLE pool (4,096 B/position, 3,072 MiB here)
# and at ubatch 2048 that squeeze halves decode: 167.2 → 109.2 t/s. There is no
# --spec-draft-cache-type knob in this build to make the draft cheap, and no
# --spec-draft-model either: the draft rides the main model's weights. Card gate:
# quantized V alongside MTP needs fork build >= prism-b10776, which is why
# LLAMA_BIN moved to the 10777 prebuilt; on an older build the pair is illegal.
# bills its own f16 KV over the WHOLE pool (4,096 B/position, 2,048 MiB at the
# 524,288 pool) and at ubatch 2048 that squeeze halves decode: 167.2 → 109.2 t/s
# on the q8_0 3-slot shape. The draft cache dtype IS a knob (--spec-draft-type-k
# / --spec-draft-type-v, both default f16 — verified in this build's --help), so
# an armed drafter can halve its own bill; there is no --spec-draft-model because
# the draft rides the main model's weights. Card gate: quantized V alongside MTP
# needs fork build >= prism-b10776, which is why LLAMA_BIN moved to the 10777
# prebuilt; exact KV removes that gate but NOT the type-142 loader lock.
# SPEC_TYPE=draft-mtp + UBATCH_SIZE=1024 is the documented MTP arm (213.5 t/s);
# SPEC_TYPE=none strips the whole set (flags move together).
: "${SPEC_TYPE:=none}"
@@ -104,7 +112,7 @@ fi
: "${NGL:=99}"
# Log verbosity threshold (llama.cpp -lv). 3 is the engine default (info);
# 4 adds debug detail (KV layout, buffer sizes, graph capture) which is what
# the VRAM-fit forensics need — the q8_0 KV contract and the draft-KV bill are
# the VRAM-fit forensics need — the exact-KV size and the draft-KV bill are
# only provable from this log. Levels above 4 flood the journal.
: "${VERBOSITY:=4}"
# /metrics needs the flag: llama.cpp returns 501 unless the server starts with
@@ -169,11 +177,11 @@ fi
# open after boot; make sure it exists before the server needs it.
nvidia-modprobe -u -c=0 2>/dev/null || true
# Flash attention stays pinned on: it is REQUIRED for quantized V (q8_0),
# and the build carries GGML_CUDA_FA_ALL_QUANTS=ON (since 2026-09-17), so
# the q8_0 KV contract in frank-zealot.env is a real path — without this
# flag or that build option the engine silently falls back and the
# contract becomes a lie.
# Flash attention stays pinned on. Exact f16 KV runs fine with or without it,
# but the documented fallback rung (quantized V) is ILLEGAL without it, and the
# build carries GGML_CUDA_FA_ALL_QUANTS=ON (since 2026-09-17) so that rung is a
# real path — dropping the flag here would leave the retreat route silently
# falling back to something the env file does not describe.
ARGS=(
--model "$MODEL_FILE"
--alias "$ALIAS"