Skip to main content

M42 Hybrid Forecasting Service - Integration Guide

Last Updated: October 26, 2025 Status: ✅ Ready for Production Integration Milestone: M42 (Complete - All 3 Phases)


Overview

M42 (Hybrid Forecasting Service) is a complete, production-ready forecasting engine that integrates with the Node.js backend. It provides:

  1. Phase 1: Hybrid Prophet + XGBoost forecasting with walk-forward validation
  2. Phase 2: External data fusion with FinBERT sentiment analysis
  3. Phase 3: LLM meta-cognitive gating agent for forecast validation

Architecture

Service Component Structure

┌─────────────────────────────────────────────────────────────────┐
│ Node.js Backend (port 3000) │
│ │
│ HybridForecastingService.js (Enhanced with M42 support) │
│ ├─ Calls /v1/forecast-gated (M42 Phase 3 - default) │
│ ├─ Calls /v1/forecast (M42 Phase 1/2 - fallback) │
│ ├─ Calls /v1/backtest (M42 Phase 1 - validation) │
│ └─ Integrates gating decisions in response │
│ │
└─────────────────┬───────────────────────────────────────────────┘

│ HTTP REST (Async, 60-120s timeout)

┌─────────────────┴───────────────────────────────────────────────┐
│ Python Forecasting Service (port 8000) │
│ (M42 Complete) │
│ │
│ Main API Endpoints: │
│ ├─ /v1/forecast (Prophet+XGBoost hybrid) │
│ ├─ /v1/backtest (Walk-forward validation) │
│ └─ /v1/forecast-gated (With LLM gating agent) │
│ │
│ Core Modules: │
│ ├─ forecasting_engine.py (Phase 1 - Hybrid model) │
│ ├─ sentiment_engine.py (Phase 2 - FinBERT NLP) │
│ └─ llm_gating_agent.py (Phase 3 - LLM reasoning) │
│ │
└─────────────────────────────────────────────────────────────────┘

Data Flow

Historical Actuals

├─→ Convert to TimeSeries (Darts)

├─→ Prophet Model (Linear patterns)
│ └─→ Extract Residuals

├─→ XGBoost Model (Non-linear residuals + covariates)
│ └─→ Combine Forecasts (Prophet + XGBoost)

├─→ Fetch External Data:
│ ├─ News articles (→ FinBERT sentiment)
│ ├─ Weather data
│ └─ Policy events (→ sentiment mapping)

├─→ LLM Gating Agent (Meta-cognitive validation)
│ ├─ Heuristic rules (always available)
│ └─ LangChain reasoning (LLM-powered)

└─→ Final Forecast + Gating Decision

Integration Setup

1. Prerequisites

Python Service Requirements

  • Python 3.9+
  • Dependencies in requirements.txt:
    • fastapi, uvicorn (web framework)
    • pandas, numpy (data processing)
    • darts, prophet, xgboost (time series models)
    • transformers, torch (NLP - FinBERT)
    • requests (HTTP calls)
    • pydantic (data validation)
    • scipy (statistics)

Node.js Backend Updates

  • Already has HybridForecastingService.js enhanced with M42 support
  • Calls /v1/forecast-gated endpoint by default
  • Falls back to /v1/forecast if gating fails
  • Extracts gating_decision from response

2. Environment Variables

.env Configuration

# Python Forecasting Service
FORECASTING_SERVICE_URL=http://forecasting-service:8000

# LLM Integration (M42 Phase 3)
GEMINI_API_KEY=<your-gemini-api-key> # For gating agent LLM reasoning
LANGCHAIN_LLM_PROVIDER=gemini # or "openai"

# Optional: OpenAI support for gating agent
OPENAI_API_KEY=<your-openai-api-key>

# Backend API URL (for news/weather/policy data)
BACKEND_URL=http://localhost:3000 # or http://chainalign-backend:3000 in Docker

3. Docker Compose Setup

The docker-compose.yml already includes the forecasting service:

forecasting-service:
build:
context: ./python-services/forecasting_service
ports:
- "8000:8000"
volumes:
- ./python-services/forecasting_service:/app
env_file: .env
environment:
NODE_ENV: development
GEMINI_API_KEY: ${GEMINI_API_KEY}
networks:
- chainalign-net
depends_on:
- chainalign-backend # Needs backend for news/weather/policy APIs

4. Starting the Services

# Start all services including Python forecasting service
docker-compose up -d

# Verify forecasting service is running
curl http://localhost:8000/

# Expected response:
# {"message": "Hybrid Forecasting Service is running!"}

API Endpoints

/v1/forecast - Basic Hybrid Forecast (M42 Phase 1/2)

Method: POST URL: http://forecasting-service:8000/v1/forecast

Request Body:

{
"time_series": [
{"timestamp": "2023-01-01T00:00:00Z", "value": 100.5},
{"timestamp": "2023-01-02T00:00:00Z", "value": 102.3}
],
"forecast_horizon": 10,
"past_covariates": [
{"timestamp": "2023-01-01T00:00:00Z", "data": {"promo": 1, "weather_temp": 25.5}}
],
"future_covariates": [
{"timestamp": "2023-01-11T00:00:00Z", "data": {"promo": 0, "weather_temp": 22.0}}
],
"future_covariates_are_known": true
}

Response:

{
"forecast": [
{"timestamp": "2023-01-11T00:00:00Z", "value": 115.2}
],
"model_components": {
"prophet_forecast": [...],
"xgboost_residual_forecast": [...]
},
"residuals_for_uncertainty": {
"distribution_type": "empirical",
"statistics": {...},
"appropriate_for_mc": true
},
"model_diagnostics": {...},
"execution_metadata": {
"model_name": "Hybrid Prophet+XGBoost",
"execution_time_ms": 2341.5
}
}

/v1/forecast-gated - Gated Hybrid Forecast with LLM Validation (M42 Phase 3)

Method: POST URL: http://forecasting-service:8000/v1/forecast-gated ⚠️ DEFAULT ENDPOINT - Used by Node.js backend

Request Body: Same as /v1/forecast

Response:

{
"forecast": {
"forecast": [...],
"model_components": {...},
"residuals_for_uncertainty": {...},
"model_diagnostics": {...},
"execution_metadata": {...}
},
"gating_decision": {
"approve": true,
"confidence": 0.92,
"reason": "Forecast approved (high confidence: 92.0%)",
"flags": [],
"recommendations": ["Monitor inventory levels during forecast period"],
"reasoning_chain": "Heuristic rule-based gating",
"timestamp": "2025-10-26T12:34:56.789Z"
}
}

/v1/backtest - Walk-Forward Validation (M42 Phase 1)

Method: POST URL: http://forecasting-service:8000/v1/backtest

Request Body:

{
"time_series": [...],
"forecast_horizon": 10,
"backtest_params": {
"strategy": "rolling_window",
"window_size": 30
},
"future_covariates_are_known": true
}

Response:

{
"metrics": {
"mape": 0.0834,
"rmse": 45.23,
"mae": 32.1,
"hybrid_mape": 0.0834,
"prophet_only_mape": 0.1125,
"improvement_percentage": 25.8
},
"backtest_forecasts": [...],
"execution_metadata": {
"model_name": "Hybrid Prophet+XGBoost (Backtested)",
"backtest_strategy": "rolling_window",
"execution_time_ms": 15234.5
}
}

Node.js Backend Integration

Updated HybridForecastingService Flow

  1. Calls /v1/forecast-gated (Primary - M42 Phase 3)

    • Includes external data context
    • Receives both forecast and gating decision
    • Logs gating confidence and flags
    • Flags low-confidence forecasts for human review
  2. Automatic Fallback

    • If gated endpoint fails → retries with /v1/forecast
    • Graceful degradation ensures service availability
  3. Response Enhancement

    • Includes gating_decision in final response
    • Sets requires_human_review flag if confidence < 60%
    • Propagates gating flags and recommendations to frontend

Code Integration

// In HybridForecastingService.js
let pythonServiceResponse;
let gatingDecision = null;
let useGatingAgent = true; // M42 Phase 3: Use gating agent by default

try {
// Call Python forecasting service with gating agent
pythonServiceResponse = await callForecastingService(pythonServiceRequestBody, useGatingAgent);

// Extract forecast and gating decision
if (pythonServiceResponse.gating_decision) {
gatingDecision = pythonServiceResponse.gating_decision;
statisticalBaseline = pythonServiceResponse.forecast;

// Flag for human review if confidence is low
if (gatingDecision.confidence < 0.6) {
appLogger.warn(`LOW CONFIDENCE FORECAST - Flagged for human review`);
}
} else if (pythonServiceResponse.forecast) {
statisticalBaseline = pythonServiceResponse.forecast;
}
} catch (error) {
// Fallback logic...
}

Performance & Reliability

Timeouts

  • Regular forecast: 60 seconds (model inference)
  • Backtest: 120 seconds (walk-forward validation)
  • Gated forecast: 60 seconds (includes NLP sentiment + LLM)

Fallback Strategy

/v1/forecast-gated (Primary)
↓ (failure)
/v1/forecast (Fallback)
↓ (failure)
Error response with graceful degradation

Graceful Degradation

  • LLM unavailable: Uses heuristic gating agent
  • NLP sentiment fails: Proceeds with base forecasts
  • External data unavailable: Works with available sources
  • Model fails: Returns error to frontend for handling

Monitoring & Logging

Log Levels

INFO Level:

  • Forecast request accepted
  • Python service endpoint called
  • Gating decision approved
  • Model diagnostics completed

WARN Level:

  • Low confidence forecast (<60%)
  • Gating flags detected
  • Fallback to regular endpoint
  • Missing external data sources

ERROR Level:

  • Python service unreachable
  • Invalid response format
  • Model training failed
  • LLM gating failed

Example Logs

[HybridForecastingService] Starting forecast generation for tenant: tenant-123, SKU: SKU-456
[HybridForecastingService] Calling Python forecasting service: http://forecasting-service:8000/v1/forecast-gated
[HybridForecastingService] Hybrid forecast generated with LLM gating validation.
[HybridForecastingService] Gating Decision: approve=true, confidence=0.92, flags=[]
[HybridForecastingService] Forecast generation process completed for tenant: tenant-123

Testing

Local Testing

# Test forecasting service availability
curl http://localhost:8000/

# Test basic forecast endpoint
curl -X POST http://localhost:8000/v1/forecast \
-H "Content-Type: application/json" \
-d '{
"time_series": [...],
"forecast_horizon": 10
}'

# Test gated forecast endpoint
curl -X POST http://localhost:8000/v1/forecast-gated \
-H "Content-Type: application/json" \
-d '{
"time_series": [...],
"forecast_horizon": 10
}'

# Test backtest endpoint
curl -X POST http://localhost:8000/v1/backtest \
-H "Content-Type: application/json" \
-d '{
"time_series": [...],
"forecast_horizon": 10,
"backtest_params": {"strategy": "rolling_window", "window_size": 30}
}'

Unit Tests

# Run Python service tests
cd python-services/forecasting_service
python -m pytest __tests__/ -v

# Run specific test module
python -m pytest __tests__/test_sentiment_engine.py -v
python -m pytest __tests__/test_llm_gating_agent.py -v

Integration Tests

# Docker environment integration test
docker-compose up -d
npm test # From backend directory

Deployment Checklist

  • Clone/pull latest code with M42 changes
  • Update .env with FORECASTING_SERVICE_URL
  • Update .env with GEMINI_API_KEY (for LLM gating)
  • Build Python forecasting service Docker image
  • Verify service starts in Docker: docker-compose up -d forecasting-service
  • Test /v1/forecast-gated endpoint manually
  • Verify Node.js backend can call the service
  • Check logs for integration success
  • Run integration tests: npm test
  • Monitor production logs for gating decisions
  • Set up alerts for "requires_human_review" flags

Troubleshooting

Issue: "Failed to get forecast from Python service"

Solution:

  1. Check if forecasting service is running: docker ps | grep forecasting-service
  2. Verify URL in .env: FORECASTING_SERVICE_URL
  3. Check Python service logs: docker logs forecasting-service
  4. Ensure GEMINI_API_KEY is set for gating agent

Issue: Gating confidence is low (<60%)

Cause: Model diagnostics detected issues (insufficient data, heteroscedasticity, etc.)

Action:

  • Review gating_decision.flags for specific issues
  • Check gating_decision.recommendations for guidance
  • Flag for human review (automatic in Node.js backend)

Issue: Timeout errors (60-120s)

Solution:

  1. Check machine resources (CPU, memory)
  2. Reduce forecast horizon or training data size
  3. Increase timeout values if needed
  4. Check for network latency

Issue: LLM gating agent failing

Solution:

  1. Verify GEMINI_API_KEY or OPENAI_API_KEY is set
  2. Check LLM API quota/limits
  3. Service falls back to heuristic gating (still functional)
  4. Check Python service logs for LangChain errors

Next Steps: M43

With M42 fully integrated and production-ready, the next milestone (M43) will implement:

  • Phase 0: Database migrations & repositories
  • Phase 1: Python bootstrap service
  • Phase 2: Adaptive forecasting services
  • Phase 3: Startup initialization service
  • Phase 4: E2E testing and documentation

The M42 foundation provides the forecasting backbone that M43 will enhance with adaptive parameters and bootstrap logic.


Support & Documentation

  • Python Service API: python-services/forecasting_service/README.md
  • Detailed Architecture: /docs/worksummary/milestone-42/summary.md
  • API Specification: Pydantic models in models.py
  • Testing Guide: /docs/testing/TDD Summary.md