synergy moats product advisory implementations

This commit is contained in:
master
2026-01-17 01:30:03 +02:00
parent 77ff029205
commit 702a27ac83
112 changed files with 21356 additions and 127 deletions

View File

@@ -86,9 +86,10 @@ public sealed partial class ProvenanceHintBuilder : IProvenanceHintBuilder
{
var bestMatch = matches?.OrderByDescending(m => m.Similarity).FirstOrDefault();
var confidence = bestMatch?.Similarity ?? 0.3;
var fingerprintPrefix = fingerprint.Length <= 12 ? fingerprint : fingerprint[..12];
var hypothesis = bestMatch is not null
? $"Import table matches {bestMatch.Package} {bestMatch.Version} ({bestMatch.Similarity:P0} similar)"
: $"Import fingerprint {fingerprint[..12]}... ({importedLibraries.Count} imports)";
: $"Import fingerprint {fingerprintPrefix}... ({importedLibraries.Count} imports)";
return new ProvenanceHint
{
@@ -321,7 +322,7 @@ public sealed partial class ProvenanceHintBuilder : IProvenanceHintBuilder
// If we have multiple high-confidence hints that agree, boost confidence
var agreeing = sorted
.Where(h => h.Confidence >= 0.5)
.GroupBy(h => ExtractPackageFromHypothesis(h.Hypothesis))
.GroupBy(GetAgreementKey)
.OrderByDescending(g => g.Count())
.FirstOrDefault();
@@ -351,7 +352,7 @@ public sealed partial class ProvenanceHintBuilder : IProvenanceHintBuilder
{
return confidence switch
{
>= 0.9 => HintConfidence.VeryHigh,
>= 0.85 => HintConfidence.VeryHigh,
>= 0.7 => HintConfidence.High,
>= 0.5 => HintConfidence.Medium,
>= 0.3 => HintConfidence.Low,
@@ -359,6 +360,45 @@ public sealed partial class ProvenanceHintBuilder : IProvenanceHintBuilder
};
}
private static string GetAgreementKey(ProvenanceHint hint)
{
var evidence = hint.Evidence;
var key = evidence.BuildId?.MatchedPackage
?? BestMatchPackage(evidence.ImportFingerprint?.MatchedFingerprints)
?? BestMatchPackage(evidence.SectionLayout?.MatchedLayouts)
?? ExtractPackageFromVersion(evidence.VersionString?.BestGuess)
?? ExtractPackageFromVersion(evidence.CorpusMatch?.MatchedEntry)
?? ExtractPackageFromHypothesis(hint.Hypothesis);
return string.IsNullOrWhiteSpace(key) ? hint.Hypothesis : key;
}
private static string? BestMatchPackage(IReadOnlyList<FingerprintMatch>? matches)
{
return matches is null || matches.Count == 0
? null
: matches.OrderByDescending(m => m.Similarity).First().Package;
}
private static string? BestMatchPackage(IReadOnlyList<LayoutMatch>? matches)
{
return matches is null || matches.Count == 0
? null
: matches.OrderByDescending(m => m.Similarity).First().Package;
}
private static string? ExtractPackageFromVersion(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
var trimmed = value.Trim();
var token = trimmed.Split([' ', '/', '\t'], StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
return string.IsNullOrWhiteSpace(token) ? null : token;
}
private static string ComputeLayoutHash(IReadOnlyList<SectionInfo> sections)
{
var normalized = string.Join("|",

View File

@@ -119,7 +119,7 @@ public sealed class NativeUnknownClassifier
SubjectType = UnknownSubjectType.Binary,
SubjectRef = context.UnresolvedImport,
Kind = UnknownKind.UnresolvedNativeLibrary,
Severity = UnknownSeverity.Low,
Severity = UnknownSeverity.Medium,
Context = SerializeContext(context with { ClassifiedAt = now }),
ValidFrom = now,
SysFrom = now,
@@ -251,6 +251,7 @@ public sealed class NativeUnknownClassifier
/// <summary>
/// Source-generated JSON context for NativeUnknownContext serialization.
/// </summary>
[System.Text.Json.Serialization.JsonSourceGenerationOptions(PropertyNamingPolicy = System.Text.Json.JsonKnownNamingPolicy.CamelCase)]
[System.Text.Json.Serialization.JsonSerializable(typeof(NativeUnknownContext))]
internal partial class NativeUnknownContextJsonContext : System.Text.Json.Serialization.JsonSerializerContext
{