fix(anomaly): exclude non-directional kinds from grading and backtest
Review follow-up (HIGH): the three detectors fed the same evaluator/backtest, but SuspensionFreeze is non-directional (favourite unchanged) — grading it as "favourite won" polluted the hit-rate with the base favourite-win rate, and its high frozen-ness score always cleared the backtest threshold. - Add AnomalyKind.IsDirectional() (flip + steam = true, freeze = false). - AnomalyOutcomeEvaluator returns Unresolved for non-directional kinds (favourites still surfaced for display) so they don't distort calibration. - RunBacktestUseCase skips non-directional anomalies when building candidates. - Tests for the classification, the evaluator path, and the backtest skip.
This commit is contained in:
@@ -73,6 +73,27 @@ public sealed class AnomalyOutcomeEvaluatorTests
|
||||
verdict.ActualWinner.Should().Be(Side.Side1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReportUnresolved_When_KindIsNonDirectional()
|
||||
{
|
||||
// SuspensionFreeze is informational (the favourite did not change) — it must NOT be
|
||||
// graded hit/miss even when a result exists, or its base favourite-win rate would
|
||||
// pollute the calibration. Favourites are still surfaced for display.
|
||||
var anomaly = new Anomaly(
|
||||
Id: Guid.NewGuid(),
|
||||
EventId: DefaultEventId,
|
||||
DetectedAt: new DateTimeOffset(2026, 5, 10, 18, 5, 0, MoscowOffset),
|
||||
Kind: AnomalyKind.SuspensionFreeze,
|
||||
Score: 0.9m,
|
||||
EvidenceJson: ThreeWayFlipJson);
|
||||
var result = MakeResult(Side.Side2, s1: 0, s2: 2);
|
||||
|
||||
var verdict = AnomalyOutcomeEvaluator.Evaluate(anomaly, new SportCode(6), result);
|
||||
|
||||
verdict.Outcome.Should().Be(AnomalyOutcomeKind.Unresolved);
|
||||
verdict.PostFlipFavourite.Should().Be(Side.Side2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReportMiss_When_DrawOccurred_AndPostFlipFavouriteIsNotDraw()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user