Files
serverAppConfigs/tests/frank_small_unit.bats
T
Frank 43ec77fee6 inference: frank-large returns to halogen, frank-small takes the 3090
Dankclaw's endpoints are re-split. frank-large is the halogen-flash-server
quadlet again -- the 2026-09-13 unit file was never touched by the two-day
ik_llama.cpp interlude, so the runtime was still in the repo and its image is
still in local storage -- retuned to the shape asked for: HALOGEN_CTX 200192
with a 400,384-position pool and two slots, exactly two 200k conversations.

frank-small is new: mainline llama.cpp on the RTX 3090 serving
ISTA-DASLab/Qwen3.8-27B-GSQ-RCO-GGUF at IQ3_S, using the -mtp build (it carries
blk.64.nextn.*, which is what lets --spec-type draft-mtp run on the main
model's own weights instead of a second 12 GiB copy) plus the BF16 vision
projector, as one 131,072-token slot with f16 KV on port 7771.

The host is shared now, and that is what the halogen retune pays for:
HALOGEN_MAX_TOK 24576 (arena 20.6 -> 16.4 GiB, ~4-5% prefill) and the vision
tower dropped (1.97 GiB) hand ~6 GiB back to the host, and the reserve rises to
20 to keep the fit check honest. Vision moved wholesale to frank-small.

Retired to scripts/.AGENTTRASH/: the ik trio (env, service, serve script), the
Qwen-Sharp template only that runtime read, and four benchmark harnesses bound
to retired runtimes. Because retiring a file makes any test that greps it pass
by absence, the seams assert the archive exists AND the live path does not.
2026-09-16 13:58:00 -07:00

107 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bats
# Seam: the frank-small mainline-llama.cpp root unit on dankclaw.
# frank-small is the RTX 3090 endpoint created on 2026-09-16, when frank-large
# went back to the halogen engine on the iGPU. This seam pins what the flags
# alone do not say: boot persistence for a NATIVE runtime (no generated quadlet
# is involved), the repo-relative paths the unit executes, the separate client
# port, the MTP contract (the head lives in the weights file, and no second copy
# of the model is loaded for it), the vision handoff from frank-large, and the
# KV budget that has to fit a 24 GiB card beside 12 GiB of weights.
load helpers
UNIT="$REPO_ROOT/scripts/frank-small.service"
SERVE="$REPO_ROOT/scripts/serve-frank-small.sh"
ENV_FILE="$REPO_ROOT/scripts/frank-small.env"
REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
QUADLET_LARGE="$REPO_ROOT/dankclaw/frank-large/quadlet/frank-large.container"
@test "frank-small unit, serve script and env exist in scripts/" {
[ -f "$UNIT" ]
[ -f "$SERVE" ]
[ -f "$ENV_FILE" ]
}
@test "frank-small is boot-persistent, self-healing and unprivileged" {
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-small runs the repo's own serve script with the repo's env" {
grep -q '^ExecStart=/home/dank/serverAppConfigs/scripts/serve-frank-small.sh$' "$UNIT"
grep -q 'FRANK_SMALL_ENV_FILE=/home/dank/serverAppConfigs/scripts/frank-small.env' "$UNIT"
}
@test "frank-small offloads every layer to the 3090 with flash attention" {
grep -q 'llama.cpp-mainline/build-cuda/bin/llama-server' "$ENV_FILE"
grep -q '^NGL=999$' "$ENV_FILE"
grep -q -- '--gpu-layers "$NGL"' "$SERVE"
grep -q '^FLASH_ATTN=on$' "$ENV_FILE"
grep -q -- '--flash-attn "$FLASH_ATTN"' "$SERVE"
# Prometheus scrapes this endpoint; without --metrics there is no /metrics.
grep -q -- '--metrics' "$SERVE"
}
@test "frank-small's MTP head comes from the weights file, not a second copy" {
grep -q '^SPEC_TYPE=draft-mtp$' "$ENV_FILE"
grep -q -- '--spec-type "$SPEC_TYPE"' "$SERVE"
# The -mtp build is the one carrying blk.64.nextn.*; the plain IQ3_S has no
# MTP tensors at all, so MTP is a property of the file, not of the flags.
grep -q '^MODEL_FILE=.*-mtp\.gguf$' "$ENV_FILE"
# A separate draft model would load a second 12 GiB copy of a 12 GiB model.
! grep -q -- '--model-draft' "$SERVE"
}
@test "frank-small carries the fleet's image path, and only it" {
grep -q '^MMPROJ_PATH=.*mmproj-Qwen3\.8-27B-BF16\.gguf$' "$ENV_FILE"
grep -q -- '--mmproj "$MMPROJ_PATH"' "$SERVE"
! grep -q 'HALOGEN_VISION_TOWER' "$QUADLET_LARGE"
}
@test "frank-small's KV fits the card beside the weights it loads" {
local ctx parallel parallel_slots cache_k cache_v
ctx="$(sed -nE 's/^CTX_SIZE=([0-9]+)$/\1/p' "$ENV_FILE")"
parallel="$(sed -nE 's/^PARALLEL=([0-9]+)$/\1/p' "$ENV_FILE")"
cache_k="$(sed -nE 's/^CACHE_TYPE_K=(.+)$/\1/p' "$ENV_FILE")"
cache_v="$(sed -nE 's/^CACHE_TYPE_V=(.+)$/\1/p' "$ENV_FILE")"
[ -n "$ctx" ] && [ -n "$parallel" ] && [ -n "$cache_k" ] && [ -n "$cache_v" ]
[ "$parallel" -ge 1 ]
# qwen35 spends KV on its 16 full-attention layers only: 2 (K,V) x 4 heads x
# 256 dim x 2 B = 64 KiB per token at f16. 11.29 GiB of weights + 0.87 of
# mmproj + ~2 GiB of context/compute/MTP leave under 10 GiB of the card's
# 24 GiB for KV, and --parallel divides --ctx-size between the slots.
[ $((ctx * 64)) -le $((10 * 1024 * 1024)) ]
# f16 is the deployed type on purpose: a quantized KV needs the
# GGML_CUDA_FA_ALL_QUANTS build option, without which prefill on CUDA
# collapses about 12x (see the CUDA lesson in AGENTS.md).
[ "$cache_k" = "f16" ] && [ "$cache_v" = "f16" ]
}
@test "frank-small runs on its own port beside frank-large's" {
grep -q '^LISTEN_PORT=7771$' "$ENV_FILE"
grep -q '^ALIAS=frank-small$' "$ENV_FILE"
grep -q -- '--port "$LISTEN_PORT"' "$SERVE"
grep -q -- '--host "$BIND_ADDR"' "$SERVE"
# The two endpoints cannot share a port, and only the halogen unit publishes
# 7770.
grep -q '^PublishPort=7770:8731$' "$QUADLET_LARGE"
! grep -q 'PublishPort=.*7771' "$QUADLET_LARGE"
}
@test "the deploy handler installs the root unit and refuses a missing model" {
grep -q 'deploy_llm_small' "$REMOTE_DEPLOY"
grep -q 'relink_unit frank-small' "$REMOTE_DEPLOY"
grep -q 'systemctl enable frank-small.service' "$REMOTE_DEPLOY"
grep -q 'systemctl restart frank-small.service' "$REMOTE_DEPLOY"
grep -q 'Qwen3.8-27B-GSQ-RCO-IQ3_S-mtp' "$REMOTE_DEPLOY"
grep -q 'refusing to start a unit that cannot load' "$REMOTE_DEPLOY"
grep -q '127.0.0.1:7771/health' "$REMOTE_DEPLOY"
}
@test "frank-small's serve script refuses to start on a half-finished download" {
grep -q 'frank-small: missing' "$SERVE"
}