The endpoint page owns its shape: the flags row, the budget equation behind it (25,088 B/token, 14,406.00 MiB of cache + 2,352.00 MiB of draft cache inside 24,123 MiB addressable), the "MTP is ON" section replacing the "OFF by measurement" one, the harness contract at the per-slot 200,704, and the fallback rungs rewritten as deltas FROM the shipped shape. The 2026-10-18 exact-KV boot (KV 16,384.00 / RS 100.50 / compute 1,408.06 + 1,088.07 / mmproj 868.32 charged after the fit check, settled 21,176/2,949) and its contended rate floors move into that era's Eras row with the one-line rollback, so the two pages that carried them collapse to one. Rates for the new shape are deliberately absent - no bench was ordered, and the fit gate, the health gate and the boot ledger are the evidence a swap needs. AGENTS.md follows the same numbers: contextWindow 200704 is the per-slot window and the trio's shape line.
28 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| reference | frank-zealot on Dankclaw — llama.cpp (PrismML fork 10777), Ternary-Bonsai-2-9B PQ2_0-MTP, 3 × 200704, f16 K + q8_0 V, MTP armed | The one frank-zealot reference: the live shape on Dankclaw's RTX 3090 (:7771) exactly as scripts/frank-zealot.env ships it, every era with its rollback path, the deduplicated laws of this card, the wire contract, and the owning files. |
|
2026-10-18 |
frank-zealot — llama.cpp (PrismML) Bonsai-2-9B PQ2_0-MTP, 3 × 200,704, f16 K + q8_0 V, MTP armed
Dankclaw's RTX 3090 endpoint — http://192.168.0.143:7771, wire id frank-zealot, the fleet's compaction hub
(three conversations at 200,704 each, the window the other two endpoints also cap at). One page per
endpoint: eras are rows below, not pages. Siblings: frank-archon,
frank-dragoon. Deploy with ./scripts/deploy.sh dankclaw --service frank-zealot; swap mechanics in
Model Swap and Rollback, sizing math in Llama Cpp Serving Sizing. scripts/frank-zealot.env and
scripts/serve-frank-zealot.sh are the authority for the shape; where any prose disagrees with them, the prose
is the bug.
Current shape
| Item | Value |
|---|---|
| Checkpoint | /home/dank/models/Bonsai2-9B-MTP/Ternary-Bonsai-2-9B-PQ2_0-MTP-Q8_0.gguf — 2,675,410,720 B, LFS sha256 c79fcdfaf6b7bf47… |
| Projector | …/Bonsai2-9B-MTP/Ternary-Bonsai-2-9B-mmproj-Q8_0.gguf — 624,229,664 B, sha256 e0cb6f6988cea323… — Q8_0 is mandatory, not a preference (see Contract) |
| Fetch | scripts/download-frank-zealot-bonsai9.sh [DEST] (--verify-only; -f, byte count, LFS sha256 per file) |
| Runtime | /home/dank/GitPackages/llama-prism-b10777/llama-server — PrismML fork, 0.2.0-dev (build 10777, commit e3de71522); the only loader for this payload |
| Trio | scripts/frank-zealot.service (root, relinked, User=dank, Restart=on-failure, RestartSec=10, LimitMEMLOCK=infinity, TimeoutStopSec=180) · scripts/frank-zealot.env · scripts/serve-frank-zealot.sh |
| Address / alias | BIND_ADDR=0.0.0.0, LISTEN_PORT=7771, ALIAS=frank-zealot (a flag, not a fact) |
| Flags | --ctx-size 602112 --parallel 3 ⇒ 200,704 per slot · --cache-type-k f16 --cache-type-v q8_0 (asymmetric, 14,406.00 MiB) · --flash-attn on · --batch-size 6144 --ubatch-size 1024 · --n-gpu-layers 99 · --jinja --reasoning auto --reasoning-format deepseek · --metrics · --mmproj · --log-verbosity 4 · --presence-penalty 1.0 · --spec-type draft-mtp with --spec-draft-n-max 2 --spec-draft-n-min 0 --spec-draft-p-min 0 |
Why this shape. general.architecture qwen35: 33 blocks (32 trunk + blk.32 = the MTP block),
full_attention_interval 4 ⇒ 8 full-attention + 24 Gated DeltaNet, 4 KV heads × 256 dim, nextn_predict_layers 1
(the head is in the file), trained window 262,144, general.sampling.* 1.0/0.95/20. Only the 8 full layers bill
per token and the DeltaNet layers add ~50 MiB of recurrent state per slot, so the shape is a single budget
equation at 25,088 B/token (f16 K 16,384 + q8_0 V 8,704): 14,406.00 MiB of cache over a 602,112 pool +
2,352.00 MiB of draft cache (blk.32 at its own f16 rate, billed over the WHOLE pool) + ~7.7 GiB of weights,
projector, buffers and states, inside the 24,123 MiB the driver leaves addressable. Exact V (32,768 B/token ⇒
18,816 MiB here) buys neither the third conversation nor the drafter; the fully quantized pair (17,408 B/token)
buys both and costs the keys their precision.
MTP is ON (Frank, 2026-10-19). The drafter was always good — 2026-10-18 measured acceptance 0.798 / 0.617 per
position, mean accepted length 2.41, and the publisher's card says depth 2 works best — and arming it is a
budget decision, not a flag: the draft context is built against the target's pool, so blk.32 bills 4,096
B/position (2,352.00 MiB at 602,112) plus ~0.45 GiB of buffers at this ubatch and its own recurrent cells.
CACHE_TYPE_V=q8_0 (−3,840 MiB against exact V at this pool) and UBATCH_SIZE=1024 (−~1,306 MiB of compute
buffers, and the rung every measured MTP arm here ran on) are what pay for it; UBATCH_SIZE=2048 beside an armed
drafter is the shape that halved decode (167.2 → 109.2 t/s). --spec-draft-type-k/--spec-draft-type-v (default
f16, verified in this build's --help) would cut the draft's bill again and stay at their default; there is no
--spec-draft-model — the draft rides the main model's weights, so a draft file would load the trunk twice.
SPEC_TYPE=none is the rollback and strips the whole set.
Harness contract (~/.omp/agent/models.yml, provider llamacpp (dankclaw-3090), id frank-zealot):
contextWindow: 200704 — the per-slot window, because llama.cpp divides --ctx-size across slots and answers a
longer prompt with a 400, never a truncation — plus maxTokens: 16384, input: [text, image],
compat.reasoningContentField: reasoning_content, compat.reasoningEffortMap (load-bearing: the template takes
only xhigh|medium|low and raises on anything else), extraBody 1.0 / 0.95 / 20 / min_p 0, and the
compactionModel of frank-archon, frank-dragoon and frank-zealot all pointing here.
This shape ships unbenchmarked, by law. Frank ordered the reslice, not a number, so the evidence a swap needs is the seam's fit gate (it prices cache + draft cache + recurrent states against the 24,123 MiB the driver leaves addressable, and refuses the two boots this shape can walk into: exact V with the drafter armed, and the retired dtype pair at the retired pool), the deployer's health gate, and the first verbosity-4 ledger of the new dtype pair — which is recorded on this page because projections drift, and nowhere else. The previous era's exact-KV boot and its rate floors live in that era's row below; those floors were measured while another consumer drove the other slot (56 prompts in three minutes, 96 % GPU-util), the exact condition a bench window exists to exclude.
Fallback rungs, cheapest first — one line of frank-zealot.env each, and each must keep the seam's fit gate green:
| Knob | Effect from the shipped shape |
|---|---|
SPEC_TYPE=none |
the drafter off: hands back 2,352 MiB of draft cache plus its buffers and recurrent cells, at the cost of the ~+28 % decode the 2026-10-18 census measured whenever the card has room |
UBATCH_SIZE=2048 |
+~1,306 MiB of compute buffers and +4.6 % prefill — and the rung that HALVED decode beside an armed drafter (167.2 → 109.2 t/s) |
CTX_SIZE=401408 |
two 200,704 conversations: frees 4,802 MiB of cache — contextWindow MUST follow the per-slot number |
CACHE_TYPE_V=f16 |
exact V: +4,410 MiB at this pool with the drafter armed, which is a cudaMalloc death the seam refuses — legal only once the drafter or a slot is gone |
CACHE_TYPE_K=q8_0 |
the fully quantized pair (17,408 B/token): frees 4,410 MiB and moves the quantization error into the keys |
Eras
| Window | Payload | Runtime | Shape | Replaced because | Rollback |
|---|---|---|---|---|---|
| 2026-10-18 21:06 → 2026-10-19 | the same 9B MTP file and projector | PrismML fork 10777 | 2 × 262,144 (pool 524,288), exact f16 K+V = 16,384.00 MiB, SPEC_TYPE=none, batch 4096 / ubatch 2048; boot ledger KV 16,384.00 / RS 100.50 / compute 1,408.06 + 1,088.07 CUDA_Host / mmproj worst case 868.32 charged after the fit check, settled 21,176 used / 2,949 free, n_ctx_slot = 262144, within 24 MiB of the projection; floors 134.1–141.5 t/s single-stream, 256.6–265.1 aggregate over two, 3,159.5 t/s prefill at 106,282, 71.5 t/s decode at 106k depth (contended — floors, not the shape's rates) |
Frank ordered the third conversation back AND the drafter armed, and exact V funds neither: it bills 18,816 MiB at the pool that pays for the third slot, leaving nothing for the draft's 2,352 | one line each — CTX_SIZE=524288 PARALLEL=2 CACHE_TYPE_V=f16 BATCH_SIZE=4096 UBATCH_SIZE=2048 SPEC_TYPE=none — and redeploy; no payload move |
2026-10-18 13:19 → same evening (the boot 68afc6d replaced) |
the same 9B MTP file and projector | PrismML fork 10777 | 3 × 262,144 (pool 786,432), q8_0 K+V = 13,056 MiB, settled 17,956 / 6,169 MiB; 168.7 t/s decode (three runs 168.4–168.7), ~300 t/s over three streams (102.8 each), 2,877 t/s prefill at 106,418 | Frank ordered unquantized KV, and that pool cannot survive it: 24,576 MiB of f16 cache > 24,123 addressable | one env line — CTX_SIZE=786432 PARALLEL=3 CACHE_TYPE_K/V=q8_0 — and redeploy; no payload move |
| 2026-10-18, 24 min (arm under the unit) | Bonsai2-PTQ1_0/Ternary-Bonsai-2-27B-PTQ1_0.gguf 5,946,648,928 B + hardlinked Q8 mmproj |
PrismML fork 10777 | 2 × 200,704, batch/ubatch 3072/1536 | Frank scratched the 27B plan — ~48 t/s decode vs 76.6 for PQ2_0 on the same weights | /home/dank/models/Bonsai2-PTQ1_0/ + scripts/download-frank-zealot-bonsai2-ptq1.sh |
| 2026-10-17 → 10-18 | Ternary-Bonsai-2-27B PQ2_0 7,206,168,928 B 3907dc16… + Q8_0 mmproj 629,246,976 B |
PrismML fork 10754 (~/GitPackages/llama-prism/) |
2 × 200,704 (pool 401,408), q8_0 K+V = 13,328 MiB, settled 22,664 / 1,461; 76.6 t/s decode, 109.4 aggregate over two streams, 691.7 t/s prefill at 166,027; MTP impossible — no head in the file | the 9B bills half the KV per token (8 full layers, not 16), which funded three slots at the native window and beat it on every rate | /home/dank/models/Bonsai2-PQ2_0/ + the 10754 fork tree, scripts/download-frank-zealot-bonsai2.sh, revert the swap commit |
| 2026-10-07 → 10-17 | Qwen3.5-9B-Uncensored-HauhauCS-Aggressive Q6_K 7,359,259,008 B c0ba7beb… + BF16 mmproj 921,704,448 B |
llama.cpp master 5fc4f3c CUDA sm_86 (~/GitPackages/llama-master/build-cuda/) |
2 × 200,704, exact f16 K+V, MTP off (no nextn tensors) |
the ternary 27B bought a larger model class at the same window | /home/dank/models/Qwen35-9B-HauhauCS-Q6K/ + the master build, scripts/download-frank-zealot.sh |
| 2026-10-07 (same day) | Gemma4-26B-A4B-QAT Q4_K_M 16,796,015,520 B + BF16 mmproj 1,194,827,776 B + unused gemma4-assistant MTP 251,937,728 B |
llama.cpp master CUDA | 1 × 200,704, f16 K + q8_0 V, ubatch 1024, MTP off; 21,868 / 2,257 settled, 139.9 t/s decode (the ~4 B-active MoE is at home here); MTP ON would cost ~1.9 GiB and boot at 319 MiB free | ONE slot serialized compaction; the 9B's lighter weights bought two slots and exact KV | /home/dank/models/Gemma4-26B-A4B/ (ungated — plain curl -fL) |
| 2026-10-03 → 10-05 | MiMo-V2.6-Distill-Qwen-9B Q6_K 7,793,710,624 B ef96d05a… + f16 mmproj 918,166,048 B |
llama.cpp master CUDA | 2 × 200,704, f16 K+V, batch 4096 / ubatch 2048; 21,846 / 2,279 settled, 94.44 t/s decode | Frank ordered the uncensored 27B with MTP drafted | /home/dank/models/MiMo-Q6K/ |
2026-10-05 (committed 77decb5→380aafa, never deployed) |
Ornith-1.5-9B Q8_0 | llama.cpp master CUDA | 1 × 262,144, f16 K+V | Swift cut over the same evening while this deploy sat blocked at the whole-tree docs gate | /home/dank/models/Ornith-Q8/; revert to 380aafa's tree |
| 2026-10-05 → 10-07 | Swift-1.5-27B-Uncensored RCO-IQ3_XXS-mtp 10,442,827,392 B e13d3e74… + publisher mmproj-BF16.gguf 931,145,888 B |
llama.cpp master CUDA | 2 × 114,688, q8_0 K+V, draft-mtp depth 3, ubatch 2048; 23,120 / 1,005 settled (489 MiB at the 2 × 131,072 shape — the tightest fit ever here), 63.3 t/s at the recipe temp, 72.9 at temp 0, 48.0 with the drafter off |
the 9B Q6_K rung returned the 200k window and exact KV | /home/dank/models/Swift15-UncIQ3XXS/; the IQ3_S-mtp rung at /home/dank/models/Swift15-IQ3S/; commits da36fa3 → f2575a1 → d8da7a9 |
| 2026-10-02 → 10-03 | MiMo Q5_K_M 6,876,124,704 B 04cf46f2… + the same f16 mmproj (hardlinked) |
llama.cpp master CUDA | 2 × 200,704, f16 K+V, batch 2048 / ubatch 1024; 20,530 used / 4,046 apparent (true free 3,571), 104.84 t/s decode |
the ~3.5 GiB it left free bought the Q6_K rung | /home/dank/models/MiMo-Q5KM/ |
| 2026-10-01 → 10-02 | MiMo Q6_K (same file as above) | llama.cpp master CUDA | 2 × 262,144, f16 K + q8_0 V | one night: the Q5 rung bought the 2–3 GiB headroom band back | /home/dank/models/MiMo-Q6K/ (same dir) |
| 2026-10-01 (hours) | MiMo-V2.6 INT8-W8A16-AutoRound, 8 shards 12,891,718,440 B | SGLang in venv ~/GitPackages/sglang-cu128 (torch cu130 + an in-venv CUDA 13.0 nvcc) |
2 × 262,144 over a pinned 606,208 pool, fp8_e4m3 KV, NEXTN off; 83.9 t/s decode, ~2,050–3,370 t/s eager prefill, ~60 s boot warm |
llama.cpp was the only runtime exposing asymmetric per-tensor KV | payload purged — re-fetch old/download-frank-zealot-sglang-int8.sh; the venv is still on disk |
| 2026-09-17 → 10-01 | Gemma4-12B-QAT-Uncensored Q4_K_M 6.87 GiB + BF16 mmproj (it carried an audio encoder) + mtp-gemma-4-12B-it.gguf sidecar 0.24 GiB |
llama.cpp master 37b53fd CUDA with -DGGML_CUDA_FA_ALL_QUANTS=ON (~/GitPackages/llama.cpp-mainline/build-cuda/) |
4 × 262,144, q8_0 K+V, draft-mtp,ngram-mod depth 3 / poll 50; idle 22,346–23,300 MiB, ~965 t/s prefill and 257–302 t/s decode at 254k depth; each extra full-context slot costs 3,450 MiB so 4 is the max |
the MiMo GGUF path (qwen35 hybrid, asymmetric KV) took the card | re-fetch HauhauCS/Gemma4-12B-QAT-Uncensored-HauhauCS-Balanced; era trio in git show 374041c:scripts/frank-small.service / .env / serve-frank-small.sh |
| 2026-09-19 (same-day revert) | gemma-4-12B-it-qat-w4a16-ct 10,264,229,896 B + bf16 assistant 845,719,296 B |
vLLM dev image localhost/vllm/vllm-openai:frank-small (8dad46d79c46, still in rootless storage), rootless Quadlet |
262,144 window, bf16 KV pool 289,647 tokens, 2 concurrent sessions (the 3rd queues), image + audio; 1,293 t/s prefill @67k falling to 608 @213k, ~13.6 t/s decode @213k depth, MTP acceptance 2.80–3.56, boot 135 s | reverted to llama.cpp the same day | both payloads purged; git show 374041c^:dankclaw/frank-small/Dockerfile and …:dankclaw/frank-small/quadlet/frank-small.container |
| 2026-09-16 → 09-17 | ISTA-DASLab Qwen3.8-27B-GSQ-RCO IQ3_S + BF16 projector, in-file MTP drafted | mainline llama.cpp | single-slot 3090 shape | superseded by the Gemma4-12B payload | re-download from ISTA-DASLab — no payload and no fetch script survive |
2026-09-02 → 09-15 (Dankserver, :7770, the card's previous host) |
batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8 ~35 GB (before it official Qwen3.6-35B-A3B-FP8) |
FreeToken v0.1.2 (ft), venv ~/freetoken/.venv |
MoE cache 2,048 slots + KV 453,005 tokens + 24 mamba-state slots; ~30 t/s single-stream decode, ~87 t/s at batch 4, ~1,130 t/s prefill at 4k | the 3090 left Dankserver and frank-medium-rocmfpx took the endpoint and port |
host units ~/.AGENTTRASH/20260915-frank-zealot-retire/host-units/, repo trio in scripts/.AGENTTRASH/ |
| ~2026-08 (Dankserver 3090, pre-FreeToken) | Qwen3.6-35B-A3B Q6_K_P, then Tiel-Coder-35B-A3B UD-Q6_K_XL, with an Ornith Q6_K rung | llama.cpp 555881ebc (b10121) CUDA |
--n-cpu-moe 38 deployed (36 recommended), batch 4096 / ubatch 2048, 700,416-token f16 K+V pool (800,768 cells did not fit); ~45.5 t/s decode and 1,188 t/s prefill at ncmoe 35 |
FreeToken kept experts in host RAM instead of CPU-offloading layers | re-download; nothing from this rung survives on disk |
Laws learned here
- Addressable ≠ advertised. The card is 24,576 MiB but leaves 24,123 MiB: quote
nvidia-smi'sfreefield, nevertotal − used— the driver's reservation is the difference. - Exact KV and a 786,432 pool cannot coexist here: 32,768 B/token ⇒ 24,576 MiB before a single weight loads (the retired "26,112 MiB" note doubled q8_0's scale overhead); the 27B analogue died at 25,088 MiB with
cudaMalloc failed: out of memory. Halving the pool funds exact KV; the per-slot window stops at the trained 262,144 (no YaRN here), so a third conversation is a KV-dtype decision, never more context. The wall's own figures:cudaMallocfailed on a 25,088.00 MiB KV request when the engine's fit projection asked for 33,198 MiB against 23,558 MiB free. It booted f16 at all because the arm env's inventedKV_CACHE_TYPEwas swallowed by the serve script's:=f16default — so a failed window became the measurement. - Exact KV reads 1.882× the bytes per generated token, not 2× (32,768 vs 17,408 B/token, 2026-10-18): a decode drop of that order is EXPECTED and must be measured, while prefill should hold — and this service can afford the dtype precisely because its load is the compaction hub's ~170k-token prefill, which is weight-bandwidth bound and never re-reads the cache per generated token. The dtype is paid in decode and concurrency.
- Never
--fitwithparallel > 1— it maximizes the total pool and shrinks each slot: setCTX_SIZEexplicitly and keep it divisible byPARALLEL(the seam enforces it). - KV rate law.
full_layers × 4 KV heads × 256 dim= 8,192 elements per token per cache on this arch (the engine printsn_embd_k_gqa = n_embd_v_gqa = 1024), ×2 B (f16), ×1.0625 (q8_0 — 32 codes plus one 2-byte scale per 32-block), ×0.625 (q4_0): 32,768 / 17,408 / 10,240 B/token on this 8-full-layer 9B, and 34,816 for a 16-full-layer 27B at q8_0. Everything else bills separately: DeltaNet recurrent state per slot (150.75 MiB for 3 cells, and an armed depth-2 drafter triples it to 452.25), compute buffers at graph capture, the mmproj after the fit. On gemma4-class hybridsattention_k_eq_vdoes not shrink the allocation — the cache reserves the K/V pair twice, 6.125 B/elem at f16 K + q8_0 V. --flash-attn onis pinned, not decorative: a quantized V exists only on the FA path and the engine falls back silently without it. llama.cpp has no true fp8 KV dtype — q8_0 is the 8-bit class (1.0625 B/elem, ~8.5 effective bits).GGML_CUDA_FA_ALL_QUANTSis vestigial and build-specific: the PrismML fork carries it ON (since 2026-09-17) while the master build had it OFF and still dispatched Q4/Q5 KV unconditionally (ggml-cuda/fattn.cuhas no guard), so quantized KV never required it.- Prices come from boots, not formulas, and an arm belongs to the payload it was measured on: 3 × 180,224 +
q8_0 V fits with Q5_K_M (21,684 used / 2,441 free) and does not fit with Q6_K inside the 2–3 GiB band. The
mmproj worst case (~870 MiB) is printed before fitting but never billed by the engine's own fit check. Only
tests/frank_zealot_unit.bats's fit gate can see a boot that would die atcudaMalloc, so every retune keeps it green — and the first verbosity-4 ledger plus settlednvidia-smiof a new dtype belongs on this page, because projections drift. The two boots that priced non-KV: 2 × 262,144 without the projector — 20,190 used, KV 12,800 ⇒ non-KV 7,390 MiB; 3 × 196,608 with it — 22,972 used, KV 14,113 ⇒ non-KV 8,859 MiB. The difference prices the vision tower at ~1.4 GiB for a 918 MB file, because the encoder's activation and compute buffers ride with it. The first 3-slot deploy (3 × 196,608) booted healthy and left only 1,153 MiB free — that is how the 2–3 GiB band got violated in practice, and why the seam prices non-KV at the measured 9 GiB and refuses that shape. - Ubatch is a prefill knob. Decode never moves with it and the logical
--batch-sizeis neutral; prefill climbs monotonically to 2048 on this CUDA card (+4.6 % at 8.9k depth; 710 → 1,188 t/s), a prompt shorter than the ubatch cannot see the knob at all (the control row), and a verdict never crosses backends — the 2× R9700 split peaks at 512. Each rung costs ~0.6–0.75 GiB of compute buffers; 2048 is the ceiling for a 27B-on-3090 shape. - A quant rung is paid in decode: Q5_K_M → Q6_K is +875 MiB of weights and −10 % rate on this bandwidth-bound card, and the byte-bandwidth law predicts a rung's rate within 1 %.
- Speculation pays only with room on the card. The 2026-10-18 arm census (all q8_0 K+V at the 786,432 pool): 3 × 262,144 spec-OFF ubatch 2048 → 17,876 / 6,249 free, 167.2 t/s; spec-ON ubatch 2048 → 22,706 / 1,419, 109.2 t/s; spec-ON ubatch 1024 → 21,400 / 2,725, 213.5 t/s; 2 × 262,144 spec-ON → 213.2; 1 × 262,144 spec-ON → 214.2. That is +28 % decode whenever the card has room, and the doors back are one window per conversation, or q8_0 KV with ubatch 1024. The draft's own bill at that shape was 3,072.00 MiB of KV plus ~1,758 MiB of buffers.
- Draft KV is built against the target's whole pool (~2.4 GiB measured on the 27B Swift boot, not the ~0.4 GiB a proposal-depth estimate suggests). Spec flags move as a SET —
SPEC_TYPE=nonestrips all of them and half a set has segfaulted at load. Two context-backed drafters cannot share a process, sodraft-mtp,ngram-modis the only legal pair, and on a qwen35 hybrid ngram-mod disables recurrent-state rollback so rejected drafts degrade silently. - Acceptance alone never justifies speculation: 2026-08-25 measured 26.8–35.2 t/s drafting against 53.7 no-spec.
- A checkpoint declaring
*_num_hidden_layersMTP while carrying zeromtp.*/nextn.*tensors boots a 4.24 GiB ghost drafter ataccept rate: 0.00— read the safetensors index, not the config. - MTP is a property of the file: the plain PQ2_0 sibling could not draft at any flag value; only the
-MTPexport carriesblk.N.nextn.*. - The format is the runtime lock. PQ2_0 is
general.file_type 141over 202 tensors of custom GGML type 142 plusprism.hadamard.*metadata: stock llama.cpp refuses the type, and a loader ignoring the Hadamard transform would dequant wrong, silently (same lock class as ROCmFPX). Build ≥ b10776 is additionally the floor that pairs MTP with a quantized V cache. - Check arch support in the source tree:
grep -con the packed binary returns 0 for every arch, including the one it serves. - Base alignment. Bonsai-2 is the censored base lineage.
/home/dank/models/Bonsai2-CRACK/matches the 27B geometry (a one-lineMODEL_FILEswap there, identical tensor census); no dealigned 9B exists, so for this payload the refusal escape hatch is a fetch, not a revert. - A stale bench drop-in hijacks the production boot and no health check sees it. An
Environment=FRANK_ZEALOT_ENV_FILE=/tmp/<arm>.envinfrank-zealot.service.d/booted a 27B PTQ1_0 payload while/healthanswered 200,/v1/modelsechoed the alias flag and the e2e gate passed 33/33 — none of them read the payload. - After any bench window:
systemctl show -p DropInPaths→tr '\0' ' ' </proc/$pid/cmdline→ ledger, in that order; drop-ins retire to~/.AGENTTRASH/<date>-<topic>/, and payload decisions land on this page the moment they are made, or an approved arm becomes indistinguishable from a rogue one a day later. - An arm env must use the serve script's own variable names (
CACHE_TYPE_K/CACHE_TYPE_V,BIND_ADDR,NGL): an inventedKV_CACHE_TYPEis swallowed by: "${CACHE_TYPE_K:=f16}"and the arm boots f16 — an OOM that reads like a model fault. - Stop, shebang, GPU node. llama.cpp rides out the default stop timeout (
TimeoutStopSec=180is on the unit for that reason) and a hand-booted arm keeps answering 7771 behind afailedunit — kill it by PID, neverpkill -f llama-server. serve-frank-zealot.shis a directExecStart, so a missing shebang is a203/EXECboot loop atMem peak: 1.9Mwith the GPU untouched:head -1is a deploy check.No CUDA GPUs are available⇒nvidia-modprobe -u -c=0; KV spilled into unified memory halves decode silently, so re-readnvidia-smiafter any shape change.
Contract
/health→{"status":"ok"};/propsreportsn_ctxandpresence_penalty;/slotsshows occupancy; a fourth concurrent conversation waits for a slot — the slot count is the concurrency contract./metricsanswers 200 with 15llamacpp:*families only with--metrics; without it llama.cpp answers 501, which Prometheus reads as DOWN while/healthstays 200. The scrape target ishost.containers.internal:7771/metricsand the oldest retained sample ofup{job="frank-zealot"}(2026-10-11) is already 0 — this target was never successfully scraped, across every payload era.METRICS=0is the documented opt-out and re-breaks it; the counters cost nothing on the request path.- Reasoning arrives in
reasoning_content(--reasoning-format deepseek) and counts againstmax_tokens: a short budget yields emptycontentwithfinish_reason: "length", which reads as a broken model, not a mid-thought one. The slot prefix cache is live (cached_tokensinusage). - A client that sends no sampler is not greedy — the engine applies the payload's own
general.sampling.*(1.0 / 0.95 / 20).presence_penaltyis the one recipe value with no GGUF metadata key, so it must reach argv; the serve script uses${PRESENCE_PENALTY=1.0}, deliberately not:=, because""is the documented opt-out. - Vision: only the OpenAI
image_urlcontent part reaches the model — the legacy top-levelimagesfield bumpsusage.prompt_tokenswhile the model invents an answer. Probe with a ≥ 256 px solid color (a postage stamp answers "video") and budget ≥ 512 tokens; a 512 px image bills ~280 prompt tokens. - Q8_0 mmproj, not BF16: the publisher warns the BF16 tower "can crash llama-server when several image requests run at once", which is exactly the
--parallel 3shape.MMPROJ_FILE=(explicitly empty) is the text-only opt-out and returns ~1.4 GiB; a path at a missing file is a boot refusal, never silent blindness. - Tools: native via
--jinja;finish_reason: tool_callswith valid JSON arguments. - Two non-faults: a
400naming 200,704 is one conversation outgrowing its slot, not pool exhaustion; and the raw/completionpath is a dead instrument on this fork build — a greedyignore_eosrun answers 500 "The model produced output that does not match the expected Content-only format", because build 10777 guards the raw path the moment reasoning markup leaks (older builds only loggedfailed to parse reasoning contentand answered anyway). The honest per-request instrument here is/v1/chat/completions, whose non-stream response carries the sametimingsobject (prompt_n,prompt_per_second,predicted_n,predicted_per_second). KeepVERBOSITY=4— 3 is the engine default and cannot prove the KV or draft sizes, while levels above 4 flood the journal. - llama.cpp does not validate the requested model id: it answers and echoes the served
ALIAS, so a rename breaks id-keyed consumers (the OpenWebUImodelrow, itsaccess_grant,openai.api_configs) and nothing server-side. Alias history:frank-small→frank-secondary(2026-10-06) →frank-zealot(7c77326, 2026-10-09); the service and unit took the name 2026-10-10 (55f87fc). - The first request after a boot is a warmup artifact (37 t/s class) and is never a measurement; never time a wall-clock aggregate on a generation that stops on its own (use
ignore_eos).
Files
scripts/frank-zealot.env— the authority for the values above and nothing else: as of 2026-10-18 it carries the knobs plus the one-line reason a reader editing that line cannot recover here. The arm table, the reference boot ledger and the KV derivation all live on this page now; the header used to hold them, and two of its rung figures were wrong (CACHE_TYPE_V=q8_0andCTX_SIZE=401408both free 3,840 MiB at the 524,288 pool, not 8,192 and not ~6.7 GiB — the Fallback rungs table above is the corrected statement).scripts/serve-frank-zealot.sh— the exec line and its rationale comments; honorsFRANK_ZEALOT_ENV_FILEfor arm boots; exits 1 naming a missing binary, GGUF or projector rather than half-loading (a restart policy would turn an unfinished download into a crash loop that reads like a runtime fault).scripts/frank-zealot.service— root unit, relinked into/etc/systemd/system/.scripts/download-frank-zealot-bonsai9.sh(active) ·…-bonsai2.sh·…-bonsai2-ptq1.sh·scripts/download-frank-zealot.sh(master-era GGUFs) ·old/download-frank-zealot-sglang-int8.sh(SGLang).tests/frank_zealot_unit.bats— stub-argv seam plus the VRAM fit gate.scripts/deploy-remote.sh—deploy_llm_zealot(payload-path gates, MainPID-hardened health); see deployment.shared/prometheus/prometheus.yml,shared/prometheus/rules/llm-fleet.yml,shared/grafana/provisioning/dashboards/llm-fleet.json— the scrape, the alert, the dashboard.- Live state, not repo files: the OpenWebUI picker row (back up
webui.dbbefore re-keying) and~/.omp/agent/models.yml.