diff --git a/scripts/backfill-binary-decision.ts b/scripts/backfill-binary-decision.ts new file mode 100644 index 0000000..82fb608 --- /dev/null +++ b/scripts/backfill-binary-decision.ts @@ -0,0 +1,84 @@ +/** + * 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 + */ + +import { PrismaClient } 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 + + 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 + const evaluations = await prisma.evaluation.findMany({ + where: { + assignment: { roundId: round.id }, + binaryDecision: null, + status: 'SUBMITTED', + criterionScoresJson: { not: undefined }, + }, + select: { id: true, criterionScoresJson: true }, + }) + + let updated = 0 + for (const ev of evaluations) { + const scores = ev.criterionScoresJson as Record | null + if (!scores) continue + + const value = scores[boolCriterion.id] + if (typeof value !== 'boolean') continue + + await prisma.evaluation.update({ + where: { id: ev.id }, + data: { binaryDecision: value }, + }) + updated++ + } + + console.log(` Updated ${updated}/${evaluations.length} evaluations`) + totalUpdated += updated + } + + console.log(`\nDone. Total evaluations updated: ${totalUpdated}`) +} + +main() + .catch(console.error) + .finally(() => prisma.$disconnect()) diff --git a/src/components/admin/round/score-distribution.tsx b/src/components/admin/round/score-distribution.tsx index 6ac8432..f6f84a2 100644 --- a/src/components/admin/round/score-distribution.tsx +++ b/src/components/admin/round/score-distribution.tsx @@ -38,13 +38,13 @@ export function ScoreDistribution({ roundId }: ScoreDistributionProps) { No evaluations submitted yet

) : ( -
+
{dist.globalDistribution.map((bucket) => { const heightPct = (bucket.count / maxCount) * 100 return ( -
+
{bucket.count || ''} -
+