File size: 5,678 Bytes
7880373 b419b7b 7880373 8727e56 7880373 8727e56 7880373 8727e56 b419b7b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | """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"}
|