@@ -51,3 +51,106 @@ def test_extract_source_records_outputs_confidence_by_source_type(tmp_path: Path
5151 assert by_symbol ["EVT3" ]["confidence" ] == "low"
5252 assert by_symbol ["EVT4" ]["event_type" ] == "procurement"
5353 assert output .exists ()
54+
55+
56+ def test_entity_evidence_prefers_strongest_alias_match (tmp_path : Path ) -> None :
57+ raw_items = tmp_path / "source_items.csv"
58+ raw_items .write_text (
59+ "item_id,published_at,source_type,source_url,author,text\n "
60+ "mixed,2026-04-01T00:00:00Z,government_procurement,https://www.govinfo.gov/example,Agency,"
61+ 'Funding for Current Company supports cybersecurity.\n ' ,
62+ encoding = "utf-8" ,
63+ )
64+ aliases = tmp_path / "aliases.csv"
65+ aliases .write_text (
66+ "symbol,name,aliases\n TEST,Current Company,cybersecurity|Current Company\n " ,
67+ encoding = "utf-8" ,
68+ )
69+
70+ rows = extract_source_records (raw_items , aliases , tmp_path / "events.csv" )
71+
72+ assert rows [0 ]["entity_match_type" ] == "direct_beneficiary"
73+ assert rows [0 ]["match_evidence" ] == "Current Company"
74+ assert rows [0 ]["relationship_type" ] == "direct_beneficiary"
75+
76+
77+ def test_generic_context_does_not_become_company_evidence (tmp_path : Path ) -> None :
78+ raw_items = tmp_path / "source_items.csv"
79+ raw_items .write_text (
80+ "item_id,published_at,source_type,source_url,author,text\n "
81+ "nist,2026-04-01T00:00:00Z,government_policy,https://www.nist.gov/example,NIST,"
82+ 'NIST guidance discusses nuclear reactor safety and tokenization.\n ' ,
83+ encoding = "utf-8" ,
84+ )
85+ aliases = tmp_path / "aliases.csv"
86+ aliases .write_text (
87+ "symbol,name,aliases\n OKLO,Oklo,Oklo|OKLO|nuclear reactor\n "
88+ "COIN,Coinbase,Coinbase|COIN|tokenization\n " ,
89+ encoding = "utf-8" ,
90+ )
91+
92+ rows = extract_source_records (raw_items , aliases , tmp_path / "events.csv" )
93+
94+ assert {row ["symbol" ] for row in rows } == {"OKLO" , "COIN" }
95+ assert {row ["entity_match_type" ] for row in rows } == {"industry_context" }
96+
97+
98+ def test_canonical_name_is_trusted_only_in_issuer_release (tmp_path : Path ) -> None :
99+ raw_items = tmp_path / "source_items.csv"
100+ raw_items .write_text (
101+ "item_id,published_at,source_type,source_url,author,text\n "
102+ "issuer,2026-04-01T00:00:00Z,issuer_release,https://example.com/release,Issuer,"
103+ 'Strategy announced a new product.\n '
104+ "policy,2026-04-01T00:00:00Z,government_policy,https://www.nist.gov/example,NIST,"
105+ 'Strategy guidance was published.\n ' ,
106+ encoding = "utf-8" ,
107+ )
108+ aliases = tmp_path / "aliases.csv"
109+ aliases .write_text ("symbol,name,aliases\n MSTR,Strategy,Strategy|MSTR\n " , encoding = "utf-8" )
110+
111+ rows = extract_source_records (raw_items , aliases , tmp_path / "events.csv" )
112+ by_id = {row ["event_id" ]: row for row in rows }
113+
114+ assert by_id ["official-issuer-release-issuer-mstr" ]["entity_match_type" ] == "issuer"
115+ assert by_id ["official-government-policy-policy-mstr" ]["entity_match_type" ] == "industry_context"
116+
117+
118+ def test_direct_beneficiary_overrides_generic_alias (tmp_path : Path ) -> None :
119+ raw_items = tmp_path / "source_items.csv"
120+ raw_items .write_text (
121+ "item_id,published_at,source_type,source_url,author,text\n "
122+ "award,2026-04-01T00:00:00Z,government_procurement,https://www.govinfo.gov/example,Agency,"
123+ 'Funding for Strategy was announced.\n ' ,
124+ encoding = "utf-8" ,
125+ )
126+ aliases = tmp_path / "aliases.csv"
127+ aliases .write_text ("symbol,name,aliases\n MSTR,Strategy,Strategy|MSTR\n " , encoding = "utf-8" )
128+
129+ rows = extract_source_records (raw_items , aliases , tmp_path / "events.csv" )
130+
131+ assert rows [0 ]["entity_match_type" ] == "direct_beneficiary"
132+
133+
134+ def test_known_ticker_collisions_remain_context_only (tmp_path : Path ) -> None :
135+ raw_items = tmp_path / "source_items.csv"
136+ raw_items .write_text (
137+ "item_id,published_at,source_type,source_url,author,text\n "
138+ "mstr,2026-04-01T00:00:00Z,government_policy,https://www.nist.gov/mstr,NIST,Strategy guidance\n "
139+ "oklo,2026-04-01T00:00:00Z,government_policy,https://www.nist.gov/oklo,NIST,nuclear reactor safety\n "
140+ "panw,2026-04-01T00:00:00Z,government_policy,https://www.nist.gov/panw,NIST,generic cybersecurity guidance\n "
141+ "coin,2026-04-01T00:00:00Z,government_policy,https://www.federalreserve.gov/coin,Fed,tokenization policy\n "
142+ "intc,2026-04-01T00:00:00Z,government_policy,https://www.commerce.gov/intc,Commerce,CHIPS Act funding\n " ,
143+ encoding = "utf-8" ,
144+ )
145+ aliases = tmp_path / "aliases.csv"
146+ aliases .write_text (
147+ "symbol,name,aliases\n MSTR,Strategy,Strategy|MSTR\n OKLO,Oklo,Oklo|OKLO|nuclear reactor\n "
148+ "PANW,Palo Alto Networks,Palo Alto Networks|PANW|cybersecurity\n "
149+ "COIN,Coinbase,Coinbase|COIN|tokenization\n INTC,Intel,Intel|INTC|CHIPS Act\n " ,
150+ encoding = "utf-8" ,
151+ )
152+
153+ rows = extract_source_records (raw_items , aliases , tmp_path / "events.csv" )
154+
155+ assert {row ["symbol" ] for row in rows } == {"MSTR" , "OKLO" , "PANW" , "COIN" , "INTC" }
156+ assert {row ["entity_match_type" ] for row in rows } == {"industry_context" }
0 commit comments