The Last Run Column Only Counted Manual Imports

Took two separate fixes, a week apart, to notice this was one bug wearing four costumes. The Ballpark Genius CLI’s admin dashboard has a “Last Run” column reading from an ImportLog table. For transactions and player_team_refresh, it sat stuck on stale “N days ago” timestamps no matter how recently those jobs actually ran. Same story a week later for statcast and war, both stuck at “3 days ago” despite a daily launchd cron firing every single morning at 06:00.

The shape was identical every time: the handler doing the actual work, importTransactionsHandler, refresh-player-teams.ts, importStatcastHandler, importWarHandler, ran fine, mutated real data, and never once called importLogService.logImport(). The only code path that did write to ImportLog was the CLI’s own ImportRunner, which only fires when a human types /import in the TUI. So “Last Run” wasn’t lying exactly, it was answering a different question than the one on the label: not “when did this last succeed” but “when did someone last do this by hand.” The daily cron had been running statcast/war every day, correctly, invisibly, for however long, while the dashboard insisted it was three days stale.

Wired logImport into each handler directly, success with a record count, failure with the error message, matching the pattern statcast.controller.ts‘s career-war handler already used. refresh-player-teams.ts runs standalone via tsx, not through Fastify, so it logs directly through the service and awaits prisma.$disconnect() after.

Chasing the second half of this surfaced a bonus bug going the other direction: transactions was already self-logging from a prior fix, but STEP_META never got marked selfLogged: true for it, so every manual /import was writing two rows for the same run, one from the handler, one from ImportRunner parsing the shell output and assuming nobody had logged yet. Marked it. Also marked player_team_refresh, which wasn’t visibly double-logging yet only because its success text didn’t happen to match ImportRunner‘s regex, a coincidence, not a design.

Also found, while at it, that the tests covering this whole runner were already stale on main: fixtures missing two steps entirely, step numbering that hadn’t matched import-all.sh in a while, 7 tests failing before I touched anything. The dashboard was lying about freshness, folks, and the tests checking the dashboard hadn’t noticed either, which is a shell of a test suite if I’ve ever seen one.