def rerank_candidates(candidates, w_cos=0.60, w_path=0.20, w_fresh=0.15, w_deg=0.05): """ Rerank chunks with a hybrid scoring formula. Weights are configurable from the ui. """ reranked = [] logs = [] for idx, c in enumerate(candidates, 1): score = ( w_cos * c.get("cosine", 0) + w_path * c.get("path_proximity", 0) + w_fresh * c.get("freshness_decay", 0) + w_deg * c.get("degree_norm", 0) ) c["final_score"] = score reranked.append(c) logs.append( f"Candidate {idx}: " f"cosine={c.get('cosine',0):.3f}, " f"path={c.get('path_proximity',0):.3f}, " f"freshness={c.get('freshness_decay',0):.3f}, " f"degree={c.get('degree_norm',0):.3f} " f"→ final={score:.3f}" ) reranked.sort(key=lambda x: x["final_score"], reverse=True) return reranked, logs