diff --git a/.github/workflows/interoperability-reference-guard.yml b/.github/workflows/interoperability-reference-guard.yml index dbbe511b1..ed1313fb5 100644 --- a/.github/workflows/interoperability-reference-guard.yml +++ b/.github/workflows/interoperability-reference-guard.yml @@ -88,6 +88,19 @@ jobs: $serverAt = $lock.sclServerAtTrial $originalTrial = $lock.commit -eq $trial.exactCommit -and [int]$lock.sourcePullRequest -eq 148 + $closure = $lock.datasetFirstDiscoveryTrial + $datasetTrial = $null -ne $closure -and + $closure.status -eq 'code-trial-not-physical' -and + [int]$closure.issue -eq 495 -and + [int]$closure.enginePullRequest -eq 157 -and + [int]$closure.consumerPullRequest -eq 497 -and + $closure.baseEngineCommit -eq $serverAt.exactCommit -and + $lock.commit -eq $closure.exactCommit -and + [int]$lock.sourcePullRequest -eq 157 -and + $lock.ref -eq 'main' -and + [bool]$closure.physicalQualificationRequired -and + [bool]$closure.fullNameListFallbackForbidden -and + [bool]$closure.cyclicMmsProcessPollingForbidden $serverAtTrial = $null -ne $serverAt -and $lock.commit -eq $serverAt.exactCommit -and $serverAt.exactCommit -eq '352c81e6a798635c6addcee0683235ca87ad416d' -and @@ -102,7 +115,7 @@ jobs: if ($trial.status -ne 'code-verified-not-physical' -or [int]$trial.issue -ne 144 -or [int]$trial.integrationPullRequest -ne 148 -or - -not ($originalTrial -or $serverAtTrial) -or + -not ($originalTrial -or $serverAtTrial -or $datasetTrial) -or -not [bool]$trial.fullDiscoveryFallbackForbidden -or -not [bool]$trial.vendorBranchingForbidden -or -not [bool]$trial.physicalPromotionRequired) { diff --git a/.github/workflows/scl-interoperability-r7.yml b/.github/workflows/scl-interoperability-r7.yml index 4c29dd4f1..45117d35c 100644 --- a/.github/workflows/scl-interoperability-r7.yml +++ b/.github/workflows/scl-interoperability-r7.yml @@ -110,6 +110,23 @@ jobs: } Write-Host 'Running exact P6.2 ServerAt trial on the P6.1 code-only ancestry; physical/main promotion remains blocked.' } + elseif ($null -ne $lock.datasetFirstDiscoveryTrial -and + $lock.commit -eq $lock.datasetFirstDiscoveryTrial.exactCommit) { + $closure = $lock.datasetFirstDiscoveryTrial + if ($lock.ref -ne 'main' -or + [int]$lock.sourcePullRequest -ne 157 -or + [int]$closure.enginePullRequest -ne 157 -or + [int]$closure.consumerPullRequest -ne 497 -or + [int]$closure.issue -ne 495 -or + $closure.status -ne 'code-trial-not-physical' -or + $closure.baseEngineCommit -ne $lock.sclServerAtTrial.exactCommit -or + -not [bool]$closure.physicalQualificationRequired -or + -not [bool]$closure.fullNameListFallbackForbidden -or + -not [bool]$closure.cyclicMmsProcessPollingForbidden) { + throw 'P7.6G DataSet-first discovery experimental pin provenance is invalid.' + } + Write-Host 'DataSet-first closure trial qualified for CI only; no physical promotion.' + } elseif ($lock.commit -eq $convergence.activeStack.engineModelAndScl.head) { if ([int]$lock.sourcePullRequest -notin @(134, 135) -or $lock.purpose -notmatch 'R7 physical SCL repair pin') { diff --git a/Services/NativeIec61850Client.SmartDiscoveryCapture.cs b/Services/NativeIec61850Client.SmartDiscoveryCapture.cs index 6fa8c0f76..bad7548db 100644 --- a/Services/NativeIec61850Client.SmartDiscoveryCapture.cs +++ b/Services/NativeIec61850Client.SmartDiscoveryCapture.cs @@ -191,9 +191,17 @@ private async Task> DiscoverSignalsSmartForCaptu 52d, 5, 10)); var typeWatch = Stopwatch.StartNew(); - var variableTypes = await LiveIedVariableTypeProbeExecutor + var initialTypes = await LiveIedVariableTypeProbeExecutor .ProbeSmartAsync(_session, discovery.IedDirectory, smartOptions, CancellationToken.None) .ConfigureAwait(false); + // The configured DataSet directories provide live wire authority for + // ST/MX LN roots beyond the frozen GetNameList pagination budget. + // No new socket, brute-force GetNameList, or process-value Reads. + var closureTypes = await _session.ProbeDataSetMemberTypesSmartAsync( + discovery, initialTypes, smartOptions, CancellationToken.None) + .ConfigureAwait(false); + IReadOnlyList variableTypes = + initialTypes.Concat(closureTypes).ToArray(); typeWatch.Stop(); // A stale owner may finish an already-issued GVA batch, but it cannot build diff --git a/engines/ARIEC61850.lock.json b/engines/ARIEC61850.lock.json index 0342f50c6..221ce6ead 100644 --- a/engines/ARIEC61850.lock.json +++ b/engines/ARIEC61850.lock.json @@ -2,9 +2,9 @@ "schemaVersion": 1, "repository": "masarray/ARIEC61850", "ref": "main", - "commit": "352c81e6a798635c6addcee0683235ca87ad416d", - "sourcePullRequest": 153, - "purpose": "CODE-VERIFIED INTEROPERABILITY TRIAL ONLY; P6.2 ServerAt authority extends P0-P6.1 at immutable commit 352c81e6a798635c6addcee0683235ca87ad416d. Neither code verification nor the SCD readout implies physical validation or production promotion. All historical physical and P6.1 baselines remain unchanged; static RCB/report semantics and no cyclic polling invariant are untouched.", + "commit": "8b0c0f7e695b016834e40a6f068994dcc945cb1a", + "sourcePullRequest": 157, + "purpose": "EXPERIMENTAL DISCOVERY DATASET TYPE CLOSURE, code qualification pending: exact engine PR #157, extends immutable P6.2 baseline without touching canonical command/RCB or cyclic polling invariants. Physical F650 parity required before promotion.", "previousTrialPin": { "commit": "4467124775d8d9d76f3db194f9fbfd97144767a8", "sourcePullRequest": 134, @@ -72,5 +72,16 @@ "fixture": "sanitized J Server / F ServerAt multi-AP", "noAutomaticMmsFailover": true, "physicalQualificationRequired": true + }, + "datasetFirstDiscoveryTrial": { + "status": "code-trial-not-physical", + "issue": 495, + "enginePullRequest": 157, + "baseEngineCommit": "352c81e6a798635c6addcee0683235ca87ad416d", + "exactCommit": "8b0c0f7e695b016834e40a6f068994dcc945cb1a", + "consumerPullRequest": 497, + "fullNameListFallbackForbidden": true, + "cyclicMmsProcessPollingForbidden": true, + "physicalQualificationRequired": true } } diff --git a/tests/ARSAS.Tests/CanonicalLiveSclExportRegressionTests.cs b/tests/ARSAS.Tests/CanonicalLiveSclExportRegressionTests.cs index 64734794e..ce96afb75 100644 --- a/tests/ARSAS.Tests/CanonicalLiveSclExportRegressionTests.cs +++ b/tests/ARSAS.Tests/CanonicalLiveSclExportRegressionTests.cs @@ -407,12 +407,21 @@ public void EngineLock_PreservesPhysicalSclRepairBaselineAcrossCodeVerifiedInter using var document = System.Text.Json.JsonDocument.Parse(lockFile); var root = document.RootElement; - // The current source is the explicit P6.2 code-only trial. P6.1 remains - // immutable ancestry, not a field-proven replacement or a new main pin. - Assert.Equal( - "352c81e6a798635c6addcee0683235ca87ad416d", + // P7.6G is a code-only experimental child of the immutable P6.2 + // engine trial. Historical source and physical acceptance stay unchanged. + var closure = root.GetProperty("datasetFirstDiscoveryTrial"); + Assert.Equal("code-trial-not-physical", closure.GetProperty("status").GetString()); + Assert.Equal(157, closure.GetProperty("enginePullRequest").GetInt32()); + Assert.Equal(497, closure.GetProperty("consumerPullRequest").GetInt32()); + Assert.Equal(495, closure.GetProperty("issue").GetInt32()); + Assert.Equal("352c81e6a798635c6addcee0683235ca87ad416d", + closure.GetProperty("baseEngineCommit").GetString()); + Assert.Equal(closure.GetProperty("exactCommit").GetString(), root.GetProperty("commit").GetString()); - Assert.Equal(153, root.GetProperty("sourcePullRequest").GetInt32()); + Assert.Equal(157, root.GetProperty("sourcePullRequest").GetInt32()); + Assert.True(closure.GetProperty("physicalQualificationRequired").GetBoolean()); + Assert.True(closure.GetProperty("fullNameListFallbackForbidden").GetBoolean()); + Assert.True(closure.GetProperty("cyclicMmsProcessPollingForbidden").GetBoolean()); Assert.Equal( "648124097621046f5f127ceb1cf853fea54db730", @@ -448,7 +457,7 @@ public void EngineLock_PreservesPhysicalSclRepairBaselineAcrossCodeVerifiedInter Assert.Equal(153, serverAt.GetProperty("sourcePullRequest").GetInt32()); Assert.Equal(trial.GetProperty("exactCommit").GetString(), serverAt.GetProperty("baseEngineCommit").GetString()); - Assert.Equal(root.GetProperty("commit").GetString(), + Assert.Equal(closure.GetProperty("baseEngineCommit").GetString(), serverAt.GetProperty("exactCommit").GetString()); Assert.True(serverAt.GetProperty("physicalQualificationRequired").GetBoolean()); Assert.True(serverAt.GetProperty("noAutomaticMmsFailover").GetBoolean()); diff --git a/tests/ARSAS.Tests/SmartInteroperabilityTrialGuardRegressionTests.cs b/tests/ARSAS.Tests/SmartInteroperabilityTrialGuardRegressionTests.cs index c3d86f7a4..bbf37e854 100644 --- a/tests/ARSAS.Tests/SmartInteroperabilityTrialGuardRegressionTests.cs +++ b/tests/ARSAS.Tests/SmartInteroperabilityTrialGuardRegressionTests.cs @@ -62,8 +62,15 @@ public void TrialLock_PreservesHistoricalPhysicalAuthorityAndExplicitlyRequiresP Assert.Equal(153, serverAt.GetProperty("sourcePullRequest").GetInt32()); Assert.Equal(trial.GetProperty("exactCommit").GetString(), serverAt.GetProperty("baseEngineCommit").GetString()); + var closure = root.GetProperty("datasetFirstDiscoveryTrial"); + Assert.Equal("code-trial-not-physical", closure.GetProperty("status").GetString()); + Assert.Equal(157, closure.GetProperty("enginePullRequest").GetInt32()); + Assert.Equal(serverAt.GetProperty("exactCommit").GetString(), + closure.GetProperty("baseEngineCommit").GetString()); Assert.Equal(root.GetProperty("commit").GetString(), - serverAt.GetProperty("exactCommit").GetString()); + closure.GetProperty("exactCommit").GetString()); + Assert.True(closure.GetProperty("physicalQualificationRequired").GetBoolean()); + Assert.True(closure.GetProperty("cyclicMmsProcessPollingForbidden").GetBoolean()); Assert.True(serverAt.GetProperty("physicalQualificationRequired").GetBoolean()); Assert.True(serverAt.GetProperty("noAutomaticMmsFailover").GetBoolean());