refactor: remove legacy direct-write fallback in batch-add-results

Every qualifying scoring_event now has tournament_id (check constraint
enforces it), so the non-canonical fallback is dead. Replace with an
explicit error surface so any configuration regression becomes visible
instead of silently bypassing canonical.

Phase 4 Task 4.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Chris Parsons 2026-05-01 23:08:19 +00:00
parent 549b437466
commit e2a62bd05b
No known key found for this signature in database

View file

@ -384,52 +384,39 @@ export async function action({ request, params }: Route.ActionArgs) {
return { error: "Scoring event not found" };
}
if (scoringEvent.tournamentId) {
// Canonical path: translate season_participant.id → canonical participant.id
const spRows = allSeasonParticipants.filter((sp) =>
incoming.some((r) => r.participantId === sp.id),
);
const missingCanonical = spRows.filter((sp) => !sp.participantId);
if (missingCanonical.length > 0) {
return {
error: `Some season participants are not linked to canonical participants: ${missingCanonical.map((sp) => sp.name).join(", ")}`,
};
}
for (const row of incoming) {
const sp = spRows.find((s) => s.id === row.participantId);
if (!sp?.participantId) continue;
await upsertTournamentResult({
tournamentId: scoringEvent.tournamentId,
participantId: sp.participantId,
placement: row.placement,
});
}
const syncReport = await syncTournamentResults(scoringEvent.tournamentId);
// Qualifying events always have a canonical tournament link (check
// constraint). Write results canonically and fan out.
if (!scoringEvent.tournamentId) {
return {
success: `${incoming.length} result${incoming.length === 1 ? "" : "s"} saved canonically. Synced to ${syncReport.windowsSynced} window${syncReport.windowsSynced === 1 ? "" : "s"}${syncReport.windowsFailed > 0 ? ` (${syncReport.windowsFailed} failed)` : ""}.`,
syncReport,
error:
"This scoring event has no canonical tournament link — cannot save batch results. Contact a developer.",
};
}
// Legacy direct-write path for non-canonical events (team sports, etc.).
const existingResults = await getEventResults(params.eventId);
const existingIds = new Set(existingResults.map((r) => r.seasonParticipantId));
const newResults = filterNewResults(incoming, existingIds);
if (newResults.length > 0) {
await createEventResultsBulk(
newResults.map((r) => ({
scoringEventId: params.eventId,
participantId: r.participantId,
placement: r.placement,
}))
);
const spRows = allSeasonParticipants.filter((sp) =>
incoming.some((r) => r.participantId === sp.id),
);
const missingCanonical = spRows.filter((sp) => !sp.participantId);
if (missingCanonical.length > 0) {
return {
error: `Some season participants are not linked to canonical participants: ${missingCanonical.map((sp) => sp.name).join(", ")}`,
};
}
for (const row of incoming) {
const sp = spRows.find((s) => s.id === row.participantId);
if (!sp?.participantId) continue;
await upsertTournamentResult({
tournamentId: scoringEvent.tournamentId,
participantId: sp.participantId,
placement: row.placement,
});
}
const syncReport = await syncTournamentResults(scoringEvent.tournamentId);
return {
success: `${newResults.length} result${newResults.length === 1 ? "" : "s"} saved${incoming.length - newResults.length > 0 ? ` (${incoming.length - newResults.length} duplicate${incoming.length - newResults.length === 1 ? "" : "s"} skipped)` : ""}.`,
success: `${incoming.length} result${incoming.length === 1 ? "" : "s"} saved canonically. Synced to ${syncReport.windowsSynced} window${syncReport.windowsSynced === 1 ? "" : "s"}${syncReport.windowsFailed > 0 ? ` (${syncReport.windowsFailed} failed)` : ""}.`,
syncReport,
};
} catch (error) {
logger.error("Error saving batch results:", error);