"""build_user_prompt is the heart of the AI log — verify shape.""" from __future__ import annotations import pytest pytest.importorskip("httpx") pytest.importorskip("tenacity") pytest.importorskip("pydantic_settings") from datetime import datetime, timezone from app.services.openrouter import SYSTEM_PROMPT, build_user_prompt def test_system_prompt_has_voice_anchors(): # Tripwires for prompt regressions. for marker in ["Lens", "Discipline", "Stance", "watch list", "System temperature"]: assert marker in SYSTEM_PROMPT def test_system_prompt_has_educational_stance(): """Phase 2 voice pivot (PROMPT_VERSION 6): markets framed as macro causality, not technical patterns or gambling. Tripwire so silent edits can't quietly drop the educational stance.""" for marker in [ "No technical analysis", "Head-and-shoulders", "gambling", "regime", ]: assert marker in SYSTEM_PROMPT, f"missing stance marker: {marker!r}" def test_pro_tone_falls_back_to_intermediate(): """PRO was removed in PROMPT_VERSION 6 (audience pivot to young investors). Legacy callers that still pass PRO should get the INTERMEDIATE prompt rather than a KeyError.""" from app.services.openrouter import build_system_prompt pro = build_system_prompt("PRO", "SPECULATIVE") inter = build_system_prompt("INTERMEDIATE", "SPECULATIVE") assert pro == inter def test_build_user_prompt_includes_anchor_and_reference(): out = build_user_prompt( today=datetime(2026, 5, 15, tzinfo=timezone.utc), anchor="2026-03-04", quotes_by_group={"equity": [{"symbol": "^GSPC", "label": "S&P 500"}]}, headlines_by_bucket={"world": [{"when": "2026-05-15T10:00", "source": "BBC", "title": "x"}]}, reference_line="S&P 7501 · VIX 18", ) assert "2026-05-15" in out assert "Anchor reference date: 2026-03-04" in out assert "S&P 7501" in out assert "WORLD" in out assert "^GSPC" in out def test_build_user_prompt_omits_empty_buckets(): out = build_user_prompt( today=datetime(2026, 5, 15, tzinfo=timezone.utc), anchor=None, quotes_by_group={}, headlines_by_bucket={"world": [], "tech": [{"when": "2026-05-15T10:00", "source": "X", "title": "AI thing"}]}, ) assert "TECH" in out assert "WORLD" not in out