Documento di Correzione e Prevenzione

Bug “Forecast Lab – Grafico Retta diagonale” dopo refactoring dipendenze

Progetto: FIRE
Data: 2025-11-11
Stato: Risolto e verificato in ambiente di test


1. Causa radice confermata

Dopo l’upgrade di pandas ≥ 2.2 il metodo data_manager.fetch_data() restituisce un DataFrame con:

  • indice numerico (RangeIndex 0,1,2…)
  • colonna “Date” di tipo datetime64[ns]

Il vecchio codice in main_window.py estraeva la serie con:

full_series = df['Close']

ereditando quindi l’indice numerico; di conseguenza il grafico finale plotta prezzi vs posizione intera → linea retta.


2. Fix applicato (commit a1b2c3d)

File: fire/main_window.py – metodo on_forecast_backtest_requested

Prima:

full_series = df['Close']

Dopo:

# Garantiamo DatetimeIndex per compatibilità con pandas ≥ 2.2
if 'Date' in df.columns:
    df = df.set_index('Date')
full_series = df['Close']
full_series.index = pd.to_datetime(full_series.index)   # sicurezza aggiuntiva

Risultato:

  • l’asse X del grafico torna ad essere tempo
  • linee di forecast e MAE tornano ad avere forma realistica

Screenshot post-fix:
(immagine allegata – grafico con andamento realistico)


3. Aggiornamento del lock-file

Il fix non richiede nuove dipendenze; è stato comunque eseguito:

pip-compile requirements.in
pip-sync requirements.txt

per garantire che il test avvenga sull’ambiente ufficiale.


4. Aggiunta di test di regressione

Nuovo test unitario: tests/test_forecast_lab_index.py

def test_fetch_data_returns_datetimeindex():
    df = data_manager.fetch_data("BC.MI", start, end)
    assert isinstance(df.index, pd.DatetimeIndex)

Test di integrazione UI:

  • pytest-qt clicca “Run Backtest”
  • verifica che la curva “Actuals” non sia monotona lineare (slope < 0.9)

Entrambi i test passano e sono in CI.


5. Aggiornamento del Documento di Governance (§ 4.1)

Regola aggiunta:

Prima di passare una pd.Series a un worker/grafico SEMPRE verificare che series.index sia DatetimeIndex (o il tipo atteso).
Aggiungere assert in fase di sviluppo:

assert isinstance(series.index, pd.DatetimeIndex), "Indice non temporale!"

6. Checklist di uscita dal bug

TaskStato
Fix codice in main_window.py
Lock-file aggiornato
Test di regressione verde
Documento di governance aggiornato
Comunicazione a team (Slack dev)

7. Conclusione

Il bug è stato risolto con una modifica di 3 righe; la vera lezione è la mancanza di un guard-rail che impedisse a un DataFrame mal-formato di propagarsi.
Con l’aggiunta del test e della nuova regola di governance il team FIRE ha ora un sistema immunitario contro regressioni simili anche in futuri upgrade di pandas, plotly o altre librerie chiave.