Files
signal-platform/tests/unit/test_fundamentals_reads.py
dennisthiessenandClaude Opus 4.8 979b4047dc fix(fundamentals): pure-core review — tie-aware percentile, null-safe reads
1. Peer percentile is now a tie-aware rank against the OTHER issuers
   ((worse + 0.5*tied)/(peers-1)): an all-equal group maps to 50 (not 100), the
   median maps to 50, a unique best to 100, a unique worst to 0.
2. Deterministic reads use the consecutive non-null suffix ending at the latest
   point (>=3 values): a null latest or an internal gap yields no read, so a read
   never reflects a period displayed as n/a.
3. Peer filtering excludes non-finite (NaN/±inf) as well as null, including an
   invalid subject.

Tests updated + added (all-equal, median rank, non-finite, latest-null history,
internal gap). 15 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 20:41:18 +02:00

64 lines
2.6 KiB
Python

"""Tests for deterministic text reads, incl. threshold boundaries."""
from __future__ import annotations
from types import SimpleNamespace
from app.services import fundamentals_reads as rd
def _hist(*values):
return [SimpleNamespace(value=v, period_end=None) for v in values]
def test_growth_read_boundaries():
assert rd.growth_read(_hist(5, 6, 8)) == "accelerating" # +2.0 exactly (>=)
assert rd.growth_read(_hist(5, 6, 7.9)) == "steady" # +1.9 < 2.0
assert rd.growth_read(_hist(10, 9, 7)) == "decelerating" # -2.0 exactly
assert rd.growth_read(_hist(5, 6)) is None # < 3 periods
def test_reads_use_latest_nonnull_suffix():
# latest displayed value is n/a -> no read (never reflect a null latest)
assert rd.growth_read(_hist(5, 6, 8, None)) is None
assert rd.margin_read(_hist(19, 20, 22, None)) is None
# an internal gap truncates the run -> fewer than 3 consecutive -> no read
assert rd.growth_read(_hist(5, 6, None, 8)) is None
# a clean 3-run after an older gap still reads
assert rd.growth_read(_hist(None, 5, 6, 8)) == "accelerating"
def test_margin_read_vs_mean_of_prior():
# prior mean = (19+20)/2 = 19.5; latest 21 -> +1.5 -> improving
assert rd.margin_read(_hist(19, 20, 21)) == "improving"
# latest exactly +1.0 over prior mean -> improving
assert rd.margin_read(_hist(20, 20, 21)) == "improving"
# within band
assert rd.margin_read(_hist(20, 20, 20.5)) == "stable"
assert rd.margin_read(_hist(21, 20)) is None # < 3 periods
def test_share_count_read():
assert rd.share_count_read(1.8) == "1.8% dilution"
assert rd.share_count_read(-2.0) == "buying back"
assert rd.share_count_read(1.0) == "flat" # boundary: not > 1.0
assert rd.share_count_read(None) is None
def test_peer_read_bands_and_polarity_phrasing():
assert rd.peer_read("operating_margin", 60) == "above peers" # boundary favorable
assert rd.peer_read("operating_margin", 40) == "below peers" # boundary adverse
assert rd.peer_read("operating_margin", 50) == "in line"
assert rd.peer_read("pe", 65) == "attractively valued"
assert rd.peer_read("pe", 30) == "priced above peers"
assert rd.peer_read("net_debt_to_ebitda", 20) == "elevated leverage"
assert rd.peer_read("pe", None) is None
def test_header_sentence_omits_missing_segments():
assert rd.header_sentence("accelerating", "stable", "priced above peers") == (
"growth accelerating · margins stable · valuation priced above peers"
)
assert rd.header_sentence(None, "improving", None) == "margins improving"
assert rd.header_sentence(None, None, None) == ""