fix(baseball): compute OBP/SLG/OPS in legacy aggregate recalc (#436)#646
Conversation
recalculatePlayerAggregates only wrote career_avg, but My Stats StatsOverviewCards reads career_obp/career_slg/career_ops — columns that never existed on baseball_player_aggregates, so OBP/SLG/OPS permanently showed "---" despite sufficient counting stats. - Add idempotent migration adding career_obp/career_slg/career_ops (numeric) to baseball_player_aggregates (ADD COLUMN IF NOT EXISTS). - Extract a pure computeCareerSlashLine helper (standard formulas, null on zero denominator) and call it from recalculatePlayerAggregates, upserting the derived slash line. - Unit test covers a multi-session aggregate with walks/SF/HBP plus the zero-denominator honesty cases. Migration is committed only, not applied. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017VUauUXsm9aXegShmpJi5n
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR Summary by QodoFix baseball aggregate recalc to persist career OBP/SLG/OPS
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
93 rules 1. Schema rollout breaks recalc
|
| career_obp: careerObp, | ||
| career_slg: careerSlg, | ||
| career_ops: careerOps, |
There was a problem hiding this comment.
2. Slash line change undocumented 📘 Rule violation ⚙ Maintainability
This PR changes business behavior by computing and persisting career_obp, career_slg, and career_ops for Baseball player aggregates, but no corresponding memory/features/* documentation update (or explicit in-code rationale for skipping it) is included. This can leave internal feature docs out of sync with user-visible stats behavior.
Agent Prompt
## Issue description
Business behavior changed (Baseball aggregate recalculation now derives and persists OBP/SLG/OPS), but the change set does not update `memory/features/*` docs or include an explicit explanation in code for why no doc update is needed.
## Issue Context
- The PR introduces a new derivation helper and persists three new aggregate columns.
- The feature registry indicates Baseball is tracked as `baseball_core`, but its docs currently point at `CLAUDE.md` rather than a `memory/features/*` doc.
## Fix Focus Areas
- src/app/baseball/actions/stats.ts[555-606]
- src/lib/baseball/aggregates/career-slash-line.ts[29-61]
- supabase/migrations/20260701020000_baseball_player_aggregates_slash_line.sql[1-20]
- memory/registry.yml[110-147]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| career_obp: careerObp, | ||
| career_slg: careerSlg, | ||
| career_ops: careerOps, |
There was a problem hiding this comment.
3. Schema rollout breaks recalc 🐞 Bug ☼ Reliability
recalculatePlayerAggregates now always upserts career_obp/career_slg/career_ops, so on any DB where those columns don’t exist yet the upsert will error and no aggregates (including career_avg) will be persisted for that run. uploadStatsCSV awaits recalculatePlayerAggregates but does not check its returned success flag, so uploads can still report success while aggregates stop updating until the migration is applied.
Agent Prompt
## Issue description
`recalculatePlayerAggregates` unconditionally writes the new `career_obp/career_slg/career_ops` columns. If code reaches an environment where the migration hasn’t been applied, Postgres will reject the upsert (`column does not exist`), which prevents *any* aggregate fields from being updated for that player.
## Issue Context
This is a common rollout ordering hazard (code deploy before schema migration). Because `uploadStatsCSV` triggers aggregate recalculation and doesn’t act on the returned `{ success: false }`, the user flow can appear successful while aggregates silently fail to update.
## Fix Focus Areas
- src/app/baseball/actions/stats.ts[555-619]
### Implementation guidance
- Keep the new behavior when the columns exist.
- Add a defensive fallback around the aggregates upsert:
- Try upsert with `career_obp/career_slg/career_ops`.
- If the error indicates missing columns (e.g., message includes `career_obp` / Postgres undefined_column `42703` if exposed), retry a second upsert with those keys omitted so legacy aggregates (AVG/etc.) still update.
- Log a clear warning (once per request) when falling back, so ops can detect an out-of-order rollout.
- Do **not** swallow other errors; only fallback on the specific missing-column case.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
🤖 Mission Control — PR summary Changes: Persists career OBP/SLG/OPS in |
What & why
recalculatePlayerAggregates(src/app/baseball/actions/stats.ts) only persistedcareer_avg, but My StatsStatsOverviewCardsreadscareer_obp/career_slg/career_ops— columns that never existed on the livebaseball_player_aggregatestable. Players with CSV/practice upload data saw AVG populated but OBP/SLG/OPS permanently show---, despite having the counting stats.Changes
supabase/migrations/20260701020000_baseball_player_aggregates_slash_line.sql— idempotentADD COLUMN IF NOT EXISTS career_obp/career_slg/career_ops numeric. Committed only, not applied to any database.src/lib/baseball/aggregates/career-slash-line.ts—computeCareerSlashLine()sums counting stats and applies standard formulas:.000).stats.tsnow derives and upserts the slash line via the helper (extracted so it is testable without a DB;stats.tsis'use server').src/lib/baseball/__tests__/career-slash-line.test.ts— multi-session aggregate with walks/SF/HBP + zero-denominator honesty cases.Acceptance criteria
recalculatePlayerAggregatesderives and storescareer_obp,career_slg,career_opsfrom summed counting stats (standard formulas, null on zero denominators).Note: the migration must be applied for the new columns to persist; per task directive it is committed only, not applied.
🤖 Generated with Claude Code