review(Runtime): record findings + fix artifact-decode type tolerance
Review at HEAD 7286d320. Runtime-002/006 (Medium): DeploymentArtifact lenient-parse
now degrades wrong-typed JSON fields to defaults/skipped-row instead of throwing (fails
the deploy) + regression tests; byte-parity with AddressSpaceComposer preserved. Runtime-001
(UNS rename) deferred cross-module (needs AddressSpacePlan rename signal + EnsureFolder
rename). 003/004/005 Won't-Fix.
This commit is contained in:
@@ -145,16 +145,27 @@ public static class DeploymentArtifact
|
||||
: all;
|
||||
}
|
||||
|
||||
/// <summary>Reads a string property, tolerating a wrong JSON type: a property that is present but
|
||||
/// NOT a JSON string (number / bool / object / array) yields null rather than throwing
|
||||
/// <see cref="InvalidOperationException"/> from <c>GetString()</c>. Keeps the artifact-decode lenient
|
||||
/// — a wrong-typed field degrades to the field default / a skipped row, matching the documented
|
||||
/// "malformed blobs return an empty list/composition" contract (Runtime-002).</summary>
|
||||
private static string? ReadString(JsonElement el, string property) =>
|
||||
el.TryGetProperty(property, out var p) && p.ValueKind == JsonValueKind.String ? p.GetString() : null;
|
||||
|
||||
private static DriverInstanceSpec? TryReadSpec(JsonElement el)
|
||||
{
|
||||
var rowId = el.TryGetProperty("DriverInstanceRowId", out var rowEl)
|
||||
&& rowEl.TryGetGuid(out var rid) ? rid : Guid.Empty;
|
||||
var id = el.TryGetProperty("DriverInstanceId", out var idEl) ? idEl.GetString() : null;
|
||||
var name = el.TryGetProperty("Name", out var nameEl) ? nameEl.GetString() : null;
|
||||
var type = el.TryGetProperty("DriverType", out var typeEl) ? typeEl.GetString() : null;
|
||||
var enabled = !el.TryGetProperty("Enabled", out var enEl) || enEl.GetBoolean();
|
||||
var config = el.TryGetProperty("DriverConfig", out var cfgEl) ? cfgEl.GetString() : null;
|
||||
var clusterId = el.TryGetProperty("ClusterId", out var clEl) ? clEl.GetString() : null;
|
||||
var id = ReadString(el, "DriverInstanceId");
|
||||
var name = ReadString(el, "Name");
|
||||
var type = ReadString(el, "DriverType");
|
||||
// A non-bool Enabled token degrades to the field default (true = "desired here"), never throws.
|
||||
var enabled = !el.TryGetProperty("Enabled", out var enEl)
|
||||
|| enEl.ValueKind is not (JsonValueKind.True or JsonValueKind.False)
|
||||
|| enEl.GetBoolean();
|
||||
var config = ReadString(el, "DriverConfig");
|
||||
var clusterId = ReadString(el, "ClusterId");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(id) || string.IsNullOrWhiteSpace(type)) return null;
|
||||
|
||||
@@ -781,48 +792,48 @@ public static class DeploymentArtifact
|
||||
|
||||
private static UnsAreaProjection? ReadAreaProjection(JsonElement el)
|
||||
{
|
||||
var id = el.TryGetProperty("UnsAreaId", out var idEl) ? idEl.GetString() : null;
|
||||
var name = el.TryGetProperty("Name", out var nameEl) ? nameEl.GetString() : null;
|
||||
var id = ReadString(el, "UnsAreaId");
|
||||
var name = ReadString(el, "Name");
|
||||
if (string.IsNullOrWhiteSpace(id)) return null;
|
||||
return new UnsAreaProjection(id!, name ?? id!);
|
||||
}
|
||||
|
||||
private static UnsLineProjection? ReadLineProjection(JsonElement el)
|
||||
{
|
||||
var id = el.TryGetProperty("UnsLineId", out var idEl) ? idEl.GetString() : null;
|
||||
var areaId = el.TryGetProperty("UnsAreaId", out var areaEl) ? areaEl.GetString() : null;
|
||||
var name = el.TryGetProperty("Name", out var nameEl) ? nameEl.GetString() : null;
|
||||
var id = ReadString(el, "UnsLineId");
|
||||
var areaId = ReadString(el, "UnsAreaId");
|
||||
var name = ReadString(el, "Name");
|
||||
if (string.IsNullOrWhiteSpace(id) || string.IsNullOrWhiteSpace(areaId)) return null;
|
||||
return new UnsLineProjection(id!, areaId!, name ?? id!);
|
||||
}
|
||||
|
||||
private static EquipmentNode? ReadEquipmentNode(JsonElement el)
|
||||
{
|
||||
var id = el.TryGetProperty("EquipmentId", out var idEl) ? idEl.GetString() : null;
|
||||
var id = ReadString(el, "EquipmentId");
|
||||
// DisplayName = the UNS level-5 Name segment (friendly browse name, matching UnsArea/UnsLine
|
||||
// + the live rebuild's source of truth) — NOT the colloquial MachineCode. NodeId stays the
|
||||
// logical EquipmentId.
|
||||
var displayName = el.TryGetProperty("Name", out var nameEl) ? nameEl.GetString() : null;
|
||||
var lineId = el.TryGetProperty("UnsLineId", out var lineEl) ? lineEl.GetString() : null;
|
||||
var displayName = ReadString(el, "Name");
|
||||
var lineId = ReadString(el, "UnsLineId");
|
||||
if (string.IsNullOrWhiteSpace(id)) return null;
|
||||
return new EquipmentNode(id!, displayName ?? id!, lineId ?? string.Empty);
|
||||
}
|
||||
|
||||
private static DriverInstancePlan? ReadDriverPlan(JsonElement el)
|
||||
{
|
||||
var id = el.TryGetProperty("DriverInstanceId", out var idEl) ? idEl.GetString() : null;
|
||||
var type = el.TryGetProperty("DriverType", out var typeEl) ? typeEl.GetString() : null;
|
||||
var config = el.TryGetProperty("DriverConfig", out var cfgEl) ? cfgEl.GetString() : null;
|
||||
var id = ReadString(el, "DriverInstanceId");
|
||||
var type = ReadString(el, "DriverType");
|
||||
var config = ReadString(el, "DriverConfig");
|
||||
if (string.IsNullOrWhiteSpace(id) || string.IsNullOrWhiteSpace(type)) return null;
|
||||
return new DriverInstancePlan(id!, type!, config ?? "{}");
|
||||
}
|
||||
|
||||
private static ScriptedAlarmPlan? ReadAlarmPlan(JsonElement el)
|
||||
{
|
||||
var id = el.TryGetProperty("ScriptedAlarmId", out var idEl) ? idEl.GetString() : null;
|
||||
var equipmentId = el.TryGetProperty("EquipmentId", out var eqEl) ? eqEl.GetString() : null;
|
||||
var script = el.TryGetProperty("PredicateScriptId", out var scEl) ? scEl.GetString() : null;
|
||||
var template = el.TryGetProperty("MessageTemplate", out var tmEl) ? tmEl.GetString() : null;
|
||||
var id = ReadString(el, "ScriptedAlarmId");
|
||||
var equipmentId = ReadString(el, "EquipmentId");
|
||||
var script = ReadString(el, "PredicateScriptId");
|
||||
var template = ReadString(el, "MessageTemplate");
|
||||
if (string.IsNullOrWhiteSpace(id)) return null;
|
||||
return new ScriptedAlarmPlan(id!, equipmentId ?? string.Empty, script ?? string.Empty, template ?? string.Empty);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user