File size: 4,850 Bytes
0810902
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12cd919
0810902
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
"""Configuration and loading contracts.

These assertions encode facts established in reports/repository_audit.md. If one
of them starts failing, either the checkpoint changed or the audit is stale —
both are worth knowing.
"""

from __future__ import annotations

import json
from pathlib import Path

import pytest

# --------------------------------------------------------------------------- #
# fast tier: no weights required
# --------------------------------------------------------------------------- #


def test_architecture_is_qwen3_5_conditional_generation(model_config: dict) -> None:
    assert model_config["architectures"] == ["Qwen3_5ForConditionalGeneration"]
    assert model_config["model_type"] == "qwen3_5"


def test_language_config_matches_audit(model_config: dict) -> None:
    text = model_config["text_config"]
    assert text["hidden_size"] == 4096
    assert text["num_hidden_layers"] == 32
    assert text["num_attention_heads"] == 16
    assert text["num_key_value_heads"] == 4
    assert text["head_dim"] == 256
    assert text["vocab_size"] == 248320
    assert text["max_position_embeddings"] == 262144


def test_layer_stack_is_hybrid(model_config: dict) -> None:
    """24 linear-attention layers, 8 full-attention, every 4th layer."""
    layers = model_config["text_config"]["layer_types"]
    assert len(layers) == 32
    assert layers.count("linear_attention") == 24
    assert layers.count("full_attention") == 8
    interval = model_config["text_config"]["full_attention_interval"]
    for index, kind in enumerate(layers):
        expected = "full_attention" if (index + 1) % interval == 0 else "linear_attention"
        assert kind == expected, f"layer {index} is {kind}, expected {expected}"


def test_vision_tower_projects_into_language_space(model_config: dict) -> None:
    vision = model_config["vision_config"]
    assert vision["depth"] == 27
    assert vision["hidden_size"] == 1152
    assert vision["patch_size"] == 16
    assert vision["out_hidden_size"] == model_config["text_config"]["hidden_size"]


def test_rope_is_native_not_scaled(model_config: dict) -> None:
    """The 262K context is architectural; no scaling factor should be present."""
    rope = model_config["text_config"]["rope_parameters"]
    assert rope["rope_type"] == "default"
    assert "factor" not in rope
    assert rope["mrope_section"] == [11, 11, 10]
    assert rope["mrope_interleaved"] is True


def test_no_remote_code_required(model_config: dict, config_dir: Path) -> None:
    assert "auto_map" not in model_config
    assert not list(config_dir.glob("*.py"))


def test_config_contains_no_absolute_paths(model_config: dict) -> None:
    """Regression guard for the absolute-path leak found in the original release."""
    blob = json.dumps(model_config)
    for marker in ("/mnt/", "/home/", "C:\\", "C:/", "\\Users\\"):
        assert marker not in blob, f"config.json leaks a local path containing {marker!r}"


def test_generation_config_defaults_to_greedy(config_dir: Path) -> None:
    path = config_dir / "generation_config.json"
    if not path.is_file():
        pytest.skip("generation_config.json not present")
    generation = json.loads(path.read_text(encoding="utf-8"))
    assert not generation.get("do_sample", False)
    assert "temperature" not in generation


def test_tokenizer_declares_vision_tokens(config_dir: Path) -> None:
    tokenizer = json.loads((config_dir / "tokenizer_config.json").read_text(encoding="utf-8"))
    special = tokenizer["model_specific_special_tokens"]
    assert special["image_token"] == "<|image_pad|>"
    assert special["vision_bos_token"] == "<|vision_start|>"
    assert tokenizer["padding_side"] == "left", "batched generation needs left padding"


def test_chat_template_present_and_handles_images(config_dir: Path) -> None:
    template = config_dir / "chat_template.jinja"
    assert template.is_file()
    body = template.read_text(encoding="utf-8")
    assert "<|vision_start|>" in body
    assert "<|image_pad|>" in body
    assert "add_generation_prompt" in body


# --------------------------------------------------------------------------- #
# slow tier: needs weights + GPU
# --------------------------------------------------------------------------- #


@pytest.mark.slow
def test_model_loads_without_trust_remote_code(loaded_model) -> None:
    model, _ = loaded_model
    assert type(model).__name__ == "Qwen3_5ForConditionalGeneration"


@pytest.mark.slow
def test_processor_loads(loaded_model) -> None:
    _, processor = loaded_model
    assert processor.__class__.__name__.startswith("Qwen3VL")


@pytest.mark.slow
def test_vision_tower_is_present_in_weights(loaded_model) -> None:
    model, _ = loaded_model
    vision_parameters = sum(p.numel() for p in model.model.visual.parameters())
    assert vision_parameters > 400_000_000