You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.5 KiB
Python
119 lines
3.5 KiB
Python
"""Integration test: merger output → review queue creation."""
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.integration
|
|
|
|
_RULE_OUTPUT = {
|
|
"schema_version": "1.0.0",
|
|
"document_id": "DOC::test",
|
|
"parser_kind": "rule",
|
|
"event_type": "earnings_release",
|
|
"event_direction": "unknown", # low confidence
|
|
"event_date": "2026-01-01",
|
|
"filing_time_bucket": "post_market",
|
|
"headline": "",
|
|
"summary": "Earnings results.",
|
|
"guidance": {"status": "unclear", "scope": "unknown", "notes": ""},
|
|
"signals": {
|
|
"demand_strength": "unknown",
|
|
"pricing_power": "unknown",
|
|
"backlog_or_bookings": "unknown",
|
|
"customer_expansion": "unknown",
|
|
"margin_quality": "unknown",
|
|
},
|
|
"risk_flags": {
|
|
"oneoff_item": True,
|
|
"tax_benefit": False,
|
|
"valuation_gain": False,
|
|
"non_gaap_heavy": True,
|
|
"financing_related": False,
|
|
"legal_or_regulatory_overhang": False,
|
|
},
|
|
"evidence": [],
|
|
"confidence": {
|
|
"overall": 0.40, # low
|
|
"event_type": 0.60,
|
|
"event_direction": 0.30,
|
|
"guidance": 0.40,
|
|
"risk_flags": 0.70,
|
|
},
|
|
"warnings": [],
|
|
}
|
|
|
|
|
|
def _make_mock_session_with_no_existing() -> AsyncMock:
|
|
session = AsyncMock()
|
|
mock_result = MagicMock()
|
|
mock_result.scalar_one_or_none.return_value = None
|
|
session.execute = AsyncMock(return_value=mock_result)
|
|
session.add = MagicMock()
|
|
session.flush = AsyncMock()
|
|
return session
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_low_confidence_merge_creates_review_item() -> None:
|
|
"""A low-confidence merged record triggers review item creation."""
|
|
from libs.parser.merger import merge, should_queue_for_review
|
|
from libs.review.queue import create_review_item
|
|
|
|
merged = merge(_RULE_OUTPUT, None) # No LLM
|
|
should_queue, reason_codes = should_queue_for_review(merged)
|
|
|
|
assert should_queue is True
|
|
assert "low_confidence" in reason_codes
|
|
|
|
# Mock session for review item creation
|
|
session = _make_mock_session_with_no_existing()
|
|
|
|
await create_review_item(
|
|
session=session,
|
|
entity_type="parser_event",
|
|
entity_id=merged["document_id"],
|
|
priority="P1",
|
|
reason_codes=reason_codes,
|
|
snapshot_refs={"document_id": merged["document_id"]},
|
|
)
|
|
|
|
session.add.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_conflict_merge_creates_p0_review_item() -> None:
|
|
"""A rule/LLM conflict triggers P0 review item."""
|
|
from libs.parser.merger import merge, should_queue_for_review
|
|
from libs.review.queue import create_review_item
|
|
|
|
llm_conflict = copy.deepcopy(_RULE_OUTPUT)
|
|
llm_conflict["parser_kind"] = "llm"
|
|
llm_conflict["event_type"] = "guidance_update" # Conflict
|
|
llm_conflict["confidence"]["overall"] = 0.80
|
|
llm_conflict["confidence"]["event_type"] = 0.85
|
|
|
|
rule_high = copy.deepcopy(_RULE_OUTPUT)
|
|
rule_high["confidence"]["overall"] = 0.80
|
|
rule_high["confidence"]["event_type"] = 0.90
|
|
|
|
merged = merge(rule_high, llm_conflict)
|
|
should_queue, reason_codes = should_queue_for_review(merged)
|
|
|
|
assert should_queue is True
|
|
|
|
session = _make_mock_session_with_no_existing()
|
|
|
|
await create_review_item(
|
|
session=session,
|
|
entity_type="parser_event",
|
|
entity_id=merged["document_id"],
|
|
priority="P0",
|
|
reason_codes=reason_codes,
|
|
snapshot_refs={"document_id": merged["document_id"]},
|
|
)
|
|
|
|
session.add.assert_called_once()
|