Skip to content
Merged
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
6 changes: 4 additions & 2 deletions .github/workflows/iedscout-convergence-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,10 @@ jobs:
throw 'P2 case-sensitive value path implementation regressed.'
}

if ($targets -notmatch 'SCL Interoperability R7 Build' -or
$targets -notmatch 'EnableSmartDiscoveryCaptureRoute' -or
if ($targets -notmatch 'VerifyPhysicalProvenSmartDiscoveryRoute' -or
$targets -notmatch '\-VerifyOnly' -or
$targets -match 'GITHUB_WORKFLOW' -or
$targets -match 'SmartDiscoveryProductionPromoted' -or
$capture -notmatch 'SmartDiscoveryStructuralFreezeContract = "P0-R9-STRUCTURAL"' -or
$capture -notmatch 'CreateP0FrozenSmartDiscoveryOptions' -or
$capture -notmatch 'MaxConcurrentChains = 8' -or
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/installer-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ on:
- "tests/ARSAS.Tests/Comtrade*Tests.cs"
- "ArIED61850Tester.csproj"
- "Directory.Build.props"
- "Directory.Build.targets"
- "Services/NativeIec61850Client.cs"
- "Services/NativeIec61850Client.SmartDiscoveryCapture.cs"
- "Services/NativeIec61850Client.SmartDiscoveryLifecycle.cs"
- "scripts/enable-smart-discovery-capture.ps1"
- "tests/ARSAS.Tests/SmartDiscoveryProductionPromotionRegressionTests.cs"
- "VERSION"
- "engines/ARIEC61850.lock.json"
- "engines/ARDIREC.lock.json"
Expand All @@ -39,6 +45,12 @@ on:
- "tests/ARSAS.Tests/Comtrade*Tests.cs"
- "ArIED61850Tester.csproj"
- "Directory.Build.props"
- "Directory.Build.targets"
- "Services/NativeIec61850Client.cs"
- "Services/NativeIec61850Client.SmartDiscoveryCapture.cs"
- "Services/NativeIec61850Client.SmartDiscoveryLifecycle.cs"
- "scripts/enable-smart-discovery-capture.ps1"
- "tests/ARSAS.Tests/SmartDiscoveryProductionPromotionRegressionTests.cs"
- "VERSION"
- "engines/ARIEC61850.lock.json"
- "engines/ARDIREC.lock.json"
Expand Down Expand Up @@ -117,6 +129,16 @@ jobs:
with:
dotnet-version: 8.0.x

- name: Verify physical-proven Smart Discovery route
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 'Installer refuses a legacy/incomplete Smart Discovery route.' }
$after = (Get-FileHash $native -Algorithm SHA256).Hash
if ($before -ne $after) { throw 'Installer verification mutated discovery source.' }

- name: Restore build and test application solution
shell: powershell
run: |
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/release-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,27 @@ jobs:
shell: powershell
run: .\ArIED61850Tester\scripts\verify-source-clean.ps1

- name: Verify physical-proven Smart Discovery route before release 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 'Release refuses a legacy/incomplete Smart Discovery route.' }
$after = (Get-FileHash $native -Algorithm SHA256).Hash
if ($before -ne $after) { throw 'Release verification mutated discovery source; refusing non-reproducible build.' }

$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 "Release Smart Discovery contract missing: $required"
}
}

- name: Restore, build and test exact release source
shell: powershell
run: |
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/scl-interoperability-r7.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,10 @@ jobs:
$capture -match 'InitialFcReadPlanner\.FromSclModel' -or
$capture -match 'ExecuteInitialFcReadPlanSmartAsync' -or
$capture -notmatch 'initialFcRoots=deferred' -or
$buildTargets -notmatch 'SCL Interoperability R7 Build' -or
$buildTargets -notmatch 'EnableSmartDiscoveryCaptureRoute' -or
$buildTargets -notmatch 'VerifyPhysicalProvenSmartDiscoveryRoute' -or
$buildTargets -notmatch '\-VerifyOnly' -or
$buildTargets -match 'GITHUB_WORKFLOW' -or
$buildTargets -match 'SmartDiscoveryProductionPromoted' -or
$lifecycle -notmatch 'PublishCanonicalModel\(model, initialRead\)' -or
$save -notmatch 'CanonicalLiveIedSclExporter\.WriteFiles' -or
$save -notmatch 'profile:\s*"full-model"' -or
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/smart-discovery-capture-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ jobs:
$patcher -notmatch '__P0_5C_CONNECT_RESET__' -or
$patcher -notmatch '__P0_5C_DISPOSE_RESET__' -or
$patcher -notmatch '_lastDiscovery\.Snapshot\.DomainVariables' -or
$targets -notmatch 'EnableSmartDiscoveryCaptureRoute') {
$targets -notmatch 'VerifyPhysicalProvenSmartDiscoveryRoute' -or
$targets -notmatch '\-VerifyOnly' -or
$targets -match 'GITHUB_WORKFLOW' -or
$targets -match 'SmartDiscoveryProductionPromoted') {
throw 'P0-5c association-scoped enrichment single-flight, authority publication, or lifecycle invalidation is incomplete.'
}
if ($helper -match 'ProbeSmartAsync\(_session, discovery\.IedDirectory, smartOptions, cancellationToken\)' -or
Expand Down
183 changes: 53 additions & 130 deletions .github/workflows/smart-discovery-production-promotion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,162 +5,85 @@ on:
workflow_dispatch:

jobs:
verify-production-promotion:
name: Verify P0-5g production promotion and merge-readiness contract
verify-production-route:
name: Verify physical-proven Smart Discovery production parity
runs-on: windows-latest
timeout-minutes: 30

steps:
- name: Checkout ARSAS branch
- name: Checkout exact ARSAS candidate
uses: actions/checkout@v4
with:
path: ArIED61850Tester

- name: Resolve immutable ARIEC61850 engine lock
shell: powershell
run: |
$ref = if ($env:GITHUB_HEAD_REF) { $env:GITHUB_HEAD_REF } else { $env:GITHUB_REF_NAME }
git clone --quiet --branch $ref "https://github.com/$env:GITHUB_REPOSITORY.git" ArIED61850Tester
$arsasHead = (git -C .\ArIED61850Tester rev-parse HEAD).Trim().ToLowerInvariant()
"ARSAS_HEAD=$arsasHead" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
Write-Host "P0-5g ARSAS head: $arsasHead"
$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 ARIEC61850 PR 134 head
- name: Checkout exact ARIEC61850 engine
shell: powershell
run: |
git clone --quiet --branch perf/smart-ied-discovery https://github.com/masarray/ARIEC61850.git ARIEC61850
$engineHead = (git -C .\ARIEC61850 rev-parse HEAD).Trim().ToLowerInvariant()
"ENGINE_HEAD=$engineHead" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
Write-Host "P0-5g engine PR head: $engineHead"
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@v4
with:
dotnet-version: 8.0.x

- name: Validate P0-5g source contract
- name: Verify tracked production route before build
shell: powershell
run: |
$root = '.\ArIED61850Tester'
$required = @(
"$root\evidence\SmartDiscoveryPromotion.props",
"$root\evidence\smart-discovery-production-promotion-target.json",
"$root\scripts\verify-smart-discovery-production-readiness.ps1",
"$root\scripts\new-smart-discovery-production-promotion-authority.ps1",
"$root\docs\P0-5G_PRODUCTION_PROMOTION_MAINLINE_READINESS.md",
"$root\tests\ARSAS.Tests\SmartDiscoveryProductionPromotionRegressionTests.cs"
)
foreach ($path in $required) {
if (-not (Test-Path $path -PathType Leaf)) { throw "P0-5g source missing: $path" }
}
foreach ($script in @(
"$root\scripts\verify-smart-discovery-production-readiness.ps1",
"$root\scripts\new-smart-discovery-production-promotion-authority.ps1")) {
$tokens = $null
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile($script, [ref]$tokens, [ref]$errors) | Out-Null
if ($errors.Count -ne 0) {
$messages = @($errors | ForEach-Object { $_.Message }) -join '; '
throw "PowerShell parse failure in ${script}: $messages"
}
$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.'
}
[xml]$props = Get-Content "$root\evidence\SmartDiscoveryPromotion.props" -Raw
$promoted = ([string]$props.Project.PropertyGroup.SmartDiscoveryProductionPromoted).Trim().ToLowerInvariant()
if ($promoted -notin @('true','false')) { throw 'P0-5g production switch is not a boolean.' }

- name: Build and test exact engine PR head
shell: powershell
run: |
.\ARIEC61850\scripts\verify-source-clean.ps1
dotnet restore .\ARIEC61850\ARIEC61850.sln
dotnet build .\ARIEC61850\ARIEC61850.sln -c Release --no-restore
dotnet test .\ARIEC61850\tests\AR.Iec61850.Tests\AR.Iec61850.Tests.csproj -c Release --no-build --no-restore

- name: Verify P0-5g readiness state
shell: powershell
run: |
$root = '.\ArIED61850Tester'
$verifier = "$root\scripts\verify-smart-discovery-production-readiness.ps1"
$physical = "$root\evidence\smart-discovery-repeat-run.authority.json"
$promotion = "$root\evidence\smart-discovery-production-promotion-authority.json"
$physicalArg = if (Test-Path $physical -PathType Leaf) { $physical } else { '' }
$promotionArg = if (Test-Path $promotion -PathType Leaf) { $promotion } else { '' }
$output = "$root\TestResults\P0-5G-production-readiness.json"
New-Item -ItemType Directory -Force "$root\TestResults" | Out-Null

& $verifier `
-TargetPath "$root\evidence\smart-discovery-production-promotion-target.json" `
-EngineLockPath "$root\engines\ARIEC61850.lock.json" `
-PromotionPropsPath "$root\evidence\SmartDiscoveryPromotion.props" `
-ArsasRepositoryPath $root `
-EngineRepositoryPath '.\ARIEC61850' `
-ArsasHeadCommit $env:ARSAS_HEAD `
-EngineHeadCommit $env:ENGINE_HEAD `
-EngineHeadCiConclusion success `
-PhysicalAuthorityPath $physicalArg `
-PromotionAuthorityPath $promotionArg `
-OutputJson $output `
-NoFailExit

$result = Get-Content $output -Raw | ConvertFrom-Json
if (-not (Test-Path $physical -PathType Leaf)) {
if ($result.Verdict -ne 'BLOCKED' -or
-not (@($result.Blockers) -match 'P0-5f physical-finalized authority is missing')) {
throw 'P0-5g must remain fail-closed until physical P0-5f authority is present.'
$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"
}
if ([bool]$result.ProductionSwitchEnabled) {
throw 'P0-5g production switch became enabled without physical authority.'
}
} elseif (-not (Test-Path $promotion -PathType Leaf)) {
if ($result.Verdict -ne 'READY_TO_PROMOTE') {
throw "Physical authority exists but P0-5g is not READY_TO_PROMOTE: $(@($result.Blockers) -join '; ')"
}
} elseif ($result.Verdict -ne 'READY_FOR_REVIEW') {
throw "Promotion authority exists but P0-5g is not READY_FOR_REVIEW: $(@($result.Blockers) -join '; ')"
}

- name: Build and test default fail-closed ARSAS path
- name: Restore build and test the exact production route
shell: powershell
run: |
# The current engine PR head is validated above, but ordinary pre-promotion
# ARSAS remains pinned to the physical-evidence engine baseline. Build the
# fail-closed route against that exact lock rather than an arbitrary newer head.
$lock = Get-Content '.\ArIED61850Tester\engines\ARIEC61850.lock.json' -Raw | ConvertFrom-Json
git -C .\ARIEC61850 checkout --quiet --detach $lock.commit
$actualEngine = (git -C .\ARIEC61850 rev-parse HEAD).Trim().ToLowerInvariant()
if ($actualEngine -ne ([string]$lock.commit).ToLowerInvariant()) {
throw "P0-5g fail-closed engine checkout mismatch: $actualEngine"
}

$native = '.\ArIED61850Tester\Services\NativeIec61850Client.cs'
$before = Get-Content $native -Raw
if ($before -match 'return await DiscoverSignalsSmartForCaptureAsync\(cancellationToken, progress\)') {
throw 'Tracked NativeIec61850Client.cs already contains the field-route patch before default build.'
}
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
$after = Get-Content $native -Raw
[xml]$props = Get-Content '.\ArIED61850Tester\evidence\SmartDiscoveryPromotion.props' -Raw
$promoted = ([string]$props.Project.PropertyGroup.SmartDiscoveryProductionPromoted).Trim().ToLowerInvariant() -eq 'true'
if (-not $promoted -and $after -match 'return await DiscoverSignalsSmartForCaptureAsync\(cancellationToken, progress\)') {
throw 'Default pre-promotion build unexpectedly installed the smart discovery route.'
}
if ($LASTEXITCODE -ne 0) { throw 'ARSAS production-route regression tests failed.' }

- name: Build and test explicit smart-route candidate
- name: Prove build did not select or synthesize another route
shell: powershell
run: |
dotnet build .\ArIED61850Tester\ArIED61850Tester.sln -c Release --no-restore -p:EnableSmartDiscoveryCaptureRoute=true
$native = Get-Content '.\ArIED61850Tester\Services\NativeIec61850Client.cs' -Raw
if ($native -notmatch 'return await DiscoverSignalsSmartForCaptureAsync\(cancellationToken, progress\)') {
throw 'Explicit P0-5g smart-route build did not install the discovery route.'
}
if ($native -notmatch '__P0_5C_CONNECT_RESET__' -or $native -notmatch '__P0_5C_DISPOSE_RESET__') {
throw 'Explicit P0-5g smart-route build did not install association lifecycle resets.'
}
if ($native -notmatch '_lastDiscovery\.Snapshot\.DomainVariables') {
throw 'Explicit P0-5g smart-route build did not install authoritative Control inventory reuse.'
}
dotnet test .\ArIED61850Tester\tests\ARSAS.Tests\ARSAS.Tests.csproj -c Release --no-build --no-restore
$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.' }

- name: Upload P0-5g readiness evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: ARSAS-p0-5g-production-readiness
path: ArIED61850Tester\TestResults\P0-5G-*.json
if-no-files-found: warn
retention-days: 14
$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.'
Loading
Loading