fix(phase-7): close review notes — hoist anomaly dedup query, drop dead expr
Phase 7 reviewer (Sonnet, combined backend + frontend) flagged 3 🟡 warnings; two real fixes here, one tracking: W1 — DetectAnomaliesUseCase had an undocumented N+1: _anomalyRepo.ListAsync was called inside ProcessEventAsync, once per event. Hoisted to ExecuteAsync before the loop and threaded into ProcessEventAsync as a parameter. The per-event slice happens in-memory now. O(N_events) DB round-trips → 1. W2 — AnomalyDetector.ExtractMatchWinProbabilities had a dead expression '(decimal?)null ?? 0m' that always evaluated to 0m. Simplified to 'drawBet is not null ? rawDraw / total : 0m'. The 0m is never surfaced anyway (PDraw in the return uses the same null guard), so behaviour is identical. W3 — PLAN.md row updated with both Phase 7 commit hashes (a6ff368backend +12208a4frontend) and review verdict. Build 0/0, 276 tests still passing.
This commit is contained in:
@@ -70,13 +70,18 @@ public sealed class DetectAnomaliesUseCase
|
||||
var now = DateTimeOffset.UtcNow.ToOffset(MoscowOffset);
|
||||
var from = now - SnapshotLookback;
|
||||
|
||||
// Hoisted outside the per-event loop: load existing anomalies ONCE per cycle
|
||||
// and slice per-event in the loop. Previously this was reloaded per event
|
||||
// (O(N_events) round-trips). Reviewer W1, Phase 7.
|
||||
var existingAnomalies = await _anomalyRepo.ListAsync(ct);
|
||||
|
||||
foreach (var ev in events)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
newAnomalyCount += await ProcessEventAsync(detector, ev, from, now, ct);
|
||||
newAnomalyCount += await ProcessEventAsync(detector, ev, from, now, existingAnomalies, ct);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -104,6 +109,7 @@ public sealed class DetectAnomaliesUseCase
|
||||
Event ev,
|
||||
DateTimeOffset from,
|
||||
DateTimeOffset to,
|
||||
IReadOnlyList<Anomaly> existingAnomalies,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var snapshots = await _snapshotRepo.ListByEventAsync(ev.Id, from, to, ct);
|
||||
@@ -112,9 +118,8 @@ public sealed class DetectAnomaliesUseCase
|
||||
if (detected.Count == 0)
|
||||
return 0;
|
||||
|
||||
// Load existing anomalies for this event so we can deduplicate.
|
||||
var existing = await _anomalyRepo.ListAsync(ct);
|
||||
var existingForEvent = existing
|
||||
// Slice the cycle-wide existing-anomaly list to just this event for dedup.
|
||||
var existingForEvent = existingAnomalies
|
||||
.Where(a => a.EventId == ev.Id)
|
||||
.ToList();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user