Files
MOPC-Portal/scripts/backfill-binary-decision.ts

107 lines
3.1 KiB
TypeScript
Raw Permalink Normal View History

/**
* 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<string, unknown> | 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<string, unknown> | 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())