Recalculate league standings after EV simulation updates (#186)
* Force standings recalculation after EV simulation After persisting updated EVs to participantExpectedValues, call recalculateAffectedLeagues so that teamStandings.projectedPoints (and all related standing fields) immediately reflect the new EV rather than remaining stale until the next scoring event. https://claude.ai/code/session_01S9Pk4wTSphANMhPWaURPTn * Use recalculateStandings directly after EV simulation Replaces recalculateAffectedLeagues (which carries Discord notification and daily snapshot side effects) with a direct call to recalculateStandings per affected fantasy season. This updates the cached projectedPoints in teamStandings so the standings page stays in sync with the team page after a simulation, without triggering unrelated side effects. https://claude.ai/code/session_01S9Pk4wTSphANMhPWaURPTn * Polish simulate route after code review - Remove redundant db variable; use database() inline consistent with all other model calls in this file - Parallelize standings recalculation with Promise.all - Update file header comment to include the standings refresh step https://claude.ai/code/session_01S9Pk4wTSphANMhPWaURPTn --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
063834d8e6
commit
3f3401f0d8
1 changed files with 13 additions and 2 deletions
|
|
@ -5,8 +5,9 @@
|
||||||
* 1. Guards against concurrent runs via simulationStatus
|
* 1. Guards against concurrent runs via simulationStatus
|
||||||
* 2. Runs the appropriate simulator based on the sport's simulatorType
|
* 2. Runs the appropriate simulator based on the sport's simulatorType
|
||||||
* 3. Persists updated EVs to participantExpectedValues (transactional)
|
* 3. Persists updated EVs to participantExpectedValues (transactional)
|
||||||
* 4. Takes an EV snapshot from simulation output (upsert for today's date)
|
* 4. Refreshes cached projectedPoints in teamStandings for all affected fantasy seasons
|
||||||
* 5. Redirects back to the sports season admin page
|
* 5. Takes an EV snapshot from simulation output (upsert for today's date)
|
||||||
|
* 6. Redirects back to the sports season admin page
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { redirect } from "react-router";
|
import { redirect } from "react-router";
|
||||||
|
|
@ -17,6 +18,10 @@ import { batchUpsertParticipantEvSnapshots } from "~/models/ev-snapshot";
|
||||||
import { findParticipantsBySportsSeasonId } from "~/models/participant";
|
import { findParticipantsBySportsSeasonId } from "~/models/participant";
|
||||||
import { getSimulator, type SimulatorType } from "~/services/simulations/registry";
|
import { getSimulator, type SimulatorType } from "~/services/simulations/registry";
|
||||||
import { calculateEV, type ScoringRules } from "~/services/ev-calculator";
|
import { calculateEV, type ScoringRules } from "~/services/ev-calculator";
|
||||||
|
import { recalculateStandings } from "~/models/scoring-calculator";
|
||||||
|
import { database } from "~/database/context";
|
||||||
|
import * as schema from "~/database/schema";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
|
||||||
// Default scoring rules — matches the season table defaults.
|
// Default scoring rules — matches the season table defaults.
|
||||||
// Per-league EV is recalculated from probabilities using league-specific rules in standings.
|
// Per-league EV is recalculated from probabilities using league-specific rules in standings.
|
||||||
|
|
@ -99,6 +104,12 @@ export async function action({ params }: Route.ActionArgs) {
|
||||||
// Persist updated EVs (transactional)
|
// Persist updated EVs (transactional)
|
||||||
await batchUpsertParticipantEVs(evInputs);
|
await batchUpsertParticipantEVs(evInputs);
|
||||||
|
|
||||||
|
// Refresh cached projectedPoints in teamStandings for all affected fantasy seasons
|
||||||
|
const seasonSports = await database().query.seasonSports.findMany({
|
||||||
|
where: eq(schema.seasonSports.sportsSeasonId, sportsSeasonId),
|
||||||
|
});
|
||||||
|
await Promise.all(seasonSports.map(({ seasonId }) => recalculateStandings(seasonId)));
|
||||||
|
|
||||||
// Take EV snapshot from simulation output (not re-read from DB)
|
// Take EV snapshot from simulation output (not re-read from DB)
|
||||||
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
||||||
await batchUpsertParticipantEvSnapshots(
|
await batchUpsertParticipantEvSnapshots(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue