Summary
filtered_convergence_runs() returns a queryset built from convergence_run_queryset() (forensics/views.py:1862-1867), which already declares prefetch_related(Prefetch("evidence_events", …), "candidates", "rule_evaluations"). But group_projection_payload re-specifies the same two lookups when it passes the queryset into paginated_payloads:
convergence.prefetch_related("candidates", "rule_evaluations") # views.py:1332
Django deduplicates identical string lookups in prefetch_related_objects (the second prefetch_to is found in done_queries and skipped), so this issues no extra query — it is dead/redundant code, not a perf regression.
The redundancy is also asymmetric: the sibling api_group_convergence_runs (views.py:1057) and the streaming export (views.py:3247) call paginated_payloads on the same queryset without the extra .prefetch_related(...), so the base queryset was clearly meant to carry the prefetch.
Suggested fix
Drop .prefetch_related("candidates", "rule_evaluations") at views.py:1332 and pass convergence directly, matching the other two call sites.
Not a duplicate
No open issue flags this redundant view-layer prefetch. The convergence perf/prefetch issues (#152, #166, #177) concern the ingest hot path; #200/#154 concern LIMIT-dropping amplification; #158/#194/#248/#259/#201 concern admin changelists.
Summary
filtered_convergence_runs()returns a queryset built fromconvergence_run_queryset()(forensics/views.py:1862-1867), which already declaresprefetch_related(Prefetch("evidence_events", …), "candidates", "rule_evaluations"). Butgroup_projection_payloadre-specifies the same two lookups when it passes the queryset intopaginated_payloads:Django deduplicates identical string lookups in
prefetch_related_objects(the secondprefetch_tois found indone_queriesand skipped), so this issues no extra query — it is dead/redundant code, not a perf regression.The redundancy is also asymmetric: the sibling
api_group_convergence_runs(views.py:1057) and the streaming export (views.py:3247) callpaginated_payloadson the same queryset without the extra.prefetch_related(...), so the base queryset was clearly meant to carry the prefetch.Suggested fix
Drop
.prefetch_related("candidates", "rule_evaluations")atviews.py:1332and passconvergencedirectly, matching the other two call sites.Not a duplicate
No open issue flags this redundant view-layer prefetch. The convergence perf/prefetch issues (#152, #166, #177) concern the ingest hot path; #200/#154 concern LIMIT-dropping amplification; #158/#194/#248/#259/#201 concern admin changelists.