**Core value:** Admins can describe ranking criteria in natural language, the system interprets and ranks projects accordingly, and they can advance the top projects to the next round with one click — all with full override control.
Decisions are logged in PROJECT.md Key Decisions table.
Recent decisions affecting current work:
- [Init]: RankingSnapshot model (new table) preferred over Round.metadataJson for audit history — confirm with client before writing migration
- [Init]: Per-category processing (STARTUP / BUSINESS_CONCEPT) — two parallel AI calls, not one combined call
- [Init]: Phase 4 is independent and can be parallelized with Phases 2-3
- [01-01]: Used separate relation names per FK pair (RoundRankingSnapshots / TriggeredRankingSnapshots) — Prisma requires unique relation names per FK, not per target model
- [01-01]: All EvaluationConfig ranking fields are optional/defaulted for backward compatibility with existing rounds
- [01-01]: Created migration SQL manually (20260227000000_add_ranking_snapshot) — local DB credentials unavailable; migration applies on next deploy
- [01-02]: fetchAndRankCategory exported (not private) so tRPC router can execute pre-parsed rules without re-parsing
- [01-02]: Projects with zero SUBMITTED evaluations excluded from ranking entirely (not ranked last)
- [01-02]: PrismaClient imported as real type (not import type) so transaction clients are compatible
- [Phase 01-04]: triggerAutoRankIfComplete defined as module-level non-exported function in evaluation.ts — avoids circular imports, colocated with the mutation it serves
- [Phase 01-04]: EvaluationConfig null fallback typed as {} as EvaluationConfig — required for TypeScript strict mode to recognize rankingCriteria and autoRankOnComplete fields
- [Phase 01-04]: retroactiveScan uses RETROACTIVE triggerType to distinguish from MANUAL/AUTO/QUICK — prevents duplicate re-runs on subsequent scans