Session 7j: Soccer intelligence - 9 leagues, 11 signals, 6 traps, poller, prefetch, 131 new tests (1173 total)

This commit is contained in:
Kev
2026-06-10 14:50:13 -04:00
parent b9084408bf
commit ad5ea8d5a8
28 changed files with 3175 additions and 49 deletions
+236
View File
@@ -0,0 +1,236 @@
/**
* FIFA World Cup 2026 reference data — June 11July 19, 2026.
*
* Static, hand-curated. The poller pulls fixtures/standings/squads from
* APIs (football-data.org + worldcup2026 OSS); this file holds the
* intelligence the APIs don't carry: venue altitudes, host-continent
* teams, designated penalty/set-piece takers, and historical tournament
* performers.
*
* Updated manually as the tournament progresses (squad confirmations,
* penalty-taker shifts, etc.). Not consumed during normal cache misses —
* the feature extractor reads this once per process load.
*
* Venue altitudes sourced from public elevation data (NOAA / Google
* Earth, ft above sea level). Estadio Akron is in Zapopan (Guadalajara
* metro) at ~5,100 ft; Estadio Azteca's stadium floor sits at ~7,349 ft
* — the highest altitude in tournament history for the host venue.
*/
const VENUES = Object.freeze({
// United States (11)
'AT&T Stadium': { city: 'Arlington, TX', altitude_ft: 600, climate: 'hot', country: 'USA' },
'Mercedes-Benz Stadium': { city: 'Atlanta, GA', altitude_ft: 1050, climate: 'hot_humid', country: 'USA' },
'Gillette Stadium': { city: 'Foxborough, MA', altitude_ft: 260, climate: 'temperate', country: 'USA' },
'NRG Stadium': { city: 'Houston, TX', altitude_ft: 80, climate: 'hot_humid', country: 'USA' },
'Arrowhead Stadium': { city: 'Kansas City, MO', altitude_ft: 820, climate: 'temperate', country: 'USA' },
'SoFi Stadium': { city: 'Inglewood, CA', altitude_ft: 100, climate: 'temperate', country: 'USA' },
'Hard Rock Stadium': { city: 'Miami Gardens, FL', altitude_ft: 10, climate: 'hot_humid', country: 'USA' },
'MetLife Stadium': { city: 'East Rutherford, NJ', altitude_ft: 7, climate: 'temperate', country: 'USA' },
'Lincoln Financial Field': { city: 'Philadelphia, PA', altitude_ft: 30, climate: 'temperate', country: 'USA' },
"Levi's Stadium": { city: 'Santa Clara, CA', altitude_ft: 33, climate: 'temperate', country: 'USA' },
'Lumen Field': { city: 'Seattle, WA', altitude_ft: 15, climate: 'cool', country: 'USA' },
// Canada (2)
'BMO Field': { city: 'Toronto, ON', altitude_ft: 250, climate: 'temperate', country: 'Canada' },
'BC Place': { city: 'Vancouver, BC', altitude_ft: 33, climate: 'cool', country: 'Canada' },
// Mexico (3)
'Estadio Azteca': { city: 'Mexico City', altitude_ft: 7349, climate: 'altitude', country: 'Mexico' },
'Estadio BBVA': { city: 'Monterrey', altitude_ft: 1765, climate: 'hot', country: 'Mexico' },
'Estadio Akron': { city: 'Guadalajara (Zapopan)', altitude_ft: 5138, climate: 'altitude', country: 'Mexico' },
});
// Host-continent teams (CONCACAF) — historically benefit from reduced
// travel, fan support, and altitude acclimation. The 2026 hosts (USA,
// Canada, Mexico) auto-qualified; the rest qualified through CONCACAF.
const CONCACAF_TEAMS = Object.freeze([
'USA', 'Canada', 'Mexico', 'Costa Rica', 'Jamaica', 'Honduras',
'Panama', 'El Salvador', 'Haiti', 'Trinidad and Tobago',
'Guatemala', 'Curacao', 'Suriname',
]);
// CONMEBOL teams travel less than European/African squads and are
// historically strong in 2026-style climates. Used as a softer secondary
// modifier (not full home-continent advantage).
const CONMEBOL_TEAMS = Object.freeze([
'Argentina', 'Brazil', 'Uruguay', 'Colombia', 'Ecuador', 'Paraguay',
'Peru', 'Chile', 'Venezuela', 'Bolivia',
]);
// Designated penalty takers — primary plus secondary fallback if primary
// is off the pitch. Sourced from each team's most recent qualifier or
// pre-tournament friendly; updated as confirmations come in.
//
// Penalty-taker status adds ~0.15 goals per 90 to the player's base rate.
// Keys are team names matching football-data.org's `team.name` field;
// values are arrays in preference order.
const PENALTY_TAKERS = Object.freeze({
'Argentina': ['Lionel Messi', 'Lautaro Martínez'],
'Brazil': ['Vinicius Junior', 'Neymar'],
'France': ['Kylian Mbappé', 'Antoine Griezmann'],
'England': ['Harry Kane', 'Bukayo Saka'],
'Portugal': ['Cristiano Ronaldo', 'Bruno Fernandes'],
'Spain': ['Álvaro Morata', 'Mikel Merino'],
'Germany': ['Kai Havertz', 'İlkay Gündoğan'],
'Netherlands': ['Memphis Depay', 'Cody Gakpo'],
'Belgium': ['Romelu Lukaku', 'Kevin De Bruyne'],
'Italy': ['Jorginho', 'Lorenzo Pellegrini'],
'Croatia': ['Luka Modrić', 'Andrej Kramarić'],
'Uruguay': ['Darwin Núñez', 'Federico Valverde'],
'Colombia': ['James Rodríguez', 'Luis Díaz'],
'Mexico': ['Raúl Jiménez', 'Hirving Lozano'],
'USA': ['Christian Pulisic', 'Folarin Balogun'],
'Canada': ['Jonathan David', 'Alphonso Davies'],
'Morocco': ['Hakim Ziyech', 'Achraf Hakimi'],
'Senegal': ['Sadio Mané', 'Ismaïla Sarr'],
'Japan': ['Takefusa Kubo', 'Wataru Endō'],
'South Korea': ['Son Heung-min', 'Hwang Hee-chan'],
'Australia': ['Jackson Irvine', 'Mitchell Duke'],
'Switzerland': ['Granit Xhaka', 'Xherdan Shaqiri'],
'Poland': ['Robert Lewandowski', 'Piotr Zieliński'],
'Denmark': ['Christian Eriksen', 'Pierre-Emile Højbjerg'],
'Serbia': ['Aleksandar Mitrović', 'Dušan Vlahović'],
});
// Designated corner takers (set-piece delivery role). Multi-name arrays
// reflect rotation; the first is the most common deliverer. Corner-taker
// status meaningfully boosts assist probability for headed goals.
const CORNER_TAKERS = Object.freeze({
'Argentina': ['Lionel Messi', 'Ángel Di María'],
'Brazil': ['Lucas Paquetá', 'Bruno Guimarães'],
'France': ['Antoine Griezmann', 'Kylian Mbappé'],
'England': ['Bukayo Saka', 'Phil Foden', 'Trent Alexander-Arnold'],
'Portugal': ['Bruno Fernandes', 'João Cancelo'],
'Spain': ['Dani Olmo', 'Mikel Merino'],
'Germany': ['Joshua Kimmich', 'Toni Kroos'],
'Netherlands': ['Frenkie de Jong', 'Cody Gakpo'],
'Belgium': ['Kevin De Bruyne', 'Yannick Carrasco'],
'Italy': ['Lorenzo Pellegrini', 'Federico Chiesa'],
'Croatia': ['Luka Modrić', 'Mateo Kovačić'],
'Uruguay': ['Federico Valverde', 'Giorgian de Arrascaeta'],
'Mexico': ['Andrés Guardado', 'Hirving Lozano'],
'USA': ['Christian Pulisic', 'Gio Reyna'],
'Canada': ['Stephen Eustáquio', 'Tajon Buchanan'],
});
// Direct free-kick specialists. These players take long-range and
// dangerous-area free kicks. Boosts both goal AND assist probability
// when a foul is drawn in shooting range.
const FREE_KICK_TAKERS = Object.freeze({
'Argentina': ['Lionel Messi'],
'Brazil': ['Neymar', 'Vinicius Junior'],
'France': ['Kylian Mbappé'],
'England': ['Trent Alexander-Arnold', 'Bukayo Saka'],
'Portugal': ['Cristiano Ronaldo', 'Bruno Fernandes'],
'Spain': ['Dani Olmo'],
'Germany': ['Joshua Kimmich'],
'Belgium': ['Kevin De Bruyne'],
'Italy': ['Federico Chiesa'],
'Croatia': ['Luka Modrić'],
'Colombia': ['James Rodríguez'],
'Mexico': ['Raúl Jiménez'],
'USA': ['Christian Pulisic'],
'Morocco': ['Hakim Ziyech'],
'South Korea': ['Son Heung-min'],
'Poland': ['Piotr Zieliński'],
'Serbia': ['Dušan Tadić'],
});
// "Tournament players" — historical World Cup performers with three or
// more career WC goals. These names lift the prior on big-game scoring.
// Threshold: >=3 career WC goals OR >=2 in the most recent WC.
const TOURNAMENT_PLAYERS = Object.freeze({
'Lionel Messi': { wc_goals_career: 13, wc_appearances: 26 },
'Cristiano Ronaldo': { wc_goals_career: 8, wc_appearances: 22 },
'Kylian Mbappé': { wc_goals_career: 12, wc_appearances: 14 },
'Harry Kane': { wc_goals_career: 8, wc_appearances: 11 },
'Neymar': { wc_goals_career: 8, wc_appearances: 16 },
'Olivier Giroud': { wc_goals_career: 5, wc_appearances: 18 },
'Antoine Griezmann': { wc_goals_career: 6, wc_appearances: 17 },
'Romelu Lukaku': { wc_goals_career: 5, wc_appearances: 11 },
'Luka Modrić': { wc_goals_career: 2, wc_appearances: 18 }, // captain bias
'Robert Lewandowski': { wc_goals_career: 2, wc_appearances: 8 },
'Karim Benzema': { wc_goals_career: 3, wc_appearances: 11 },
'Edinson Cavani': { wc_goals_career: 4, wc_appearances: 14 },
'Luis Suárez': { wc_goals_career: 7, wc_appearances: 14 },
'Andrés Guardado': { wc_goals_career: 1, wc_appearances: 20 }, // captain bias
'Thomas Müller': { wc_goals_career: 10, wc_appearances: 16 },
'Eden Hazard': { wc_goals_career: 3, wc_appearances: 11 },
'Hirving Lozano': { wc_goals_career: 2, wc_appearances: 7 },
'Sadio Mané': { wc_goals_career: 1, wc_appearances: 5 },
});
// Lookup helpers — case-insensitive on player names, exact-match on
// team names. Each returns a primitive so the feature extractor can
// drop the result straight into the feature vector.
function isPenaltyTaker(playerName, teamName) {
if (!playerName || !teamName) return false;
const takers = PENALTY_TAKERS[teamName];
if (!Array.isArray(takers)) return false;
const p = String(playerName).toLowerCase();
return takers.some((t) => t.toLowerCase() === p);
}
function isCornerTaker(playerName, teamName) {
if (!playerName || !teamName) return false;
const takers = CORNER_TAKERS[teamName];
if (!Array.isArray(takers)) return false;
const p = String(playerName).toLowerCase();
return takers.some((t) => t.toLowerCase() === p);
}
function isFreeKickTaker(playerName, teamName) {
if (!playerName || !teamName) return false;
const takers = FREE_KICK_TAKERS[teamName];
if (!Array.isArray(takers)) return false;
const p = String(playerName).toLowerCase();
return takers.some((t) => t.toLowerCase() === p);
}
function getTournamentHistory(playerName) {
if (!playerName) return null;
// Exact match first, then case-insensitive scan.
if (TOURNAMENT_PLAYERS[playerName]) return TOURNAMENT_PLAYERS[playerName];
const p = String(playerName).toLowerCase();
for (const [name, history] of Object.entries(TOURNAMENT_PLAYERS)) {
if (name.toLowerCase() === p) return history;
}
return null;
}
function isHomeContinent(teamName) {
if (!teamName) return false;
return CONCACAF_TEAMS.includes(teamName);
}
function getVenue(venueName) {
if (!venueName) return null;
return VENUES[venueName] || null;
}
// Classify altitude impact for non-acclimatized teams. The historical
// goal-output reduction kicks in around 1,500 ft and gets material above
// 4,000 ft (per CSIC studies on player physiology at altitude).
function altitudeImpact(altitudeFt) {
if (!Number.isFinite(altitudeFt)) return 'none';
if (altitudeFt >= 4000) return 'high';
if (altitudeFt >= 1500) return 'moderate';
return 'none';
}
module.exports = {
VENUES,
CONCACAF_TEAMS,
CONMEBOL_TEAMS,
PENALTY_TAKERS,
CORNER_TAKERS,
FREE_KICK_TAKERS,
TOURNAMENT_PLAYERS,
isPenaltyTaker,
isCornerTaker,
isFreeKickTaker,
getTournamentHistory,
isHomeContinent,
getVenue,
altitudeImpact,
};