/** * One-off script: backfill binaryDecision from custom boolean criterion * "Move to the Next Stage?" for evaluations where binaryDecision is null. * * Usage: npx tsx scripts/backfill-binary-decision.ts * * What it does: * 1. Finds all rounds with a boolean criterion labeled "Move to the Next Stage?" * 2. For evaluations in those rounds where binaryDecision IS NULL, * copies the boolean value from criterionScoresJson into binaryDecision * * Safe to re-run: only updates evaluations where binaryDecision is still null. */ import { PrismaClient, Prisma } from '@prisma/client' const prisma = new PrismaClient() type CriterionConfig = { id: string label: string type?: string } async function main() { // Find all rounds that have evaluation config with criteria const rounds = await prisma.round.findMany({ where: { roundType: 'EVALUATION' }, select: { id: true, name: true, configJson: true }, }) let totalUpdated = 0 let totalSkipped = 0 for (const round of rounds) { const config = round.configJson as Record | null if (!config) continue const criteria = (config.criteria ?? config.evaluationCriteria ?? []) as CriterionConfig[] // Find the boolean criterion for "Move to the Next Stage?" const boolCriterion = criteria.find( (c) => (c.type === 'boolean') && c.label?.toLowerCase().includes('move to the next stage'), ) if (!boolCriterion) continue console.log(`Round "${round.name}" (${round.id}): found criterion "${boolCriterion.label}" (${boolCriterion.id})`) // Find evaluations in this round where binaryDecision is null // Use Prisma.JsonNull for proper null filtering const evaluations = await prisma.evaluation.findMany({ where: { assignment: { roundId: round.id }, binaryDecision: null, status: 'SUBMITTED', }, select: { id: true, criterionScoresJson: true }, }) let updated = 0 let skipped = 0 for (const ev of evaluations) { const scores = ev.criterionScoresJson as Record | null if (!scores) { skipped++ continue } const value = scores[boolCriterion.id] let resolved: boolean | null = null if (typeof value === 'boolean') { resolved = value } else if (value === 'true' || value === 1) { resolved = true } else if (value === 'false' || value === 0) { resolved = false } if (resolved === null) { console.log(` Skipping eval ${ev.id}: criterion value is ${JSON.stringify(value)}`) skipped++ continue } await prisma.evaluation.update({ where: { id: ev.id }, data: { binaryDecision: resolved }, }) updated++ } console.log(` Updated ${updated}/${evaluations.length} evaluations (skipped ${skipped})`) totalUpdated += updated totalSkipped += skipped } console.log(`\nDone. Total updated: ${totalUpdated}, Total skipped: ${totalSkipped}`) } main() .catch(console.error) .finally(() => prisma.$disconnect())