DET-004: Refactor Policy Gates for determinism
- EarnedCapacityEvaluator: inject TimeProvider - BudgetThresholdNotifier: inject TimeProvider Replace DateTimeOffset.UtcNow with _timeProvider.GetUtcNow() Sprint: SPRINT_20260104_001_BE_determinism_timeprovider_injection
This commit is contained in:
@@ -18,6 +18,7 @@ public sealed class BudgetThresholdNotifier
|
|||||||
{
|
{
|
||||||
private readonly INotifyEventPublisher _publisher;
|
private readonly INotifyEventPublisher _publisher;
|
||||||
private readonly ILogger<BudgetThresholdNotifier> _logger;
|
private readonly ILogger<BudgetThresholdNotifier> _logger;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thresholds for different budget status levels.
|
/// Thresholds for different budget status levels.
|
||||||
@@ -37,10 +38,12 @@ public sealed class BudgetThresholdNotifier
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public BudgetThresholdNotifier(
|
public BudgetThresholdNotifier(
|
||||||
INotifyEventPublisher publisher,
|
INotifyEventPublisher publisher,
|
||||||
ILogger<BudgetThresholdNotifier> logger)
|
ILogger<BudgetThresholdNotifier> logger,
|
||||||
|
TimeProvider? timeProvider = null)
|
||||||
{
|
{
|
||||||
_publisher = publisher ?? throw new ArgumentNullException(nameof(publisher));
|
_publisher = publisher ?? throw new ArgumentNullException(nameof(publisher));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -73,7 +76,7 @@ public sealed class BudgetThresholdNotifier
|
|||||||
{
|
{
|
||||||
if (budget.Status >= BudgetStatus.Yellow)
|
if (budget.Status >= BudgetStatus.Yellow)
|
||||||
{
|
{
|
||||||
var payload = CreatePayload(budget, "warning");
|
var payload = CreatePayload(budget, "warning", _timeProvider);
|
||||||
await _publisher.PublishAsync(
|
await _publisher.PublishAsync(
|
||||||
BudgetEventKinds.PolicyBudgetWarning,
|
BudgetEventKinds.PolicyBudgetWarning,
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -95,7 +98,7 @@ public sealed class BudgetThresholdNotifier
|
|||||||
string tenantId,
|
string tenantId,
|
||||||
CancellationToken ct = default)
|
CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var payload = CreatePayload(budget, "exceeded");
|
var payload = CreatePayload(budget, "exceeded", _timeProvider);
|
||||||
await _publisher.PublishAsync(
|
await _publisher.PublishAsync(
|
||||||
BudgetEventKinds.PolicyBudgetExceeded,
|
BudgetEventKinds.PolicyBudgetExceeded,
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -118,7 +121,7 @@ public sealed class BudgetThresholdNotifier
|
|||||||
? BudgetEventKinds.PolicyBudgetExceeded
|
? BudgetEventKinds.PolicyBudgetExceeded
|
||||||
: BudgetEventKinds.PolicyBudgetWarning;
|
: BudgetEventKinds.PolicyBudgetWarning;
|
||||||
|
|
||||||
var payload = CreatePayload(after, after.Status.ToString().ToLowerInvariant());
|
var payload = CreatePayload(after, after.Status.ToString().ToLowerInvariant(), _timeProvider);
|
||||||
payload["previousStatus"] = before.Status.ToString().ToLowerInvariant();
|
payload["previousStatus"] = before.Status.ToString().ToLowerInvariant();
|
||||||
|
|
||||||
await _publisher.PublishAsync(eventKind, tenantId, payload, ct);
|
await _publisher.PublishAsync(eventKind, tenantId, payload, ct);
|
||||||
@@ -130,7 +133,7 @@ public sealed class BudgetThresholdNotifier
|
|||||||
after.Status);
|
after.Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonObject CreatePayload(RiskBudget budget, string severity)
|
private static JsonObject CreatePayload(RiskBudget budget, string severity, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
return new JsonObject
|
return new JsonObject
|
||||||
{
|
{
|
||||||
@@ -144,7 +147,7 @@ public sealed class BudgetThresholdNotifier
|
|||||||
["percentageUsed"] = budget.PercentageUsed,
|
["percentageUsed"] = budget.PercentageUsed,
|
||||||
["status"] = budget.Status.ToString().ToLowerInvariant(),
|
["status"] = budget.Status.ToString().ToLowerInvariant(),
|
||||||
["severity"] = severity,
|
["severity"] = severity,
|
||||||
["timestamp"] = DateTimeOffset.UtcNow.ToString("O")
|
["timestamp"] = timeProvider.GetUtcNow().ToString("O")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public sealed class EarnedCapacityEvaluator
|
|||||||
private readonly IPerformanceMetricsStore _metricsStore;
|
private readonly IPerformanceMetricsStore _metricsStore;
|
||||||
private readonly IBudgetStore _budgetStore;
|
private readonly IBudgetStore _budgetStore;
|
||||||
private readonly EarnedCapacityOptions _options;
|
private readonly EarnedCapacityOptions _options;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new earned capacity evaluator.
|
/// Create a new earned capacity evaluator.
|
||||||
@@ -23,11 +24,13 @@ public sealed class EarnedCapacityEvaluator
|
|||||||
public EarnedCapacityEvaluator(
|
public EarnedCapacityEvaluator(
|
||||||
IPerformanceMetricsStore metricsStore,
|
IPerformanceMetricsStore metricsStore,
|
||||||
IBudgetStore budgetStore,
|
IBudgetStore budgetStore,
|
||||||
EarnedCapacityOptions? options = null)
|
EarnedCapacityOptions? options = null,
|
||||||
|
TimeProvider? timeProvider = null)
|
||||||
{
|
{
|
||||||
_metricsStore = metricsStore ?? throw new ArgumentNullException(nameof(metricsStore));
|
_metricsStore = metricsStore ?? throw new ArgumentNullException(nameof(metricsStore));
|
||||||
_budgetStore = budgetStore ?? throw new ArgumentNullException(nameof(budgetStore));
|
_budgetStore = budgetStore ?? throw new ArgumentNullException(nameof(budgetStore));
|
||||||
_options = options ?? new EarnedCapacityOptions();
|
_options = options ?? new EarnedCapacityOptions();
|
||||||
|
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -116,7 +119,7 @@ public sealed class EarnedCapacityEvaluator
|
|||||||
var updatedBudget = budget with
|
var updatedBudget = budget with
|
||||||
{
|
{
|
||||||
Allocated = budget.Allocated + additionalPoints,
|
Allocated = budget.Allocated + additionalPoints,
|
||||||
UpdatedAt = DateTimeOffset.UtcNow
|
UpdatedAt = _timeProvider.GetUtcNow()
|
||||||
};
|
};
|
||||||
|
|
||||||
await _budgetStore.UpdateAsync(updatedBudget, ct);
|
await _budgetStore.UpdateAsync(updatedBudget, ct);
|
||||||
|
|||||||
Reference in New Issue
Block a user