"""Tests for the CLI startup gates (design doc §10 step 4, §8.1). ``_startup_gates`` is the shared refuse-startup path for the chat entry and ``serve``: legacy model-configuration artifacts abort with the reset guide, and a bootstrap registry aborts with ``MODEL_REGISTRY_NOT_READY`` — both with exit code 1, never a silent fall-through to an implicit model. """ from __future__ import annotations from unittest.mock import MagicMock import pytest import typer import EvoScientist.config.legacy_artifacts as legacy_artifacts import EvoScientist.model_registry.runtime as runtime_module from EvoScientist.cli.commands import _startup_gates from EvoScientist.config.legacy_artifacts import LegacyArtifactsError from EvoScientist.model_registry.errors import ( MODEL_REGISTRY_NOT_READY, ModelRegistryError, ) def test_legacy_artifacts_abort_startup(monkeypatch): monkeypatch.setattr( legacy_artifacts, "assert_no_legacy_artifacts", MagicMock(side_effect=LegacyArtifactsError("legacy providers.yaml found")), ) with pytest.raises(typer.Exit) as excinfo: _startup_gates() assert excinfo.value.exit_code == 1 def test_bootstrap_registry_aborts_startup(monkeypatch): monkeypatch.setattr( legacy_artifacts, "assert_no_legacy_artifacts", MagicMock() ) runtime = MagicMock() runtime.registry_default.side_effect = ModelRegistryError( MODEL_REGISTRY_NOT_READY, "bootstrap" ) monkeypatch.setattr(runtime_module, "get_snapshot_runtime", lambda: runtime) with pytest.raises(typer.Exit) as excinfo: _startup_gates() assert excinfo.value.exit_code == 1 def test_clean_environment_passes(monkeypatch): monkeypatch.setattr( legacy_artifacts, "assert_no_legacy_artifacts", MagicMock() ) runtime = MagicMock() runtime.registry_default.return_value = (MagicMock(), 2) monkeypatch.setattr(runtime_module, "get_snapshot_runtime", lambda: runtime) _startup_gates() # must not raise def test_non_bootstrap_registry_error_propagates(monkeypatch): """Only NOT_READY is converted to a guided exit; other errors bubble up.""" monkeypatch.setattr( legacy_artifacts, "assert_no_legacy_artifacts", MagicMock() ) runtime = MagicMock() runtime.registry_default.side_effect = ModelRegistryError( "SNAPSHOT_EXPIRED", "expired" ) monkeypatch.setattr(runtime_module, "get_snapshot_runtime", lambda: runtime) with pytest.raises(ModelRegistryError): _startup_gates()