Files
EvoScientist/tests/test_snapshots.py
T

718 lines
28 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests for the run runtime snapshot service (design doc 5.2, 8.1, 8.2).
Covers creation with inherit semantics, the selection-hash idempotency
rules, bind/abort state transitions, binding validation on reads, TTLs,
adapter-spec revalidation, and credential resolution against frozen
revisions — with no in-process secret caching.
"""
from __future__ import annotations
import json
import time
import pytest
from pydantic import ValidationError
from EvoScientist.model_registry.adapters import adapter_specs, find_adapter_spec
from EvoScientist.model_registry.errors import (
ADAPTER_NOT_SUPPORTED,
MODEL_REGISTRY_NOT_READY,
RUN_CREDENTIAL_REVISION_UNAVAILABLE,
RUN_REQUEST_CONFLICT,
SNAPSHOT_ALREADY_BOUND,
SNAPSHOT_EXPIRED,
SNAPSHOT_NOT_FOUND,
UNSUPPORTED_RUNTIME_PARAMETER,
ModelRegistryError,
)
from EvoScientist.model_registry.hashing import configuration_hash
from EvoScientist.model_registry.resolver import ModelRegistryResolver
from EvoScientist.model_registry.schemas import (
CredentialWrite,
ModelRef,
RegistryV4,
SamplingOverride,
)
from EvoScientist.model_registry.snapshots import (
BOUND_RETENTION_SECONDS,
PREPARED_TTL_SECONDS,
SnapshotCreateRequest,
SnapshotService,
compute_selection_hash,
config_for_role,
public_snapshot_view,
)
from EvoScientist.model_registry.store import ModelRuntimeStore
ZHIPU_REF = ModelRef(provider_id="zhipu-glm", model_key="glm-5.2")
OLLAMA_REF = ModelRef(provider_id="local-ollama", model_key="qwen3")
SECRET = "sk-live-9876abcd"
def _model_runtime(**overrides):
payload = {
"limit_mode": "combined",
"context_window_tokens": 1048576,
"max_input_tokens": None,
"max_output_tokens": 32768,
"min_effective_input_tokens": 8192,
"fixed_system_reserve_tokens": 4096,
"fixed_tools_reserve_tokens": 8192,
"fixed_attachments_reserve_tokens": 4096,
"limits_status": "confirmed",
"limits_source": "provider",
"temperature": None,
"top_p": None,
"reasoning_effort": "auto",
"declared_capabilities": {
"tools": True,
"vision": False,
"structured_output": True,
},
}
payload.update(overrides)
return payload
def _zhipu_provider():
return {
"id": "zhipu-glm",
"name": "Zhipu GLM",
"adapter": "openai-compatible",
"base_url": "https://open.bigmodel.cn/api/paas/v4",
"auth": {"mode": "api_key", "credential_id": "zhipu-primary"},
"enabled": True,
"runtime": {
"timeout_seconds": 120,
"max_retries": 2,
"default_temperature": 0.7,
"default_top_p": 0.95,
"default_reasoning_effort": "auto",
},
"models": [
{
"key": "glm-5.2",
"name": "GLM-5.2",
"upstream_model_id": "glm-5.2",
"enabled": True,
"runtime": _model_runtime(),
}
],
}
def _ollama_provider():
return {
"id": "local-ollama",
"name": "Local Ollama",
"adapter": "ollama",
"base_url": "http://localhost:11434",
"auth": {"mode": "none", "credential_id": None},
"enabled": True,
"runtime": {"timeout_seconds": 120, "max_retries": 2},
"models": [
{
"key": "qwen3",
"name": "Qwen3",
"upstream_model_id": "qwen3",
"enabled": True,
"runtime": _model_runtime(),
}
],
}
def _registry() -> RegistryV4:
return RegistryV4.model_validate(
{
"version": 4,
"revision": 1,
"state": "bootstrap",
"defaults": {
"primary": {"provider_id": "zhipu-glm", "model_key": "glm-5.2"},
},
"providers": [_zhipu_provider(), _ollama_provider()],
}
)
def _verify(store, registry, provider_id, model_key):
provider = registry.find_provider(provider_id)
model = provider.find_model(model_key)
spec = find_adapter_spec(provider.adapter, model.upstream_model_id)
store.record_model_verification(
provider_id=provider_id,
model_key=model_key,
configuration_hash=configuration_hash(provider, model),
credential_revision=1 if provider.auth.credential_id else 0,
adapter_spec_revision=spec.spec_revision,
result="passed",
verified_capabilities={
"tools": True,
"vision": False,
"structured_output": True,
},
)
@pytest.fixture
def store(tmp_path):
return ModelRuntimeStore(config_dir=tmp_path)
@pytest.fixture
def active_store(store):
registry = store.save_registry(
expected_revision=1,
registry=_registry(),
credential_writes=[
CredentialWrite(credential_id="zhipu-primary", secret_value=SECRET)
],
)
assert registry.state == "active"
_verify(store, registry, "zhipu-glm", "glm-5.2")
_verify(store, registry, "local-ollama", "qwen3")
return store
@pytest.fixture
def service(active_store):
return SnapshotService(active_store, ModelRegistryResolver(active_store))
def _request(**overrides):
payload = {
"run_request_id": "req-1",
"thread_id": "thread-1",
"deployment_id": "local",
"model_selection_revision": 0,
"primary": None,
}
payload.update(overrides)
return SnapshotCreateRequest.model_validate(payload)
# SHA-256 of the canonical JSON
# '{"primary":null,"reasoning_effort":null,"sampling_override":null}' —
# the inherit selection with no overrides. Pinned as a literal to lock the
# wire contract.
INHERIT_SELECTION_HASH = (
"417399175386cea86c726c1bd2b833bd951066eae2e8f419b99076e9c91724a6"
)
class TestCreate:
def test_inherit_resolves_registry_defaults(self, service, active_store):
creation = service.create(_request(model_selection_revision=4))
assert creation.created is True
snapshot = creation.snapshot
assert snapshot.status == "prepared"
assert snapshot.langgraph_run_id is None
payload = snapshot.payload
assert payload.registry_revision == 2
assert payload.model_selection_revision == 4
assert payload.primary.model_ref == ZHIPU_REF
assert payload.primary.role == "primary"
def test_explicit_selection_freezes_primary(self, service):
creation = service.create(_request(primary=OLLAMA_REF))
payload = creation.snapshot.payload
assert payload.primary.model_ref == OLLAMA_REF
def test_reasoning_effort_override_freezes_into_primary(self, active_store):
# glm-5.2's model-specific contract rejects reasoning overrides, so
# add a generic-contract model on the same provider to exercise the
# override path (disabled → verify → enable, the standard flow).
store = active_store
registry = store.load_registry()
payload = registry.model_dump(mode="json")
payload["providers"][0]["models"].append(
{
"key": "glm-air",
"name": "GLM Air",
"upstream_model_id": "glm-air",
"enabled": False,
"runtime": _model_runtime(),
}
)
registry = store.save_registry(
expected_revision=registry.revision,
registry=RegistryV4.model_validate(payload),
)
_verify(store, registry, "zhipu-glm", "glm-air")
payload = registry.model_dump(mode="json")
payload["providers"][0]["models"][1]["enabled"] = True
registry = store.save_registry(
expected_revision=registry.revision,
registry=RegistryV4.model_validate(payload),
)
service = SnapshotService(store, ModelRegistryResolver(store))
creation = service.create(
_request(
primary={"provider_id": "zhipu-glm", "model_key": "glm-air"},
reasoning_effort="high",
)
)
result = creation.snapshot.payload
assert result.primary.request_options.reasoning_effort == "high"
def test_reasoning_effort_override_rejected_by_model_contract(self, service):
# glm-5.2's model-specific contract does not accept reasoning_effort.
with pytest.raises(ModelRegistryError) as excinfo:
service.create(_request(reasoning_effort="high"))
assert excinfo.value.code == UNSUPPORTED_RUNTIME_PARAMETER
def test_reasoning_effort_override_changes_selection_hash(self, service):
plain = service.create(_request())
assert compute_selection_hash(None, "low") != plain.snapshot.selection_hash
assert compute_selection_hash(None, "low") != INHERIT_SELECTION_HASH
# The hash covers the raw field, so an explicit ``auto`` differs from
# no override; both resolve to the same frozen configuration.
assert compute_selection_hash(None, "auto") != INHERIT_SELECTION_HASH
def test_reasoning_effort_override_rejected_for_unsupported_adapter(
self, service
):
with pytest.raises(ModelRegistryError) as excinfo:
service.create(_request(primary=OLLAMA_REF, reasoning_effort="high"))
assert excinfo.value.code == UNSUPPORTED_RUNTIME_PARAMETER
def test_sampling_override_freezes_and_omits_the_other(self, active_store):
# glm-5.2's model-specific contract caps temperature at 1, so add a
# generic-contract model on the same provider to exercise the
# override path (disabled → verify → enable, the standard flow).
store = active_store
registry = store.load_registry()
payload = registry.model_dump(mode="json")
payload["providers"][0]["models"].append(
{
"key": "glm-air",
"name": "GLM Air",
"upstream_model_id": "glm-air",
"enabled": False,
"runtime": _model_runtime(),
}
)
registry = store.save_registry(
expected_revision=registry.revision,
registry=RegistryV4.model_validate(payload),
)
_verify(store, registry, "zhipu-glm", "glm-air")
payload = registry.model_dump(mode="json")
payload["providers"][0]["models"][1]["enabled"] = True
registry = store.save_registry(
expected_revision=registry.revision,
registry=RegistryV4.model_validate(payload),
)
service = SnapshotService(store, ModelRegistryResolver(store))
ref = {"provider_id": "zhipu-glm", "model_key": "glm-air"}
# temperature override: top_p (provider default 0.95) is omitted.
creation = service.create(
_request(
primary=ref,
sampling_override={"kind": "temperature", "value": 1.1},
)
)
options = creation.snapshot.payload.primary.request_options
assert options.temperature == 1.1
assert options.top_p is None
# top_p override: temperature (provider default 0.7) is omitted.
creation = service.create(
_request(
run_request_id="req-2",
primary=ref,
sampling_override={"kind": "top_p", "value": 0.5},
)
)
options = creation.snapshot.payload.primary.request_options
assert options.top_p == 0.5
assert options.temperature is None
def test_sampling_override_value_range_enforced(self):
for bad in (
{"kind": "temperature", "value": -0.1},
{"kind": "temperature", "value": 2.1},
{"kind": "temperature", "value": float("nan")},
{"kind": "top_p", "value": 0},
{"kind": "top_p", "value": 1.01},
):
with pytest.raises(ValidationError):
SamplingOverride.model_validate(bad)
def test_overrides_rejected_outside_model_contract(self, service):
# glm-5.2 走模型专属契约:temperature 上限 1;1.5 通过请求模型
# (0–2) 校验但被 adapter 契约拒绝。
with pytest.raises(ModelRegistryError) as excinfo:
service.create(
_request(sampling_override={"kind": "temperature", "value": 1.5})
)
assert excinfo.value.code == UNSUPPORTED_RUNTIME_PARAMETER
def test_sampling_override_changes_selection_hash(self, service):
plain = service.create(_request())
assert compute_selection_hash(
None, None, SamplingOverride(kind="temperature", value=0.5)
) != plain.snapshot.selection_hash
assert compute_selection_hash(
None, None, SamplingOverride(kind="top_p", value=0.9)
) != plain.snapshot.selection_hash
# 未覆盖(None)与缺省一致:不传覆盖时 hash 与旧语义相同。
assert compute_selection_hash(None, None, None) == (
plain.snapshot.selection_hash
)
def test_bootstrap_registry_is_not_ready(self, store):
service = SnapshotService(store, ModelRegistryResolver(store))
with pytest.raises(ModelRegistryError) as excinfo:
service.create(_request())
assert excinfo.value.code == MODEL_REGISTRY_NOT_READY
assert excinfo.value.http_status == 422
def test_selection_hash_uses_pre_resolution_semantics(self, service):
creation = service.create(_request())
snapshot = creation.snapshot
# The inherit hash is pinned to a known literal (computed offline
# from the canonical JSON) so the contract can't drift together with
# a reimplemented expectation.
assert snapshot.selection_hash == INHERIT_SELECTION_HASH
assert compute_selection_hash(None) == INHERIT_SELECTION_HASH
# An explicit selection equal to the default still hashes differently.
assert compute_selection_hash(ZHIPU_REF) != INHERIT_SELECTION_HASH
def test_selection_hash_ignores_selection_revision(self, service):
first = service.create(_request(model_selection_revision=4))
second = service.create(_request(model_selection_revision=9))
assert second.created is False
assert second.snapshot.snapshot_id == first.snapshot.snapshot_id
def test_idempotent_same_selection_returns_original(self, service):
first = service.create(_request())
second = service.create(_request())
assert first.created is True
assert second.created is False
assert second.snapshot.snapshot_id == first.snapshot.snapshot_id
def test_conflicting_selection_same_triplet(self, service):
service.create(_request())
with pytest.raises(ModelRegistryError) as excinfo:
service.create(_request(primary=ZHIPU_REF))
assert excinfo.value.code == RUN_REQUEST_CONFLICT
assert excinfo.value.http_status == 409
def test_recreate_after_expired(self, service, active_store):
first = service.create(_request())
active_store.set_run_snapshot_status(first.snapshot.snapshot_id, "expired")
second = service.create(_request())
assert second.created is True
assert second.snapshot.snapshot_id != first.snapshot.snapshot_id
def test_recreate_after_aborted(self, service):
first = service.create(_request())
service.abort(first.snapshot.snapshot_id)
second = service.create(_request())
assert second.created is True
assert second.snapshot.snapshot_id != first.snapshot.snapshot_id
def test_payload_freezes_credential_revision_without_secret(self, service):
creation = service.create(_request())
payload = creation.snapshot.payload
assert payload.primary.auth_ref.credential_id == "zhipu-primary"
assert payload.primary.auth_ref.credential_revision == 1
encoded = json.dumps(payload.model_dump(mode="json"))
assert SECRET not in encoded
def test_prepared_ttl_is_fifteen_minutes(self, service):
creation = service.create(_request())
snapshot = creation.snapshot
assert PREPARED_TTL_SECONDS == 15 * 60
delta = snapshot.expires_at - snapshot.created_at
assert PREPARED_TTL_SECONDS - 1 <= delta <= PREPARED_TTL_SECONDS + 1
class TestBind:
def test_bind_once(self, service):
creation = service.create(_request())
before = int(time.time())
bound = service.bind(creation.snapshot.snapshot_id, "lg-run-1")
assert bound.status == "bound"
assert bound.langgraph_run_id == "lg-run-1"
assert BOUND_RETENTION_SECONDS == 24 * 60 * 60
delta = bound.expires_at - before
assert BOUND_RETENTION_SECONDS - 1 <= delta <= BOUND_RETENTION_SECONDS + 1
def test_bind_same_run_id_is_idempotent(self, service):
creation = service.create(_request())
service.bind(creation.snapshot.snapshot_id, "lg-run-1")
again = service.bind(creation.snapshot.snapshot_id, "lg-run-1")
assert again.status == "bound"
assert again.langgraph_run_id == "lg-run-1"
def test_bind_different_run_id_conflicts(self, service):
creation = service.create(_request())
service.bind(creation.snapshot.snapshot_id, "lg-run-1")
with pytest.raises(ModelRegistryError) as excinfo:
service.bind(creation.snapshot.snapshot_id, "lg-run-2")
assert excinfo.value.code == SNAPSHOT_ALREADY_BOUND
def test_bind_expired_snapshot(self, service, active_store):
creation = service.create(_request())
active_store.set_run_snapshot_status(creation.snapshot.snapshot_id, "expired")
with pytest.raises(ModelRegistryError) as excinfo:
service.bind(creation.snapshot.snapshot_id, "lg-run-1")
assert excinfo.value.code == SNAPSHOT_EXPIRED
def test_bind_aborted_snapshot(self, service):
creation = service.create(_request())
service.abort(creation.snapshot.snapshot_id)
with pytest.raises(ModelRegistryError) as excinfo:
service.bind(creation.snapshot.snapshot_id, "lg-run-1")
assert excinfo.value.code == SNAPSHOT_EXPIRED
def test_bind_unknown_snapshot(self, service):
with pytest.raises(ModelRegistryError) as excinfo:
service.bind("snap-missing", "lg-run-1")
assert excinfo.value.code == SNAPSHOT_NOT_FOUND
assert excinfo.value.http_status == 404
class TestAbort:
def test_abort_prepared(self, service, active_store):
creation = service.create(_request())
service.abort(creation.snapshot.snapshot_id)
row = active_store.get_run_snapshot(creation.snapshot.snapshot_id)
assert row["status"] == "aborted"
def test_abort_is_idempotent(self, service):
creation = service.create(_request())
service.abort(creation.snapshot.snapshot_id)
service.abort(creation.snapshot.snapshot_id)
def test_abort_bound_conflicts(self, service):
creation = service.create(_request())
service.bind(creation.snapshot.snapshot_id, "lg-run-1")
with pytest.raises(ModelRegistryError) as excinfo:
service.abort(creation.snapshot.snapshot_id)
assert excinfo.value.code == SNAPSHOT_ALREADY_BOUND
def test_abort_expired(self, service, active_store):
creation = service.create(_request())
active_store.set_run_snapshot_status(creation.snapshot.snapshot_id, "expired")
with pytest.raises(ModelRegistryError) as excinfo:
service.abort(creation.snapshot.snapshot_id)
assert excinfo.value.code == SNAPSHOT_EXPIRED
def test_abort_unknown(self, service):
with pytest.raises(ModelRegistryError) as excinfo:
service.abort("snap-missing")
assert excinfo.value.code == SNAPSHOT_NOT_FOUND
def test_abort_run_snapshot_store_update_is_conditional(
self, service, active_store
):
creation = service.create(_request())
snapshot_id = creation.snapshot.snapshot_id
# The store-level abort only fires on prepared rows.
assert active_store.abort_run_snapshot(snapshot_id) is True
assert active_store.abort_run_snapshot(snapshot_id) is False
bound = service.create(_request(run_request_id="req-2"))
service.bind(bound.snapshot.snapshot_id, "lg-run-7")
assert active_store.abort_run_snapshot(bound.snapshot.snapshot_id) is False
row = active_store.get_run_snapshot(bound.snapshot.snapshot_id)
assert row["status"] == "bound"
assert row["langgraph_run_id"] == "lg-run-7"
def test_abort_losing_bind_race_keeps_bound_state(
self, service, active_store, monkeypatch
):
"""A bind committing between abort's read and write must win.
The abort read observes ``prepared``; a concurrent bind then commits;
the abort write must fail its conditional update, re-read, and raise
``SNAPSHOT_ALREADY_BOUND`` instead of clobbering the bound row (and
its ``langgraph_run_id``) back to ``aborted``.
"""
creation = service.create(_request())
snapshot_id = creation.snapshot.snapshot_id
original_get = active_store.get_run_snapshot
raced = False
def get_with_concurrent_bind(sid):
nonlocal raced
row = original_get(sid)
if not raced and row is not None and row["status"] == "prepared":
raced = True
assert active_store.bind_run_snapshot(
sid,
langgraph_run_id="lg-run-9",
expires_at=row["expires_at"] + 100,
)
return row
monkeypatch.setattr(active_store, "get_run_snapshot", get_with_concurrent_bind)
with pytest.raises(ModelRegistryError) as excinfo:
service.abort(snapshot_id)
assert raced is True
assert excinfo.value.code == SNAPSHOT_ALREADY_BOUND
row = active_store.get_run_snapshot(snapshot_id)
assert row["status"] == "bound"
assert row["langgraph_run_id"] == "lg-run-9"
class TestGet:
def test_get_returns_snapshot(self, service):
creation = service.create(_request())
snapshot = service.get(
creation.snapshot.snapshot_id,
deployment_id="local",
thread_id="thread-1",
)
assert snapshot.snapshot_id == creation.snapshot.snapshot_id
assert snapshot.payload.primary.model_ref == ZHIPU_REF
def test_get_rejects_foreign_thread(self, service):
creation = service.create(_request())
with pytest.raises(ModelRegistryError) as excinfo:
service.get(
creation.snapshot.snapshot_id,
deployment_id="local",
thread_id="thread-2",
)
assert excinfo.value.code == SNAPSHOT_NOT_FOUND
def test_get_rejects_foreign_deployment(self, service):
creation = service.create(_request())
with pytest.raises(ModelRegistryError) as excinfo:
service.get(
creation.snapshot.snapshot_id,
deployment_id="other",
thread_id="thread-1",
)
assert excinfo.value.code == SNAPSHOT_NOT_FOUND
def test_get_expired_fails(self, service, active_store):
creation = service.create(_request())
active_store.set_run_snapshot_status(creation.snapshot.snapshot_id, "expired")
with pytest.raises(ModelRegistryError) as excinfo:
service.get(
creation.snapshot.snapshot_id,
deployment_id="local",
thread_id="thread-1",
)
assert excinfo.value.code == SNAPSHOT_EXPIRED
def test_get_fails_when_frozen_spec_revision_removed(self, active_store):
service = SnapshotService(active_store, ModelRegistryResolver(active_store))
creation = service.create(_request())
# Simulate a contract upgrade that removed spec_revision 1 entirely.
bumped = tuple(
spec.model_copy(update={"spec_revision": 2}) for spec in adapter_specs()
)
stale_service = SnapshotService(
active_store, ModelRegistryResolver(active_store, specs=bumped)
)
with pytest.raises(ModelRegistryError) as excinfo:
stale_service.get(
creation.snapshot.snapshot_id,
deployment_id="local",
thread_id="thread-1",
)
assert excinfo.value.code == ADAPTER_NOT_SUPPORTED
class TestCleanupExpired:
def _insert(self, store, snapshot_id, *, status, expires_at):
store.insert_run_snapshot(
snapshot_id=snapshot_id,
deployment_id="local",
thread_id="thread-1",
run_request_id=f"req-{snapshot_id}",
selection_hash="b" * 64,
payload={},
expires_at=expires_at,
status=status,
langgraph_run_id="lg-run" if status == "bound" else None,
)
def test_cleanup_marks_due_snapshots_expired(self, store):
service = SnapshotService(store, ModelRegistryResolver(store))
now = 1_000_000
self._insert(store, "snap-p-old", status="prepared", expires_at=now - 1)
self._insert(store, "snap-b-old", status="bound", expires_at=now - 1)
self._insert(store, "snap-p-new", status="prepared", expires_at=now + 900)
expired = service.cleanup_expired(now)
assert sorted(expired) == ["snap-b-old", "snap-p-old"]
assert store.get_run_snapshot("snap-p-old")["status"] == "expired"
assert store.get_run_snapshot("snap-b-old")["status"] == "expired"
assert store.get_run_snapshot("snap-p-new")["status"] == "prepared"
class TestRoleMapping:
def test_primary_role_maps_to_frozen_primary(self, service):
snapshot = service.create(_request()).snapshot
assert config_for_role(snapshot, "primary").model_ref == ZHIPU_REF
def test_unknown_role_rejected(self, service):
snapshot = service.create(_request()).snapshot
with pytest.raises(ValueError, match="role"):
config_for_role(snapshot, "planner")
class TestSnapshotCredentials:
def test_resolves_frozen_revision(self, service):
snapshot = service.create(_request()).snapshot
assert service.resolve_snapshot_credential(snapshot, "primary") == SECRET
def test_rotation_keeps_frozen_revision(self, service, active_store):
snapshot = service.create(_request()).snapshot
active_store.write_credential_version("zhipu-primary", "sk-rotated-2222")
assert service.resolve_snapshot_credential(snapshot, "primary") == SECRET
def test_destroyed_revision_fails_loudly(self, service, active_store):
snapshot = service.create(_request()).snapshot
active_store.retire_credential_version("zhipu-primary", 1)
with pytest.raises(ModelRegistryError) as excinfo:
service.resolve_snapshot_credential(snapshot, "primary")
assert excinfo.value.code == RUN_CREDENTIAL_REVISION_UNAVAILABLE
def test_no_in_process_secret_cache(self, service, active_store):
snapshot = service.create(_request()).snapshot
# A brand-new store/service pair on the same database still resolves.
fresh_store = ModelRuntimeStore(config_dir=active_store.config_dir)
fresh_service = SnapshotService(fresh_store, ModelRegistryResolver(fresh_store))
assert fresh_service.resolve_snapshot_credential(snapshot, "primary") == SECRET
def test_mode_none_returns_empty_string(self, service):
snapshot = service.create(_request(primary=OLLAMA_REF)).snapshot
assert service.resolve_snapshot_credential(snapshot, "primary") == ""
class TestPublicView:
def test_matches_section_8_2_shape(self, service):
snapshot = service.create(_request()).snapshot
view = public_snapshot_view(snapshot)
assert view["snapshot_id"] == snapshot.snapshot_id
assert view["registry_revision"] == 2
primary = view["primary"]
assert primary["provider_id"] == "zhipu-glm"
assert primary["model_key"] == "glm-5.2"
assert primary["adapter_spec_revision"] == 1
assert primary["runtime"] == {
"max_output_tokens": 32768,
"temperature": 0.7,
"top_p": 0.95,
"reasoning_effort": "auto",
"timeout_seconds": 120,
"max_retries": 2,
}
def test_never_contains_secret_or_base_url(self, service):
snapshot = service.create(_request()).snapshot
encoded = json.dumps(public_snapshot_view(snapshot))
assert SECRET not in encoded
assert "open.bigmodel.cn" not in encoded
assert "localhost" not in encoded