diff --git a/DynamicReportQualificationResultWindow.G24C.cs b/DynamicReportQualificationResultWindow.G24C.cs new file mode 100644 index 000000000..52d1d8ec3 --- /dev/null +++ b/DynamicReportQualificationResultWindow.G24C.cs @@ -0,0 +1,92 @@ +using System.Text; +using ArIED61850Tester.Services; + +namespace ArIED61850Tester; + +internal partial class DynamicReportQualificationResultWindow +{ + internal DynamicReportQualificationResultWindow(DynamicReportCleanupClosureCommissioningResult result) + { + ArgumentNullException.ThrowIfNull(result); + InitializeComponent(); + + Title = "G2.4-C Fresh Association Cleanup Closure Evidence"; + HeaderText.Text = "G2.4-C Fresh Association Cleanup Closure"; + SummaryText.Text = result.Summary; + StateText.Text = result.IsSuccess + ? "G2.4 Cleanup Closed" + : result.IsBlocked + ? "Blocked" + : "Cleanup closure not proven"; + EvidenceTextBox.Text = BuildG24CEvidence(result); + + if (result.IsSuccess) + SetPassBadge(); + } + + private static string BuildG24CEvidence(DynamicReportCleanupClosureCommissioningResult result) + { + var builder = new StringBuilder(); + builder.AppendLine("ARSAS G2.4-C FRESH ASSOCIATION CLEANUP CLOSURE EVIDENCE"); + builder.AppendLine(new string('=', 72)); + builder.AppendLine($"Result: {result.Summary}"); + builder.AppendLine($"Blocked: {result.IsBlocked}"); + builder.AppendLine($"G2.4-C success: {result.IsSuccess}"); + + if (result.Identity is not null) + { + builder.AppendLine(); + builder.AppendLine("IED IDENTITY"); + builder.AppendLine($"Stable identity: {result.Identity.StableIdentityKey}"); + builder.AppendLine($"Model fingerprint: {result.Identity.ModelFingerprint}"); + builder.AppendLine($"Model: {result.Identity.Model}"); + builder.AppendLine($"Firmware: {result.Identity.FirmwareRevision}"); + builder.AppendLine($"Profile revision: {result.Identity.ProfileRevision}"); + } + + builder.AppendLine(); + builder.AppendLine("G2.4 PROVEN TARGET"); + builder.AppendLine($"Input profile state: {result.InputProfile?.State.ToString() ?? "-"}"); + builder.AppendLine($"URCB: {G24CTextOrDash(result.RcbReference)}"); + builder.AppendLine($"Previous temporary DataSet: {G24CTextOrDash(result.TemporaryDataSetReference)}"); + + if (result.FreshRcbSnapshot is not null) + { + var snapshot = result.FreshRcbSnapshot; + builder.AppendLine(); + builder.AppendLine("FRESH-ASSOCIATION RCB CLOSURE"); + builder.AppendLine($"Availability: {snapshot.Availability}"); + builder.AppendLine($"DatSet probe: {snapshot.DataSetProbeState}"); + builder.AppendLine($"DatSet: {G24CTextOrDash(snapshot.DataSetReference)}"); + builder.AppendLine($"RptEna: {G24CTextOrDash(snapshot.EnabledState)}"); + builder.AppendLine($"Resv: {G24CTextOrDash(snapshot.ReservationState)}"); + builder.AppendLine($"Owner: {G24CTextOrDash(snapshot.Owner)}"); + builder.AppendLine($"Reservation time: {G24CTextOrDash(snapshot.ReservationTimeSeconds)}"); + builder.AppendLine($"TrgOps read-only: {G24CTextOrDash(snapshot.TriggerOptions)}"); + builder.AppendLine($"OptFlds read-only: {G24CTextOrDash(snapshot.OptionalFields)}"); + builder.AppendLine($"RptID: {G24CTextOrDash(snapshot.ReportId)}"); + } + + builder.AppendLine(); + builder.AppendLine("TEMPORARY DATASET CLOSURE"); + builder.AppendLine($"Absent from fresh NamedVariableList: {result.TemporaryDataSetAbsentFromNameList}"); + builder.AppendLine($"Direct DataSet directory absent: {result.TemporaryDataSetDirectoryAbsent}"); + builder.AppendLine($"Fresh association healthy: {result.AssociationHealthy}"); + + builder.AppendLine(); + builder.AppendLine("WIRE / SAFETY EVIDENCE"); + foreach (var line in result.EvidenceLines) + builder.AppendLine(line); + + builder.AppendLine(); + builder.AppendLine("SAFETY STATE"); + builder.AppendLine("G2.4-C is read-only and performs zero MMS writes or DataSet mutations."); + builder.AppendLine("G2.4-C does not alter the persisted InformationReportProven profile."); + builder.AppendLine("G2.4 Cleanup Closed != ProductionEligible."); + builder.AppendLine("Production automatic dynamic reporting remains OFF until G2.5/G2.6 acceptance gates pass."); + return builder.ToString(); + } + + private static string G24CTextOrDash(string? value) + => string.IsNullOrWhiteSpace(value) ? "-" : value.Trim(); +} diff --git a/DynamicReportQualificationResultWindow.P1.cs b/DynamicReportQualificationResultWindow.P1.cs new file mode 100644 index 000000000..a3808d9a5 --- /dev/null +++ b/DynamicReportQualificationResultWindow.P1.cs @@ -0,0 +1,88 @@ +using System.Text; +using ArIED61850Tester.Services; + +namespace ArIED61850Tester; + +internal partial class DynamicReportQualificationResultWindow +{ + internal DynamicReportQualificationResultWindow(DynamicReportOptionalFieldsProbeCommissioningResult result) + { + ArgumentNullException.ThrowIfNull(result); + InitializeComponent(); + + Title = "P1 Isolated OptFlds Micro-Probe Evidence"; + HeaderText.Text = "P1 Isolated OptFlds Micro-Probe"; + SummaryText.Text = result.Summary; + StateText.Text = result.IsSuccess + ? "P1 OptFlds Proven" + : result.IsBlocked + ? "Blocked" + : result.CleanupSucceeded + ? "Not proven / restored" + : "Restore unproven"; + EvidenceTextBox.Text = BuildP1Evidence(result); + + if (result.IsSuccess) + SetPassBadge(); + } + + private static string BuildP1Evidence(DynamicReportOptionalFieldsProbeCommissioningResult result) + { + var builder = new StringBuilder(); + builder.AppendLine("ARSAS P1 ISOLATED OPTFLDS MICRO-PROBE EVIDENCE"); + builder.AppendLine(new string('=', 62)); + builder.AppendLine($"Result: {result.Summary}"); + builder.AppendLine($"Blocked: {result.IsBlocked}"); + builder.AppendLine($"P1 success: {result.IsSuccess}"); + builder.AppendLine($"Restore proven: {result.CleanupSucceeded}"); + + if (result.Identity is not null) + { + builder.AppendLine(); + builder.AppendLine("IED IDENTITY"); + builder.AppendLine($"Stable identity: {result.Identity.StableIdentityKey}"); + builder.AppendLine($"Model fingerprint: {result.Identity.ModelFingerprint}"); + builder.AppendLine($"Model: {result.Identity.Model}"); + builder.AppendLine($"Firmware: {result.Identity.FirmwareRevision}"); + builder.AppendLine($"Profile revision: {result.Identity.ProfileRevision}"); + } + + builder.AppendLine(); + builder.AppendLine("P1 TARGET"); + builder.AppendLine($"Input profile state: {result.InputProfile?.State.ToString() ?? "-"}"); + builder.AppendLine($"URCB: {P1TextOrDash(result.RcbReference)}"); + builder.AppendLine("Requested optional fields: reason-for-inclusion + data-set-name"); + builder.AppendLine("Correct canonical OptFlds raw target: 061800"); + + if (result.Probe is not null) + { + builder.AppendLine(); + builder.AppendLine("OPTFLDS READ / WRITE / RESTORE"); + builder.AppendLine($"Original raw: {P1TextOrDash(result.Probe.OriginalRaw)}"); + builder.AppendLine($"Requested raw: {P1TextOrDash(result.Probe.RequestedRaw)}"); + builder.AppendLine($"Readback raw: {P1TextOrDash(result.Probe.ReadbackRaw)}"); + builder.AppendLine($"Restore readback raw: {P1TextOrDash(result.Probe.RestoreReadbackRaw)}"); + builder.AppendLine($"Requested semantic match: {result.Probe.RequestedComparison?.IsSemanticMatch.ToString() ?? "-"}"); + builder.AppendLine($"Requested raw exact: {result.Probe.RequestedComparison?.IsRawExact.ToString() ?? "-"}"); + builder.AppendLine($"Requested padding-only diff: {result.Probe.RequestedComparison?.PaddingOnlyDifference.ToString() ?? "-"}"); + builder.AppendLine($"Restore semantic match: {result.Probe.RestoreComparison?.IsSemanticMatch.ToString() ?? "-"}"); + builder.AppendLine($"Restore raw exact: {result.Probe.RestoreComparison?.IsRawExact.ToString() ?? "-"}"); + builder.AppendLine($"Restore padding-only diff: {result.Probe.RestoreComparison?.PaddingOnlyDifference.ToString() ?? "-"}"); + } + + builder.AppendLine(); + builder.AppendLine("WIRE / SAFETY EVIDENCE"); + foreach (var line in result.EvidenceLines) + builder.AppendLine(line); + + builder.AppendLine(); + builder.AppendLine("SAFETY STATE"); + builder.AppendLine("P1 writes OptFlds only on one forced-live proven-free URCB and immediately restores it."); + builder.AppendLine("No TrgOps, DatSet, Resv, RptEna, GI or dynamic DataSet service is used by P1."); + builder.AppendLine("P1 does not advance the G2 profile and production automatic dynamic reporting remains OFF."); + return builder.ToString(); + } + + private static string P1TextOrDash(string? value) + => string.IsNullOrWhiteSpace(value) ? "-" : value.Trim(); +} diff --git a/DynamicReportQualificationResultWindow.xaml b/DynamicReportQualificationResultWindow.xaml index 1dc5e4ca0..da6cf2c4b 100644 --- a/DynamicReportQualificationResultWindow.xaml +++ b/DynamicReportQualificationResultWindow.xaml @@ -2,7 +2,7 @@ x:ClassModifier="internal" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - Title="G2 Dynamic Reporting Qualification Evidence" + Title="G2 Dynamic Reporting Commissioning Evidence" Width="980" Height="720" MinWidth="760" MinHeight="520" WindowStartupLocation="CenterOwner" Background="#F4F7FB" @@ -23,12 +23,12 @@ - + - + @@ -52,7 +52,7 @@ -