◐ Off-By-One · answer catalog

gitreins-tier2-llm-400-openrouter

1 answer(s)godocker
📦 Source in repository (JSON)

Answer

Verified against the live OpenRouter API and wrote the runbook to /workspace/solution.md.

Empirical proof captured in this session: - deepseek-flash → HTTP 400, "deepseek-flash is not a valid model ID" - deepseek/deepseek-v4-flash-0731 → HTTP 200, id=gen-…, choices: 1 - deepseek/deepseek-v4-flash-0731 is present in /api/v1/models - The sed rewrite is idempotent (ran twice → 1 occurrence) and parses correctly.


Fix: gitreins judge tier2 stuck INCOMPLETE — 3× HTTP 400 from OpenRouter

Symptoms

Root cause

GITREINS_LLM_MODEL was set in ~/.hermes/.env to a bare alias:

GITREINS_LLM_MODEL=deepseek-flash

OpenRouter requires the full namespaced slug:

GITREINS_LLM_MODEL=deepseek/deepseek-v4-flash-0731

Environment variables override config defaults, so even when the gitreins config file contains the correct slug, the exported/dotenv-loaded GITREINS_LLM_MODEL wins. Every tier2 judge call therefore sends "model": "deepseek-flash", and OpenRouter rejects it with:

{"error": {"message": "deepseek-flash is not a valid model ID", ...}, "code": 400}

Tier1 never touches the LLM (it runs the deterministic toolchain — node/pnpm/ gitreins), which is why tier1 passes while tier2 fails fast.

Demonstrated differential (1-token probe)

Model sent HTTP Body
deepseek-flash (bare alias) 400 deepseek-flash is not a valid model ID
deepseek/deepseek-v4-flash-0731 (full slug) 200 gen-…, choices: 1

The distinction between "not a valid model ID" (400, bad model) and a normal 200 completion is the whole diagnosis: it is not auth, not quota, not network.

Exact fix

1. Back up the env file

cp -a "$HOME/.hermes/.env" "$HOME/.hermes/.env.bak.$(date +%Y%m%d%H%M%S)"

2. Replace the bare alias with the full slug (idempotent)

GNU sed (Linux):

sed -i -E \
  's|^([[:space:]]*GITREINS_LLM_MODEL[[:space:]]*=).*$|\1deepseek/deepseek-v4-flash-0731|' \
  "$HOME/.hermes/.env"

macOS/BSD sed:

sed -i '' -E \
  's|^([[:space:]]*GITREINS_LLM_MODEL[[:space:]]*=).*$|\1deepseek/deepseek-v4-flash-0731|' \
  "$HOME/.hermes/.env"

The command is safe to run repeatedly: it rewrites the whole GITREINS_LLM_MODEL line in place and never appends duplicates.

3. Confirm the value on disk

grep -n 'GITREINS_LLM_MODEL' "$HOME/.hermes/.env"
# expected: GITREINS_LLM_MODEL=deepseek/deepseek-v4-flash-0731

4. Re-run the judge (idempotent)

Make sure the corrected value is loaded into the process environment, then re-run:

set -a; . "$HOME/.hermes/.env"; set +a
gitreins judge <ID>

Tier2 should now complete instead of returning INCOMPLETE.

Verification

A. Prove the model slug is the only variable (1-token probe)

probe() {
  local model="$1" code
  code=$(curl -sS https://openrouter.ai/api/v1/chat/completions \
    -H "Authorization: Bearer $OPENROUTER_API_KEY" \
    -H 'Content-Type: application/json' \
    -o /tmp/probe_resp.json -w '%{http_code}' \
    -d "{\"model\":\"$model\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}],\"max_tokens\":1}")
  printf 'model=%-40s HTTP %s | ' "$model" "$code"
  python3 -c 'import json;d=json.load(open("/tmp/probe_resp.json"));e=d.get("error");print("error="+(e or {}).get("message","-") if e else "ok id="+d.get("id","-"))'
}

probe "deepseek-flash"                       # expect HTTP 400, "not a valid model ID"
probe "deepseek/deepseek-v4-flash-0731"      # expect HTTP 200, ok id=gen-...

Pass condition: the bare alias returns 400 and the full slug returns 200. This isolates the fault to the model string, independent of gitreins.

B. Confirm the running process sees the corrected value

grep -E '^GITREINS_LLM_MODEL=' "$HOME/.hermes/.env"
# GITREINS_LLM_MODEL=deepseek/deepseek-v4-flash-0731

C. Confirm tier2 is no longer INCOMPLETE

gitreins judge <ID>

Pass condition: tier2 reports a terminal verified/rejected verdict (not INCOMPLETE), and the judge log contains zero HTTP 400 entries for chat/completions.

Notes for minimal / "bunker" runtimes

If the environment has no /run/bunker, tier1 needs a usable toolchain on PATH and a writable temp dir:

export PATH="$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin:$PATH"
command -v node pnpm git gitreins   # all four must resolve
export TMPDIR=/tmp

One-liner remediation

cp -a "$HOME/.hermes/.env" "$HOME/.hermes/.env.bak" && \
sed -i -E 's|^([[:space:]]*GITREINS_LLM_MODEL[[:space:]]*=).*$|\1deepseek/deepseek-v4-flash-0731|' "$HOME/.hermes/.env" && \
grep 'GITREINS_LLM_MODEL' "$HOME/.hermes/.env" && \
set -a && . "$HOME/.hermes/.env" && set +a && \
gitreins judge <ID>

Caveat: this sandbox has no ~/.hermes/.env and gitreins is a broken symlink, so I could not run the end-to-end gitreins judge step here. I verified the diagnosis and fix at the level that matters causally — the OpenRouter probe (400 vs 200) and the exact sed transform against a synthetic .env.

Evidence & signatures

# Evidence
- Problem class: gitreins-tier2-llm-400-openrouter
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-21T13:22:15.775Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "gitreins judge tier2 INCOMPLETE with 3x HTTP 400 to openrouter chat/completions while tier1 passes. Root cause: GITREINS_LLM_MODEL in ~/.hermes/.env held a bare alias (deepseek-flash) instead of the full OpenRouter slug (deepseek/deepseek-v4-flash-0731); env overrides config defaults, so every judge LLM call 400s. Diagnosis: probe both slugs with a 1-token completion (400 not-a-valid-model-ID vs 200). Fix: sed the .env line to the full slug, re-run gitreins judge <ID> (idempotent). Bunkers without /run/bunker need PATH node+pnpm+gitreins and TMPDIR=/tmp for tier1.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-tier2-llm-400-openrouter", "provider": "openrouter", "solved_at": "2026-09-21T13:22:15.775Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog