chore: retire legacy oil prediction pipeline
Removes everything that was made redundant by the new forecasting stack. Per docs/superpowers/specs/2026-05-01-prediction-rebuild-design.md, this was the cleanup planned at the end of Phase 4. Deleted services and code: - App\Services\Prediction\Signals\* (the old six-signal aggregator — trend, supermarket, day-of-week, brand-behaviour, stickiness, regional-momentum, oil — replaced by RidgeRegressionModel). - App\Services\NationalFuelPredictionService (the post-Phase-4 thin shim; StationSearchService now depends on WeeklyForecastService directly, set up in the previous commit). - App\Services\LlmPrediction\* (AbstractLlmPredictionProvider plus the four provider implementations — Anthropic, OpenAI, Gemini, and the OilPredictionProvider router. Replaced by LlmOverlayService). - App\Services\BrentPricePredictor and App\Services\Ewma. The Ewma helper had no callers left after BrentPricePredictor went. - App\Models\PricePrediction and its factory. - App\Console\Commands\PredictOilPrices (the oil:predict command). - App\Filament\Resources\OilPredictionResource and its Pages. Schema and dashboard: - Drop the price_predictions table via a new migration. - Repoint the Filament StatsOverviewWidget tile from PricePrediction to WeeklyForecast so the dashboard reflects the new pipeline. - Remove the OilPredictionProvider binding from AppServiceProvider. Test cleanup: - Delete tests for every retired service. - Update StatsOverviewWidgetTest to seed weekly_forecasts instead of price_predictions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,10 +3,10 @@
|
||||
namespace App\Filament\Widgets;
|
||||
|
||||
use App\Models\ApiLog;
|
||||
use App\Models\PricePrediction;
|
||||
use App\Models\Search;
|
||||
use App\Models\Station;
|
||||
use App\Models\User;
|
||||
use App\Models\WeeklyForecast;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
|
||||
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||
@@ -21,7 +21,7 @@ class StatsOverviewWidget extends BaseWidget
|
||||
$this->usersStat(),
|
||||
$this->searchesStat(),
|
||||
$this->stationsStat(),
|
||||
$this->oilPredictionStat(),
|
||||
$this->weeklyForecastStat(),
|
||||
$this->apiErrorsStat(),
|
||||
];
|
||||
}
|
||||
@@ -56,23 +56,23 @@ class StatsOverviewWidget extends BaseWidget
|
||||
->color('success');
|
||||
}
|
||||
|
||||
private function oilPredictionStat(): Stat
|
||||
private function weeklyForecastStat(): Stat
|
||||
{
|
||||
$prediction = PricePrediction::bestFirst()->latest('generated_at')->first();
|
||||
$forecast = WeeklyForecast::query()->latest('generated_at')->first();
|
||||
|
||||
if ($prediction === null) {
|
||||
return Stat::make('Latest oil prediction', 'None')
|
||||
if ($forecast === null) {
|
||||
return Stat::make('Latest weekly forecast', 'None')
|
||||
->icon('heroicon-o-beaker')
|
||||
->color('gray');
|
||||
}
|
||||
|
||||
$ageHours = $prediction->generated_at->diffInHours(now());
|
||||
$color = $ageHours > 24 ? 'warning' : 'success';
|
||||
$value = $prediction->direction->label().' · '.$prediction->confidence.'%';
|
||||
$ageHours = $forecast->generated_at->diffInHours(now());
|
||||
$color = $ageHours > 168 ? 'warning' : 'success'; // weekly forecast → stale after a week
|
||||
$directionLabel = ucfirst($forecast->direction);
|
||||
$value = $directionLabel.' · '.$forecast->ridge_confidence.'%';
|
||||
|
||||
return Stat::make('Latest oil prediction', $value)
|
||||
->description('Generated '.$prediction->generated_at->diffForHumans())
|
||||
->url(route('filament.admin.resources.oil-predictions.index'))
|
||||
return Stat::make('Latest weekly forecast', $value)
|
||||
->description('For week of '.$forecast->forecast_for->toDateString())
|
||||
->icon('heroicon-o-beaker')
|
||||
->color($color);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user