"""Regression tests for GraphMemory report-context formatting. Incident: job_829f9c99 - when the novelty agent's LLM call failed under the Groq quota storm it stored novelty_score=None, and get_novelty_context raised "unsupported format string passed to NoneType.__format__", crashing the report agent and stopping the whole pipeline (no PDF, no email). """ from unittest.mock import MagicMock import pytest from memory.graph_memory import GraphMemory @pytest.fixture def graph_memory(mock_neo4j, mock_embedder): return GraphMemory(neo4j=mock_neo4j, embedder=mock_embedder) def test_novelty_context_with_none_score(graph_memory): """novelty_score=None (LLM failure) must render as 0.0, not crash.""" graph_memory.neo4j.run.return_value = [ {"novelty_score": None, "verdict": "UNKNOWN", "problem_statement": "ps", "rationale": "r", "similar_works": []} ] ctx = graph_memory.get_novelty_context("doc_x") assert "Novelty score: 0.0/10 (UNKNOWN)" in ctx def test_novelty_context_with_real_score(graph_memory): graph_memory.neo4j.run.return_value = [ {"novelty_score": 7.3, "verdict": "NOVEL", "problem_statement": "ps", "rationale": "r", "similar_works": []} ] ctx = graph_memory.get_novelty_context("doc_x") assert "Novelty score: 7.3/10 (NOVEL)" in ctx def test_counterfactuality_context_with_none_scores(graph_memory): """None overall_score/cf_score (LLM failure) must not crash the report.""" graph_memory.neo4j.run.side_effect = [ [{"overall_score": None, "common_type": "factual", "concerns": [], "strengths": [], "summary": "s"}], [{"text": "c1", "cf_type": "unsupported", "cf_score": None}], ] ctx = graph_memory.get_counterfactuality_context("doc_x") assert "Overall counterfactuality score: 0.00/1.0" in ctx assert "(score=0.00) c1" in ctx