diff --git a/src/components/admin/round/ranking-dashboard.tsx b/src/components/admin/round/ranking-dashboard.tsx
index f379afa..2528bab 100644
--- a/src/components/admin/round/ranking-dashboard.tsx
+++ b/src/components/admin/round/ranking-dashboard.tsx
@@ -169,10 +169,11 @@ function SortableProjectRow({
{a.user?.name ?? a.user?.email ?? 'Unknown'}
- {a.evaluation?.binaryDecision != null && (
+ {a.evaluation?.decision != null && (
- {a.evaluation.binaryDecision ? 'Yes' : 'No'}
+ {a.evaluation.decision ? 'Yes' : 'No'}
)}
Score: {a.evaluation?.globalScore?.toFixed(1) ?? '—'}
diff --git a/src/server/routers/project.ts b/src/server/routers/project.ts
index a8c2339..7e48465 100644
--- a/src/server/routers/project.ts
+++ b/src/server/routers/project.ts
@@ -1305,6 +1305,27 @@ export const projectRouter = router({
}),
])
+ // Resolve the boolean "advance to next round" criterion id for each round
+ // so we can fall back to criterionScoresJson when binaryDecision is null.
+ // Mirrors ranking.ts logic: prefer type='advance', else legacy boolean
+ // criterion labeled "move to the next stage".
+ const roundIdsInUse = Array.from(new Set(assignments.map((a) => a.round.id)))
+ const advanceCriterionByRound = new Map()
+ if (roundIdsInUse.length > 0) {
+ const forms = await ctx.prisma.evaluationForm.findMany({
+ where: { roundId: { in: roundIdsInUse }, isActive: true },
+ select: { roundId: true, criteriaJson: true },
+ })
+ for (const form of forms) {
+ if (advanceCriterionByRound.has(form.roundId)) continue
+ const criteria = (form.criteriaJson as Array<{ id: string; type?: string; label?: string }> | null) ?? []
+ const found =
+ criteria.find((c) => c.type === 'advance') ??
+ criteria.find((c) => c.type === 'boolean' && c.label?.toLowerCase().includes('move to the next stage'))
+ advanceCriterionByRound.set(form.roundId, found?.id ?? null)
+ }
+ }
+
// Compute evaluation stats
let stats = null
if (submittedEvaluations.length > 0) {
@@ -1355,13 +1376,30 @@ export const projectRouter = router({
}))
),
Promise.all(
- assignments.map(async (a) => ({
- ...a,
- user: {
- ...a.user,
- avatarUrl: await getUserAvatarUrl(a.user.profileImageKey, a.user.profileImageProvider),
- },
- }))
+ assignments.map(async (a) => {
+ // Resolve decision: column first, criterion fallback second.
+ let decision: boolean | null = a.evaluation?.binaryDecision ?? null
+ if (decision == null && a.evaluation) {
+ const advCritId = advanceCriterionByRound.get(a.round.id) ?? null
+ if (advCritId) {
+ const scores = a.evaluation.criterionScoresJson as Record | null
+ if (scores) {
+ const val = scores[advCritId]
+ if (typeof val === 'boolean') decision = val
+ else if (val === 'true') decision = true
+ else if (val === 'false') decision = false
+ }
+ }
+ }
+ return {
+ ...a,
+ user: {
+ ...a.user,
+ avatarUrl: await getUserAvatarUrl(a.user.profileImageKey, a.user.profileImageProvider),
+ },
+ evaluation: a.evaluation ? { ...a.evaluation, decision } : null,
+ }
+ })
),
projectRaw.mentorAssignment
? (async () => ({