← all models

north-mini

Kept / trial  active in llama-swap.yaml · aliases: north-mini-code-1.0-cohere2moe-488k

Grill run history

RunScoretok/stepR5Log
20260728-08535022/23174.1results-north-mini-20260728-085350.log

Memory notes

north-mini-code (north-mini-code.md)

north-mini — CohereLabs North-Mini-Code-1.0, added 2026-07-28

unsloth/North-Mini-Code-1.0-GGUF:UD-Q4_K_XL, 17.93 GiB. Arch cohere2moe

(Cohere2MoeForCausalLM) — supported in b10133 (LLM_ARCH_COHERE2MOE +

src/models/cohere2moe.cpp). Real sparse MoE: 128 experts, 8/tok. 49 layers,

32 q-heads / 4 kv-heads, head_dim 128, vocab 262144, rope_theta 50000.

Port 9115. 79-94 t/s decode, ~356-616 t/s prompt.

Why it earns a slot: 488k context, verified

layer_types interleaves 1 full-attention layer per 3 sliding

(sliding_window: 4096), so only 13 of 49 layers grow with context; the

other 36 are capped at 4096 tokens. With 4 kv-heads:

``

KV/token/layer = 4 x 128 x 2 = 1024 elements

q8_0 @ 500k = 13 x 1024 x 1.0625 x 500000 = 6.59 GiB

+ 36 sliding layers, capped = 0.15 GiB -> ~6.74 GiB

`

So 17.93 GiB weights + ~6.7 GiB KV fits the 31 GiB pool with room — the **full

native window at q8_0**, not the usual q4 compromise. First time on this box that

maximum context and quality-first KV were not in tension (cf.

[[vram-spend-priority]]).

NEEDLE 3/3 PASS at 440,181 tokens (depths 0.1/0.5/0.9, answer in content,

~710s each) — bench/needle-north-mini-20260728.log. ~1.7x the previous best

verified recall here (262144 on [[kimi-distill]]).

Why it is NOT the agentic pick

> READ THE 2026-07-28 UPDATE AT THE BOTTOM BEFORE QUOTING ANY NUMBER HERE.

> This section was written from a single run and overstated the case. Corrected

> summary: 22/23 on the 23-task suite, R5 4-6/6 across 6 runs (mean ~4.8),

> with interrupt_replan failing ~5/6 on runaway verbosity. Loops occur in ~3/6

> runs on varying tasks — not the one fixed search_navigate loop claimed below.

First run measured R5 4/6 with a loop on search_navigate (worst-repeat 4,

verified via recompute_r5_redundancy.py, which also cleared 3 false positives,

22.5% -> 15.0%). Failures were runaway verbosity, not confusion:

interrupt_replan burned 16,682 tokens, expr_eval the full 16,000 cap.

The direction holds — the 23-task score says top-tier and round 5 disagrees, the

pattern MODEL-RANKING's headline calls out for coder. **Route long-document

reading to north-mini; route agentic work to [[pocket-35b]] / [[kimi-distill]]**

(both 22/23 + clean 6/6 at ~102 t/s).

Heavy reasoner: 659 tok / 2438 chars of thought for a trivial task, and at

max_tokens=700 it hits the cap MID-THINK and returns an EMPTY content with

finish=length. Short-budget clients will look broken.

Serving gotchas

  • A clean LOAD is not a clean config. First attempt (45,55, -ub 512)

loaded but printed compute buffer allocation failed, retrying without

pipeline parallelism and left 180MiB free on CUDA1. Fixes, both needed:

-ub 512 -> 256 (vocab 262144 makes the logit buffer ~536MB at ub 512 vs

~268MB at ub 256 — the dominant term) and split 45,55 -> 50,50. Then clean:

1060/1104 MiB free, static across generation.

  • Tool paths all clean — single-turn 200, multi-turn non-first system 200 (no

[[jinja-system-guard-tool-parser]] guard, unlike the Qwen-family templates),

prose-with-tools 200 (not [[llama-cpp-peg-native-tool-parser-500]]). No

--chat-template-file needed.

  • Use unsloth, NOT byteshape/North-Mini-Code-1.0-GGUF — that repo ships

three files all named IQ4_XS at 4.14/4.27/5.64 bpw. IQ4_XS is a fixed

~4.25bpw format, so the names do not describe the contents and an -hf

repo:IQ4_XS selector is ambiguous across three matches.

needle.py harness gotchas (cost a false alarm here)

The first needle run died with KeyError: 'choices', which reads like a model

failure and was not:

1. The ~13 tok/line constant is tokenizer-specific. This tokenizer gives

16.00 tok/line, so needle.py 450000 built 34,615 lines = ~554k actual

tokens and overflowed the 500k window. Measure first, then

TARGET = (desired / measured_tok_per_line) * 13.

2. /tokenize 404s through llama-swap (8090) — only OpenAI routes are

proxied. tok_count() swallows the exception and returns -1, silently

disabling the size check that would have caught it. Point NEEDLE_BASE at

the backend port.

Both recorded as MODEL-RANKING caveat 13.

2026-07-28 UPDATE — R5 re-measured 6x; the original verdict was overstated

The "R5 4/6 with a genuine loop on search_navigate" above came from one run.

Six runs of identical weights (3 solo, 1 x2 single-stream, 2 x2 concurrent):

4/6, 6/6, 5/6, 5/6, 5/6, 4/6 — mean ~4.8/6, spread 4-6, loops in 3 of 6 runs

landing on *different* tasks.

What actually reproduces: interrupt_replan fails ~5 of 6 runs, always by

runaway verbosity (16,682 / 3,920 / 8,445 / 8,679 / 3,805 output tokens).

search_navigate fails 2/6. So the durable signal is *which task fails

repeatedly*, not the aggregate or which run tripped the loop detector.

Conclusion unchanged in direction (still not the agentic pick — [[pocket-35b]] is

22/23 with a clean 6/6 at 102 t/s) but the reason is verbosity-driven task

failure, not a specific loop. See MODEL-RANKING caveat 14: **a single R5 number

is a sample, not a measurement** — which also qualifies every other single-run

R5 recorded that day.

north-mini-x2 (2-slot, 250112 tok/slot, port 9116): loads clean with MORE

headroom than solo (1468/1512 MiB free — halving per-slot ctx shrinks compute

buffers), 1.38x aggregate throughput on straight generation. Grill 21/23, R5 6/6

single-stream; concurrent R5 5/6 + 4/6 — inside the solo range, so **no

concurrency-specific failure mode**. Scope it to parallel long-context READING;

send concurrent agentic work to [[kimi-distill-x2]].

2026-08-01 UPDATE — 3 more R5 repeats (now 9 runs); x2 entry RESTORED

bench/metric_sweep.py north-mini --rounds 5 --repeats 3

bench/metric-sweep-20260801-211211.jsonl. Base tier 4/6, 4/6, 5/6; full

base+hard mean 7.7/10, 1.3 loops per repeat, 3 flaky tasks (interrupt_replan,

registry_cascade, selective_rename).

Running tally is now 9 runs: 4,6,5,5,5,4,4,4,5 → mean ~4.7/6. The per-task

signal SHIFTED and is worth noting: search_navigate failed 3/3 here (was

2/6 before → 5/9 overall), twice with stop=loop at 5 and 6 redundant

calls; interrupt_replan failed 2/3 (→ 7/9 overall), once looping and once

running away to 8780 tokens. So BOTH tasks are unreliable, and the earlier

reading that search_navigate was the milder of the two no longer holds.

Verdict unchanged and now well-supported at n=9: not the agentic pick. The

6 tasks that pass in every repeat do so cleanly — 38 steps, 5208 tokens

(4552-5847), 0.0 redundant, 67s — so when it works it is lean; it is the

tail that disqualifies it.

PROCESS NOTE (cost real time this session): I proposed this re-grill arguing

the dismissal "rested on n=1 that a later run contradicted." That was WRONG —

this file already documented 6 runs. I had read the north-mini-x4 yaml comment

instead of this memory file. CLAUDE.md says read the fact file before touching

the area it covers; doing so would have reframed the work as "add repeats to an

existing 6-run tally", not "overturn a single-run verdict".

north-mini-x2 was RESTORED to llama-swap.yaml on 2026-08-01 (it had been

replaced by an unvalidated north-mini-x4` in b9bccfe1). Re-load-tested: cold

load 85.6s from ssd, idle 1454/1500 MiB free, **static 1454/1498 under two

concurrent generations**, both slots finish=stop — consistent with the 1468/1512

recorded above. Both x2 and x4 now coexist as a menu choice.

llama-swap.yaml entry

  "north-mini":
    aliases: [north-mini-code-1.0-cohere2moe-488k]
    # unsloth/North-Mini-Code-1.0-GGUF:UD-Q4_K_XL (17.93GiB) — TRIAL 2026-07-28.
    # CohereLabs North-Mini-Code-1.0. ARCH: cohere2moe (Cohere2MoeForCausalLM) —
    # SUPPORTED in this build: LLM_ARCH_COHERE2MOE is registered in
    # llama.cpp/src/llama-arch.cpp with a dedicated src/models/cohere2moe.cpp.
    # Real sparse MoE: 128 experts, 8 per token. 49 layers, 32 q-heads / 4 kv-heads,
    # head_dim 128, vocab 262144, rope_theta 50000.
    #
    # THE POINT OF THIS ENTRY IS THE CONTEXT. max_position_embeddings is 500000 and
    # the architecture actually pays for it: layer_types interleaves 1 full_attention
    # layer per 3 sliding_attention layers — only **13 of 49** layers grow with
    # context; the other 36 are capped at sliding_window=4096. With 4 kv-heads that
    # makes long context extraordinarily cheap:
    #   KV/token/layer = 4 x 128 x 2 = 1024 elements
    #   q8_0 @ 500k = 13 layers x 1024 x 1.0625 x 500000  = 6.59GiB
    #              + 36 sliding layers capped at 4096      = 0.15GiB  -> ~6.74GiB
    # So 17.93GiB weights + ~6.74GiB KV = ~24.7GiB, leaving ~6GiB in the 31GiB pool.
    # That is why this runs the FULL native context at **q8_0** KV rather than
    # dropping to q4 — quality-first per [[vram-spend-priority]], for once affordable
    # at 488k. Longest context on the box by ~2x (previous best 262144).
    #
    # VERIFY AT LOAD: the numbers above assume llama.cpp applies its SWA KV
    # optimisation to this arch. If it instead allocates full KV for all 49 layers,
    # that is 49 x 1024 x 1.0625 x 500000 = ~26.6GiB and it will NOT fit. Check
    # measured free VRAM against the ~6.7GiB prediction; if it is ~26GiB, SWA is not
    # being applied — drop -c to 262144 rather than fighting it.
    #
    # MEASURED 2026-07-28 — SWA IS applied, the full 500000 ctx loads at q8_0 KV.
    # But the FIRST attempt (45,55 / -b 2048 -ub 512) was a DEGRADED load: it printed
    # "compute buffer allocation failed, retrying without pipeline parallelism" and
    # left only 180MiB free on CUDA1 vs 2890MiB on CUDA0. Two fixes, both needed:
    #   * -ub 512 -> 256. vocab is 262144, so the logit buffer is vocab x ub x 4B =
    #     ~536MB at ub 512 vs ~268MB at ub 256 — the single biggest compute-buffer term.
    #   * split 45,55 -> 50,50 to correct the starved CUDA1.
    # Result: CLEAN load (no pipeline-parallelism warning), 1060/1104 MiB free,
    # static across generation. 94.1 t/s decode, ~356 t/s prompt.
    # TOOLS: all three probes clean — single-turn 200, MULTI-turn non-first system
    # 200 (no [[jinja-system-guard-tool-parser]] guard, unlike the Qwen-family
    # templates), and prose-with-tools 200 (not affected by
    # [[llama-cpp-peg-native-tool-parser-500]]). No --chat-template-file needed.
    # HEAVY REASONER: budget max_tokens generously. Answering the merge_intervals
    # task took 659 completion tokens with 2438 chars of reasoning; at max_tokens=700
    # it hit the cap MID-THINK and returned an EMPTY `content` with finish=length.
    #
    # SOURCE NOTE: use unsloth, NOT byteshape/North-Mini-Code-1.0-GGUF — that repo
    # ships three files all named "IQ4_XS" at 4.14/4.27/5.64 bpw (IQ4_XS is a fixed
    # ~4.25bpw format, so 5.64 is mislabelled), which also makes an -hf `:IQ4_XS`
    # selector ambiguous.
    # STORAGE (2026-08-03): switched from `-hf` to the NVMe copy by absolute path,
    # matching what north-mini-x2 and north-mini-x8 already did. The `-hf` form
    # resolved through ~/.cache/huggingface/hub, whose repo dir is a SYMLINK to
    # /mnt/ssk500 (the SSK ssd) — so the solo entry was the only one of the three
    # still cold-loading 17.93GiB at the ssd's 0.23 GiB/s (85.6s measured) while
    # its siblings read the identical file from nvme at 1.08 GiB/s (16.6-16.9s
    # measured). Same weights: both copies verified byte-identical 2026-08-03
    # (equal size, head-512MB `cmp`, tail-512MB sha256 both 6de8554fb30827c1).
    # Bonus: -m sidesteps HF resolution entirely, so this entry can no longer hit
    # the offline dangling refs/main death in [[llama-cpp-offline-hf-refs]].
    # The ssd blob is left in place (18GB) — deleting it is a separate decision;
    # nothing references it once this entry is repointed.
    # STORAGE TIER: moved off the NVMe to /mnt/ssk500 on 2026-08-08. This is a
    # spare, not a driver, so it pays the slow-disk penalty: measured 380 MB/s
    # on ssk500 vs 2.5 GB/s on the NVMe, i.e. ~+60-100s on a cold load (a 16 GB
    # vLLM model took 196s from ssk500 vs 98-136s from the NVMe).
    # NVMe RESIDENCY as of 2026-08-12: `coder-agentic` + `fable-fusion` (both
    # promoted back today). muse-glimmer was moved OFF to ssk500 deliberately.
    cmd: |
      /usr/bin/env
      CUDA_DEVICE_ORDER=PCI_BUS_ID
      ${llama_bin}
      -m /mnt/ssk500/gguf/North-Mini-Code-1.0-UD-Q4_K_XL.gguf
      --alias north-mini
      --jinja -ngl 99 -c 500000 -fa on
      --tensor-split 50,50
      -b 1024 -ub 256
      --temp 0.2 --top-p 0.9 --top-k 40
      --cache-type-k q8_0 --cache-type-v q8_0
      --host 127.0.0.1 --port 9117 --parallel 1
    proxy: http://127.0.0.1:9117