Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions .github/workflows/scl-semantic-parity-candidate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
name: SCL Semantic Parity Candidate

on:
pull_request:
paths:
- "engines/ARIEC61850.lock.json"
- "evidence/p0.7-release-candidate-lock.json"
- "tests/ARSAS.Tests/P07ReleaseCandidateLockRegressionTests.cs"
- "tests/ARSAS.Tests/SclSemanticIntegrationRegressionTests.cs"
- ".github/workflows/scl-semantic-parity-candidate.yml"
workflow_dispatch:

concurrency:
group: scl-semantic-parity-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
build-semantic-candidate:
name: Build locked SCL semantic integration candidate
runs-on: windows-latest

steps:
- name: Checkout exact ARSAS semantic candidate
shell: pwsh
env:
ARSAS_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
if ($env:ARSAS_SOURCE_SHA -notmatch '^[0-9a-f]{40}$') {
throw "Invalid ARSAS source SHA: $env:ARSAS_SOURCE_SHA"
}

git clone --quiet --filter=blob:none --no-checkout "https://github.com/$env:GITHUB_REPOSITORY.git" ARSAS
git -C .\ARSAS fetch --quiet --depth 1 origin $env:ARSAS_SOURCE_SHA
git -C .\ARSAS checkout --quiet --detach $env:ARSAS_SOURCE_SHA

$actual = (git -C .\ARSAS rev-parse HEAD).Trim().ToLowerInvariant()
if ($actual -ne $env:ARSAS_SOURCE_SHA.ToLowerInvariant()) {
throw "ARSAS SHA mismatch. Expected $env:ARSAS_SOURCE_SHA, got $actual."
}

"ARSAS_COMMIT=$actual" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append

- name: Validate frozen P0.7 baseline and explicit semantic engine candidate
shell: pwsh
run: |
$lock = Get-Content .\ARSAS\engines\ARIEC61850.lock.json -Raw | ConvertFrom-Json
$baseline = Get-Content .\ARSAS\evidence\p0.7-release-candidate-lock.json -Raw | ConvertFrom-Json

if ($lock.repository -ne 'masarray/ARIEC61850' -or
$lock.commit -notmatch '^[0-9a-f]{40}$' -or
[int]$lock.sourcePullRequest -ne 139) {
throw 'Semantic candidate must pin the explicit ARIEC61850 PR #139 revision.'
}

if ($baseline.contractId -ne 'P0.7-RELEASE-CANDIDATE-LOCK') {
throw 'P0.7 release-candidate lock is missing or changed.'
}

if ($baseline.physicalReference.consumerAcceptedHead -ne '0d0b9204d6637e3d62e2eee94000386ae43cd0e9' -or
$baseline.physicalReference.engineBaseline -ne '648124097621046f5f127ceb1cf853fea54db730') {
throw 'Physically accepted P0.7 source authority was modified.'
}

$runtime = $baseline.acceptedRuntime
if ([int]$runtime.staticMembers -ne 58 -or
[int]$runtime.selectedLiveRows -ne 58 -or
[int]$runtime.analogRows -ne 22 -or
[int]$runtime.digitalRows -ne 36 -or
[int]$runtime.reportBackedRows -ne 58 -or
[int]$runtime.cyclicMmsProcessPolling -ne 0 -or
-not [bool]$runtime.actualInformationReportObserved -or
-not [bool]$runtime.saveSclWhileMonitoring -or
-not [bool]$runtime.savedSclReusable -or
[int]$runtime.reopenedSclLiveRows -ne 58) {
throw 'P0.7 physical runtime acceptance was weakened.'
}

$candidate = $baseline.sclSemanticParity.integrationCandidate
if ($candidate.repository -ne 'masarray/ARIEC61850' -or
[int]$candidate.pullRequest -ne 139 -or
$candidate.engineCommit -ne $lock.commit -or
[bool]$candidate.acquisitionChanges -or
-not [bool]$candidate.physicalAcceptancePending) {
throw 'SCL semantic integration evidence does not match the engine lock.'
}

if ($baseline.sclSemanticParity.knownExample.object -ne 'CBClsCounter' -or
$baseline.sclSemanticParity.knownExample.expectedCdc -ne 'INS' -or
$baseline.sclSemanticParity.knownExample.expectedTypeFamily -ne 'integer') {
throw 'Known integer-status semantic acceptance was weakened.'
}

"ARIEC61850_REPOSITORY=$($lock.repository)" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
"ARIEC61850_COMMIT=$($lock.commit)" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
$version = (Get-Content .\ARSAS\VERSION -Raw).Trim()
"ARSAS_VERSION=$version" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append

- name: Checkout exact semantic engine revision
shell: pwsh
run: |
git clone --quiet --filter=blob:none --no-checkout "https://github.com/$env:ARIEC61850_REPOSITORY.git" ARIEC61850
git -C .\ARIEC61850 fetch --quiet --depth 1 origin $env:ARIEC61850_COMMIT
git -C .\ARIEC61850 checkout --quiet --detach $env:ARIEC61850_COMMIT

$actual = (git -C .\ARIEC61850 rev-parse HEAD).Trim().ToLowerInvariant()
if ($actual -ne $env:ARIEC61850_COMMIT.ToLowerInvariant()) {
throw "Engine SHA mismatch. Expected $env:ARIEC61850_COMMIT, got $actual."
}

- name: Verify semantic export boundary and acquisition freeze
shell: pwsh
run: |
$cdc = Get-Content .\ARIEC61850\src\AR.Iec61850\Discovery\CdcInferenceEngine.cs -Raw
$exporter = Get-Content .\ARIEC61850\src\AR.Iec61850\Scl\Export\LiveIedSclExporter.cs -Raw
$engineRegression = Get-Content .\ARIEC61850\tests\AR.Iec61850.Tests\Scl\LiveIedSclSemanticAuthorityTests.cs -Raw
$runtime = Get-Content .\ARSAS\Services\Iec61850MonitorRuntime.cs -Raw
$save = Get-Content .\ARSAS\MainWindow.xaml.cs -Raw
$consumerRegression = Get-Content .\ARSAS\tests\ARSAS.Tests\SclSemanticIntegrationRegressionTests.cs -Raw

foreach ($required in @(
'TryInferTypedStatusCdc',
'exact stVal type is',
'ResolveExportCdc',
'ExactLiveTypeCdcAuthority')) {
if (($cdc + $exporter) -notmatch [regex]::Escape($required)) {
throw "Typed SCL semantic authority is incomplete: $required"
}
}

foreach ($required in @(
'ExactLiveIntegerStatus_RepairsStaleBooleanCdc_AndRoundTripsAsInsInt32',
'Assert.Equal("INS"',
'Assert.Equal("INT32"')) {
if ($engineRegression -notmatch [regex]::Escape($required)) {
throw "Engine SCL round-trip regression is incomplete: $required"
}
}

if ($runtime -notmatch 'cyclic MMS process polling=0' -or
$runtime -notmatch 'state\.NextPollUtc = DateTime\.MaxValue' -or
$save -notmatch 'monitoring remains active; Save SCL uses the current canonical model' -or
$consumerRegression -notmatch 'ExactIntegerCounter_ExportsAndReopensAsInsInt32_WithIntegerPresentation') {
throw 'P0.7 acquisition freeze or consumer semantic regression contract is missing.'
}

- name: Setup .NET 8
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Restore engine
run: dotnet restore .\ARIEC61850\ARIEC61850.sln

- name: Build engine
run: dotnet build .\ARIEC61850\ARIEC61850.sln -c Release --no-restore

- name: Test engine
run: dotnet test .\ARIEC61850\ARIEC61850.sln -c Release --no-build --no-restore --logger "trx;LogFileName=ariec61850-scl-semantic-tests.trx" --results-directory .\ARSAS\TestResults

- name: Restore ARSAS
run: dotnet restore .\ARSAS\ArIED61850Tester.sln

- name: Build ARSAS
run: dotnet build .\ARSAS\ArIED61850Tester.sln -c Release --no-restore

- name: Run full ARSAS regression suite
run: dotnet test .\ARSAS\tests\ARSAS.Tests\ARSAS.Tests.csproj -c Release --no-build --no-restore --logger "trx;LogFileName=arsas-scl-semantic-tests.trx" --results-directory .\ARSAS\TestResults

- name: Publish semantic candidate portable EXE
shell: pwsh
run: |
.\ARSAS\scripts\publish-windows-portable.ps1 `
-Version $env:ARSAS_VERSION `
-Runtime win-x64 `
-SingleFile $true `
-SelfContained $true `
-EngineProject "$env:GITHUB_WORKSPACE\ARIEC61850\src\AR.Iec61850\AR.Iec61850.csproj" `
-NpcapProject "$env:GITHUB_WORKSPACE\ARIEC61850\src\AR.Iec61850.Transports.Npcap\AR.Iec61850.Transports.Npcap.csproj"

- name: Smoke test semantic candidate
shell: pwsh
run: |
$exe = ".\ARSAS\dist\ARSAS-$env:ARSAS_VERSION-win-x64-portable.exe"
if (!(Test-Path $exe -PathType Leaf)) {
throw "Portable EXE missing: $exe"
}

$env:DOTNET_BUNDLE_EXTRACT_BASE_DIR = Join-Path $env:RUNNER_TEMP 'ARSAS-scl-semantic-bundle-cache'
$process = Start-Process -FilePath $exe -ArgumentList @('--portable-smoke-test') -PassThru
if (-not $process.WaitForExit(30000)) {
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
throw 'Portable EXE smoke test timed out.'
}
if ($process.ExitCode -ne 0) {
throw "Portable EXE smoke test failed: $($process.ExitCode)"
}

$baseline = Get-Content .\ARSAS\evidence\p0.7-release-candidate-lock.json -Raw | ConvertFrom-Json
@(
'ARSAS SCL semantic parity physical-retest candidate',
"ARSAS commit: $env:ARSAS_COMMIT",
"ARIEC61850 commit: $env:ARIEC61850_COMMIT",
"Accepted physical engine baseline: $($baseline.physicalReference.engineBaseline)",
'',
'Candidate semantic acceptance:',
'CBClsCounter exact integer stVal -> SCL CDC INS -> stVal INT32 -> reopened integer presentation.',
'',
'Frozen physical acceptance to preserve:',
'Static members/live rows 58/58; Analog 22/22; Digital 36/36; report-backed 58; cyclic MMS process polling 0.',
'Save SCL while monitoring must remain non-disruptive and generated SCL must reopen into the same report-backed workflow.',
'',
'This artifact is a physical-retest candidate, not release authority.'
) | Set-Content .\ARSAS\dist\SCL-SEMANTIC-CANDIDATE.txt -Encoding utf8

- name: Upload semantic candidate
uses: actions/upload-artifact@v4
with:
name: ARSAS-scl-semantic-parity-win-x64
path: |
ARSAS\dist\ARSAS-*-win-x64-portable.exe
ARSAS\dist\SCL-SEMANTIC-CANDIDATE.txt
ARSAS\evidence\p0.7-release-candidate-lock.json
ARSAS\TestResults\*.trx
if-no-files-found: error
retention-days: 14
6 changes: 3 additions & 3 deletions engines/ARIEC61850.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"schemaVersion": 1,
"repository": "masarray/ARIEC61850",
"ref": "main",
"commit": "648124097621046f5f127ceb1cf853fea54db730",
"sourcePullRequest": 135,
"purpose": "R7 physical SCL repair pin on the complete PR #134 smart-discovery performance head. Accepted remote AP-title/AE/PSEL/SSEL remain decoded from the exact association request bytes accepted by the IED and TSEL remains bound to the accepted COTP destination selector. Physical AA1E1F06R4 evidence additionally proved that indexed RCB siblings may differ in writable/current BufTm, IntgPd, TrgOps and OptFlds while still representing one logical SCL ReportControl; engine head 648124097621046f5f127ceb1cf853fea54db730 preserves DataSet/ConfRev/domain/LN/buffered identity while allowing that runtime-mutable setting drift. ARSAS consumer-side reconnect must reproduce the proven native calling identity byte-for-byte and canonical save uses full-model SCL with prefixed-LN identity, CDC-aware WYE/DEL/SEQ SDO and FC ownership, plus exact standard TCTR/TVTR/LTIM/EEName/MltLev CDC authority and Edition-2-only LTRK service-tracking CDCs with Edition-1 schema downgrade protection; physical R8 reuse evidence additionally requires exact MMS TypeSpecification declaration order through canonical model/SCL reload, treats SG/SE as setting data rather than control blocks, and maps MHAI THD phase groups as WYE/CMV; safety is enforced by bounded FC-read policy rather than deleting discovered model leaves. Production promotion remains fail-closed and still requires fresh physical authority. R9 reuse lock additionally preserves rptID-backed preallocated singleton RCB indexing, case-distinct canonical instance values, and compile-safe logical RCB projection; unresolved 46 trusted-SCL projection errors remain a fail-open diagnostic gap but a fail-closed promotion gap until physical evidence reaches zero. P1 trusted-SCL projection repair removes cross-DO positional dependence for multi-DO CF structures: SCL LNodeType order is not treated as MMS FC-structure order, so CF hydration is split into exact DO-scoped structured Reads and remains batched/bounded. P0 structural discovery remains unchanged. P2 makes instance-value identity exact-case end-to-end: ARSAS trusted-SCL caching uses StringComparer.Ordinal and reports projectedUniqueValues/cacheLoss; engine TypeSpecification member resolution and canonical DO/DA instance-value targeting are case-sensitive so legal paths such as tracking t/T cannot collapse or cross-resolve. R10 physical acceptance passed on AA1E1F06R4: Ed2 and Ed1 both reached projectionErrors=0 and cacheLoss=0, all planned reads succeeded, 58/58 runtime points were report-backed, and actual InformationReport traffic was observed. The exact tested commit 9935d6902d786cc69b299260fe36b835944d5e81 and merged main commit 648124097621046f5f127ceb1cf853fea54db730 have the identical source tree 1cf7e08f333f24994625e8fe8416dbd0a16195b1.",
"commit": "090d81944791be5b690d24342f9262495eda1a09",
"sourcePullRequest": 139,
"purpose": "R7 physical SCL repair pin on the complete PR #134 smart-discovery performance head. Accepted remote AP-title/AE/PSEL/SSEL remain decoded from the exact association request bytes accepted by the IED and TSEL remains bound to the accepted COTP destination selector. Physical AA1E1F06R4 evidence additionally proved that indexed RCB siblings may differ in writable/current BufTm, IntgPd, TrgOps and OptFlds while still representing one logical SCL ReportControl; engine head 648124097621046f5f127ceb1cf853fea54db730 preserves DataSet/ConfRev/domain/LN/buffered identity while allowing that runtime-mutable setting drift. ARSAS consumer-side reconnect must reproduce the proven native calling identity byte-for-byte and canonical save uses full-model SCL with prefixed-LN identity, CDC-aware WYE/DEL/SEQ SDO and FC ownership, plus exact standard TCTR/TVTR/LTIM/EEName/MltLev CDC authority and Edition-2-only LTRK service-tracking CDCs with Edition-1 schema downgrade protection; physical R8 reuse evidence additionally requires exact MMS TypeSpecification declaration order through canonical model/SCL reload, treats SG/SE as setting data rather than control blocks, and maps MHAI THD phase groups as WYE/CMV; safety is enforced by bounded FC-read policy rather than deleting discovered model leaves. Production promotion remains fail-closed and still requires fresh physical authority. R9 reuse lock additionally preserves rptID-backed preallocated singleton RCB indexing, case-distinct canonical instance values, and compile-safe logical RCB projection; unresolved 46 trusted-SCL projection errors remain a fail-open diagnostic gap but a fail-closed promotion gap until physical evidence reaches zero. P1 trusted-SCL projection repair removes cross-DO positional dependence for multi-DO CF structures: SCL LNodeType order is not treated as MMS FC-structure order, so CF hydration is split into exact DO-scoped structured Reads and remains batched/bounded. P0 structural discovery remains unchanged. P2 makes instance-value identity exact-case end-to-end: ARSAS trusted-SCL caching uses StringComparer.Ordinal and reports projectedUniqueValues/cacheLoss; engine TypeSpecification member resolution and canonical DO/DA instance-value targeting are case-sensitive so legal paths such as tracking t/T cannot collapse or cross-resolve. R10 physical acceptance passed on AA1E1F06R4: Ed2 and Ed1 both reached projectionErrors=0 and cacheLoss=0, all planned reads succeeded, 58/58 runtime points were report-backed, and actual InformationReport traffic was observed. The exact tested commit 9935d6902d786cc69b299260fe36b835944d5e81 and merged main commit 648124097621046f5f127ceb1cf853fea54db730 have the identical source tree 1cf7e08f333f24994625e8fe8416dbd0a16195b1. P0.7 semantic-integration candidate PR #139 is intentionally pinned on a stacked ARSAS branch only: exact live stVal TypeSpecification becomes status CDC authority and the SCL export boundary revalidates exact live status semantics before serialization. This candidate must preserve the locked physical P0.7 runtime/reporting baseline and remains physically unaccepted until relay retest.",
"previousTrialPin": {
"commit": "4467124775d8d9d76f3db194f9fbfd97144767a8",
"sourcePullRequest": 134,
Expand Down
16 changes: 13 additions & 3 deletions evidence/p0.7-release-candidate-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,27 @@
}
},
"sclSemanticParity": {
"status": "open-before-release",
"status": "integration-candidate-ci-passed-physical-retest-pending",
"target": "Generated SCL must preserve the actual IED semantic model and converge with the trusted independent interoperability reference SCL for semantically authoritative CDC/type information without changing the accepted acquisition baseline.",
"knownExample": {
"object": "CBClsCounter",
"currentProblem": "export/reload may classify the integer counter status as SPS/Boolean",
"expectedCdc": "INS",
"expectedTypeFamily": "integer",
"engineCandidatePullRequest": 139,
"engineCandidateHead": "9123c8aa1cc51a1e13c6750c0e1f8bee2a2de3b7",
"engineCandidateHead": "090d81944791be5b690d24342f9262495eda1a09",
"integrationRule": "Any integration of this engine semantic correction must rerun and preserve every P0.7 accepted runtime and presentation invariant."
},
"integrationCandidate": {
"repository": "masarray/ARIEC61850",
"pullRequest": 139,
"engineCommit": "090d81944791be5b690d24342f9262495eda1a09",
"ciRun": 691,
"ciStatus": "success",
"scope": "Exact live stVal TypeSpecification is status CDC authority through discovery, SCL export and SCL reopen. Exporter corrects stale conservative live CDC only when exact live typed evidence proves a stronger semantic result.",
"acquisitionChanges": false,
"physicalAcceptancePending": true
}
},
"releaseRule": "Do not call the application release-ready while SCL semantic parity remains open. Continue SCL/CDC/type corrections from this locked baseline and reject any candidate that regresses the accepted runtime, report-only, Save-SCL, reuse, or presentation behavior."
"releaseRule": "Do not call the application release-ready until the SCL semantic integration candidate passes physical retest while preserving every locked P0.7 runtime, report-only, Save-SCL, reuse and presentation invariant."
}
Loading
Loading