FoolDev's picture
Claude Opus 5 (1M context)
release 0.9.10: check.sh's pyflakes hint named a command that fails on this host
ec7ddfa
Raw History Blame Contribute Delete
12.5 kB
#!/usr/bin/env bash
# Janus-35B — repo-local sanity checks.
#
# Runs everything that's cheap and catches a real-world bug we've already hit:
#
# 1. bash -n on every *.sh (catches syntax errors)
# 2. shellcheck on every *.sh, if installed (catches quoting/SC2086 bugs)
# 3. python3 -m pyflakes on every *.py (catches NameError, unused imports)
# 4. python3 -m py_compile on every *.py (catches actual syntax errors)
# 5. the Modelfile's FROM target is the GGUF this repo actually ships
# (the local-build path da34705 broke, with nothing here to catch it)
# 6. multi-line-aware scan for the VAR="$(cmd 2>/dev/null | filter)" silent-exit
# under set -e + pipefail (the bug the sibling repo shipped and fixed; those
# commits live in Thanatos-27B-HERETIC, not here)
# 7. Modelfile <-> template/system/params bridge-file sync
# 8. Go template keeps Ollama's thinking detection, the replay condition and
# the reasoning-effort mapping
#
# Exit non-zero on any failure; a check whose tooling or input is missing is
# reported as skipped and never counted as a pass. Designed to run from
# .git/hooks/pre-commit.
#
# Usage:
# ./scripts/check.sh # one-shot
# ./scripts/install-hooks.sh # install as pre-commit hook
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT}"
red() { printf "\033[31m%s\033[0m\n" "$*"; }
green() { printf "\033[32m%s\033[0m\n" "$*"; }
yellow() { printf "\033[33m%s\033[0m\n" "$*"; }
blue() { printf "\033[34m%s\033[0m\n" "$*"; }
FAIL=0
SKIPPED=0
CHECKS=8 # the numbered checks above; keep in sync with that list
# ---- collect targets -------------------------------------------------------
# Find every shell script and every python file, ignoring vendored / hidden dirs.
# The exclusions below are the ones .gitignore anticipates: without them a repo-local
# virtualenv would be fed to shellcheck and py_compile, and the __pycache__ sweep further
# down would delete bytecode caches inside it.
mapfile -t SH_FILES < <(find . -type f -name '*.sh' \
-not -path './.git/*' -not -path './.venv/*' -not -path './venv/*' -not -path './.cache/*')
mapfile -t PY_FILES < <(find . -type f -name '*.py' \
-not -path './.git/*' -not -path './.venv/*' -not -path './venv/*' -not -path './.cache/*' \
-not -path '*/__pycache__/*')
blue "[*] checking ${#SH_FILES[@]} shell file(s) and ${#PY_FILES[@]} python file(s)"
# ---- 1. bash -n ------------------------------------------------------------
if (( ${#SH_FILES[@]} )); then
blue "[*] bash -n"
for f in "${SH_FILES[@]}"; do
if ! bash -n "$f" 2>/dev/null; then
red " [FAIL] bash -n $f"
bash -n "$f" || true
FAIL=1
else
echo " [ ok ] $f"
fi
done
fi
# ---- 2. shellcheck (optional) ---------------------------------------------
if command -v shellcheck >/dev/null 2>&1; then
blue "[*] shellcheck"
for f in "${SH_FILES[@]}"; do
if ! shellcheck -S warning "$f"; then
red " [FAIL] shellcheck $f"
FAIL=1
else
echo " [ ok ] $f"
fi
done
else
yellow "[~] shellcheck not installed (skip). Install with: apt install shellcheck"
SKIPPED=$((SKIPPED + 1))
fi
# ---- 3. pyflakes -----------------------------------------------------------
if (( ${#PY_FILES[@]} )); then
if python3 -c 'import pyflakes' 2>/dev/null; then
blue "[*] pyflakes"
for f in "${PY_FILES[@]}"; do
if ! python3 -m pyflakes "$f"; then
red " [FAIL] pyflakes $f"
FAIL=1
else
echo " [ ok ] $f"
fi
done
else
# The hint matters more than it looks: this check runs `python3 -m pyflakes`,
# so pyflakes has to be importable by the SYSTEM python3. A venv or a pipx
# install - which is exactly what PEP 668's own error message suggests -
# leaves this check skipping forever. And on a PEP 668 distro (Arch,
# Debian 12+, Fedora) the plain pip command below is refused outright.
yellow "[~] pyflakes not installed (skip). This check runs 'python3 -m pyflakes',"
yellow " so it must be importable by the SYSTEM python3 - a venv or pipx install"
yellow " does not satisfy it. Install with: pip install pyflakes"
yellow " PEP 668 distro (Arch, Debian 12+, Fedora), either:"
yellow " pip install --user --break-system-packages pyflakes # ~/.local, per python version"
yellow " <your package manager> python-pyflakes # e.g. pacman -S python-pyflakes"
SKIPPED=$((SKIPPED + 1))
fi
fi
# ---- 4. py_compile ---------------------------------------------------------
if (( ${#PY_FILES[@]} )); then
blue "[*] python3 -m py_compile"
for f in "${PY_FILES[@]}"; do
if ! python3 -m py_compile "$f" 2>&1; then
red " [FAIL] py_compile $f"
FAIL=1
else
echo " [ ok ] $f"
fi
done
# py_compile leaves __pycache__ artifacts; clean them up.
find . -type d -name __pycache__ -not -path './.git/*' -exec rm -rf {} + 2>/dev/null || true
fi
# ---- 5. footgun: Modelfile FROM target vs the bundled GGUF -----------------
#
# 'ollama create janus -f Modelfile' resolves the FROM line against the repo
# root, so that filename and the blob this repo actually ships have to be the
# same file. The 0.2.0 rebase renamed FROM ahead of the blob: for a day the
# repo tracked one bundle and FROM named another, so the local-build path
# failed outright from a fresh clone until the blob swap in da34705 caught up
# — and nothing here noticed (CHANGELOG: "the broken Modelfile FROM path
# shipped unnoticed"). A rename on either side alone breaks it again.
#
# This replaces the '-MTP-Preserved-Q<quant>.gguf' grep that used to sit here:
# no Qwen 3.6 quant filename carries that substring, so the guard was green by
# construction rather than by inspection. What still guards the MTP footgun is
# scripts/strip_mtp.py itself — build.sh runs every fetched quant through it,
# and it no-ops on the MTP-clean quant this repo bundles.
blue "[*] Modelfile FROM target is the GGUF this repo ships"
if [[ ! -f "${ROOT}/Modelfile" ]]; then
yellow "[~] Modelfile missing; skipping FROM target check"
SKIPPED=$((SKIPPED + 1))
else
# Skip build byproducts git ignores. build.sh defaults GGUF_PATH into the repo
# root and writes a *.stripped.gguf sibling beside it, and .gitignore covers
# both - so after any `make build` this check counted three GGUFs, failed, and
# (being wired into the pre-commit hook) rejected every commit, while git
# status stayed clean because the extras are ignored. An untracked file that
# git does NOT ignore still counts: that is the case the check exists for.
mapfile -t BUNDLES < <(
find . -maxdepth 1 -type f -name '*.gguf' | sed 's|^\./||' | sort |
while IFS= read -r f; do
git -C "${ROOT}" check-ignore -q -- "${f}" || printf '%s\n' "${f}"
done
)
FROM_TARGET="$(awk '/^FROM[[:space:]]/{print $2; exit}' "${ROOT}/Modelfile")"
if (( ${#BUNDLES[@]} != 1 )); then
red " [FAIL] expected exactly one bundled *.gguf in the repo root, found ${#BUNDLES[@]}"
(( ${#BUNDLES[@]} )) && red " found: ${BUNDLES[*]}"
(( ${#BUNDLES[@]} > 1 )) && red " Leftover build output that git does not ignore? 'make clean' clears it."
FAIL=1
elif [[ "${FROM_TARGET#./}" != "${BUNDLES[0]}" ]]; then
red " [FAIL] Modelfile FROM '${FROM_TARGET}' is not the bundled '${BUNDLES[0]}'"
red " 'ollama create janus -f Modelfile' cannot resolve it from a fresh clone."
FAIL=1
elif ! git -C "${ROOT}" ls-files --error-unmatch "${BUNDLES[0]}" >/dev/null 2>&1; then
red " [FAIL] bundled '${BUNDLES[0]}' is not tracked by git"
red " It exists on disk but would be absent from a fresh clone and from the"
red " published repo. Stage it: git add '${BUNDLES[0]}'"
FAIL=1
else
echo " [ ok ] FROM ${FROM_TARGET} == bundled ${BUNDLES[0]} (tracked)"
fi
fi
# ---- 6. footgun: VAR="$(cmd 2>/dev/null | filter)" silent-exit pattern -----
#
# Under `set -euo pipefail`, a direct command substitution like
# VAR="$(ollama show "${TAG}" 2>/dev/null | awk ...)"
# silently kills the script when ollama show fails: pipefail
# propagates the non-zero exit through the pipeline, set -e
# aborts on the assignment, and the explicit `[[ -z "${VAR}" ]]`
# check below it never runs. The user sees only
# make: *** [Makefile:N: <target>] Error 1
# with no diagnostic. The sibling repo (Thanatos-27B-HERETIC) shipped
# this exact bug in a script never ported here, and caught it only by
# running that script against an empty store. The fix recipe: split the
# assignment with
# if VAR="$(cmd 2>/dev/null)"; then
# VAR2="$(filter <<<"${VAR}")"
# fi
# The `2>/dev/null` is the tell — its presence says "this command
# can fail loudly, we want to suppress the noise" — which is
# exactly the case where set -e + pipefail silently kills.
# NOTE: this guard used to be a line-anchored grep. A command substitution
# split across backslash-continued lines is invisible to that, and one lived in
# the sibling's scripts/heal_hf_pull.sh (never ported here) the entire time the
# check reported green.
# Joining continuations into logical lines before matching is the whole point.
blue "[*] python: forbidden VAR=\$(... 2>/dev/null | ...) silent-exit pattern"
if python3 - <<'SILENTEXIT'
import glob, re, sys
pat = re.compile(r'^\s*[A-Za-z_]\w*="?\$\(.*2>/dev/null.*\|')
bad = []
for path in sorted(glob.glob('scripts/*.sh')):
lines = open(path, encoding='utf-8').read().splitlines()
i = 0
while i < len(lines):
start, logical = i + 1, lines[i]
while logical.rstrip().endswith('\\') and i + 1 < len(lines):
i += 1
logical = logical.rstrip()[:-1] + ' ' + lines[i].strip()
if pat.search(logical):
bad.append(f"{path}:{start}: {logical.strip()}")
i += 1
for b in bad:
print(b)
sys.exit(1 if bad else 0)
SILENTEXIT
then
echo " [ ok ] no silent-exit substitution patterns"
else
red " [FAIL] silent-exit substitution under set -e + pipefail."
red " Rewrite as 'if VAR=\$(cmd 2>/dev/null); then VAR2=\$(filter <<<\"\${VAR}\"); fi'."
red " Split it: if VAR=\$(cmd 2>/dev/null); then ...; fi - never pipe inside the"
red " same substitution, or a failing cmd exits the script with no diagnostic."
FAIL=1
fi
# ---- 7. Modelfile <-> bridge files sync -----------------------------------
#
# 'Modelfile' (consumed by 'ollama create -f Modelfile') and the root-level
# 'template' / 'system' / 'params' files (consumed by HF's Ollama bridge,
# which does NOT read Modelfile) must stay in sync. If they drift, hf.co/...
# users and 'make build' users get different behaviour.
if [[ -f "${ROOT}/Modelfile" && -f "${ROOT}/template" \
&& -f "${ROOT}/system" && -f "${ROOT}/params" ]]; then
blue "[*] python: Modelfile <-> bridge files sync"
if ! python3 "${ROOT}/scripts/check_bridge_sync.py"; then
FAIL=1
fi
else
yellow "[~] bridge files missing; skipping sync check"
SKIPPED=$((SKIPPED + 1))
fi
# ---- 8. Go template: Ollama's thinking detection + replay condition ------
#
# Ollama picks between the Go 'template' and the GGUF's embedded Jinja template
# by comparing their capabilities, and infers the Go template's "thinking" from
# one .Thinking reference. Losing it once switched Ollama's template silently
# while every render test passed; restricting it once dropped a tool-call
# chain's reasoning. check_go_template.py fails on both.
if [[ -f "${ROOT}/template" ]]; then
blue "[*] python: Go template thinking detection + replay + effort mapping"
if ! python3 "${ROOT}/scripts/check_go_template.py"; then
FAIL=1
fi
else
yellow "[~] template missing; skipping Go template check"
SKIPPED=$((SKIPPED + 1))
fi
# ---- result ----------------------------------------------------------------
echo
if (( FAIL )); then
red "[!] FAIL"
exit 1
fi
if (( SKIPPED )); then
yellow "[+] $(( CHECKS - SKIPPED )) of ${CHECKS} checks passed, ${SKIPPED} skipped"
else
green "[+] all ${CHECKS} checks passed"
fi