Selection Committee
The Selection Committee (SC) is a group of invited reviewers who watch every film in their assigned screening group and score each one across all eligible award categories. Their scores — after ballot validation — determine which films receive award nominations.
This is distinct from the Judge and Academy scoring processes, which have their own result pages (/admin/results/judge, /admin/results/academy).
Feature Flag
The entire SC workflow is gated behind the selection_committee OpenFeature flag. All SC pages check this flag via middleware. The admin results page uses role middleware instead (admin-only, always accessible regardless of flag state).
Data Model
Key Tables
| Table | Purpose |
|---|---|
film_groups | Screening groups of type "selection" — each group contains ~8 teams |
film_group_users | Which SC members are assigned to which group |
selection_metrics | One row per (SC member × team × award) — stores the member’s score (1–10) |
selection_progress | Tracks which team index a SC member is currently reviewing within a group |
award_nominations | Nominations per team per award — used to determine which awards are scoreable for each film |
Key Constraints
selection_metrics: unique on(real_user_id, team_id, award_id)— upserted, not insertedselection_progress: unique on(film_group_id, real_user_id)— upserted, not inserted
Awards
Only awards where max_nominations != 0 appear in the SC interface. They are fetched ordered by name. Each award has a max_nominations field:
- If
max_nominations < 0→ the metric is always enabled for every film (e.g. Best Film) - Otherwise → the metric is only enabled for a film if that film has an
award_nominationrecord for that award
This means SC members can only score a film in a category if the film was actually nominated in that category — except for always-on awards.
The Pinia Store (selectionCommittee.ts)
A single Pinia store powers all SC pages. It is initialized once and shared across the selection/ route tree.
Data Fetched
SelectionFilmGroups query (scoped to the current film festival via current_film_festival OpenFeature number):
- All
film_groupsof type"selection"for the current festival - For each group: all teams (ordered by
sort), each team’s:- Film metadata (name, genre, description, studio, Mux playback ID)
- Poster asset
selection_metrics(scores already submitted by this SC member)selection_metrics_aggregate(count of scores > 0, for progress tracking)award_nominations— filtered to nominations wheremembership.id is not null(active memberships only), ordered by award name
selection_progresses— the SC member’s current position in each group- All eligible awards
Live Updates
A GraphQL subscription (SelectionMetrics) watches for any changes to selection_metrics globally and triggers a refetch() of the main query when fired. This keeps all open SC sessions in sync.
Computed State
filmGroups All SC film groups for the current festival
awards All eligible awards
filmGroup The currently active group (resolved from route.params.filmGroupId)
teamIndex Which team the SC member is reviewing (persisted via selection_progress) — settable
currentTeam The team at teamIndex in the current group
teamMetricEnabled (teamId, awardId) => boolean — whether a score input is active
getTeamMetric (teamId, awardId) => number — current score (0 if unscored)
setTeamMetric (teamId, awardId, value) => void — upserts a score via mutation
metricProgress Per-group completion ratio (0–1)
metricFilmProgress (filmGroupId, teamId) => number — completion ratio for a single film
Progress Calculation
For each film, the denominator is unique award nominations for that film + 1 (the +1 accounts for the always-on award). The numerator is the count of selection_metrics with value > 0 for that team. A film is “complete” when this ratio equals 1.
SC Member Pages
/selection — Group Dashboard
The landing page. Shows:
- A training video (Mux embed, loaded via
scm_training_videoOpenFeature feature) - A card per film group, each showing:
- A progress bar (green when 100% complete, primary color otherwise)
- A poster grid of all films in the group
- Link to
/selection/[filmGroupId]
/selection/[filmGroupId] — Scoring Interface
The main scoring page. Layout:
Top strip: film poster thumbnails for all teams in the group. Clicking a poster selects that team (updates teamIndex, which is persisted). Active team is scaled up (CSS transform). Each poster has a green/grey badge indicating complete/incomplete.
Left column (main):
- Mux video embed for the currently selected film
- Film poster thumbnail (click to expand), film name, genre chip, team number, studio
- Avatar thumbnails for each nomination (except “Song or Music”) showing the nominee’s headshot — hovering shows award name + nominee name
Right column:
- One
SelectionMetriccomponent per award - Each shows an info tooltip with the award description
- Only enabled (interactive) if
teamMetricEnabledreturns true for that award
A “Review Rankings” button navigates to /selection/[filmGroupId]/review.
/selection/[filmGroupId]/review — Per-Group Rankings Preview
A read-only view for the SC member to review their own rankings before finalizing. Shows expansion panels, one per award:
- Panel header: award name + the SC member’s current top pick for that award
- Panel body: horizontal scroll of all films in the group, sorted by that SC member’s score descending, showing a Mux GIF preview and the ordinal rank (1st, 2nd, 3rd…)
The SC member can adjust scores inline via the same SelectionMetric component.
Admin Results Page (/admin/results/selection)
Admin-only (role middleware). Aggregates all SC member scores across a group into a final ranked result per team per award.
Controls
- Awards combobox — select which award columns to display in the table
- Film Festival Year selector — view any past year (currently supports 23–26)
- “Fix the Bug” checkbox — toggles between the buggy and corrected nomination count when computing ballot validity (see 2026-Selection-Committee-Bug)
Ballot Validation (filmGroupUsers)
For each group, computes a required threshold:
required = sum over all teams of (award_nominations_aggregate.count + 1)With “Fix the Bug” on:
required = sum over all teams of (award_nominations_aggregate_new.count + 1)Where award_nominations_aggregate_new filters to nominations where membership.deleted IS NULL (active memberships only).
A SC member’s ballot is valid for a group only if their total number of submitted selection_metrics in that group is >= required. Invalid ballots are excluded from scoring entirely.
Score Aggregation (filmGroupBallots → rankings → results)
For each valid SC member ballot in a group:
- For each award, their scores across all films in the group are rank-ordered (highest score = rank 1)
- This converts raw 1–10 scores into relative rankings within that SC member’s ballot
Then across all valid ballots:
- Each team’s ranks per award are averaged across all valid SC members
- Final
value=(11 - mean_rank) * 10— so rank 1 = 100 points, rank 10 = 10 points
The result is a score from 0–100 per (team × award), representing the film’s average standing in that category across the full committee.
Results Table
Displays all films (sorted by team number by default), with a column per selected award. Each cell shows:
- A colored progress bar (green → yellow → red based on rank)
- The numeric mean rank to 2 decimal places
- Clicking a cell opens a dialog showing each SC member’s individual rank for that film in that category, with an impersonate button to view their ballot
Scoring Formula Summary
mean_rank = average of each valid SC member's rank for (team, award)
value = (11 - mean_rank) * 10
A film ranked 1st by every SC member gets value = 100. A film ranked 10th by every SC member gets value = 10. A film with no valid ballots (due to the 2026 bug) gets null.