"""Pure helper tests for the PM Flash decision screen.""" from __future__ import annotations from datetime import date from dashboard.provenance import filing_staleness from dashboard.verdict import ( _collect_source_types, _evidence_coverage_label, _normalize_watch_items, _select_swing_factor, ) from dashboard.signals_view import _sentiment_display_allowed from dashboard.i18n import STRINGS, t from dashboard.nav import NAV_ITEMS, VALID_KEYS def test_collect_source_types_is_recursive_deduplicated_and_ordered(): brief = { "bull_points": [{"source": "transcript, 10-Q"}], "risks_categorized": [{"evidence": {"source": "10-K"}}], "management_commentary": [{"source": "news"}, {"source": "10-Q"}], "ignored": {"source": "yfinance"}, } assert _collect_source_types(brief) == ["10-K", "10-Q", "Transcript", "News"] def test_evidence_coverage_uses_verified_counts_with_legacy_source_fallback(): brief = { "evidence_coverage": { "status": "INCOMPLETE", "verified": 7, "unverified": 2, "failed": 1, "total": 10, }, "bull_points": [{"source": "10-Q"}], } assert _evidence_coverage_label(brief) == "Incomplete · 7/10 verified · 10-Q" assert _evidence_coverage_label( {"bull_points": [{"source": "transcript"}]} ) == "Legacy / unverified · Transcript" assert _evidence_coverage_label({ "evidence_coverage": {"status": "VERIFIED", "verified": 2, "total": 3} }).startswith("Incomplete") assert _evidence_coverage_label({ "evidence_coverage": {"status": "VERIFIED", "verified": 3, "total": 3} }) == "Verified · 3/3 verified" def test_normalize_watch_items_supports_legacy_and_structured_values(): result = _normalize_watch_items([ "Q2 gross margin", { "label": "Data-center growth", "metric": "Revenue growth", "trigger": "below 30%", "event_date": "Q2 FY27", "source": "10-Q", "status": "open", }, {}, None, ]) assert result[0] == { "text": "Q2 gross margin", "metric": "", "threshold": "", "period": "", "source": "", "status": "", } assert result[1]["text"] == "Data-center growth" assert result[1]["threshold"] == "below 30%" assert result[1]["period"] == "Q2 FY27" assert len(result) == 2 def test_select_swing_factor_prefers_material_tension_stably(): brief = { "analytical_tensions": [ {"headline": "Watch first", "weight": "watch"}, {"headline": "Material first", "weight": "material"}, {"headline": "Material second", "weight": "material"}, ] } factor = _select_swing_factor(brief) assert factor is not None assert factor["kind"] == "tension" assert factor["headline"] == "Material first" def test_select_swing_factor_falls_back_to_top_tell(): brief = { "between_the_lines": [{ "observation": "Management stopped quantifying backlog", "reading": "Visibility may be weakening", "implication": "Watch conversion next quarter", "signal_type": "omission", "evidence": { "source": "transcript", "reliability": "MEDIUM", "impact": "HIGH", "evidence_snippet": "Backlog was not discussed.", }, }] } factor = _select_swing_factor(brief) assert factor is not None assert factor["kind"] == "tell" assert factor["headline"] == "Management stopped quantifying backlog" assert factor["implication"] == "Watch conversion next quarter" def test_select_swing_factor_returns_none_without_interpretive_data(): assert _select_swing_factor({}) is None def test_sentiment_display_policy_fails_closed(): assert _sentiment_display_allowed({}) is False assert _sentiment_display_allowed({"display_policy": {"sentiment_calibrated": "true"}}) is False assert _sentiment_display_allowed({"display_policy": {"sentiment_calibrated": True}}) is True def test_nav_order_is_analyst_flow(): assert VALID_KEYS == {"company", "verdict", "signals", "financials", "chat"} assert [item["key"] for item in NAV_ITEMS] == [ "company", "verdict", "signals", "financials", "chat" ] assert not any(item.get("secondary") for item in NAV_ITEMS) def test_nav_items_have_no_hardcoded_display_label(): assert not any("display_label" in item for item in NAV_ITEMS) def test_nav_i18n_labels_complete(): for item in NAV_ITEMS: labels = STRINGS[item["i18n_key"]] assert set(labels) == {"en", "fr", "es", "de"} assert t("nav_company") == "Company Overview" def test_filing_staleness_flags_old_filings(): assert filing_staleness( "2026-07-29", today=date(2026, 8, 2) ) == {"days_old": 4, "likely_newer_filing": False} assert filing_staleness( "2026-07-29", today=date(2026, 12, 15) ) == {"days_old": 139, "likely_newer_filing": True} assert filing_staleness("", today=date(2026, 8, 2)) == { "days_old": None, "likely_newer_filing": False, } assert filing_staleness("garbage", today=date(2026, 8, 2)) == { "days_old": None, "likely_newer_filing": False, } def test_partial_notice_strings_exist_in_all_languages(): for key in ( "freshness_stale_note", "partial_brief_notice_zero", "data_through_label", ): assert set(STRINGS[key]) == {"en", "fr", "es", "de"}