from __future__ import annotations from chat.db.connection import open_db from chat.db.migrate import apply_migrations from chat.eventlog.log import append_event from chat.eventlog.projector import project import chat.state.entities # registers bot_authored handler import chat.state.world # registers chat_created / guest_added / guest_removed from chat.state.world import get_chat def _bot_payload(bot_id: str, name: str) -> dict: return { "id": bot_id, "name": name, "persona": "...", "voice_samples": ["sample"], "traits": ["shy"], "backstory": "...", "initial_relationship_to_you": "coworker", "kickoff_prose": "you stay late", } def _chat_payload(**overrides) -> dict: payload = { "id": "chat_bot_a", "host_bot_id": "bot_a", "initial_time": "2026-04-26T20:00:00+00:00", "narrative_anchor": "Day 1 evening", "weather": "clear", } payload.update(overrides) return payload def test_guest_added_sets_guest_bot_id(tmp_path): db = tmp_path / "t.db" apply_migrations(db) with open_db(db) as conn: append_event(conn, kind="bot_authored", payload=_bot_payload("bot_a", "BotA")) append_event(conn, kind="bot_authored", payload=_bot_payload("bot_b", "BotB")) append_event(conn, kind="chat_created", payload=_chat_payload()) append_event(conn, kind="guest_added", payload={ "chat_id": "chat_bot_a", "guest_bot_id": "bot_b", }) project(conn) chat = get_chat(conn, "chat_bot_a") assert chat is not None assert chat["guest_bot_id"] == "bot_b" def test_guest_removed_clears_guest_bot_id(tmp_path): db = tmp_path / "t.db" apply_migrations(db) with open_db(db) as conn: append_event(conn, kind="bot_authored", payload=_bot_payload("bot_a", "BotA")) append_event(conn, kind="bot_authored", payload=_bot_payload("bot_b", "BotB")) append_event(conn, kind="chat_created", payload=_chat_payload()) append_event(conn, kind="guest_added", payload={ "chat_id": "chat_bot_a", "guest_bot_id": "bot_b", }) append_event(conn, kind="guest_removed", payload={ "chat_id": "chat_bot_a", }) project(conn) chat = get_chat(conn, "chat_bot_a") assert chat is not None assert chat["guest_bot_id"] is None def test_guest_added_idempotent_overwrite(tmp_path): db = tmp_path / "t.db" apply_migrations(db) with open_db(db) as conn: append_event(conn, kind="bot_authored", payload=_bot_payload("bot_a", "BotA")) append_event(conn, kind="bot_authored", payload=_bot_payload("bot_b", "BotB")) append_event(conn, kind="bot_authored", payload=_bot_payload("bot_c", "BotC")) append_event(conn, kind="chat_created", payload=_chat_payload()) append_event(conn, kind="guest_added", payload={ "chat_id": "chat_bot_a", "guest_bot_id": "bot_b", }) append_event(conn, kind="guest_added", payload={ "chat_id": "chat_bot_a", "guest_bot_id": "bot_c", }) project(conn) chat = get_chat(conn, "chat_bot_a") assert chat is not None assert chat["guest_bot_id"] == "bot_c"