From c885ddc3c44ed1f620cd906633338b13badb8683 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Tue, 18 Aug 2026 08:40:45 +0700 Subject: [PATCH 1/5] P2: pin ARIEC dynamic-first engine revision --- engines/ARIEC61850.lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/ARIEC61850.lock.json b/engines/ARIEC61850.lock.json index 51f5571ba..e0c3fa6fc 100644 --- a/engines/ARIEC61850.lock.json +++ b/engines/ARIEC61850.lock.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "repository": "masarray/ARIEC61850", "ref": "main", - "commit": "becda399b4a3ae34831215fc915798b4f846c1be", - "sourcePullRequest": 81, - "purpose": "Pins the ARIEC61850 engine used by ARSAS. PR #76 preserves unresolved static DataSet members, PR #77 canonicalizes cross-logical-device SCL references, PR #78 keeps one descriptor per static DataSet member while separating resolved runtime primary leaves from the original FCDA/FCD identity, PR #79 projects generic Boolean status structures to scalar stVal while preserving quality/timestamp, PR #80 normalizes validated DataRef-enabled InformationReport ordering, and PR #81 accepts valid zero OptFlds reports while quarantining unmapped canonical report metadata so OptFlds/inclusion/reason fields can never leak into process values." + "commit": "9ca4ee490a27046d5d2ffdc21f3614b2d7d58725", + "sourcePullRequest": 84, + "purpose": "Pins the ARIEC61850 engine used by ARSAS. PR #76 preserves unresolved static DataSet members, PR #77 canonicalizes cross-logical-device SCL references, PR #78 keeps one descriptor per static DataSet member while separating resolved runtime primary leaves from the original FCDA/FCD identity, PR #79 projects generic Boolean status structures to scalar stVal while preserving quality/timestamp, PR #80 normalizes validated DataRef-enabled InformationReport ordering, PR #81 accepts valid zero OptFlds reports while quarantining unmapped canonical report metadata so OptFlds/inclusion/reason fields can never leak into process values, and PR #84 routes exact PrimaryValue residuals through dynamic reporting before MMS polling while preventing quality/timestamp descriptors from hijacking the primary-value fallback." } From b6956639d6daf2547ddbf12ef0a1905b88d5b93b Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Tue, 18 Aug 2026 08:41:01 +0700 Subject: [PATCH 2/5] test: ensure every uncovered point remains dynamic-first --- .../Iec61850ReportPlannerRegressionTests.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/ARSAS.Tests/Iec61850ReportPlannerRegressionTests.cs b/tests/ARSAS.Tests/Iec61850ReportPlannerRegressionTests.cs index f66b44bc3..65cb08e4f 100644 --- a/tests/ARSAS.Tests/Iec61850ReportPlannerRegressionTests.cs +++ b/tests/ARSAS.Tests/Iec61850ReportPlannerRegressionTests.cs @@ -35,6 +35,36 @@ public void BuildPlans_FastPointWithoutStaticCoverage_BecomesDynamicCandidate() Assert.Contains(point, plan.Bindings); } + [Fact] + public void BuildPlans_SlowMeasurementWithoutStaticCoverage_BecomesDynamicCandidate() + { + var device = BuildDevice(); + var point = BuildSlowMeasurementPoint(device); + + var plans = Iec61850ReportPlanner.BuildPlans(device, new[] { point }); + + var plan = Assert.Single(plans); + Assert.Equal("Dynamic candidate", plan.Status); + Assert.True(plan.AllowDynamicDataSetWrites); + Assert.Contains(point, plan.Bindings); + } + + [Fact] + public void BuildPlans_AllUncoveredPoints_AppearExactlyOnceInDynamicCandidates() + { + var device = BuildDevice(); + var fast = BuildFastStatusPoint(device); + var slow = BuildSlowMeasurementPoint(device); + + var plans = Iec61850ReportPlanner.BuildPlans(device, new[] { fast, slow }); + + Assert.All(plans, plan => Assert.Equal("Dynamic candidate", plan.Status)); + var bindings = plans.SelectMany(plan => plan.Bindings).ToArray(); + Assert.Equal(2, bindings.Length); + Assert.Single(bindings, point => point.PointKey == fast.PointKey); + Assert.Single(bindings, point => point.PointKey == slow.PointKey); + } + [Fact] public void BuildDynamicFallbackPlans_FastPoint_IsNotExcludedByPollingInterval() { @@ -70,4 +100,18 @@ private static Iec61850MonitorPoint BuildFastStatusPoint(Iec61850MonitorDevice d Category = "Position", PollingIntervalMs = 250 }; + + private static Iec61850MonitorPoint BuildSlowMeasurementPoint(Iec61850MonitorDevice device) + => new() + { + DeviceId = device.DeviceId, + DeviceName = device.Name, + IpAddress = device.IpAddress, + SignalName = "Phase A current", + IecReference = "IED1LD0/MMXU1.A.phsA.cVal.mag.f", + FunctionalConstraint = "MX", + IecDataType = "Float32", + Category = "Measurement", + PollingIntervalMs = 2000 + }; } From 1cbda9bdec6cd5780f5b78b795b3de3e70b60a83 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Tue, 18 Aug 2026 08:45:25 +0700 Subject: [PATCH 3/5] test: advance reviewed ARIEC pin guard to P2 --- tests/ARSAS.Tests/VisualSystemP0RegressionTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ARSAS.Tests/VisualSystemP0RegressionTests.cs b/tests/ARSAS.Tests/VisualSystemP0RegressionTests.cs index 8b8f10c96..8a1e76d97 100644 --- a/tests/ARSAS.Tests/VisualSystemP0RegressionTests.cs +++ b/tests/ARSAS.Tests/VisualSystemP0RegressionTests.cs @@ -86,8 +86,8 @@ public void P0_KeepsTheReviewedAriecEnginePinUntouched() var testDirectory = Path.GetDirectoryName(FindRepoFile("MainWindow.xaml"))!; var engineLock = File.ReadAllText(Path.Combine(testDirectory, "engines", "ARIEC61850.lock.json")); - Assert.Contains("becda399b4a3ae34831215fc915798b4f846c1be", engineLock, StringComparison.OrdinalIgnoreCase); - Assert.Contains("\"sourcePullRequest\": 81", engineLock, StringComparison.Ordinal); + Assert.Contains("9ca4ee490a27046d5d2ffdc21f3614b2d7d58725", engineLock, StringComparison.OrdinalIgnoreCase); + Assert.Contains("\"sourcePullRequest\": 84", engineLock, StringComparison.Ordinal); } private static string Slice(string source, string start, string end) From d8d49cd0fb728550a64c78f6e7f8ea23364feaa6 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Tue, 18 Aug 2026 08:45:46 +0700 Subject: [PATCH 4/5] test: preserve member-centric inventory on reviewed P2 engine --- .../OfflineDataSetSignalSelectionRegressionTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ARSAS.Tests/OfflineDataSetSignalSelectionRegressionTests.cs b/tests/ARSAS.Tests/OfflineDataSetSignalSelectionRegressionTests.cs index 5cb5c3e37..97dc1b38a 100644 --- a/tests/ARSAS.Tests/OfflineDataSetSignalSelectionRegressionTests.cs +++ b/tests/ARSAS.Tests/OfflineDataSetSignalSelectionRegressionTests.cs @@ -72,13 +72,14 @@ public void EngineLock_PinsMergedReportProjectionEngineWithoutLosingMemberCentri { var source = File.ReadAllText(FindRepoFile("engines/ARIEC61850.lock.json")); - Assert.Contains("becda399b4a3ae34831215fc915798b4f846c1be", source, StringComparison.OrdinalIgnoreCase); - Assert.Contains("\"sourcePullRequest\": 81", source, StringComparison.Ordinal); + Assert.Contains("9ca4ee490a27046d5d2ffdc21f3614b2d7d58725", source, StringComparison.OrdinalIgnoreCase); + Assert.Contains("\"sourcePullRequest\": 84", source, StringComparison.Ordinal); Assert.Contains("one descriptor per static DataSet member", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("generic Boolean status structures", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("DataRef-enabled InformationReport ordering", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("zero OptFlds", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("quarantining unmapped canonical report metadata", source, StringComparison.OrdinalIgnoreCase); + Assert.Contains("dynamic reporting before MMS polling", source, StringComparison.OrdinalIgnoreCase); } [Fact] From da28f4a5592571d3580d821f8af2e95d8ecfa841 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Tue, 18 Aug 2026 08:46:09 +0700 Subject: [PATCH 5/5] test: advance workspace provenance guard to reviewed P2 engine --- tests/ARSAS.Tests/WorkspaceNoiseP1RegressionTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ARSAS.Tests/WorkspaceNoiseP1RegressionTests.cs b/tests/ARSAS.Tests/WorkspaceNoiseP1RegressionTests.cs index 9c4e4a366..30bc9842c 100644 --- a/tests/ARSAS.Tests/WorkspaceNoiseP1RegressionTests.cs +++ b/tests/ARSAS.Tests/WorkspaceNoiseP1RegressionTests.cs @@ -87,8 +87,8 @@ public void P1_KeepsReviewedAriecEnginePinUntouched() var root = Path.GetDirectoryName(FindRepoFile("MainWindow.xaml"))!; var engineLock = File.ReadAllText(Path.Combine(root, "engines", "ARIEC61850.lock.json")); - Assert.Contains("becda399b4a3ae34831215fc915798b4f846c1be", engineLock, StringComparison.OrdinalIgnoreCase); - Assert.Contains("\"sourcePullRequest\": 81", engineLock, StringComparison.Ordinal); + Assert.Contains("9ca4ee490a27046d5d2ffdc21f3614b2d7d58725", engineLock, StringComparison.OrdinalIgnoreCase); + Assert.Contains("\"sourcePullRequest\": 84", engineLock, StringComparison.Ordinal); } private static string Slice(string source, string start, string end)