From e3e3fa9da4d1fea8d2b0f0c16a638b30b53b773e Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 5 Feb 2026 14:14:19 +0100 Subject: [PATCH] Fix AI assignment errors and tag matching - Add missing updatedAt column to AssignmentJob table - Fix algorithmic assignment to use AI-assigned projectTags instead of raw CSV tags - Add case-insensitive tag matching for better expertise matching - Scores should now properly reflect tag matches between judges and projects Co-Authored-By: Claude Opus 4.5 --- .../migration.sql | 11 ++++++++++ src/server/routers/assignment.ts | 22 ++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 prisma/migrations/20260205210000_fix_assignment_job_updated_at/migration.sql diff --git a/prisma/migrations/20260205210000_fix_assignment_job_updated_at/migration.sql b/prisma/migrations/20260205210000_fix_assignment_job_updated_at/migration.sql new file mode 100644 index 0000000..c5de518 --- /dev/null +++ b/prisma/migrations/20260205210000_fix_assignment_job_updated_at/migration.sql @@ -0,0 +1,11 @@ +-- Add missing updatedAt column to AssignmentJob table + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'AssignmentJob' AND column_name = 'updatedAt' + ) THEN + ALTER TABLE "AssignmentJob" ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; + END IF; +END $$; diff --git a/src/server/routers/assignment.ts b/src/server/routers/assignment.ts index d32d3ae..f1e9d38 100644 --- a/src/server/routers/assignment.ts +++ b/src/server/routers/assignment.ts @@ -613,6 +613,9 @@ export const assignmentRouter = router({ id: true, title: true, tags: true, + projectTags: { + include: { tag: { select: { name: true } } }, + }, _count: { select: { assignments: true } }, }, }) @@ -656,13 +659,22 @@ export const assignmentRouter = router({ const reasoning: string[] = [] let score = 0 - // Expertise match (35% weight) - const matchingTags = juror.expertiseTags.filter((tag) => - project.tags.includes(tag) - ) + // Expertise match (35% weight) - use AI-assigned projectTags if available + const projectTagNames = project.projectTags.map((pt) => pt.tag.name.toLowerCase()) + + // Match against AI-assigned tags first, fall back to raw tags + const matchingTags = projectTagNames.length > 0 + ? juror.expertiseTags.filter((tag) => + projectTagNames.includes(tag.toLowerCase()) + ) + : juror.expertiseTags.filter((tag) => + project.tags.map((t) => t.toLowerCase()).includes(tag.toLowerCase()) + ) + + const totalTags = projectTagNames.length > 0 ? projectTagNames.length : project.tags.length const expertiseScore = matchingTags.length > 0 - ? matchingTags.length / Math.max(project.tags.length, 1) + ? matchingTags.length / Math.max(totalTags, 1) : 0 score += expertiseScore * 35 if (matchingTags.length > 0) {