diff --git a/src/dotnet/QuantEngine.Application/Services/HistoryIngestionService.cs b/src/dotnet/QuantEngine.Application/Services/HistoryIngestionService.cs index 40cea6f7..17aee588 100644 --- a/src/dotnet/QuantEngine.Application/Services/HistoryIngestionService.cs +++ b/src/dotnet/QuantEngine.Application/Services/HistoryIngestionService.cs @@ -15,16 +15,16 @@ namespace QuantEngine.Application.Services } public Task AppendDecisionAsync(IDictionary payload) - => _store.AppendAsync("decision_result_history", payload); + => _store.AppendAsync("decision_result_history", RequirePayload(payload)); public Task AppendFactorOutputAsync(IDictionary payload) - => _store.AppendAsync("factor_output_history", payload); + => _store.AppendAsync("factor_output_history", RequirePayload(payload)); public Task AppendMarketRawAsync(IDictionary payload) - => _store.AppendAsync("market_raw_history", payload); + => _store.AppendAsync("market_raw_history", RequirePayload(payload)); public Task AppendGapAsync(IDictionary payload) - => _store.AppendAsync("market_vs_engine_gap_history", payload); + => _store.AppendAsync("market_vs_engine_gap_history", RequirePayload(payload)); public Task AppendDecisionAsync( FinalDecisionResult decision, @@ -113,5 +113,11 @@ namespace QuantEngine.Application.Services private static string? NormalizeOptional(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim(); + + private static IDictionary RequirePayload(IDictionary payload) + { + ArgumentNullException.ThrowIfNull(payload); + return payload; + } } } diff --git a/src/dotnet/QuantEngine.Core.Tests/HistoryIngestionServiceTests.cs b/src/dotnet/QuantEngine.Core.Tests/HistoryIngestionServiceTests.cs index 601391d1..a9196a85 100644 --- a/src/dotnet/QuantEngine.Core.Tests/HistoryIngestionServiceTests.cs +++ b/src/dotnet/QuantEngine.Core.Tests/HistoryIngestionServiceTests.cs @@ -48,4 +48,12 @@ public class HistoryIngestionServiceTests 1.0, "PASS")); } + + [Fact] + public async Task AppendDecisionAsync_RejectsNullRawPayload() + { + var service = new HistoryIngestionService(new Mock().Object); + + await Assert.ThrowsAsync(() => service.AppendDecisionAsync((IDictionary)null!)); + } }