diff --git a/src/app/baseball/actions/insights.ts b/src/app/baseball/actions/insights.ts index c977c06d2..b96093347 100644 --- a/src/app/baseball/actions/insights.ts +++ b/src/app/baseball/actions/insights.ts @@ -300,7 +300,10 @@ function analyzePlayer( if (totalHits >= 50 && totalHits % 25 === 0) { insights.push({ player_id: playerId, - insight_type: 'development_milestone', + // Distinct from the HR milestone so both survive reconciliation, which + // keys insights by `${playerId}::${insight_type}`. A player crossing both + // a hit and an HR milestone in one run now persists two independent rows. + insight_type: 'milestone_hits', priority: 'low', title: `${playerName} reached ${totalHits} hits!`, description: `Career milestone: ${totalHits} hits in ${aggregates?.total_sessions || 0} sessions.`, @@ -316,7 +319,9 @@ function analyzePlayer( if (totalHR >= 10 && totalHR % 5 === 0) { insights.push({ player_id: playerId, - insight_type: 'development_milestone', + // Distinct from the hits milestone (see above) so the HR milestone is + // reconciled and refreshed independently rather than overwriting it. + insight_type: 'milestone_hr', priority: 'low', title: `${playerName} hit ${totalHR} home runs!`, description: `Power milestone achieved.`, diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 2836a8140..71abc4261 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -108,6 +108,10 @@ export type BaseballInsightType = | 'breakout_candidate' | 'position_opportunity' | 'development_milestone' + // Milestone-kind-specific types so a player crossing both a hit and an HR + // milestone in one run persists both (reconcile keys by playerId::insight_type). + | 'milestone_hits' + | 'milestone_hr' | 'comparison_alert' // Additional types for AI insights engine | 'decline'