"""Task E: change significance narrative. Severity itself stays deterministic (app/change_detection/scoring.py) - see ARCHITECTURE.md: "the LLM narrates why a change matters; it does not decide how much it matters." This task supplies the narrative explanation and a second, independent opinion on whether the change looks real/meaningful and notification-worthy, which the notification layer (Phase 8) can use as an extra signal alongside the deterministic severity - it never overrides it. """ from __future__ import annotations from pydantic import BaseModel, Field from app.analysis.llm.base import LLMProvider from app.prompts.base import build_user_prompt SYSTEM_PROMPT = ( "You are a competitive intelligence analyst reviewing one detected change between two " "snapshots of a company's public information. Explain in plain language why this change " "would or wouldn't matter to someone monitoring this company, given their stated focus. " "Be honest about uncertainty - do not overstate a routine wording tweak as significant, " "and do not undersell a genuine signal." ) class ChangeSignificanceAssessment(BaseModel): is_real_change: bool = Field(description="Does this look like a genuine change, not noise?") is_meaningful: bool why_it_matters: str confidence: float = Field(ge=0.0, le=1.0) should_notify: bool async def assess_change_significance( llm: LLMProvider, *, company_name: str, monitoring_focus: str | None, change_type: str, change_summary: str, added_text: list[str], removed_text: list[str], deterministic_severity: str, deterministic_confidence: float, ) -> ChangeSignificanceAssessment: evidence = { "company_name": company_name, "monitoring_focus": monitoring_focus, "change_type": change_type, "change_summary": change_summary, "text_added": added_text[:20], "text_removed": removed_text[:20], "deterministic_severity": deterministic_severity, "deterministic_confidence": deterministic_confidence, } user_prompt = build_user_prompt( "Assess this detected change and explain why it does or doesn't matter.", evidence ) return await llm.generate_structured(SYSTEM_PROMPT, user_prompt, ChangeSignificanceAssessment)