Add fuel API ingestion and historic storage design spec
Includes verified API authentication flow, correct base URL, all DB table schemas for stations, current prices, history, and archive. Fuel types corrected to match live API (B7_STANDARD, B7_PREMIUM). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
76
.claude/rules/scoring.md
Normal file
76
.claude/rules/scoring.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Scoring Engine (AlertScoringService)
|
||||
|
||||
## Purpose
|
||||
|
||||
Produces a "fill up now or wait?" recommendation per user based on their local
|
||||
station history. Output is one of: `fill_up`, `wait`, `no_signal`.
|
||||
Never guess — stay silent (no_signal) when signals conflict or data is insufficient.
|
||||
|
||||
## The 4 signals (in priority order)
|
||||
|
||||
### Signal 1 — Local price trend (HIGHEST WEIGHT)
|
||||
- Query `station_prices` for user's nearest 5 stations (within 5km of user lat/lng)
|
||||
- Use last 14 days of history for `e10` (or user's preferred fuel type)
|
||||
- Calculate 3-day rolling average vs 7-day rolling average
|
||||
- **Falling**: 3-day avg < 7-day avg by ≥ 0.5p → positive wait signal
|
||||
- **Rising**: 3-day avg > 7-day avg by ≥ 0.5p → fill_up signal
|
||||
- **Flat**: difference < 0.5p → neutral, no signal
|
||||
- Weight: 40 points max
|
||||
|
||||
### Signal 2 — Supermarket anchor effect (HIGH WEIGHT)
|
||||
- Find nearest supermarket station (is_supermarket = 1) within 10km
|
||||
- Check if supermarket cut price in last 48 hours (> 1p drop)
|
||||
- Check if nearest non-supermarket stations have NOT yet followed
|
||||
- If supermarket cut AND independents haven't moved → strong wait signal
|
||||
- Weight: 35 points max
|
||||
|
||||
### Signal 3 — Day-of-week pattern (MEDIUM WEIGHT — needs 8+ weeks data)
|
||||
- Per station: average price by day-of-week over last 90 days
|
||||
- Only activate if station has 56+ days of history
|
||||
- If today is statistically 1.5p+ cheaper than weekly average → mild fill_up
|
||||
- If today is statistically 1.5p+ more expensive → mild wait
|
||||
- Weight: 15 points max
|
||||
|
||||
### Signal 4 — Brent crude direction (LOW WEIGHT)
|
||||
- Fetched daily from FRED API, stored in a simple `brent_prices` table
|
||||
- 5-day trend: rising ≥ 3% → mild fill_up pressure; falling ≥ 3% → mild wait
|
||||
- Weight: 10 points max
|
||||
|
||||
## Confidence thresholds
|
||||
|
||||
- Score 70–100: strong signal → fire recommendation + notification
|
||||
- Score 40–69: weak signal → show in dashboard only, no push/SMS/WhatsApp
|
||||
- Score 0–39: no_signal → stay silent entirely
|
||||
|
||||
**Only send notifications when confidence ≥ 70.** Never spam.
|
||||
|
||||
## Output (stored in scoring_results)
|
||||
|
||||
```php
|
||||
[
|
||||
'recommendation' => 'wait', // fill_up | wait | no_signal
|
||||
'confidence' => 78, // 0-100
|
||||
'signals' => [
|
||||
'trend' => ['direction' => 'falling', 'points' => 32],
|
||||
'supermarket' => ['triggered' => true, 'points' => 35],
|
||||
'day_pattern' => ['triggered' => false, 'points' => 0],
|
||||
'brent' => ['direction' => 'flat', 'points' => 0],
|
||||
],
|
||||
'local_avg_pence' => 14380, // 143.80p
|
||||
'trend_delta' => -2.3, // pence change over 7 days
|
||||
]
|
||||
```
|
||||
|
||||
## Human-readable reason strings
|
||||
|
||||
Always generate a plain-English reason for the recommendation:
|
||||
- "Prices near you have been falling for 6 days. Tesco {station} cut 3p yesterday — independents usually follow within 48 hours."
|
||||
- "Prices are rising in your area — filling up today avoids paying more later."
|
||||
- "No clear pattern this week — fill up at the cheapest station near you now."
|
||||
|
||||
Reason strings are stored in `scoring_results.signals` JSON and shown in the UI and notifications.
|
||||
|
||||
## Accuracy self-tracking
|
||||
|
||||
After 3 days, check if `wait` recommendation was correct (prices did fall further).
|
||||
Store outcome in `scoring_results` for future display: "This signal has been right X% of the time in your area."
|
||||
Reference in New Issue
Block a user