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
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>
This commit is contained in:
@@ -153,12 +153,13 @@ Return JSON only:
|
||||
]
|
||||
}
|
||||
|
||||
Rules:
|
||||
- Apply filter rules first (remove projects that fail the filter)
|
||||
- Apply sort rules next (order remaining projects)
|
||||
- Apply limit rules last (keep only top N)
|
||||
- Projects not in the ranked output are considered excluded (not ranked last)
|
||||
- Use the project_id values exactly as given — do not change them`
|
||||
CRITICAL Rules:
|
||||
- You MUST include EVERY project in the ranked output — never exclude or filter out any project
|
||||
- Apply sort rules to determine the ranking order
|
||||
- If filter criteria exist, use them to inform ranking priority (projects meeting all criteria rank higher, those failing criteria rank lower) but still include ALL projects
|
||||
- Ignore any limit rules — always return all projects
|
||||
- Use the project_id values exactly as given — do not change them
|
||||
- Ranks must be contiguous (1, 2, 3, …) with no gaps`
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -471,7 +472,8 @@ export async function executeAIRanking(
|
||||
],
|
||||
jsonMode: true,
|
||||
temperature: 0,
|
||||
maxTokens: 2000,
|
||||
// ~50 tokens per project entry; scale for large pools with generous buffer
|
||||
maxTokens: Math.max(2000, projects.length * 80),
|
||||
})
|
||||
|
||||
let response: Awaited<ReturnType<typeof openai.chat.completions.create>>
|
||||
@@ -531,6 +533,30 @@ export async function executeAIRanking(
|
||||
})
|
||||
.sort((a, b) => a.rank - b.rank)
|
||||
|
||||
// ─── Ensure ALL projects are included (AI may omit some due to token limits) ──
|
||||
const rankedIds = new Set(rankedProjects.map((r) => r.projectId))
|
||||
const unrankedProjects = projects
|
||||
.filter((p) => !rankedIds.has(p.id))
|
||||
.map((p) => ({
|
||||
projectId: p.id,
|
||||
rank: 0,
|
||||
compositeScore: computeCompositeScore(p, maxEvaluatorCount, criteriaWeights, criterionDefs),
|
||||
avgGlobalScore: p.avgGlobalScore,
|
||||
normalizedAvgScore: p.normalizedAvgScore,
|
||||
passRate: p.passRate,
|
||||
evaluatorCount: p.evaluatorCount,
|
||||
}))
|
||||
.sort((a, b) => b.compositeScore - a.compositeScore)
|
||||
|
||||
let nextRank = rankedProjects.length + 1
|
||||
for (const proj of unrankedProjects) {
|
||||
proj.rank = nextRank++
|
||||
rankedProjects.push(proj)
|
||||
}
|
||||
|
||||
// Re-normalize ranks to be contiguous (1, 2, 3, …)
|
||||
rankedProjects.forEach((p, i) => { p.rank = i + 1 })
|
||||
|
||||
return {
|
||||
category,
|
||||
rankedProjects,
|
||||
|
||||
Reference in New Issue
Block a user