Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/lib/baseball/coachhelm/engine-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,10 +545,16 @@ export async function runBaseballEngineCore(
baserunningEvents: (baserunningRows ?? []) as BaserunningEventRow[],
};

// 2. RUN — pure V10 engine over the loaded data.
// 2. RUN — pure V10 engine over the loaded data. nowIso threads through every
// rolling-window loader below (readiness/lift/workload/catching) so a
// deterministic engine run stays deterministic — none of them fall back to
// the real wall clock. Root cause of the engine-run-helm-lifting regression:
// a fixed-clock test seeded data just outside a Date.now()-based window,
// which silently aged out as real time passed with zero code changes.
const boxScorePlayers = loadAllPlayerMetrics(
playerIds,
(statRows ?? []) as unknown as BoxScoreRow[],
nowIso,
);
const players = boxScorePlayers.map((p) =>
mergeEventPlayerMetrics(
Expand All @@ -557,8 +563,10 @@ export async function runBaseballEngineCore(
(readinessRows ?? []) as ReadinessRow[],
(liftSessionRows ?? []) as LiftSessionRow[],
(liftSetResultRows ?? []) as LiftSetResultRow[],
nowIso,
),
eventInputs,
nowIso,
),
);
const events = (eventRows ?? []) as ScheduleEventRow[];
Expand Down
6 changes: 4 additions & 2 deletions src/lib/coachhelm/baseball/loaders-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ export function loadPitchingEventMetrics(
export function loadCatchingMetrics(
catcherId: string,
catching: CatchingEventRow[],
nowIso: string = new Date().toISOString(),
): Partial<Record<BaseballMetricId, LoadedMetric>> {
const out: Partial<Record<BaseballMetricId, LoadedMetric>> = {};
const mine = catching.filter((c) => c.catcher_id === catcherId);
Expand All @@ -422,7 +423,7 @@ export function loadCatchingMetrics(
// Recent innings caught (workload, neutral_threshold) — rolling 7-day sum of
// the innings_caught column where present (game_call/receive grain). Honest:
// only loads when a non-zero innings figure exists in the window.
const cutoff = Date.now() - 7 * 86400_000;
const cutoff = Date.parse(nowIso) - 7 * 86400_000;
const recent = mine.filter((c) => c.measured_at && Date.parse(c.measured_at) >= cutoff);
const recentInnings = recent.reduce((s, c) => s + num(c.innings_caught), 0);
if (recentInnings > 0) {
Expand Down Expand Up @@ -642,13 +643,14 @@ export interface EventLoaderInputs {
export function mergeEventPlayerMetrics(
base: LoadedPlayerMetrics,
events: EventLoaderInputs,
nowIso: string = new Date().toISOString(),
): LoadedPlayerMetrics {
return {
...base,
metrics: {
...loadHittingEventMetrics(base.playerId, events.pitchEvents, events.battedBallEvents),
...loadPitchingEventMetrics(base.playerId, events.pitchEvents),
...loadCatchingMetrics(base.playerId, events.catchingEvents),
...loadCatchingMetrics(base.playerId, events.catchingEvents, nowIso),
...loadDefenseMetrics(base.playerId, events.fieldingEvents),
...loadBaserunningMetrics(base.playerId, events.baserunningEvents),
// existing (box-score + V10) metrics win — never overwritten.
Expand Down
11 changes: 7 additions & 4 deletions src/lib/coachhelm/baseball/loaders-v10.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,9 @@ function toMetric(
function loadReadinessMetrics(
playerId: string,
rows: ReadinessRow[],
nowIso: string = new Date().toISOString(),
): Partial<Record<BaseballMetricId, LoadedMetric>> {
const cutoff = Date.now() - 7 * 86400_000;
const cutoff = Date.parse(nowIso) - 7 * 86400_000;
const mine = rows.filter(
(r) => r.player_id === playerId && r.check_date && Date.parse(r.check_date) >= cutoff,
);
Expand Down Expand Up @@ -216,9 +217,10 @@ function loadLiftMetrics(
playerId: string,
sessions: LiftSessionRow[],
setResults: LiftSetResultRow[],
nowIso: string = new Date().toISOString(),
): Partial<Record<BaseballMetricId, LoadedMetric>> {
const out: Partial<Record<BaseballMetricId, LoadedMetric>> = {};
const now = Date.now();
const now = Date.parse(nowIso);

const mineSessions = sessions.filter(
(s) =>
Expand Down Expand Up @@ -266,12 +268,13 @@ export function mergeV10PlayerMetrics(
readiness: ReadinessRow[],
liftSessions: LiftSessionRow[],
liftSetResults: LiftSetResultRow[],
nowIso: string = new Date().toISOString(),
): LoadedPlayerMetrics {
return {
...base,
metrics: {
...loadReadinessMetrics(base.playerId, readiness),
...loadLiftMetrics(base.playerId, liftSessions, liftSetResults),
...loadReadinessMetrics(base.playerId, readiness, nowIso),
...loadLiftMetrics(base.playerId, liftSessions, liftSetResults, nowIso),
...base.metrics,
},
};
Expand Down
6 changes: 4 additions & 2 deletions src/lib/coachhelm/baseball/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ function stddev(values: number[]): number | undefined {
export function loadPlayerMetrics(
playerId: string,
rows: BoxScoreRow[],
nowIso: string = new Date().toISOString(),
): LoadedPlayerMetrics {
const mine = rows.filter((r) => r.player_id === playerId);
const hitRows = mine.filter(hasHitting);
Expand Down Expand Up @@ -449,7 +450,7 @@ export function loadPlayerMetrics(
}

// ---- Workload (rolling window = last 7 days of GAME pitching) ----
const cutoff = Date.now() - 7 * 86400_000;
const cutoff = Date.parse(nowIso) - 7 * 86400_000;
const recent = pitchRows.filter((r) => r.session_date && Date.parse(r.session_date) >= cutoff);
if (recent.length > 0) {
const recentPitches = recent.reduce((s, r) => s + num(r.pitches_thrown), 0);
Expand Down Expand Up @@ -478,8 +479,9 @@ export function loadPlayerMetrics(
export function loadAllPlayerMetrics(
playerIds: string[],
rows: BoxScoreRow[],
nowIso: string = new Date().toISOString(),
): LoadedPlayerMetrics[] {
return playerIds.map((pid) => loadPlayerMetrics(pid, rows));
return playerIds.map((pid) => loadPlayerMetrics(pid, rows, nowIso));
}

// -----------------------------------------------------------------------------
Expand Down
Loading