Files
serverAppConfigs/tests/frank_primary_unit.bats
T
Frank f2bcf84e88 frank-primary cutover: GLM-5.3-Flash W4A16 int4 (Intel AutoRound)
Payload: Intel/GLM-5.3-Flash-W4A16-AutoRound (AutoRound symmetric int4 group
128, auto_round:auto_gptq, 34 shards + 2 extras, 113,074 tensors, ~170 GiB).
It is the only W4A16 checkpoint this fork can serve with expert offload: its
quant_method "auto-round" is overridden to "inc", which routes the MoE to
libr4d's grouped W4A16 GEMM (R4dW4a16MoEMethod). A compressed-tensors W4A16
build of the same model resolves to TritonWNA16Experts, which has no offload
recipe, and refuses to serve at all (170 GiB of experts cannot fit 64 GiB of
VRAM, so offload is mandatory).

Shape: tcclaviger RDNA4 vLLM fork (same digest-pinned image as the 2026-09-29
qwen cutover), TP=2, 131,072 ctx x 2 seqs, bf16 KV (fp8 is ILLEGAL here — it
disables the sparse MLA backend's rope-free Triton path, the only MLA decode
gfx12 has), util 0.98, NBATCH 2048, --enable-expert-offload
--expert-precise-memory, prefix caching, glm47 tool + reasoning parsers,
MTP and expert prefetch absent by measurement.

Measured: decode 9.9-10.0 tok/s, prefill 918 tok/s (warm), arena 14.51 GiB =
2,383 slots/rank over 12,096 host-backed experts (73.64 GiB pinned/rank).
THE 35 tok/s TARGET IS NOT MET and the shortfall is measured: live telemetry
(R4D_LRU_TELEMETRY=1) gives a 0.53-0.66 per-layer hit rate, a step moves
0.82 GiB of misses in ~100 ms = 8.2 GB/s effective against a link measured at
22.74 GB/s — the same structural gather-path gap the qwen campaign found.
Growing the arena 13.08 -> 14.51 GiB changed decode by nothing.

Rejected by measurement: MTP4 (head loads, acceptance 3.76-4.90, but decode
unchanged and prefill collapses 918 -> 255 — a verification forward gathers the
union of the batch's experts), NBATCH 8192 (identical prefill).

Also: scripts/patches/gpu_worker-kv-cap.patch (fork-local fix for a KV-reserve
model that under-counts GLM's per-sequence KDA state; not needed by this shape),
runbook, AGENTS.md row + section, both indexes, work log.

Rollback: 2339fae (qwen FP8 + MTP4).
2026-09-30 04:22:11 -07:00

233 lines
12 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-09-30
# cutover to GLM-5.3-Flash W4A16 int4, which replaced the qwen FP8 + MTP4
# shape): the serve script drives `podman run` DIRECTLY (the image entrypoint
# execs `vllm serve`), with every engine flag qualified by boot probe on
# 2026-09-30 and carried in the repo env file. The seam pins what the flags
# alone do not say: the qualification law (131,072 x 2 seqs at bf16 KV, util
# 0.98 is what boots; the window is forced up by the fork's KV reserve model,
# not by capacity), the offload law (170 GiB of experts cannot fit 64 GiB of
# VRAM — the engine MUST run with --enable-expert-offload), 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 73.64 GiB/rank expert pin legal, the deployer's image/payload
# gates with the false-green MainPID check, and the three measured-absent
# flags: expert prefetch (36% precision, costs ~40-50% decode), MTP spec
# decode (buys zero decode and collapses prefill on an offload-bound shape),
# and fp8 KV (disables the only MLA decode path gfx12 has).
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"
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-glm' "$UNIT"
grep -q '^FRANK_PRIMARY_CONTAINER=frank-primary-glm$' "$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-09-30 boot probe: 131,072 x 2 seqs at bf16 KV, util 0.98 boots and
# serves (measured "GPU KV cache size: 138,561 tokens"). 0.99 fails the
# free-memory wall. The window is not a capacity choice: the engine's own
# reserve model (one max_model_len request) needs a large L for this
# model's per-sequence KDA state, and below ~92k the boot REFUSES with
# "needed ... larger than the available KV cache memory". NBATCH pins the
# prefill chunk that was measured.
grep -q '^FRANK_PRIMARY_MAXLEN=131072$' "$ENV_FILE"
grep -q '^FRANK_PRIMARY_SEQS=2$' "$ENV_FILE"
grep -q '^FRANK_PRIMARY_UTIL=0.98$' "$ENV_FILE"
grep -q '^FRANK_PRIMARY_NBATCH=2048$' "$ENV_FILE"
grep -q '^FRANK_PRIMARY_MODEL_SHARDS=34$' "$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 -- '--max-num-batched-tokens "$FRANK_PRIMARY_NBATCH"' "$SERVE"
grep -q -- '--tensor-parallel-size 2' "$SERVE"
grep -q -- '--enable-prefix-caching' "$SERVE"
grep -q -- '--trust-remote-code' "$SERVE"
}
@test "the endpoint advertises the GLM tool dialect" {
# Without --enable-auto-tool-choice the engine rejects tool_choice "auto"
# with a 400 ("requires --enable-auto-tool-choice and --tool-call-parser"),
# which breaks every tool-using agent on the endpoint.
grep -q -- '--enable-auto-tool-choice' "$SERVE"
grep -q -- '--tool-call-parser "$FRANK_PRIMARY_TOOLPARSER"' "$SERVE"
grep -q -- '--reasoning-parser "$FRANK_PRIMARY_REASONINGPARSER"' "$SERVE"
grep -q '^FRANK_PRIMARY_TOOLPARSER=glm47$' "$ENV_FILE"
grep -q '^FRANK_PRIMARY_REASONINGPARSER=glm47$' "$ENV_FILE"
}
@test "expert offload is ON — the payload cannot fit VRAM without it" {
# 170 GiB of int4 experts against 64 GiB of VRAM. Without the offload flag
# the engine has no home for the expert tensors at all; the arena
# (14.51 GiB = 2,383 slots) plus 73.64 GiB/rank of pinned host rows is the
# only shape that boots. --expert-precise-memory is the qualified sizing.
grep -q -- '--enable-expert-offload' "$SERVE"
grep -q -- '--expert-precise-memory' "$SERVE"
}
@test "MTP spec decode is absent BY MEASUREMENT, not by omission" {
# 2026-09-30: the MTP head loads and accepts well (mean accepted length
# 3.76-4.90), but decode was unchanged (9.6-11.2 vs 10.0 tok/s) while
# prefill collapsed 918 -> 255 tok/s — the verification forward gathers the
# union of the batch's experts, so spec decode does not amortize a
# residency-bound gather. It also costs 2.6 GiB of arena.
! grep -q -- '--speculative-config' "$SERVE"
! grep -q 'speculative' "$ENV_FILE"
}
@test "fp8 KV is absent — it would disable the only MLA decode path on gfx12" {
# _use_rocm_sparse_triton() in the ROCM_AITER_MLA_SPARSE backend requires a
# non-fp8 KV cache, and that rope-free Triton path is the only MLA decode
# available on gfx12: aiter's MLA decode op is registered under
# @if_aiter_supported, gated on CDNA>2. With fp8 KV the MTP draft step dies
# with "_OpNamespace 'vllm' object has no attribute
# 'rocm_aiter_mla_decode_fwd'". KV dtype therefore stays auto/bf16.
! grep -q -- '--kv-cache-dtype' "$SERVE"
! grep -q '^FRANK_PRIMARY_KV_DTYPE=' "$ENV_FILE"
}
@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/GLM-5.3-Flash-W4A16-AutoRound$' "$ENV_FILE"
grep -q '^FRANK_PRIMARY_MODEL_SHARDS=34$' "$ENV_FILE"
grep -q 'GLM-5.3-Flash-W4A16-AutoRound' "$DOWNLOAD"
grep -q 'Intel/GLM-5.3-Flash-W4A16-AutoRound' "$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-glm' "$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"
}