From 48ef59b7f2a03919a192bb6f74ba218f790f29b2 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Wed, 16 Sep 2026 20:36:46 +0700 Subject: [PATCH 1/2] fix(v1.6.37): preserve DPC semantics in static DataSet feedback --- ...850StaticControlStatusProjectionService.cs | 23 ++++++++++++- .../Iec61850ValueFormatterTests.cs | 34 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Services/Iec61850StaticControlStatusProjectionService.cs b/Services/Iec61850StaticControlStatusProjectionService.cs index 06b306d40..836e9a25b 100644 --- a/Services/Iec61850StaticControlStatusProjectionService.cs +++ b/Services/Iec61850StaticControlStatusProjectionService.cs @@ -135,7 +135,10 @@ public static Iec61850StaticControlStatusProjectionResult EnsureProjections(Iec6 LiteralEquals(signal.DisplayReference, memberReference) && LiteralEquals(signal.ObjectReference, exactFeedbackReference)); if (existingFeedback is not null) + { + PromoteRuntimeFeedbackSemantics(existingFeedback, descriptor, cdc); continue; + } var feedback = CreateRuntimeFeedback( descriptor, @@ -161,6 +164,11 @@ public static Iec61850StaticControlStatusProjectionResult EnsureProjections(Iec6 internal static bool IsControllableCdc(string? cdc) => ControllableCdcs.Contains((cdc ?? string.Empty).Trim()); + internal static string ResolveRuntimeFeedbackDataType(string? cdc, string? mmsType, string? sclBType) + => string.Equals((cdc ?? string.Empty).Trim(), "DPC", StringComparison.OrdinalIgnoreCase) + ? "Dbpos" + : FirstNonEmpty(mmsType, sclBType, "Unknown"); + private static string ResolveExactFeedbackReference( Iec61850SignalDescriptor descriptor, Iec61850SignalDataSetMembership membership) @@ -299,7 +307,7 @@ private static SignalDefinition CreateRuntimeFeedback( ObjectReference = exactFeedbackReference, DisplayReference = memberReference, FunctionalConstraint = fc, - DataType = FirstNonEmpty(descriptor.MmsType, descriptor.SclBType, "Unknown"), + DataType = ResolveRuntimeFeedbackDataType(cdc, descriptor.MmsType, descriptor.SclBType), Category = category, Confidence = "High", DataSetReference = membership.DataSetReference, @@ -322,6 +330,19 @@ private static SignalDefinition CreateRuntimeFeedback( }; } + private static void PromoteRuntimeFeedbackSemantics( + SignalDefinition feedback, + Iec61850SignalDescriptor descriptor, + string cdc) + { + var semanticType = ResolveRuntimeFeedbackDataType(cdc, descriptor.MmsType, descriptor.SclBType); + if (semanticType.Equals("Dbpos", StringComparison.OrdinalIgnoreCase)) + { + feedback.DataType = semanticType; + feedback.Category = "Position"; + } + } + private static Iec61850StaticControlStatusProjectionResult EmptyResult() => new(Array.Empty(), 0); diff --git a/tests/ARSAS.Tests/Iec61850ValueFormatterTests.cs b/tests/ARSAS.Tests/Iec61850ValueFormatterTests.cs index 15aa43b22..bd28a58e2 100644 --- a/tests/ARSAS.Tests/Iec61850ValueFormatterTests.cs +++ b/tests/ARSAS.Tests/Iec61850ValueFormatterTests.cs @@ -63,4 +63,38 @@ public void Format_Does_Not_Collapse_NonStVal_Structures() Assert.Equal(value, formatted); } + + [Theory] + [InlineData("off", "Open [01]")] + [InlineData("on", "Closed [10]")] + [InlineData("00", "Intermediate [00]")] + [InlineData("11", "Bad state [11]")] + public void Format_Preserves_Dpc_Process_Semantics_For_Report_Values(string raw, string expected) + { + var formatted = Iec61850ValueFormatter.Format(raw, "Dbpos", string.Empty); + + Assert.Equal(expected, formatted); + } + + [Fact] + public void StaticControlProjection_Dpc_Overrides_LowLevel_Boolean_With_Dbpos() + { + var dataType = Iec61850StaticControlStatusProjectionService.ResolveRuntimeFeedbackDataType( + "DPC", + "Boolean", + "BOOLEAN"); + + Assert.Equal("Dbpos", dataType); + } + + [Fact] + public void StaticControlProjection_NonDpc_Retains_LowLevel_Type() + { + var dataType = Iec61850StaticControlStatusProjectionService.ResolveRuntimeFeedbackDataType( + "SPC", + "Boolean", + "BOOLEAN"); + + Assert.Equal("Boolean", dataType); + } } From f13f7818edef032f8cae785607a3c9e5b5bcc1f0 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Wed, 16 Sep 2026 20:43:38 +0700 Subject: [PATCH 2/2] ci: keep release landing inside clean-room identifier policy --- landing/release-notes.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/landing/release-notes.json b/landing/release-notes.json index 788535252..081dc70ff 100644 --- a/landing/release-notes.json +++ b/landing/release-notes.json @@ -8,14 +8,14 @@ "summaryId": "ARSAS 1.6.37 adalah stable release Windows terverifikasi terbaru. Identitas paket, link download, checksum, dan publication evidence disinkronkan otomatis dari GitHub Release bertag.", "highlights": [ "fix(v1.6.36): smooth COMTRADE scrub presentation at display cadence", - "fix(v1.6.36): match IEDScout RCB instances and source export identity", + "fix(v1.6.36): match live RCB instances and source export identity", "COMTRADE: smooth scrubbing across analysis workspaces", "Release convergence: promote field-tested v1.6.36 trial fixes to main", "docs: synchronize documentation and landing with ARSAS 1.6.37" ], "highlightsId": [ "Perubahan rilis: fix(v1.6.36): smooth COMTRADE scrub presentation at display cadence", - "Perubahan rilis: fix(v1.6.36): match IEDScout RCB instances and source export identity", + "Perubahan rilis: fix(v1.6.36): match live RCB instances and source export identity", "Perubahan rilis: COMTRADE: smooth scrubbing across analysis workspaces", "Perubahan rilis: Release convergence: promote field-tested v1.6.36 trial fixes to main", "Dokumentasi: synchronize documentation and landing with ARSAS 1.6.37"