Frank's call 2026-10-01: MAXLEN 262144 x SEQS 3 = 786,432 tokens of contract. Measured fp8 KV costs 7,698 B/token (4-slot boot 8,311,013,376 B -> 1,079,582 tokens; 5-slot boot 10,388,766,720 B -> 1,350,182 tokens), so the pool floor for the contract is 6.054e9 B. Pinned at 6,100,000,000 (~792k tokens, ~5.9k margin) so the remaining ~2.2 GiB versus the 4-slot shape goes to the expert ARENA - the fork sizes its decode-critical expert cache from the remainder after weights, pool and workspace. MNBT 2048 (Frank): the arena sweep measured 6,499 slots at every rung <= 4096, so the larger batch costs the arena nothing. Seam retargeted (3 seqs / 6.1e9 / MNBT 2048); docs + AGENTS row + log updated, including the closed DCP investigation.
293 lines
15 KiB
Bash
Executable File
293 lines
15 KiB
Bash
Executable File
#!/usr/bin/env bats
|
|
# Seam: frank-primary — the Dankserver LLM endpoint on :7770.
|
|
#
|
|
# This file asserts the tcclaviger RDNA4 vLLM ROOT-UNIT shape (the
|
|
# 2026-10-01 BF16 cutover, the overnight redo campaign's verdict): the serve
|
|
# script drives `podman run` DIRECTLY (the image entrypoint execs
|
|
# `vllm serve`), with every engine flag qualified by boot probe and carried
|
|
# in the repo env file. The seam pins what the flags alone do not say: the
|
|
# KV qualification law (the night ladder: 262144/245760 OOM at graph
|
|
# capture; 241664 boots at 732,359 tokens / 3.03x, util 0.98;
|
|
# the bf16-KV trade (double the attention-KV bytes/token, ~14% decode cost,
|
|
# clean cache + 262k windows), the automatic-offload law (the fork plans
|
|
# the tiered-expert offload itself; no flag exists to set), the self-healing
|
|
# law (the run returns before the engine is up, so the serve script must
|
|
# wait on the container for Restart=on-failure to mean anything), the
|
|
# memlock law that makes the pinned host rows legal, the deployer's
|
|
# image/payload gates with the false-green MainPID check, and the measured
|
|
# laws: expert prefetch ABSENT (36% precision), NO speculative decode (the
|
|
# no-spec family measured fastest once the prefetch tax was removed; MTP
|
|
# re-measures pending), gather geometry 32x64 PRESENT (+18.7% decode),
|
|
# MNBT 1024 (Frank's lock), and the client contract (reasoning parser qwen3,
|
|
# tool parser qwen3_xml, preserve_thinking on).
|
|
|
|
load helpers
|
|
|
|
UNIT="$REPO_ROOT/scripts/frank-primary.service"
|
|
SERVE="$REPO_ROOT/scripts/serve-frank-primary.sh"
|
|
ENV_FILE="$REPO_ROOT/scripts/frank-primary.env"
|
|
REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
|
|
DOWNLOAD="$REPO_ROOT/scripts/download-frank-primary.sh"
|
|
|
|
@test "frank-primary unit, serve script and env exist in scripts/" {
|
|
[ -f "$UNIT" ]
|
|
[ -x "$SERVE" ]
|
|
[ -f "$ENV_FILE" ]
|
|
}
|
|
|
|
@test "frank-primary is boot-persistent, self-healing and unprivileged" {
|
|
# Root unit parity with frank-large/frank-small: enable is the [Install]
|
|
# section, the restart policy survives a crash, and the tiered-expert
|
|
# pin needs an unbounded memlock (a root unit grants it via PID1; the
|
|
# dank session's own hard limit is 8 MiB and cannot be raised without
|
|
# restarting user@1000.service).
|
|
grep -q '^WantedBy=multi-user.target$' "$UNIT"
|
|
# Restart=always, not on-failure: a runtime worker OOM makes vLLM's API
|
|
# server exit CLEAN, so ExecStart returns 0 and on-failure never fires
|
|
# (measured 2026-10-01 — the endpoint stayed down until a human noticed).
|
|
grep -q '^Restart=always$' "$UNIT"
|
|
! grep -q '^Restart=on-failure$' "$UNIT"
|
|
grep -q '^RestartSec=' "$UNIT"
|
|
grep -q '^User=dank$' "$UNIT"
|
|
grep -q '^LimitMEMLOCK=infinity$' "$UNIT"
|
|
}
|
|
|
|
@test "frank-primary runs the repo's own serve script with the repo's env" {
|
|
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-primary.sh$' "$UNIT"
|
|
grep -q 'FRANK_PRIMARY_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-primary.env' "$UNIT"
|
|
}
|
|
|
|
@test "the unit stops the container child explicitly" {
|
|
# The serve script blocks on podman wait, which cannot stop the
|
|
# container child; systemd stop goes through ExecStop or the engine
|
|
# outlives the unit and holds both GPUs. The container name must match
|
|
# the env file's identity.
|
|
grep -q '^ExecStop=/usr/bin/podman stop' "$UNIT"
|
|
grep -q 'frank-primary-qwen' "$UNIT"
|
|
grep -q '^FRANK_PRIMARY_CONTAINER=frank-primary-qwen$' "$ENV_FILE"
|
|
}
|
|
|
|
@test "the serve shape is direct podman run, not a launcher or shim" {
|
|
# The tcclaviger stack is fully expressed by flags; the R9V launcher,
|
|
# docker->podman shim and setup-state layering are the RETIRED shape.
|
|
grep -q 'podman run' "$SERVE"
|
|
! grep -q 'launch.sh' "$SERVE"
|
|
! grep -q 'podman-shim' "$SERVE"
|
|
! grep -q 'R9V_STATE_FILE' "$SERVE"
|
|
! grep -q -- '--model-draft' "$SERVE"
|
|
! grep -q -- '--spec-type' "$SERVE"
|
|
}
|
|
|
|
@test "the qualified engine shape is in the env file" {
|
|
# 2026-10-01 night ladder (Frank's method), then a runtime-survivability
|
|
# correction. SEQS=3 bf16 topped out at 241664 (KV 732,359 / 3.03x);
|
|
# SEQS=6 fp8 does NOT fit (6 x 241664 asked 10.70 GiB against 9.18 GiB
|
|
# free); SEQS=5 fp8 x 262144 BOOTED (KV 1,350,182 / 5.15x) but left ~0
|
|
# bytes free at runtime and a real client request (995-token prompt with
|
|
# max_tokens=261149) killed the worker with `Tried to allocate 50.00 MiB
|
|
# ... 0 bytes free`. FOUR slots at the full native 262144 window is the
|
|
# deployed shape: ~1.93 GiB more headroom per rank for
|
|
# activations/graphs. UTIL stays 0.98 (lowering it shrinks the engine's
|
|
# own budget instead of buying slack).
|
|
# 3 x 262144 = 786,432 tokens; at the measured 7,698 B/token the pool
|
|
# floor is 6.054e9 B, pinned at 6.1e9 so the margin is ~5.9k tokens and
|
|
# EVERYTHING ELSE goes to the expert arena (the decode-critical expert
|
|
# cache is the remainder after weights, pool and workspace).
|
|
grep -q '^FRANK_PRIMARY_MAXLEN=262144$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_SEQS=3$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_UTIL=0.98$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_KV_BYTES=6100000000$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_MNBT=2048$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_KV_DTYPE=fp8$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_GATHER_CHUNKS=32$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_GATHER_LANES=64$' "$ENV_FILE"
|
|
! grep -q '^FRANK_PRIMARY_SPEC=' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_MODEL_SHARDS=131$' "$ENV_FILE"
|
|
}
|
|
|
|
@test "the serve script wires the engine flags from the env" {
|
|
grep -q -- '--max-num-seqs "$FRANK_PRIMARY_SEQS"' "$SERVE"
|
|
grep -q -- '--max-model-len "$FRANK_PRIMARY_MAXLEN"' "$SERVE"
|
|
grep -q -- '--kv-cache-memory-bytes "$FRANK_PRIMARY_KV_BYTES"' "$SERVE"
|
|
grep -q -- '--kv-cache-dtype "$FRANK_PRIMARY_KV_DTYPE"' "$SERVE"
|
|
grep -q -- '--max-num-batched-tokens "$FRANK_PRIMARY_MNBT"' "$SERVE"
|
|
grep -q -- '-e R4D_LRU_GATHER_CHUNKS="$FRANK_PRIMARY_GATHER_CHUNKS"' "$SERVE"
|
|
grep -q -- '-e R4D_LRU_GATHER_LANES="$FRANK_PRIMARY_GATHER_LANES"' "$SERVE"
|
|
! grep -q -- '--speculative-config' "$SERVE"
|
|
grep -q -- '--tensor-parallel-size 2' "$SERVE"
|
|
grep -q -- '--enable-prefix-caching' "$SERVE"
|
|
grep -q -- '--trust-remote-code' "$SERVE"
|
|
# DCP is opt-in: the flag is passed only when FRANK_PRIMARY_DCP is set
|
|
# (DCP reuses the TP ranks when PCP is off, so TP=2 + DCP=2 fits two GPUs).
|
|
grep -q -- '--decode-context-parallel-size "$FRANK_PRIMARY_DCP"' "$SERVE"
|
|
! grep -q '^FRANK_PRIMARY_DCP=' "$ENV_FILE"
|
|
}
|
|
|
|
@test "tools and reasoning are wired — the client contract is served" {
|
|
# 2026-10-01: the rollback-era trio served NO tool dialect and left
|
|
# thinking inline in `content` with a dangling `</think>` and a null
|
|
# `reasoning` field (measured: content 'We need answer...Brief.\n</think>
|
|
# \n\n391') — the malformed thinking block clients choke on. The working
|
|
# values are the ones ecaad36 shipped for this model and this fork's
|
|
# registries confirm: reasoning parser `qwen3`, tool parser `qwen3_xml`.
|
|
# preserve_thinking keeps prior thinking blocks across turns.
|
|
grep -q '^FRANK_PRIMARY_REASONING_PARSER=qwen3$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_TOOL_PARSER=qwen3_xml$' "$ENV_FILE"
|
|
grep -q -- '--reasoning-parser "$FRANK_PRIMARY_REASONING_PARSER"' "$SERVE"
|
|
grep -q -- '--enable-auto-tool-choice' "$SERVE"
|
|
grep -q -- '--tool-call-parser "$FRANK_PRIMARY_TOOL_PARSER"' "$SERVE"
|
|
grep -q -- '--default-chat-template-kwargs "$FRANK_PRIMARY_CHAT_TEMPLATE_KWARGS"' "$SERVE"
|
|
grep -q 'preserve_thinking' "$ENV_FILE"
|
|
grep -q 'enable_thinking' "$ENV_FILE"
|
|
}
|
|
|
|
@test "expert offload is AUTOMATIC — the payload cannot fit VRAM and no flag sets it" {
|
|
# ~86 GiB/rank of FP8 trunk against 32 GiB of VRAM: the fork's tiered-
|
|
# expert planner moves the overflow to pinned host rows by itself (the
|
|
# arena 6,574 slots x 2.344 MiB plus host rows). There is no
|
|
# --enable-expert-offload flag in this arm; the legality of the pin is
|
|
# the unit's unbounded LimitMEMLOCK.
|
|
! grep -q -- '--enable-expert-offload' "$SERVE"
|
|
! grep -q -- '--expert-precise-memory' "$SERVE"
|
|
grep -q '^LimitMEMLOCK=infinity$' "$UNIT"
|
|
grep -q -- '--ipc=host --ulimit memlock=-1:-1' "$SERVE"
|
|
}
|
|
|
|
@test "speculative decode is ABSENT BY MEASUREMENT" {
|
|
# The 2026-10-01 overnight redo (prefetch OFF) re-measured the whole
|
|
# spec family against no-spec at matched geometry: no-spec measured
|
|
# 41.46/41.29/41.47 tok/s while the spec-era incumbent's 37-40 carried
|
|
# the prefetch tax, and MTP's 2.6 GiB/rank drafter reservation halves
|
|
# the pool (729,545 vs 975,342 tokens). The MTP3/4/6 untaxed re-measures
|
|
# never completed; until one shows a real win, no spec is the incumbent.
|
|
! grep -q '^FRANK_PRIMARY_SPEC=' "$ENV_FILE"
|
|
! grep -q -- '--speculative-config' "$SERVE"
|
|
}
|
|
|
|
@test "fp8 KV is PRESENT — capacity won over the bf16 decode edge" {
|
|
# --kv-cache-dtype fp8 (the stock flag quantizes K and V together).
|
|
# Capacity is what buys the five full 262,144-token contexts: fp8 costs
|
|
# 7,926 B/token against bf16's ~13,900-14,047, so 5x262144 fits in
|
|
# 10,388,766,720 B/rank (KV 1,350,182 tokens / 5.15x) where bf16 topped
|
|
# out at three 241,664-token contexts. The bf16 ~4% decode edge was
|
|
# traded away for it (Frank's call, 2026-10-01).
|
|
grep -q '^FRANK_PRIMARY_KV_DTYPE=fp8$' "$ENV_FILE"
|
|
grep -q -- '--kv-cache-dtype "$FRANK_PRIMARY_KV_DTYPE"' "$SERVE"
|
|
}
|
|
|
|
@test "gather geometry 32x64 is PRESENT BY MEASUREMENT" {
|
|
# R4D_LRU_GATHER_CHUNKS=32 / R4D_LRU_GATHER_LANES=64: the overnight
|
|
# sweep's biggest lever, +18.7% decode vs default geometry, and the win
|
|
# GROWS with depth (39.5@166 -> 54.1@1087 -> 49.3@4064 in the fp8 era).
|
|
# g64x128 is past the peak; g8x16 mild. They are container ENV (the
|
|
# fork's knobs), not engine flags — passed through with -e.
|
|
grep -q '^FRANK_PRIMARY_GATHER_CHUNKS=32$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_GATHER_LANES=64$' "$ENV_FILE"
|
|
grep -q -- '-e R4D_LRU_GATHER_CHUNKS="$FRANK_PRIMARY_GATHER_CHUNKS"' "$SERVE"
|
|
}
|
|
|
|
@test "MNBT is at Frank's 2048 with the arena intact" {
|
|
# MNBT 512 doubles TTFT at 4064 ctx (2.46 s vs 1.36 s); 1024-4096 are
|
|
# interchangeable on decode AND identical on arena (the sweep measured
|
|
# 6,499 slots at every rung <=4096); 12288 costs 2.5% plus arena.
|
|
# 2048 is Frank's setting as of 2026-10-01 — it keeps the workspace floor
|
|
# so the expert arena stays max.
|
|
grep -q '^FRANK_PRIMARY_MNBT=2048$' "$ENV_FILE"
|
|
grep -q -- '--max-num-batched-tokens "$FRANK_PRIMARY_MNBT"' "$SERVE"
|
|
}
|
|
|
|
@test "expert prefetch is absent BY LAW, not by omission" {
|
|
# Telemetry (2026-09-29): the prefetcher served 13,369 of 36,720
|
|
# prefetched slabs (36% precision) — roughly half the gather traffic was
|
|
# waste, and the "savings" would have been installs anyway. Deleting the
|
|
# flag moved decode 26.8 -> 40.6 tok/s. Any future flag must come with a
|
|
# fresh A/B, so the serve script must NOT wire it unconditionally.
|
|
! grep -q -- '--expert-prefetch' "$SERVE"
|
|
! grep -q 'expert_prefetch' "$ENV_FILE"
|
|
grep -q 'PREFETCH IS ABSENT BY LAW' "$ENV_FILE"
|
|
}
|
|
|
|
@test "TunableOp stays off" {
|
|
# CLAV_TUNABLEOP_SWEEP silently skips under expert offload unless
|
|
# CLAV_TUNABLEOP_WITH_OFFLOAD=1, and forcing it corrupts numerics
|
|
# (repetition loops, early halts, invalid measurements).
|
|
! grep -q 'TUNABLEOP' "$ENV_FILE"
|
|
! grep -q 'TUNABLEOP' "$SERVE"
|
|
}
|
|
|
|
@test "the serve script gates the digest-pinned image and the payload" {
|
|
# The image is pinned by OCI manifest digest (the floating :latest moved
|
|
# once already). The payload gate checks config.json and the exact shard
|
|
# count from the env — a missing shard means a guaranteed long-timeout
|
|
# boot instead of a fast failure.
|
|
grep -q 'FRANK_PRIMARY_IMAGE' "$SERVE"
|
|
grep -q 'RepoDigests' "$SERVE"
|
|
grep -q 'FRANK_PRIMARY_MODEL_SHARDS' "$SERVE"
|
|
grep -q 'config.json' "$SERVE"
|
|
grep -q '/dev/kfd' "$SERVE"
|
|
grep -q -- '--device /dev/dri' "$SERVE"
|
|
! grep -q 'tcclaviger/vllm:latest' "$ENV_FILE"
|
|
}
|
|
|
|
@test "the serve script clears stale containers and self-heals via podman wait" {
|
|
# A crashed unit can leave the container name registered forever after;
|
|
# the legacy identities (the retired R9V container and the ad hoc
|
|
# experiment container) hold the same GPUs and die here too. Then block
|
|
# on the container so a crash is a nonzero ExecStart.
|
|
grep -q 'FRANK_PRIMARY_LEGACY_CONTAINERS' "$ENV_FILE"
|
|
grep -q 'frank-primary-r9v' "$ENV_FILE"
|
|
grep -q 'qwen-fp8' "$ENV_FILE"
|
|
grep -q 'exec podman wait "$FRANK_PRIMARY_CONTAINER"' "$SERVE"
|
|
}
|
|
|
|
@test "frank-primary holds the single fleet port under its own alias" {
|
|
# The scratch identity (qwen3.8-flash-next on :7773) must never leak
|
|
# into production: LAN publish of :7770, the harness's model id.
|
|
grep -q '^FRANK_PRIMARY_PUBLISH=7770:7770$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_SERVED_NAME=frank-primary$' "$ENV_FILE"
|
|
}
|
|
|
|
@test "the model id matches the payload's served alias wiring" {
|
|
# The payload dir and its shard count are the fetch script's output
|
|
# layout; the fetch script must write where the env points.
|
|
grep -q '^FRANK_PRIMARY_MODEL_DIR=/home/dank/models/Qwen3.8-Flash-Next-Uncensored-FP8$' "$ENV_FILE"
|
|
grep -q '^FRANK_PRIMARY_MODEL_SHARDS=131$' "$ENV_FILE"
|
|
grep -q 'Qwen3.8-Flash-Next-Uncensored-FP8' "$DOWNLOAD"
|
|
grep -q 'orcarouter/Qwen3.8-Flash-Next-Uncensored-FP8' "$DOWNLOAD"
|
|
}
|
|
|
|
@test "no bare HIP-reserved env var is defined" {
|
|
# HIP reads bare TEMP for its JIT cache path (2026-08-13: TEMP=1.0
|
|
# segfaulted every load), and HOST/GPU_MAX_HEAP_SIZE are the same
|
|
# class. Every key here is FRANK_PRIMARY_-prefixed.
|
|
! grep -qE '^(TEMP|HOST|GPU_MAX_HEAP_SIZE)=' "$ENV_FILE"
|
|
! grep -qE '^(export )?(TEMP|HOST|GPU_MAX_HEAP_SIZE)=' "$SERVE"
|
|
}
|
|
|
|
@test "the deployer gates the image digest and payload, then health-checks" {
|
|
# The deployer refuses when the pinned image is absent from rootless
|
|
# storage or the payload is missing/wrong-sharded — then clears stale
|
|
# containers (including the legacy identities), waits out the port,
|
|
# relinks/enables/restarts the root unit and health-gates it.
|
|
grep -q 'LLM_PRIMARY_CONTAINER=frank-primary-qwen' "$REMOTE_DEPLOY"
|
|
grep -q 'FRANK_PRIMARY_IMAGE' "$REMOTE_DEPLOY"
|
|
grep -q "podman images --format '{{.RepoDigests}}'" "$REMOTE_DEPLOY"
|
|
grep -q 'FRANK_PRIMARY_MODEL_SHARDS' "$REMOTE_DEPLOY"
|
|
grep -q 'config.json' "$REMOTE_DEPLOY"
|
|
grep -q 'qwen-fp8' "$REMOTE_DEPLOY"
|
|
grep -q 'glm-probe' "$REMOTE_DEPLOY"
|
|
grep -q 'wait_port_free 7770' "$REMOTE_DEPLOY"
|
|
grep -q 'relink_unit frank-primary' "$REMOTE_DEPLOY"
|
|
grep -q 'systemctl enable frank-primary.service' "$REMOTE_DEPLOY"
|
|
grep -q 'systemctl restart frank-primary.service' "$REMOTE_DEPLOY"
|
|
grep -q 'wait_for_health frank-primary http://127.0.0.1:7770/health 1800' "$REMOTE_DEPLOY"
|
|
}
|
|
|
|
@test "the deployer will not report green on a stray port-holder" {
|
|
# The 2026-09-26 false green: a leftover probe held :7770 and satisfied
|
|
# the health curl while the real unit was stopped. The deploy is only
|
|
# green when the unit's own MainPID is live behind the health answer.
|
|
grep -q 'systemctl show -p MainPID --value frank-primary.service' "$REMOTE_DEPLOY"
|
|
grep -q 'stray process holds the port' "$REMOTE_DEPLOY"
|
|
}
|