"""Tests for the synthesized-memories service (T54). When the user jump-skips ("a week later") they are prompted "anything notable happen?" If they answer with prose, this service parses it into 1-N synthesized memories per present bot. Each memory carries ``source="synthesized"`` and ``reliability=0.7`` (the caller — T62 skip flow — applies those tags when persisting; this service just produces the structured digest). These tests cover: * The happy path: a canned classifier response parses cleanly into a populated :class:`SynthesizedDigest` with one memory. * Empty prose short-circuits before any classifier call — the mock has no canned responses, so an accidental call would raise ``IndexError``. * Classifier failure (3 bad responses, exhausting :func:`classify`'s retry budget) falls back to an empty default digest. """ from __future__ import annotations import json import pytest from chat.llm.mock import MockLLMClient from chat.services.synthesized_memories import ( SynthesizedDigest, SynthesizedMemory, synthesize_memories, ) @pytest.mark.asyncio async def test_synthesize_parses_canned_prose(): canned = json.dumps( { "memories": [ { "text": "Maya started a new pottery class.", "significance": 1, "affinity_delta": 0, "trust_delta": 0, } ] } ) mock = MockLLMClient(canned=[canned]) result = await synthesize_memories( mock, classifier_model="x", prose="we saw each other at her pottery class once", bot_name="Maya", bot_persona="warm potter, mid-30s", you_name="Sam", ) assert isinstance(result, SynthesizedDigest) assert len(result.memories) == 1 mem = result.memories[0] assert isinstance(mem, SynthesizedMemory) assert mem.text == "Maya started a new pottery class." assert mem.significance == 1 assert mem.affinity_delta == 0 assert mem.trust_delta == 0 @pytest.mark.asyncio async def test_empty_prose_returns_empty_digest(): """Empty prose short-circuits — the classifier must not be called.""" mock = MockLLMClient(canned=[]) result = await synthesize_memories( mock, classifier_model="x", prose="", bot_name="Maya", bot_persona="warm potter, mid-30s", you_name="Sam", ) assert result == SynthesizedDigest() assert result.memories == [] @pytest.mark.asyncio async def test_classifier_failure_returns_empty_default(): """Three bad responses exhaust the classifier's retry budget; the service then returns the empty default digest.""" mock = MockLLMClient(canned=["bad", "bad", "bad"]) result = await synthesize_memories( mock, classifier_model="x", prose="we saw each other at her pottery class once", bot_name="Maya", bot_persona="warm potter, mid-30s", you_name="Sam", ) assert result == SynthesizedDigest() assert result.memories == []