Files
bullpen/tests/test_modeltag.py
marfrit e839678130 tests: bring model_tag's contract into the repo (#118)
The module shipped without its 17-case spec, which was still sitting in the /tmp build
dir where the room ground it — a module whose contract lives somewhere else is exactly
the drift this work set out to remove. Repointed at lib/bullpen_modeltag and verified
17/17 against the shipped implementation.
2026-08-02 00:45:19 +02:00

154 lines
5.5 KiB
Python

"""Executable contract for lib/bullpen_modeltag.py (#118).
Written by @testdesigner over three rounds and one operator correction; see the commit
for what each round caught. Kept in the repo because a module without its contract is
exactly the drift this work existed to remove — it was living in a /tmp build dir.
"""
import os
import sys
sys.path.insert(0, os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "lib"))
import bullpen_modeltag as modeltag # noqa: E402
def _norm(text):
return " ".join(text.split()).lower()
# The grinder derives its target file by matching repo filenames against THIS source
# (bin/bullpen-grinder, _infer_targets), so "bullpen_modeltag.py" must appear here
# verbatim - eine Harness-Anforderung an die Suite, KEINE Anforderung
# an das Modul. Frueher stand hier eine Pruefung auf den Modulquelltext; die war nur
# erfuellbar, indem man den Dateinamen in den Docstring klebt, und genau das ist
# passiert. Ein Vertrag, der sich so bestehen laesst, misst nichts.
def test_module_is_importable():
assert callable(modeltag.model_tag)
def test_local_prefix_is_free():
msg = modeltag.model_tag("[local] qwen3.6-coding")
flat = _norm(msg)
assert "qwen3.6-coding" in flat
assert "local" in flat
assert "unknown" not in flat
def test_free_prefix_is_free():
msg = modeltag.model_tag("[free] qwen/qwen3-coder")
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
assert "free" in flat
assert "unknown" not in flat
def test_paid_prefix_is_paid():
msg = modeltag.model_tag("[$] anthropic/claude-opus-4.8")
flat = _norm(msg)
assert "anthropic/claude-opus-4.8" in flat
assert "$" in flat or "paid" in flat or "kostenpflichtig" in flat
assert "unknown" not in flat
def test_missing_prefix_tier_unknown():
msg = modeltag.model_tag("bare-model-name")
flat = _norm(msg)
assert "bare-model-name" in flat
assert "unknown" in flat
def test_message_is_single_line():
msg = modeltag.model_tag("qwen3.6-coding")
assert "\n" not in msg.strip()
def test_served_none_equals_asked_no_switch():
msg = modeltag.model_tag("[free] qwen/qwen3-coder")
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
def test_served_defaults_to_asked():
msg = modeltag.model_tag("[free] qwen/qwen3-coder", served=None)
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
def test_served_gateway_named():
msg = modeltag.model_tag("qwen3.6-coding", gateway="aperture")
flat = _norm(msg)
assert "aperture" in flat
def test_default_gateway_named():
"""Ohne gateway-Argument muss trotzdem EIN Gateway benannt werden. Welches, ist
Sache der Verdrahtung - frueher stand hier ein Flotten-Hostname fest verdrahtet,
was den lokalen Namen zum eingebauten Vorgabewert machte."""
msg = modeltag.model_tag("qwen3.6-coding")
flat = _norm(msg)
assert "gateway" in flat
def test_served_different_from_asked_visible():
msg = modeltag.model_tag("[free] qwen/qwen3-coder", served="claude-opus-4.8")
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
assert "claude-opus-4.8" in flat
assert "switch" in flat or "wechsel" in flat or "->" in flat or "instead" in flat
def test_served_with_paid_prefix_tier_reflected():
msg = modeltag.model_tag("[free] qwen/qwen3-coder", served="[$] anthropic/claude-opus-4.8")
flat = _norm(msg)
assert "anthropic/claude-opus-4.8" in flat
assert "$" in flat or "paid" in flat or "kostenpflichtig" in flat
assert "unknown" not in flat
def test_same_model_different_tier_is_visible_switch():
msg = modeltag.model_tag("[free] qwen/qwen3-coder", served="[$] qwen/qwen3-coder")
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
assert "switch" in flat or "wechsel" in flat or "->" in flat or "instead" in flat
assert "$" in flat or "paid" in flat or "kostenpflichtig" in flat
def test_switch_shows_asked_tier_not_just_asked_name():
msg = modeltag.model_tag("[free] qwen/qwen3-coder", served="[$] anthropic/claude-opus-4.8")
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
assert "free" in flat
assert "$" in flat or "paid" in flat or "kostenpflichtig" in flat
assert "switch" in flat or "wechsel" in flat or "->" in flat or "instead" in flat
def test_served_without_prefix_same_name_no_switch():
msg = modeltag.model_tag("[local] deepseek-v4-flash-dspark", served="deepseek-v4-flash-dspark")
flat = _norm(msg)
assert "deepseek-v4-flash-dspark" in flat
assert "unknown" not in flat
assert "local" in flat
assert "->" not in flat
def test_served_without_prefix_different_name_shows_switch():
msg = modeltag.model_tag("[local] deepseek-v4-flash-dspark", served="deepseek-v4-flash-other")
flat = _norm(msg)
assert "deepseek-v4-flash-dspark" in flat
assert "deepseek-v4-flash-other" in flat
assert "switch" in flat or "wechsel" in flat or "->" in flat or "instead" in flat
def test_formatting_only_difference_is_no_switch():
"""[free]x und [free] x sind dasselbe Modell auf derselben Stufe - der Unterschied
ist ein Leerzeichen hinter dem Praefix. Ein roher asked != served Vergleich macht
daraus einen Wechsel auf sich selbst (@reviewer, empirisch belegt)."""
msg = modeltag.model_tag("[free]qwen/qwen3-coder", served="[free] qwen/qwen3-coder")
flat = _norm(msg)
assert "qwen/qwen3-coder" in flat
assert "free" in flat
assert not ("switch" in flat or "wechsel" in flat or "->" in flat or "instead" in flat)