DET-004: Refactor Policy BudgetLedger for determinism

- Inject TimeProvider and IGuidProvider in BudgetLedger constructor
- Replace DateTimeOffset.UtcNow with _timeProvider.GetUtcNow()
- Replace Guid.NewGuid() with _guidProvider.NewGuid()
- Add Determinism.Abstractions reference to Policy csproj

Sprint: SPRINT_20260104_001_BE_determinism_timeprovider_injection
Task: DET-004 (in progress - Policy module)
This commit is contained in:
StellaOps Bot
2026-01-04 12:38:35 +02:00
parent cb898a4ac8
commit 8e0cc71b2e
2 changed files with 18 additions and 8 deletions

View File

@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Determinism;
namespace StellaOps.Policy.Gates; namespace StellaOps.Policy.Gates;
@@ -10,10 +11,18 @@ public sealed class BudgetLedger : IBudgetLedger
{ {
private readonly IBudgetStore _store; private readonly IBudgetStore _store;
private readonly ILogger<BudgetLedger> _logger; private readonly ILogger<BudgetLedger> _logger;
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
public BudgetLedger(IBudgetStore store, ILogger<BudgetLedger>? logger = null) public BudgetLedger(
IBudgetStore store,
TimeProvider? timeProvider = null,
IGuidProvider? guidProvider = null,
ILogger<BudgetLedger>? logger = null)
{ {
_store = store ?? throw new ArgumentNullException(nameof(store)); _store = store ?? throw new ArgumentNullException(nameof(store));
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
_logger = logger ?? NullLogger<BudgetLedger>.Instance; _logger = logger ?? NullLogger<BudgetLedger>.Instance;
} }
@@ -64,12 +73,12 @@ public sealed class BudgetLedger : IBudgetLedger
// Record the consumption // Record the consumption
var entry = new BudgetEntry var entry = new BudgetEntry
{ {
EntryId = Guid.NewGuid().ToString(), EntryId = _guidProvider.NewGuid().ToString(),
ServiceId = serviceId, ServiceId = serviceId,
Window = budget.Window, Window = budget.Window,
ReleaseId = releaseId, ReleaseId = releaseId,
RiskPoints = riskPoints, RiskPoints = riskPoints,
ConsumedAt = DateTimeOffset.UtcNow ConsumedAt = _timeProvider.GetUtcNow()
}; };
await _store.AddEntryAsync(entry, ct).ConfigureAwait(false); await _store.AddEntryAsync(entry, ct).ConfigureAwait(false);
@@ -78,7 +87,7 @@ public sealed class BudgetLedger : IBudgetLedger
var updatedBudget = budget with var updatedBudget = budget with
{ {
Consumed = budget.Consumed + riskPoints, Consumed = budget.Consumed + riskPoints,
UpdatedAt = DateTimeOffset.UtcNow UpdatedAt = _timeProvider.GetUtcNow()
}; };
await _store.UpdateAsync(updatedBudget, ct).ConfigureAwait(false); await _store.UpdateAsync(updatedBudget, ct).ConfigureAwait(false);
@@ -122,7 +131,7 @@ public sealed class BudgetLedger : IBudgetLedger
var updatedBudget = budget with var updatedBudget = budget with
{ {
Allocated = newAllocation, Allocated = newAllocation,
UpdatedAt = DateTimeOffset.UtcNow UpdatedAt = _timeProvider.GetUtcNow()
}; };
await _store.UpdateAsync(updatedBudget, ct).ConfigureAwait(false); await _store.UpdateAsync(updatedBudget, ct).ConfigureAwait(false);
@@ -148,15 +157,15 @@ public sealed class BudgetLedger : IBudgetLedger
Window = window, Window = window,
Allocated = DefaultBudgetAllocations.GetMonthlyAllocation(tier), Allocated = DefaultBudgetAllocations.GetMonthlyAllocation(tier),
Consumed = 0, Consumed = 0,
UpdatedAt = DateTimeOffset.UtcNow UpdatedAt = _timeProvider.GetUtcNow()
}; };
await _store.CreateAsync(budget, ct).ConfigureAwait(false); await _store.CreateAsync(budget, ct).ConfigureAwait(false);
return budget; return budget;
} }
private static string GetCurrentWindow() => private string GetCurrentWindow() =>
DateTimeOffset.UtcNow.ToString("yyyy-MM"); _timeProvider.GetUtcNow().ToString("yyyy-MM");
private Task<ServiceTier> GetServiceTierAsync(string serviceId, CancellationToken ct) private Task<ServiceTier> GetServiceTierAsync(string serviceId, CancellationToken ct)
{ {

View File

@@ -28,5 +28,6 @@
<ProjectReference Include="../../../Attestor/__Libraries/StellaOps.Attestor.ProofChain/StellaOps.Attestor.ProofChain.csproj" /> <ProjectReference Include="../../../Attestor/__Libraries/StellaOps.Attestor.ProofChain/StellaOps.Attestor.ProofChain.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.Canonical.Json/StellaOps.Canonical.Json.csproj" /> <ProjectReference Include="../../../__Libraries/StellaOps.Canonical.Json/StellaOps.Canonical.Json.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" /> <ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.Determinism.Abstractions/StellaOps.Determinism.Abstractions.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>