fix(qwen): gadfly round 3 — stop guarding a duplicate, delete it
Build & push image / build-and-push (pull_request) Successful in 5s
Build & push image / test (pull_request) Canceled after 7m27s

Twelve findings, all real, and the two that matter are about the pre-flight I
added rather than about qwen.

The credential check had a false pass in the OTHER direction from round 2's: on
the GADFLY_BASE_URL override path, resolveModel builds the client with
GADFLY_API_KEY and never reads QWEN_API_KEY/KIMI_API_KEY, so treating the
provider's own key as sufficient there let a doomed run proceed. Having now
been wrong about these rules in both directions, the check no longer tries to
model both paths: it covers the REGISTRY path, whose rules it can state
exactly, and says nothing about the override path — which is hand-configured by
definition, while the registry path is the one you hit by adding a model id to
a var and forgetting the secret.

The logic moves to scripts/preflight.sh, sourced by both run.sh and the test.
The previous answer to "this test duplicates production logic" was a regex
drift-guard, and that guard compared only the provider table — not the decision
logic, which is precisely the half that carried the bug. A duplicate you guard
is still a duplicate; this deletes it, and the test now runs under `set -u`
like production does.

Also: the test that pins the shared provider slice held its own copy of the
list (now ranges the slice); endpointProviderNames had nothing tying it to the
switches it describes, which is how it shipped without "gemini" (a new test
asserts every advertised name resolves); two godoc lists had drifted; and the
"sanity" line that asserted nothing is gone.

And the repo had NO test job — `go test` and the pre-flight table both existed
and neither was ever executed by CI, which reads as coverage while providing
none. Added one (build/vet/gofmt/test/pre-flight), running alongside the image
build rather than gating it, so red is loud without standing between a push and
a rebuild.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-08-12 17:20:44 -04:00
co-authored by Claude Opus 5
parent 1d6eaa08c5
commit 67a73616e1
6 changed files with 212 additions and 119 deletions
+9 -36
View File
@@ -48,6 +48,11 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MAX_DIFF_CHARS="${MAX_DIFF_CHARS:-60000}"
# Credential pre-flight, shared verbatim with scripts/preflight_test.sh so the
# tested logic and the running logic are the same bytes.
# shellcheck source=preflight.sh
. "$SCRIPT_DIR/preflight.sh"
: "${GITEA_API:?GITEA_API required}"
: "${GITEA_TOKEN:?GITEA_TOKEN required}"
: "${PR:?PR required}"
@@ -162,42 +167,10 @@ case "$PROVIDER" in
fi
GADFLY_PROVIDER_EFF="$MODEL_PROVIDER"
# Pre-flight the credential for providers that need one. Why bother, when
# majordomo already fails closed with a 401: without this, a missing key
# surfaces as five identical per-lens agent failures that name no variable,
# and the operator has to read a stack trace to learn which secret they
# forgot to forward. GADFLY_API_KEY overrides any entry.
#
# A provider is absent from this table for one of TWO different reasons —
# do not assume the first one and add an arm:
# 1. It needs no key, or carries it in its endpoint/DSN: local ollama,
# llama-swap, foreman.
# 2. It needs a key but has more than one acceptable variable, so a
# single-variable check would skip a correctly-configured run.
# **google** is this case: it accepts GOOGLE_API_KEY *or*
# GEMINI_API_KEY. Adding `google) KEY_ENV="GOOGLE_API_KEY"` here would
# silently skip every reviewer configured with GEMINI_API_KEY. If you
# want google pre-flighted, the check has to accept either variable,
# not the table's one-name shape.
KEY_ENV=""; KEY_HINT=""
case "$GADFLY_PROVIDER_EFF" in
ollama-cloud) KEY_ENV="OLLAMA_API_KEY"; KEY_HINT="OLLAMA_CLOUD_API_KEY" ;;
qwen) KEY_ENV="QWEN_API_KEY"; KEY_HINT="QWEN_API_KEY" ;;
kimi) KEY_ENV="KIMI_API_KEY"; KEY_HINT="KIMI_API_KEY" ;;
openai|openai-compatible) KEY_ENV="OPENAI_API_KEY"; KEY_HINT="OPENAI_API_KEY" ;;
anthropic) KEY_ENV="ANTHROPIC_API_KEY"; KEY_HINT="ANTHROPIC_API_KEY" ;;
esac
# GADFLY_API_KEY substitutes for the provider's own variable ONLY on the
# endpoint-override path: resolveModel reads it after the `baseURL == ""`
# early return, so with GADFLY_BASE_URL unset the built-in reads its own
# env var and GADFLY_API_KEY is never consulted. Treating it as a universal
# substitute made a mis-set GADFLY_API_KEY pass pre-flight and then 401 five
# times anyway — the exact failure this check exists to prevent.
KEY_OK=0
[ -n "$KEY_ENV" ] && [ -n "${!KEY_ENV:-}" ] && KEY_OK=1 # indirect expansion (bash)
[ -n "${GADFLY_BASE_URL:-}" ] && [ -n "${GADFLY_API_KEY:-}" ] && KEY_OK=1
if [ -n "$KEY_ENV" ] && [ "$KEY_OK" -eq 0 ]; then
REVIEW="⚠️ No API key configured for provider \`${GADFLY_PROVIDER_EFF}\` (set \`${KEY_HINT}\`, or \`GADFLY_API_KEY\` together with \`GADFLY_BASE_URL\`); this reviewer was skipped."
# Credential pre-flight — one definition, shared with preflight_test.sh.
MISSING_KEY="$(gadfly_preflight_key "$GADFLY_PROVIDER_EFF")"
if [ -n "$MISSING_KEY" ]; then
REVIEW="⚠️ No API key configured for provider \`${GADFLY_PROVIDER_EFF}\` (set \`${MISSING_KEY}\`); this reviewer was skipped."
else
BIN="${GADFLY_BIN:-gadfly}"
if ! command -v "$BIN" >/dev/null 2>&1 && [ ! -x "$BIN" ]; then