Files
Timmy-time-dashboard/tests/sovereignty/test_sovereignty_loop.py
Perplexity Computer 4ec4558a2f
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
[perplexity] feat: Sovereignty Loop core framework — auto-crystallizer, graduation test, orchestration (#953) (#1331)
Co-authored-by: Perplexity Computer <perplexity@tower.local>
Co-committed-by: Perplexity Computer <perplexity@tower.local>
2026-03-24 02:29:39 +00:00

240 lines
8.0 KiB
Python

"""Tests for the sovereignty loop orchestrator.
Refs: #953
"""
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
@pytest.mark.unit
@pytest.mark.asyncio
class TestSovereignPerceive:
"""Tests for sovereign_perceive (perception layer)."""
async def test_cache_hit_skips_vlm(self):
"""When cache has high-confidence match, VLM is not called."""
from timmy.sovereignty.perception_cache import CacheResult
from timmy.sovereignty.sovereignty_loop import sovereign_perceive
cache = MagicMock()
cache.match.return_value = CacheResult(
confidence=0.95, state={"template_name": "health_bar"}
)
vlm = AsyncMock()
screenshot = MagicMock()
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
) as mock_emit:
result = await sovereign_perceive(screenshot, cache, vlm)
assert result == {"template_name": "health_bar"}
vlm.analyze.assert_not_called()
mock_emit.assert_called_once_with("perception_cache_hit", session_id="")
async def test_cache_miss_calls_vlm_and_crystallizes(self):
"""On cache miss, VLM is called and output is crystallized."""
from timmy.sovereignty.perception_cache import CacheResult
from timmy.sovereignty.sovereignty_loop import sovereign_perceive
cache = MagicMock()
cache.match.return_value = CacheResult(confidence=0.3, state=None)
vlm = AsyncMock()
vlm.analyze.return_value = {"items": []}
screenshot = MagicMock()
crystallize_fn = MagicMock(return_value=[])
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
):
await sovereign_perceive(screenshot, cache, vlm, crystallize_fn=crystallize_fn)
vlm.analyze.assert_called_once_with(screenshot)
crystallize_fn.assert_called_once()
@pytest.mark.unit
@pytest.mark.asyncio
class TestSovereignDecide:
"""Tests for sovereign_decide (decision layer)."""
async def test_rule_hit_skips_llm(self, tmp_path):
"""Reliable rule match bypasses the LLM."""
from timmy.sovereignty.auto_crystallizer import Rule, RuleStore
from timmy.sovereignty.sovereignty_loop import sovereign_decide
store = RuleStore(path=tmp_path / "strategy.json")
store.add(
Rule(
id="r1",
condition="health low",
action="heal",
confidence=0.9,
times_applied=5,
times_succeeded=4,
)
)
llm = AsyncMock()
context = {"health": "low", "mana": 50}
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
):
result = await sovereign_decide(context, llm, rule_store=store)
assert result["action"] == "heal"
assert result["source"] == "crystallized_rule"
llm.reason.assert_not_called()
async def test_no_rule_calls_llm_and_crystallizes(self, tmp_path):
"""Without matching rules, LLM is called and reasoning is crystallized."""
from timmy.sovereignty.auto_crystallizer import RuleStore
from timmy.sovereignty.sovereignty_loop import sovereign_decide
store = RuleStore(path=tmp_path / "strategy.json")
llm = AsyncMock()
llm.reason.return_value = {
"action": "attack",
"reasoning": "I chose attack because enemy_health was below 50%.",
}
context = {"enemy_health": 45}
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
):
result = await sovereign_decide(context, llm, rule_store=store)
assert result["action"] == "attack"
llm.reason.assert_called_once_with(context)
# The reasoning should have been crystallized (threshold pattern detected)
assert len(store) > 0
@pytest.mark.unit
@pytest.mark.asyncio
class TestSovereignNarrate:
"""Tests for sovereign_narrate (narration layer)."""
async def test_template_hit_skips_llm(self):
"""Known event type uses template without LLM."""
from timmy.sovereignty.sovereignty_loop import sovereign_narrate
template_store = {
"combat_start": "Battle begins against {enemy}!",
}
llm = AsyncMock()
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
) as mock_emit:
result = await sovereign_narrate(
{"type": "combat_start", "enemy": "Cliff Racer"},
llm=llm,
template_store=template_store,
)
assert result == "Battle begins against Cliff Racer!"
llm.narrate.assert_not_called()
mock_emit.assert_called_once_with("narration_template", session_id="")
async def test_unknown_event_calls_llm(self):
"""Unknown event type falls through to LLM and crystallizes template."""
from timmy.sovereignty.sovereignty_loop import sovereign_narrate
template_store = {}
llm = AsyncMock()
llm.narrate.return_value = "You discovered a hidden cave in the mountains."
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
):
with patch(
"timmy.sovereignty.sovereignty_loop._crystallize_narration_template"
) as mock_cryst:
result = await sovereign_narrate(
{"type": "discovery", "location": "mountains"},
llm=llm,
template_store=template_store,
)
assert result == "You discovered a hidden cave in the mountains."
llm.narrate.assert_called_once()
mock_cryst.assert_called_once()
async def test_no_llm_returns_default(self):
"""Without LLM and no template, returns a default narration."""
from timmy.sovereignty.sovereignty_loop import sovereign_narrate
with patch(
"timmy.sovereignty.sovereignty_loop.emit_sovereignty_event",
new_callable=AsyncMock,
):
result = await sovereign_narrate(
{"type": "unknown_event"},
llm=None,
template_store={},
)
assert "[unknown_event]" in result
@pytest.mark.unit
@pytest.mark.asyncio
class TestSovereigntyEnforcedDecorator:
"""Tests for the @sovereignty_enforced decorator."""
async def test_cache_hit_skips_function(self):
"""Decorator returns cached value without calling the wrapped function."""
from timmy.sovereignty.sovereignty_loop import sovereignty_enforced
call_count = 0
@sovereignty_enforced(
layer="decision",
cache_check=lambda a, kw: "cached_result",
)
async def expensive_fn():
nonlocal call_count
call_count += 1
return "expensive_result"
with patch("timmy.sovereignty.sovereignty_loop.get_metrics_store") as mock_store:
mock_store.return_value = MagicMock()
result = await expensive_fn()
assert result == "cached_result"
assert call_count == 0
async def test_cache_miss_runs_function(self):
"""Decorator calls function when cache returns None."""
from timmy.sovereignty.sovereignty_loop import sovereignty_enforced
@sovereignty_enforced(
layer="decision",
cache_check=lambda a, kw: None,
)
async def expensive_fn():
return "computed_result"
with patch("timmy.sovereignty.sovereignty_loop.get_metrics_store") as mock_store:
mock_store.return_value = MagicMock()
result = await expensive_fn()
assert result == "computed_result"