Skip to content

P7.2 #446: harden association lifecycle and event-driven traffic proof #476

P7.2 #446: harden association lifecycle and event-driven traffic proof

P7.2 #446: harden association lifecycle and event-driven traffic proof #476

name: Smart Discovery Production Promotion Guard
on:
pull_request:
paths:
- "*.cs"
- "**/*.cs"
- "*.csproj"
- "**/*.csproj"
- "*.sln"
- "**/*.sln"
- "*.props"
- "**/*.props"
- "*.targets"
- "**/*.targets"
- "global.json"
- "*.xaml"
- "**/*.xaml"
- "app.manifest"
- "VERSION"
- ".release/**"
- ".github/workflows/**"
- "Assets/**"
- "Resources/**"
- "installer/**"
- "engine-patches/**"
- "landing/release-notes*.json"
- "landing/latest.json"
- "engines/**"
- "scripts/**"
- "tests/**"
- "evidence/**"
- "docs/INTEROPERABILITY_REFERENCE_CONTRACT.md"
- ".github/workflows/smart-discovery-*.yml"
workflow_dispatch:
jobs:
verify-production-route:
name: Verify physical-proven Smart Discovery production parity
runs-on: windows-latest
timeout-minutes: 30
steps:
- name: Checkout exact ARSAS candidate
uses: actions/checkout@v7
with:
path: ArIED61850Tester
- name: Resolve immutable ARIEC61850 engine lock
shell: powershell
run: |
$lock = Get-Content '.\ArIED61850Tester\engines\ARIEC61850.lock.json' -Raw | ConvertFrom-Json
if ($lock.repository -ne 'masarray/ARIEC61850' -or $lock.commit -notmatch '^[0-9a-f]{40}$') {
throw 'Invalid ARIEC61850 production lock.'
}
"ARIEC61850_REPOSITORY=$($lock.repository)" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
"ARIEC61850_COMMIT=$($lock.commit)" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
- name: Checkout exact ARIEC61850 engine
shell: powershell
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 pin mismatch: expected $env:ARIEC61850_COMMIT got $actual"
}
- name: Setup .NET 8
uses: actions/setup-dotnet@v6
with:
dotnet-version: 8.0.x
- name: Verify tracked production route before build
shell: powershell
run: |
$native = '.\ArIED61850Tester\Services\NativeIec61850Client.cs'
$before = (Get-FileHash $native -Algorithm SHA256).Hash
& .\ArIED61850Tester\scripts\enable-smart-discovery-capture.ps1 -VerifyOnly
if ($LASTEXITCODE -ne 0) { throw 'Smart Discovery route verification failed.' }
$after = (Get-FileHash $native -Algorithm SHA256).Hash
if ($after -ne $before) {
throw 'Verification mutated NativeIec61850Client.cs; build-time source mutation is forbidden.'
}
$source = Get-Content $native -Raw
foreach ($required in @(
'return await DiscoverSignalsSmartForCaptureAsync(cancellationToken, progress).ConfigureAwait(false);',
'__P0_5C_CONNECT_RESET__',
'__P0_5C_DISPOSE_RESET__',
'_lastDiscovery.Snapshot.DomainVariables')) {
if ($source -notmatch [regex]::Escape($required)) {
throw "Production Smart Discovery contract missing: $required"
}
}
- name: Restore build and test the exact production route
shell: powershell
run: |
dotnet restore .\ArIED61850Tester\ArIED61850Tester.sln
if ($LASTEXITCODE -ne 0) { throw 'ARSAS restore failed.' }
dotnet build .\ArIED61850Tester\ArIED61850Tester.sln -c Release --no-restore
if ($LASTEXITCODE -ne 0) { throw 'ARSAS production-route build failed.' }
dotnet test .\ArIED61850Tester\tests\ARSAS.Tests\ARSAS.Tests.csproj -c Release --no-build --no-restore
if ($LASTEXITCODE -ne 0) { throw 'ARSAS production-route regression tests failed.' }
- name: Prove build did not select or synthesize another route
shell: powershell
run: |
$native = '.\ArIED61850Tester\Services\NativeIec61850Client.cs'
& .\ArIED61850Tester\scripts\enable-smart-discovery-capture.ps1 -VerifyOnly
if ($LASTEXITCODE -ne 0) { throw 'Post-build Smart Discovery route verification failed.' }
$targets = Get-Content '.\ArIED61850Tester\Directory.Build.targets' -Raw
if ($targets -match 'GITHUB_WORKFLOW' -or $targets -match 'SmartDiscoveryProductionPromoted') {
throw 'Discovery runtime still depends on workflow name or promotion switch.'
}
Write-Host 'Production, R7, installer and local builds now compile the same tracked Smart Discovery route.'