update evidence bundle to include new evidence types and implement ProofSpine integration
Some checks failed
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
sm-remote-ci / build-and-test (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
sm-remote-ci / build-and-test (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
This commit is contained in:
@@ -16,6 +16,11 @@ public interface IUnknownsRepository
|
||||
/// </summary>
|
||||
Task BulkUpdateAsync(IEnumerable<UnknownSymbolDocument> items, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all known subject keys containing unknowns.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<string>> GetAllSubjectKeysAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets unknowns due for rescan in a specific band.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StellaOps.Signals.Persistence;
|
||||
|
||||
public sealed class InMemoryDeploymentRefsRepository : IDeploymentRefsRepository
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, int> _deploymentsByPurl = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void SetDeployments(string purl, int deployments)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(purl);
|
||||
if (deployments < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(deployments), "Deployments cannot be negative.");
|
||||
}
|
||||
|
||||
_deploymentsByPurl[purl.Trim()] = deployments;
|
||||
}
|
||||
|
||||
public Task<int> CountDeploymentsAsync(string purl, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(purl))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
return Task.FromResult(_deploymentsByPurl.TryGetValue(purl.Trim(), out var count) ? count : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StellaOps.Signals.Persistence;
|
||||
|
||||
public sealed class InMemoryGraphMetricsRepository : IGraphMetricsRepository
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, GraphMetrics> _metrics = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void SetMetrics(string symbolId, string callgraphId, GraphMetrics metrics)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(symbolId);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(callgraphId);
|
||||
|
||||
var key = BuildKey(symbolId, callgraphId);
|
||||
_metrics[key] = metrics;
|
||||
}
|
||||
|
||||
public Task<GraphMetrics?> GetMetricsAsync(string symbolId, string callgraphId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(symbolId) || string.IsNullOrWhiteSpace(callgraphId))
|
||||
{
|
||||
return Task.FromResult<GraphMetrics?>(null);
|
||||
}
|
||||
|
||||
var key = BuildKey(symbolId, callgraphId);
|
||||
return Task.FromResult(_metrics.TryGetValue(key, out var metrics) ? metrics : null);
|
||||
}
|
||||
|
||||
private static string BuildKey(string symbolId, string callgraphId)
|
||||
=> $"{callgraphId.Trim()}|{symbolId.Trim()}";
|
||||
}
|
||||
@@ -78,7 +78,9 @@ internal sealed class UnknownsIngestionService : IUnknownsIngestionService
|
||||
EdgeFrom = entry.EdgeFrom?.Trim(),
|
||||
EdgeTo = entry.EdgeTo?.Trim(),
|
||||
Reason = entry.Reason?.Trim(),
|
||||
CreatedAt = now
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now,
|
||||
LastAnalyzedAt = now
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -75,9 +75,11 @@ public sealed class UnknownsScoringService : IUnknownsScoringService
|
||||
UnknownsScoringOptions opts,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
|
||||
var trace = new UnknownsNormalizationTrace
|
||||
{
|
||||
ComputedAt = _timeProvider.GetUtcNow(),
|
||||
ComputedAt = now,
|
||||
Weights = new Dictionary<string, double>
|
||||
{
|
||||
["wP"] = opts.WeightPopularity,
|
||||
@@ -139,24 +141,21 @@ public sealed class UnknownsScoringService : IUnknownsScoringService
|
||||
trace.FinalScore = score;
|
||||
|
||||
// Band assignment
|
||||
unknown.Band = score switch
|
||||
{
|
||||
>= 0.70 => UnknownsBand.Hot,
|
||||
>= 0.40 => UnknownsBand.Warm,
|
||||
_ => UnknownsBand.Cold
|
||||
};
|
||||
unknown.Band = score >= opts.HotThreshold
|
||||
? UnknownsBand.Hot
|
||||
: score >= opts.WarmThreshold ? UnknownsBand.Warm : UnknownsBand.Cold;
|
||||
trace.AssignedBand = unknown.Band.ToString();
|
||||
|
||||
// Schedule next rescan based on band
|
||||
unknown.NextScheduledRescan = unknown.Band switch
|
||||
{
|
||||
UnknownsBand.Hot => _timeProvider.GetUtcNow().AddMinutes(15),
|
||||
UnknownsBand.Warm => _timeProvider.GetUtcNow().AddHours(opts.WarmRescanHours),
|
||||
_ => _timeProvider.GetUtcNow().AddDays(opts.ColdRescanDays)
|
||||
UnknownsBand.Hot => now.AddMinutes(opts.HotRescanMinutes),
|
||||
UnknownsBand.Warm => now.AddHours(opts.WarmRescanHours),
|
||||
_ => now.AddDays(opts.ColdRescanDays)
|
||||
};
|
||||
|
||||
unknown.NormalizationTrace = trace;
|
||||
unknown.UpdatedAt = _timeProvider.GetUtcNow();
|
||||
unknown.UpdatedAt = now;
|
||||
|
||||
_logger.LogDebug(
|
||||
"Scored unknown {UnknownId}: P={P:F2} E={E:F2} U={U:F2} C={C:F2} S={S:F2} → Score={Score:F2} Band={Band}",
|
||||
@@ -270,9 +269,28 @@ public sealed class UnknownsScoringService : IUnknownsScoringService
|
||||
return (1.0, opts.StalenessMaxDays); // Never analyzed = maximum staleness
|
||||
|
||||
var daysSince = (int)(_timeProvider.GetUtcNow() - lastAnalyzedAt.Value).TotalDays;
|
||||
if (daysSince < 0)
|
||||
{
|
||||
daysSince = 0;
|
||||
}
|
||||
|
||||
// Formula: S = min(1, age_days / max_days)
|
||||
var score = Math.Min(1.0, (double)daysSince / opts.StalenessMaxDays);
|
||||
// Exponential staleness: decayFactor = exp(-t/tau), staleness = (1 - decayFactor) normalized to reach 1 at maxDays.
|
||||
// This models confidence decay (higher staleness means lower confidence in evidence freshness).
|
||||
if (opts.StalenessTauDays > 0 && opts.StalenessMaxDays > 0)
|
||||
{
|
||||
var maxDays = Math.Max(1, opts.StalenessMaxDays);
|
||||
var decayFactor = Math.Exp(-daysSince / opts.StalenessTauDays);
|
||||
var maxDecayFactor = Math.Exp(-maxDays / opts.StalenessTauDays);
|
||||
var numerator = 1.0 - decayFactor;
|
||||
var denominator = 1.0 - maxDecayFactor;
|
||||
var normalized = denominator <= 0 ? 0.0 : numerator / denominator;
|
||||
return (Math.Clamp(normalized, 0.0, 1.0), daysSince);
|
||||
}
|
||||
|
||||
// Fallback linear: S = min(1, age_days / max_days)
|
||||
var score = opts.StalenessMaxDays <= 0
|
||||
? 0.0
|
||||
: Math.Min(1.0, (double)daysSince / opts.StalenessMaxDays);
|
||||
|
||||
return (score, daysSince);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user