Session 16: Live hero prop, sport-specific markets fix, soccer weather, Sentry CSP (1429 tests)
This commit is contained in:
@@ -27,6 +27,12 @@
|
||||
const { cacheGet } = require('../../utils/redis');
|
||||
const { normalizeName } = require('../../utils/normalize');
|
||||
const wc = require('../../data/worldcup2026');
|
||||
// Session 16 — World Cup venue weather. Open-Meteo lookup is cached
|
||||
// 1h, has a 5s timeout, and degrades silently on failure. Dome
|
||||
// venues skip the fetch entirely (operators close the roof when
|
||||
// conditions warrant — weather doesn't drive grade in that case).
|
||||
const { getWcVenueCoords } = require('../../data/venueCoordinates');
|
||||
const weatherService = require('../weatherService');
|
||||
|
||||
const SOCCER_SPORTS = new Set(['soccer', 'football']);
|
||||
|
||||
@@ -183,6 +189,22 @@ async function extractSoccerFeatures(input = {}) {
|
||||
const homeContinent = wc.isHomeContinent(team);
|
||||
const altImpact = wc.altitudeImpact(altitudeFt);
|
||||
|
||||
// Session 16 — weather for outdoor World Cup venues. The venue
|
||||
// coords file is keyed by venue name; dome venues (BC Place,
|
||||
// AT&T, etc.) are skipped via the `dome` flag rather than the
|
||||
// network call so we don't burn the 5s timeout on stadiums that
|
||||
// will close the roof anyway.
|
||||
let weather = null;
|
||||
const coords = venueName ? getWcVenueCoords(venueName) : null;
|
||||
if (coords && !coords.dome && Number.isFinite(coords.lat) && Number.isFinite(coords.lon)) {
|
||||
try {
|
||||
weather = await weatherService.getWeather(coords.lat, coords.lon);
|
||||
} catch (err) {
|
||||
// Best-effort — never block the grade on the weather fetch.
|
||||
console.warn('[soccerFeatureExtractor] weather skipped:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Set-piece + penalty roles (static data — no async).
|
||||
const isPK = wc.isPenaltyTaker(player, team);
|
||||
const isCorner = wc.isCornerTaker(player, team);
|
||||
@@ -221,6 +243,13 @@ async function extractSoccerFeatures(input = {}) {
|
||||
venue_altitude_ft: altitudeFt,
|
||||
altitude_impact: altImpact,
|
||||
climate,
|
||||
// Session 16 — weather. Null when venue is a dome / not in the
|
||||
// WC venue index / Open-Meteo fetch failed. Trap detection +
|
||||
// reasoning surface these signals when present.
|
||||
weather_temp_f: weather?.temp_f ?? null,
|
||||
weather_wind_mph: weather?.wind_mph ?? null,
|
||||
weather_wind_dir: weather?.wind_dir ?? null,
|
||||
weather_precip_mm: weather?.precip_mm ?? null,
|
||||
opp_goals_conceded_per_game: oppDefense?.goals_conceded_per_game ?? null,
|
||||
opp_clean_sheet_rate: oppDefense?.clean_sheet_rate ?? null,
|
||||
opp_defensive_rank: oppDefense?.defensive_rank ?? null,
|
||||
|
||||
Reference in New Issue
Block a user