fix(template-engine): resolve TemplateEngine-011,013,014 — remove dead converter, duplicate-id-safe cycle detection, unified deletion logic; TemplateEngine-012 deferred
This commit is contained in:
@@ -8,19 +8,24 @@ namespace ScadaLink.TemplateEngine.Flattening;
|
||||
|
||||
/// <summary>
|
||||
/// Produces a deterministic SHA-256 hash of a FlattenedConfiguration.
|
||||
/// Same content always produces the same hash across runs by using
|
||||
/// canonical JSON serialization with sorted keys.
|
||||
/// Same content always produces the same hash across runs.
|
||||
/// <para>
|
||||
/// DETERMINISM CONTRACT: System.Text.Json serializes properties in CLR
|
||||
/// declaration order, which it does NOT sort. Stable output therefore relies
|
||||
/// on the private <c>Hashable*</c> records below declaring their properties
|
||||
/// in alphabetical order. A contributor adding a property out of alphabetical
|
||||
/// order would silently change every revision hash; the ordering is guarded
|
||||
/// by <c>RevisionHashServiceTests.HashableRecords_PropertiesDeclaredAlphabetically</c>.
|
||||
/// Collections are explicitly sorted by <c>CanonicalName</c> before hashing.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class RevisionHashService
|
||||
{
|
||||
private static readonly JsonSerializerOptions CanonicalJsonOptions = new()
|
||||
{
|
||||
// Sort properties alphabetically for determinism
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
WriteIndented = false,
|
||||
// Ensure consistent ordering
|
||||
Converters = { new SortedPropertiesConverterFactory() }
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -84,7 +89,9 @@ public class RevisionHashService
|
||||
return $"sha256:{Convert.ToHexStringLower(hashBytes)}";
|
||||
}
|
||||
|
||||
// Internal types for deterministic serialization (sorted property names via camelCase + alphabetical)
|
||||
// Internal types for deterministic serialization. Properties MUST be declared
|
||||
// in alphabetical order — System.Text.Json emits them in declaration order and
|
||||
// does not sort. See the DETERMINISM CONTRACT note on the class summary.
|
||||
private sealed record HashableConfiguration
|
||||
{
|
||||
public List<HashableAlarm> Alarms { get; init; } = [];
|
||||
@@ -128,14 +135,3 @@ public class RevisionHashService
|
||||
public string? TriggerType { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A JSON converter factory that ensures properties are serialized in alphabetical order
|
||||
/// for deterministic output. Works with record types.
|
||||
/// </summary>
|
||||
internal class SortedPropertiesConverterFactory : JsonConverterFactory
|
||||
{
|
||||
public override bool CanConvert(Type typeToConvert) => false;
|
||||
|
||||
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) => null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user