fix(feeder): preserve pre-match odds when match goes live
Deploy Iddaai Backend / build-and-deploy (push) Successful in 29s
Deploy Iddaai Backend / build-and-deploy (push) Successful in 29s
Live odds have missing selections (e.g. '1' key removed from Maç Sonucu after kickoff), causing the AI model to produce wildly incorrect predictions (e.g. 3.5% home win for Bristol City). Two guards added: 1. fetchOddsForMatches: Exclude live/finished matches from odds fetch query 2. processMatchOdds: Skip odds/lineups/sidelined overwrite if match already has pre-match odds and is live/finished
This commit is contained in:
@@ -307,6 +307,9 @@ export class DataFetcherTask {
|
||||
const allowedLeagueIds = Array.from(new Set(topLeagueIds));
|
||||
|
||||
// Get matches needing odds (from 12 hours ago onward)
|
||||
// CRITICAL: Only fetch odds/lineups for NOT STARTED matches.
|
||||
// Once a match goes live, odds selections disappear or change,
|
||||
// corrupting the pre-match data the AI model relies on.
|
||||
const twelveHoursAgo = new Date(Date.now() - 12 * 60 * 60 * 1000);
|
||||
|
||||
const matchesToFetch = await this.prisma.liveMatch.findMany({
|
||||
@@ -315,6 +318,15 @@ export class DataFetcherTask {
|
||||
...(allowedLeagueIds.length > 0
|
||||
? { leagueId: { in: allowedLeagueIds } }
|
||||
: {}),
|
||||
// Exclude live and finished matches — preserve their pre-match odds
|
||||
NOT: {
|
||||
OR: [
|
||||
{ status: { in: FINISHED_STATUS_VALUES_FOR_DB } },
|
||||
{ state: { in: FINISHED_STATE_VALUES_FOR_DB } },
|
||||
{ status: { in: LIVE_STATUS_VALUES_FOR_DB } },
|
||||
{ state: { in: LIVE_STATE_VALUES_FOR_DB } },
|
||||
],
|
||||
},
|
||||
},
|
||||
include: {
|
||||
homeTeam: { select: { name: true } },
|
||||
@@ -891,7 +903,40 @@ export class DataFetcherTask {
|
||||
}
|
||||
}
|
||||
|
||||
// ALWAYS update oddsUpdatedAt to ensure rotation
|
||||
// Guard: If match already has pre-match odds and is now live/finished,
|
||||
// do NOT overwrite odds/lineups/sidelined — the model needs stable pre-match data.
|
||||
const matchState = match.state?.toLowerCase() ?? '';
|
||||
const matchStatus = match.status?.toLowerCase() ?? '';
|
||||
const liveStates = LIVE_STATE_VALUES_FOR_DB.map((s) => s.toLowerCase());
|
||||
const liveStatuses = LIVE_STATUS_VALUES_FOR_DB.map((s) => s.toLowerCase());
|
||||
const finishedStates = FINISHED_STATE_VALUES_FOR_DB.map((s) => s.toLowerCase());
|
||||
const finishedStatuses = FINISHED_STATUS_VALUES_FOR_DB.map((s) => s.toLowerCase());
|
||||
|
||||
const isLiveOrFinished =
|
||||
liveStates.includes(matchState) ||
|
||||
liveStatuses.includes(matchStatus) ||
|
||||
finishedStates.includes(matchState) ||
|
||||
finishedStatuses.includes(matchStatus);
|
||||
|
||||
const existingOdds = match.odds as Record<string, unknown> | null;
|
||||
const hasExistingOdds =
|
||||
!!existingOdds &&
|
||||
typeof existingOdds === 'object' &&
|
||||
Object.keys(existingOdds).length > 0;
|
||||
|
||||
if (isLiveOrFinished && hasExistingOdds) {
|
||||
// Match is live/finished and already has pre-match odds — skip data update
|
||||
this.logger.debug(
|
||||
`🛡️ Preserving pre-match data for ${match.matchName} (status: ${matchStatus}, state: ${matchState})`,
|
||||
);
|
||||
await this.prisma.liveMatch.update({
|
||||
where: { id: match.id },
|
||||
data: { oddsUpdatedAt: new Date() },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Update odds/lineups/sidelined for pre-match (NS) matches
|
||||
await this.prisma.liveMatch.update({
|
||||
where: { id: match.id },
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user