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"}