169 lines
6.3 KiB
Python
169 lines
6.3 KiB
Python
import asyncio
|
|
from datetime import datetime, timezone
|
|
|
|
from orchestrator.contracts.error_taxonomy import ReasonCode
|
|
from orchestrator.contracts.result_contract import CombinedSignalFailure, FinalSignal, Signal
|
|
from orchestrator.live_mode import LiveMode
|
|
|
|
|
|
def _signal(*, source: str, direction: int, confidence: float) -> Signal:
|
|
return Signal(
|
|
ticker="AAPL",
|
|
direction=direction,
|
|
confidence=confidence,
|
|
source=source,
|
|
timestamp=datetime(2026, 4, 11, 12, 0, tzinfo=timezone.utc),
|
|
)
|
|
|
|
|
|
class _StubOrchestrator:
|
|
def __init__(self, responses):
|
|
self._responses = responses
|
|
|
|
def get_combined_signal(self, ticker: str, date: str):
|
|
response = self._responses[(ticker, date)]
|
|
if isinstance(response, Exception):
|
|
raise response
|
|
return response
|
|
|
|
|
|
def test_live_mode_serializes_degraded_contract_shape():
|
|
live_mode = LiveMode(
|
|
_StubOrchestrator(
|
|
{
|
|
("AAPL", "2026-04-11"): FinalSignal(
|
|
ticker="AAPL",
|
|
direction=-1,
|
|
confidence=0.42,
|
|
quant_signal=None,
|
|
llm_signal=_signal(source="llm", direction=-1, confidence=0.6),
|
|
timestamp=datetime(2026, 4, 11, 12, 1, tzinfo=timezone.utc),
|
|
degrade_reason_codes=(ReasonCode.QUANT_SIGNAL_FAILED.value,),
|
|
metadata={
|
|
"contract_version": "v1alpha1",
|
|
"data_quality": {"state": "stale_data", "source": "quant"},
|
|
"research": {
|
|
"research_status": "degraded",
|
|
"research_mode": "degraded_synthesis",
|
|
"timed_out_nodes": ["Bull Researcher"],
|
|
"degraded_reason": "bull_researcher_timeout",
|
|
"covered_dimensions": ["market"],
|
|
"manager_confidence": None,
|
|
},
|
|
"source_diagnostics": {
|
|
"quant": {"reason_code": ReasonCode.STALE_DATA.value}
|
|
},
|
|
},
|
|
)
|
|
}
|
|
)
|
|
)
|
|
|
|
results = asyncio.run(live_mode.run_once(["AAPL"], "2026-04-11"))
|
|
|
|
assert results == [
|
|
{
|
|
"contract_version": "v1alpha1",
|
|
"ticker": "AAPL",
|
|
"date": "2026-04-11",
|
|
"status": "degraded_success",
|
|
"result": {
|
|
"direction": -1,
|
|
"confidence": 0.42,
|
|
"quant_direction": None,
|
|
"llm_direction": -1,
|
|
"timestamp": "2026-04-11T12:01:00+00:00",
|
|
},
|
|
"error": None,
|
|
"degradation": {
|
|
"degraded": True,
|
|
"reason_codes": [ReasonCode.QUANT_SIGNAL_FAILED.value],
|
|
"source_diagnostics": {
|
|
"quant": {"reason_code": ReasonCode.STALE_DATA.value}
|
|
},
|
|
},
|
|
"data_quality": {"state": "stale_data", "source": "quant"},
|
|
"research": {
|
|
"research_status": "degraded",
|
|
"research_mode": "degraded_synthesis",
|
|
"timed_out_nodes": ["Bull Researcher"],
|
|
"degraded_reason": "bull_researcher_timeout",
|
|
"covered_dimensions": ["market"],
|
|
"manager_confidence": None,
|
|
},
|
|
}
|
|
]
|
|
|
|
|
|
def test_live_mode_serializes_failure_contract_shape():
|
|
live_mode = LiveMode(
|
|
_StubOrchestrator(
|
|
{
|
|
("AAPL", "2026-04-11"): CombinedSignalFailure(
|
|
"both quant and llm signals are None",
|
|
reason_codes=(ReasonCode.BOTH_SIGNALS_UNAVAILABLE.value, ReasonCode.PROVIDER_MISMATCH.value),
|
|
source_diagnostics={
|
|
"llm": {
|
|
"reason_code": ReasonCode.PROVIDER_MISMATCH.value,
|
|
"research": {
|
|
"research_status": "failed",
|
|
"research_mode": "degraded_synthesis",
|
|
"timed_out_nodes": ["Bull Researcher"],
|
|
"degraded_reason": "bull_researcher_connectionerror",
|
|
"covered_dimensions": ["market"],
|
|
"manager_confidence": None,
|
|
},
|
|
}
|
|
},
|
|
data_quality={"state": "provider_mismatch", "source": "llm"},
|
|
)
|
|
}
|
|
)
|
|
)
|
|
|
|
results = asyncio.run(live_mode.run_once(["AAPL"], "2026-04-11"))
|
|
|
|
assert results == [
|
|
{
|
|
"contract_version": "v1alpha1",
|
|
"ticker": "AAPL",
|
|
"date": "2026-04-11",
|
|
"status": "failed",
|
|
"result": None,
|
|
"error": {
|
|
"code": "live_signal_failed",
|
|
"message": "both quant and llm signals are None",
|
|
"retryable": False,
|
|
},
|
|
"degradation": {
|
|
"degraded": True,
|
|
"reason_codes": [
|
|
ReasonCode.BOTH_SIGNALS_UNAVAILABLE.value,
|
|
ReasonCode.PROVIDER_MISMATCH.value,
|
|
],
|
|
"source_diagnostics": {
|
|
"llm": {
|
|
"reason_code": ReasonCode.PROVIDER_MISMATCH.value,
|
|
"research": {
|
|
"research_status": "failed",
|
|
"research_mode": "degraded_synthesis",
|
|
"timed_out_nodes": ["Bull Researcher"],
|
|
"degraded_reason": "bull_researcher_connectionerror",
|
|
"covered_dimensions": ["market"],
|
|
"manager_confidence": None,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"data_quality": {"state": "provider_mismatch", "source": "llm"},
|
|
"research": {
|
|
"research_status": "failed",
|
|
"research_mode": "degraded_synthesis",
|
|
"timed_out_nodes": ["Bull Researcher"],
|
|
"degraded_reason": "bull_researcher_connectionerror",
|
|
"covered_dimensions": ["market"],
|
|
"manager_confidence": None,
|
|
},
|
|
}
|
|
]
|