All checks were successful
Build and Push Docker Image / build (push) Successful in 9m26s
- Add adminEditEvaluation mutation and getJurorEvaluations query - Create shared EvaluationEditSheet component with inline feedback editing - Add Evaluations tab to member detail page (grouped by round) - Make jury group member names clickable (link to member detail) - Replace inline EvaluationDetailSheet on project page with shared component - Fix project status transition validation (skip when status unchanged) - Fix frontend to not send status when unchanged on project edit - Ranking dashboard improvements and boolean decision converter fixes - Backfill script updates for binary decisions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
3.1 KiB
TypeScript
107 lines
3.1 KiB
TypeScript
/**
|
|
* 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())
|