up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Policy.Engine.AdvisoryAI;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory store for Advisory AI knobs (POLICY-ENGINE-31-001).
|
||||
/// </summary>
|
||||
internal sealed class AdvisoryAiKnobsService
|
||||
{
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly object _lock = new();
|
||||
private AdvisoryAiKnobsProfile _current;
|
||||
|
||||
public AdvisoryAiKnobsService(TimeProvider timeProvider)
|
||||
{
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
_current = BuildProfile(DefaultKnobs());
|
||||
}
|
||||
|
||||
public AdvisoryAiKnobsProfile Get() => _current;
|
||||
|
||||
public AdvisoryAiKnobsProfile Set(IReadOnlyList<AdvisoryAiKnob> knobs)
|
||||
{
|
||||
var normalized = Normalize(knobs);
|
||||
var profile = BuildProfile(normalized);
|
||||
lock (_lock)
|
||||
{
|
||||
_current = profile;
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
private AdvisoryAiKnobsProfile BuildProfile(IReadOnlyList<AdvisoryAiKnob> knobs)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(knobs, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = false
|
||||
});
|
||||
|
||||
var hash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(json)));
|
||||
return new AdvisoryAiKnobsProfile(knobs, hash);
|
||||
}
|
||||
|
||||
private IReadOnlyList<AdvisoryAiKnob> Normalize(IReadOnlyList<AdvisoryAiKnob> knobs)
|
||||
{
|
||||
var normalized = knobs
|
||||
.Where(k => !string.IsNullOrWhiteSpace(k.Name))
|
||||
.Select(k => new AdvisoryAiKnob(
|
||||
Name: k.Name.Trim().ToLowerInvariant(),
|
||||
DefaultValue: k.DefaultValue,
|
||||
Min: k.Min,
|
||||
Max: k.Max,
|
||||
Step: k.Step <= 0 ? 0.001m : k.Step,
|
||||
Description: string.IsNullOrWhiteSpace(k.Description) ? string.Empty : k.Description.Trim()))
|
||||
.OrderBy(k => k.Name, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<AdvisoryAiKnob> DefaultKnobs() =>
|
||||
new[]
|
||||
{
|
||||
new AdvisoryAiKnob("ai_signal_weight", 1.0m, 0m, 2m, 0.01m, "Weight applied to AI signals"),
|
||||
new AdvisoryAiKnob("reachability_boost", 0.2m, 0m, 1m, 0.01m, "Boost when asset is reachable"),
|
||||
new AdvisoryAiKnob("time_decay_half_life_days", 30m, 1m, 365m, 1m, "Half-life for decay"),
|
||||
new AdvisoryAiKnob("evidence_freshness_threshold_hours", 72m, 1m, 720m, 1m, "Max evidence age")
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user