""" The shared contract every forecaster in this project implements, so Moirai-MoE, AutoARIMA, and Chronos-2 are interchangeable to decision_engine.py / backtest_engine.py / app.py without any of them knowing about each other. Lives in its own module rather than inside moirai_model.py on purpose: having arima_model.py or chronos_model.py import a dataclass from a file named "moirai_model" would be exactly the kind of cross-model coupling "each model on its own, don't mix them" rules out, even for something as small as a shared type. Every model file's Forecaster class implements: .load() -> None (raises ModelLoadError on failure) .predict(context_df, target_col, past_covariate_cols, prediction_length, freq) -> QuantileForecast (raises ModelInputError for bad input, ModelInferenceError for a failure during inference) None of the three models call each other, fall back to each other, or blend/ensemble their outputs anywhere in this codebase — app.py's model selector picks exactly one forecaster instance per request and that is the only forecaster used for that request. """ from dataclasses import dataclass from typing import List, Optional import numpy as np class ModelLoadError(Exception): pass class ModelInputError(Exception): pass class ModelInferenceError(Exception): pass @dataclass class QuantileForecast: horizon: int quantile_levels: List[float] quantiles: np.ndarray # shape (horizon, len(quantile_levels)) samples: Optional[np.ndarray] # shape (num_samples, horizon), if the backend exposes it context_length_used: int prediction_length: int