Commit Graph

23 Commits

Author SHA1 Message Date
Matt
387f84c338 feat: per-round balanced-scoring toggle in side sheet
A Switch at the top of the project side panel writes
useBalancedRanking onto Round.configJson via the existing round.update
mutation. The flip is shared across all viewers because the value
lives in the round's persisted config; hydration runs on every
roundData refetch so the UI converges quickly when another admin
flips it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:20:21 +02:00
Matt
9a2c10a6f8 fix: scope admin ranking dashboard side-sheet stats to current round
The admin dashboard fetches its side-sheet detail from project.getFullDetail
(not analytics.getProjectDetail as the audit assumed), and that procedure
had the same cross-round contamination bug. Add an optional roundId to
its input, filter the SUBMITTED-evaluations query when provided, and pass
roundId from the dashboard's useQuery so the Avg Score / Pass Rate /
Evaluators card now matches the per-juror list rendered below it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:15:47 +02:00
Matt
901d9ba982 feat: rank projects by balanced score in ranking dashboard
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m0s
Initial ranking order, advancement cutoff line, and per-row "advancing"
highlight now all use the juror-balanced (z-score corrected) average,
falling back to the raw avgGlobalScore when no balanced score exists.
The init effect waits for evalScores so the sort has the data it needs.

Admin drag-reorders still take precedence — saved reorders override the
default sort exactly as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 15:33:56 +02:00
Matt
982d5193c5 feat: surface juror-balanced scores and AI calibration advisory
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m27s
Adds a shared juror-balancing utility (z-score normalization per juror,
rescaled back onto the raw 1-10 scale) and wires it into:

- Admin reports page: Top-10 project table now shows "Raw Avg" and
  "Balanced" columns side by side, and the summary stats row shows a
  balanced-average tile. Sort defaults to balanced so harsh and lenient
  graders no longer skew the ranking.
- Ranking dashboard: each project row shows a green/amber balanced-score
  chip next to the raw average when the two differ by ≥0.05, making it
  obvious when juror calibration moved a project's effective ranking.

Also adds AI Juror Calibration Advisory — a mutation that takes
anonymized per-juror stats, calls OpenAI, and produces a plain-language
explanation of the cohort's grading patterns plus per-juror severity
(normal / notable / outlier) with a one-sentence narrative. The advisory
describes the statistical balance that already runs; it does not
introduce a new weighting layer. Rendered as a panel in the Juror
Consistency tab when a specific round is selected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 16:19:00 +02:00
37351044ed feat: multi-role jury fix, country flags, applicant deadline banner, timeline
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Fix project list returning empty for users with both SUPER_ADMIN and
  JURY_MEMBER roles (jury filter now skips admins) in project, assignment,
  and evaluation routers
- Add CountryDisplay component showing flag emoji + name everywhere
  country is displayed (admin, observer, jury, mentor views — 17 files)
- Add countdown deadline banner on applicant dashboard for INTAKE,
  SUBMISSION, and MENTORING rounds with live timer
- Remove quick action buttons from applicant dashboard
- Fix competition timeline sidebar: green dots/connectors only up to
  current round, yellow dot for current round, red connector into
  rejected round, grey after

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:00:29 +01:00
050836d522 feat: finalization tab respects ranking overrides, grouped by category
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m2s
- processRoundClose now applies reordersJson drag-reorder overrides
  when building the evaluation pass set (was ignoring admin reorders)
- Finalization tab groups proposed outcomes by category (Startup/Concept)
  with per-group pass/reject/total counts
- Added category filter dropdown alongside the existing outcome filter
- Removed legacy "Advance Top N" button and dialog from ranking page
  (replaced by the finalization workflow)
- Fix project edit status defaultValue showing empty placeholder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:10:04 +01:00
c0f2b9bd38 fix: show 0/N Yes instead of "N jurors", color 1/2 Yes amber
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m38s
- Always display yes/no count format (e.g. "0/2 Yes") instead of
  generic "2 jurors" when no advance votes exist
- Color coding: 2/2 Yes = green, 1/2 Yes = amber, 0/2 Yes = red

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:31:13 +01:00
8c5f4998a8 fix: sort ranking display by avgGlobalScore, not compositeScore
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m33s
The display was sorted by compositeScore (which factors in pass rate and
z-score normalization) but the cutoff line and displayed values use
avgGlobalScore. This caused projects with high averages but low pass
rates (e.g. 1/2 Yes) to appear below the cutoff even when their average
exceeded the threshold.

Now sorts by avgGlobalScore (the visible metric) with compositeScore as
tiebreaker. Also adds a green left border to advancing projects for
clearer threshold highlighting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:20:11 +01:00
761a203063 fix: sort ranking display by compositeScore, fix threshold cutoff line
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m41s
- Sort deduped ranking entries by compositeScore descending during
  localOrder init — ensures correct display order for both formula
  and old AI snapshots
- Fix threshold cutoff: scan forward to find first non-qualifying
  project instead of backward scan that left non-qualifying projects
  above the line

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:43:49 +01:00
cb688ba3e6 feat: formula-based ranking with optional AI, configurable score/pass-rate weights
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m56s
Add scoreWeight and passRateWeight (0-10) to evaluation config for
configurable composite score formula. When ranking criteria text is
empty, triggerAutoRank uses pure formula ranking (no LLM calls).
When criteria text is present, AI-assisted ranking runs as before.

- Add FORMULA to RankingMode enum with migration
- Extract fetchCategoryProjects helper, add formulaRank service
- Update computeCompositeScore to accept configurable weights
- Add score/pass-rate weight sliders to ranking dashboard UI
- Mode-aware button labels (Calculator/formula vs Sparkles/AI)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:24:17 +01:00
ac86e025e2 feat: ranking in-progress indicator persists across all admin users
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m1s
- Create snapshot with status RUNNING before AI call starts
- Update to COMPLETED/FAILED when done
- Dashboard derives rankingInProgress from server snapshot status
- All admins see the spinner, not just the one who triggered it
- Poll snapshots every 3s so progress updates appear quickly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:57:11 +01:00
2bccb52a16 fix: ranking sorted by composite score, deduplicate AI results, single cutoff line
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m0s
- Sort all ranked projects by compositeScore descending so highest-rated
  projects always appear first (instead of relying on AI's inconsistent rank order)
- Deduplicate AI ranking response (AI sometimes returns same project multiple times)
- Deduplicate ranking entries and reorder IDs on dashboard load as defensive measure
- Show advancement cutoff line only once (precompute last advancing index)
- Override badge only shown when admin has actually drag-reordered (not on fresh rankings)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:34:31 +01:00
8db9c72f4c fix: ranking reorders persist across all admin sessions
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m49s
Apply saved reordersJson when initializing the dashboard so any admin
sees the latest drag-reorder state, not just the original AI order.
The latest reorder event per category is used as the initial localOrder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:04:14 +01:00
80a7bedddc fix: ranking shows all reviewed projects, fix override badge sync issue
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m17s
- AI ranking now includes ALL projects (never filters/excludes any)
- Updated system prompt: filter criteria inform priority, not exclusion
- Dynamic maxTokens scaling for large project pools (80 tokens/project)
- Fallback: projects AI omits are appended sorted by composite score
- Override badge uses snapshotOrder state (synced with localOrder in same
  useEffect) instead of rankingMap.originalIndex to prevent stale-render
  mismatch where all items incorrectly showed as overridden

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:10:48 +01:00
d2e0dbdc94 fix: override badge only shows when admin actually reordered a project
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m17s
Compare against original snapshot array position, not AI's internal rank number.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:29:40 +01:00
36045bef9d fix: ranking dashboard respects threshold advancement mode
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Header shows "Score >= X advance" instead of "Top N" in threshold mode
- Cutoff line placed after last project meeting threshold, not at fixed count
- Projects advancing determined by avg score vs threshold, not position

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:25:49 +01:00
19b58e4434 feat: weighted criteria in AI ranking, z-score normalization, threshold advancement, CSV export
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m16s
- Add criteriaWeights to EvaluationConfig for per-criterion weight assignment (0-10)
- Rewrite ai-ranking service: fetch eval form criteria, compute per-criterion averages,
  z-score normalize juror scores to correct grading bias, send weighted criteria to AI
- Update AI prompts with criteria_definitions and per-project criteria_scores
- compositeScore uses weighted criteria when configured, falls back to globalScore
- Add collapsible ranking config section to dashboard (criteria text + weight sliders)
- Move rankingCriteria textarea from eval config tab to ranking dashboard
- Store criteriaWeights in ranking snapshot parsedRulesJson for audit
- Enhance projectScores CSV export with per-criterion averages, category, country
- Add Export CSV button to ranking dashboard header
- Add threshold-based advancement mode (decimal score threshold, e.g. 6.5)
  alongside existing top-N mode in advance dialog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:24:14 +01:00
c6ebd169dd feat: admin evaluation editing, ranking improvements, status transition fix
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>
2026-03-02 10:46:52 +01:00
2f1136646e feat: ranking UI improvements - highlight advancing projects, expandable reviews, view project link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:34:32 +01:00
ba7f068b1e fix: show project title, team & country in ranking rows instead of truncated IDs
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Adds getProjectStates query to build a projectInfoMap lookup. Each row now
shows the project title, team name, and country. Also renames "Pass" label
to "Yes" to match the binary yes/no vote semantics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:08:30 +01:00
a6f3945337 feat(02-03): add Advance Top N dialog + batch-reject to RankingDashboard
- Add pendingReorderCount ref + onMutate/onSettled to saveReorderMutation (DASH-07)
- Add advanceMutation (trpc.round.advanceProjects) with getProjectStates invalidation
- Add batchRejectMutation (trpc.roundEngine.batchTransition) using .length per MEMORY.md
- Add handleAdvance: advances top N per category, optionally batch-rejects the rest
- Add Advance Top N button in header (disabled when saveReorderMutation.isPending)
- Add Dialog with per-category N inputs, batch-reject checkbox, and count preview
- Import Dialog, Input, Label, Trophy from shadcn/lucide
2026-02-27 09:53:49 +01:00
6512e4ea2a feat(02-02): implement full RankingDashboard component
- Replace stub with complete drag-and-drop ranked project list (DASH-01, DASH-02)
- localOrder in useState with useRef init guard prevents snap-back (DASH-03)
- Per-category DndContext (STARTUP / BUSINESS_CONCEPT) with SortableProjectRow
- AI-order rows show dark-blue rank badge; admin-reordered show amber '(override)' badge
- Sheet panel lazy-loads trpc.project.getFullDetail on row click (DASH-04)
- Per-juror evaluation breakdown with score, binary decision, feedback text
- 'Run Ranking' button in header triggers triggerAutoRank mutation
- Empty categories show placeholder message (no empty drag zone)
- Zero TypeScript errors; build passes
2026-02-27 09:48:06 +01:00
8f71527353 feat(02-01): register Ranking tab in round detail page + create component stub
- Create src/components/admin/round/ranking-dashboard.tsx (stub with placeholder text)
- Import RankingDashboard in round detail page.tsx
- Add Ranking tab entry guarded by isEvaluation (uses existing BarChart3 icon)
- Add TabsContent block rendering RankingDashboard with competitionId + roundId props
2026-02-27 09:41:59 +01:00