refact(frank-dragoon): serve gates run on the shared gate library
The hand-written image/ck/tokenizer gates are require_image, require_bytes and require_dir_files from scripts/lib/llm-gates.sh. The serve seam is unchanged and still green (its podman stub now models `podman image exists`, the primitive the gate uses). Behaviour preserved: every refusal names the artifact, the endpoint and the fetch script.
This commit is contained in:
1 parent
acf2a5cee5
commit
028afdeb58
4 files changed
+50
-42
No files matched your search
@@ -69,12 +69,14 @@ require_min_mib() {
|
||||
|
||||
# require_dir_files — DIR must be a directory and every named member a
|
||||
# regular file (the flat-tokenizer law: snapshot symlinks dangle in the
|
||||
# container mount even when the directory itself is real).
|
||||
# container mount even when the directory itself is real. A symlinked
|
||||
# DIRECTORY is refused too: a HF cache snapshot can link the directory
|
||||
# itself, and a link dangles inside the container mount.
|
||||
require_dir_files() {
|
||||
local dir="$1" label="$2" hint="$3"
|
||||
shift 3
|
||||
local f
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
if [[ -L "$dir" || ! -d "$dir" ]]; then
|
||||
_gate_fail "$label: missing at $dir" "$hint"
|
||||
fi
|
||||
for f in "$@"; do
|
||||
|
||||
@@ -29,7 +29,14 @@
|
||||
# exactly like frank-archon's.
|
||||
set -euo pipefail
|
||||
|
||||
# The artifact gates are the shared library — the serve script and the
|
||||
# deployer refuse the same missing/truncated payload with the same words
|
||||
# (the 2026-10-01 crash-loop was the two hand-written twins disagreeing).
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
export GATE_PREFIX=frank-dragoon
|
||||
# shellcheck disable=SC1091
|
||||
source "$SCRIPT_DIR/lib/llm-gates.sh"
|
||||
|
||||
ENV_FILE="${FRANK_DRAGOON_ENV_FILE:-$SCRIPT_DIR/frank-dragoon.env}"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "frank-dragoon: env file not found: $ENV_FILE" >&2
|
||||
@@ -57,55 +64,37 @@ set +a
|
||||
: "${HALOGEN_KV_SLOTS:?HALOGEN_KV_SLOTS must be set}"
|
||||
: "${HALOGEN_SPEC_ADAPT:?HALOGEN_SPEC_ADAPT must be set (0 = head always on)}"
|
||||
|
||||
# Capture podman's output BEFORE grepping: under `set -o pipefail` the
|
||||
# `podman images | grep -q` pattern races (grep exits on first match,
|
||||
# podman dies SIGPIPE 141, pipefail turns the 141 into "no match" — the
|
||||
# 2026-09-30 deploy refusal).
|
||||
DIGESTS="$(podman images --format '{{.RepoDigests}}')"
|
||||
if ! grep -qF "${FRANK_DRAGOON_IMAGE#*@}" <<<"$DIGESTS"; then
|
||||
echo "frank-dragoon: image $FRANK_DRAGOON_IMAGE not in podman storage;" >&2
|
||||
echo " pull it: podman pull ${FRANK_DRAGOON_IMAGE%@*}" >&2
|
||||
exit 1
|
||||
fi
|
||||
# The image gate is the digest-pinned ref itself: `podman image exists` takes
|
||||
# a name@sha256 ref in one command, so a retagged look-alike or a newer
|
||||
# latest cannot satisfy it and there is no pipefail/SIGPIPE race with grep
|
||||
# (the 2026-09-30 deploy refusal). Runs as dank: the unit's process uses
|
||||
# dank's rootless storage.
|
||||
require_image "$FRANK_DRAGOON_IMAGE" \
|
||||
"pull it: podman pull docker://$FRANK_DRAGOON_IMAGE" || exit 1
|
||||
|
||||
# Size-exact gates on all three payload files: a truncated curl exits 0 on
|
||||
# some failures and a partial .hgn loads far enough to look alive, so the
|
||||
# byte counts from the Hub tree API are the contract (fleet fetch law).
|
||||
ck() {
|
||||
# ck <env-name> <path> <expected-bytes>
|
||||
if [ ! -f "$2" ]; then
|
||||
echo "frank-dragoon: $1 $2 missing;" >&2
|
||||
echo " fetch it: bash scripts/download-frank-dragoon-flashnext.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
local sz
|
||||
sz="$(stat -c %s "$2")"
|
||||
if [ "$sz" != "$3" ]; then
|
||||
echo "frank-dragoon: $1 is $sz bytes, expected $3 (partial download?)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
ck checkpoint "$FRANK_DRAGOON_MODEL_DIR/$FRANK_DRAGOON_CHECKPOINT" "$FRANK_DRAGOON_CHECKPOINT_BYTES"
|
||||
ck n-gram-table "$FRANK_DRAGOON_MODEL_DIR/$FRANK_DRAGOON_NGRAM_TABLE" "$FRANK_DRAGOON_NGRAM_BYTES"
|
||||
ck vision-tower "$FRANK_DRAGOON_MODEL_DIR/$FRANK_DRAGOON_VISION_TOWER" "$FRANK_DRAGOON_VISION_BYTES"
|
||||
require_bytes "$FRANK_DRAGOON_MODEL_DIR/$FRANK_DRAGOON_CHECKPOINT" \
|
||||
checkpoint "$FRANK_DRAGOON_CHECKPOINT_BYTES" \
|
||||
"fetch it: bash scripts/download-frank-dragoon-flashnext.sh" || exit 1
|
||||
require_bytes "$FRANK_DRAGOON_MODEL_DIR/$FRANK_DRAGOON_NGRAM_TABLE" \
|
||||
n-gram-table "$FRANK_DRAGOON_NGRAM_BYTES" \
|
||||
"fetch it: bash scripts/download-frank-dragoon-flashnext.sh" || exit 1
|
||||
require_bytes "$FRANK_DRAGOON_MODEL_DIR/$FRANK_DRAGOON_VISION_TOWER" \
|
||||
vision-tower "$FRANK_DRAGOON_VISION_BYTES" \
|
||||
"fetch it: bash scripts/download-frank-dragoon-flashnext.sh" || exit 1
|
||||
|
||||
# The payload ships the tokenizer as a FLAT DIRECTORY. A HuggingFace cache
|
||||
# snapshot symlinks each file into a sibling blobs/, and those symlinks
|
||||
# dangle inside the container mount — so the directory must be real and
|
||||
# every named file must be a regular file, not a link.
|
||||
TOK_DIR="$FRANK_DRAGOON_MODEL_DIR/tokenizer"
|
||||
if [ -L "$TOK_DIR" ] || [ ! -d "$TOK_DIR" ]; then
|
||||
echo "frank-dragoon: tokenizer dir $TOK_DIR missing or a symlink (HF cache snapshot?);" >&2
|
||||
echo " fetch it: bash scripts/download-frank-dragoon-flashnext.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
for TF in $FRANK_DRAGOON_TOKENIZER_FILES; do
|
||||
if [ ! -f "$TOK_DIR/$TF" ] || [ -L "$TOK_DIR/$TF" ]; then
|
||||
echo "frank-dragoon: tokenizer file $TOK_DIR/$TF missing or a symlink;" >&2
|
||||
echo " fetch it: bash scripts/download-frank-dragoon-flashnext.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# The tokenizer file list is word-separated ON PURPOSE (one argument per
|
||||
# file), so the unquoted expansion below is the interface, not a slip.
|
||||
# shellcheck disable=SC2086
|
||||
require_dir_files "$FRANK_DRAGOON_MODEL_DIR/tokenizer" tokenizer \
|
||||
"fetch it: bash scripts/download-frank-dragoon-flashnext.sh" \
|
||||
$FRANK_DRAGOON_TOKENIZER_FILES || exit 1
|
||||
|
||||
# GPU access is mandatory but the node paths are variables so the seam can
|
||||
# drive the gate on a box without an AMD GPU.
|
||||
@@ -115,6 +104,7 @@ if [ ! -e "$DEV_KFD" ] || [ ! -d "$DEV_DRI" ]; then
|
||||
echo "frank-dragoon: $DEV_KFD or $DEV_DRI missing — no gfx1151 to serve on" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Host-RAM preflight — the engine's pin gate, checked BEFORE podman run.
|
||||
# The engine refuses to pin when MemAvailable is below the checkpoint plus
|
||||
# a 16 GiB floor: pinned pages cannot be swapped, and under the floor the
|
||||
|
||||
Reference in new issue
Block a user