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.
107 lines
4.9 KiB
Bash
Executable File
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"
|
|
}
|