param( [Parameter(Mandatory = $true)][string]$Rustc, [Parameter(Mandatory = $true)][string]$IcedRlib, [Parameter(Mandatory = $true)][string]$UnicodeSegmentationRlib, [Parameter(Mandatory = $true)][string]$DependencyDirectory, [Parameter(Mandatory = $true)][string]$Linker, [Parameter(Mandatory = $true)][string]$NativeLibraryDirectory, [Parameter(Mandatory = $true)][string]$NewRunDirectory ) $ErrorActionPreference = 'Stop' # Only the integration owner may invoke this while holding the compiler/GPU gate. # No Cargo, dependency fetching, source mutation or existing output replacement. $labelRustc = (Resolve-Path -LiteralPath $Rustc).Path $labelIced = (Resolve-Path -LiteralPath $IcedRlib).Path $labelUnicode = (Resolve-Path -LiteralPath $UnicodeSegmentationRlib).Path $labelDeps = (Resolve-Path -LiteralPath $DependencyDirectory).Path $labelLinker = (Resolve-Path -LiteralPath $Linker).Path $labelNative = (Resolve-Path -LiteralPath $NativeLibraryDirectory).Path $labelRun = [IO.Path]::GetFullPath($NewRunDirectory) if (Test-Path -LiteralPath $labelRun) { throw 'Run directory already exists; preserve it and select a new path.' } $labelMain = Join-Path $PSScriptRoot 'main.rs' $labelModule = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../../../crates/oa-desktop/src/behavior/scenario_label.rs')) $labelScript = Join-Path $PSScriptRoot 'build-and-run.ps1' New-Item -ItemType Directory -Path $labelRun | Out-Null $labelExe = Join-Path $labelRun 'scenario-label-wgpu.exe' $labelArguments = @( '--edition=2024', '--crate-name', 'scenario_label_wgpu', '--crate-type', 'bin', '-C', 'debuginfo=0', '-L', ('dependency=' + $labelDeps), '-C', ('linker=' + $labelLinker), '-L', ('native=' + $labelNative), '--extern', ('iced=' + $labelIced), '--extern', ('unicode_segmentation=' + $labelUnicode), $labelMain, '-o', $labelExe ) $labelInputs = @($labelRustc, $labelLinker, $labelIced, $labelUnicode, $labelMain, $labelModule, $labelScript) | ForEach-Object { $labelHash = Get-FileHash -LiteralPath $_ -Algorithm SHA256 [ordered]@{ path = $_; sha256 = $labelHash.Hash } } function Get-LabelArtifactManifest([string]$Directory, [switch]$AllFiles) { Get-ChildItem -LiteralPath $Directory -File -Recurse | Where-Object { $AllFiles -or $_.Extension -in @('.rlib', '.rmeta', '.dll', '.lib', '.a', '.o', '.obj') } | Sort-Object FullName | ForEach-Object { [ordered]@{ path = [IO.Path]::GetRelativePath($Directory, $_.FullName) bytes = $_.Length sha256 = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash } } } # Supersets of Rust link/metadata artifacts and all explicit native-dir inputs, # not a claim that every inventoried artifact is actually linked. $labelDependencyManifest = @(Get-LabelArtifactManifest $labelDeps) $labelNativeManifest = @(Get-LabelArtifactManifest $labelNative -AllFiles) if ($labelDependencyManifest.Count -eq 0 -or $labelNativeManifest.Count -eq 0) { throw 'Empty dependency or native-library directory.' } ConvertTo-Json -InputObject $labelDependencyManifest -Depth 4 | Set-Content -LiteralPath (Join-Path $labelRun 'dependency-artifacts-before.json') -Encoding utf8 ConvertTo-Json -InputObject $labelNativeManifest -Depth 4 | Set-Content -LiteralPath (Join-Path $labelRun 'native-artifacts-before.json') -Encoding utf8 $labelRecord = [ordered]@{ scope = 'Standalone actual WGPU canvas label evaluator; not desktop Scene/native acceptance' startedUtc = [DateTime]::UtcNow.ToString('o') os = [Environment]::OSVersion.ToString() rustc = (& $labelRustc --version --verbose | Out-String) arguments = $labelArguments inputs = $labelInputs dependencyDirectory = $labelDeps nativeLibraryDirectory = $labelNative WGPU_BACKEND = $env:WGPU_BACKEND WGPU_ADAPTER_NAME = $env:WGPU_ADAPTER_NAME } $labelRecord | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $labelRun 'inputs.json') -Encoding utf8 & $labelRustc @labelArguments 2>&1 | Tee-Object -FilePath (Join-Path $labelRun 'build.log') $labelBuildExit = $LASTEXITCODE $labelDependenciesAfter = @(Get-LabelArtifactManifest $labelDeps) $labelNativeAfter = @(Get-LabelArtifactManifest $labelNative -AllFiles) ConvertTo-Json -InputObject $labelDependenciesAfter -Depth 4 | Set-Content -LiteralPath (Join-Path $labelRun 'dependency-artifacts-after.json') -Encoding utf8 ConvertTo-Json -InputObject $labelNativeAfter -Depth 4 | Set-Content -LiteralPath (Join-Path $labelRun 'native-artifacts-after.json') -Encoding utf8 $labelDependenciesStable = (ConvertTo-Json -InputObject $labelDependencyManifest -Depth 4 -Compress) -ceq (ConvertTo-Json -InputObject $labelDependenciesAfter -Depth 4 -Compress) $labelNativeStable = (ConvertTo-Json -InputObject $labelNativeManifest -Depth 4 -Compress) -ceq (ConvertTo-Json -InputObject $labelNativeAfter -Depth 4 -Compress) [ordered]@{ exit = $labelBuildExit; dependencyManifestStable = $labelDependenciesStable nativeManifestStable = $labelNativeStable; endedUtc = [DateTime]::UtcNow.ToString('o') } | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $labelRun 'compile-receipt.json') -Encoding utf8 if ($labelBuildExit -ne 0) { throw "Compilation failed with exit $labelBuildExit; this run is nonacceptance." } if (!$labelDependenciesStable -or !$labelNativeStable) { throw 'Dependency/native inputs changed during linking; preserve this run as nonacceptance.' } foreach ($labelInput in $labelInputs) { if ((Get-FileHash -LiteralPath $labelInput.path -Algorithm SHA256).Hash -ne $labelInput.sha256) { throw ('Input changed during compilation: ' + $labelInput.path) } } $labelExeHash = (Get-FileHash -LiteralPath $labelExe -Algorithm SHA256).Hash $labelOutput = Join-Path $labelRun 'pixels' # A single NEW process owns initialization, settled fonts, renderer and all cases. & $labelExe $labelOutput 2>&1 | Tee-Object -FilePath (Join-Path $labelRun 'run.log') $labelRunExit = $LASTEXITCODE $labelExeAfterHash = (Get-FileHash -LiteralPath $labelExe -Algorithm SHA256).Hash $labelReceipt = [ordered]@{ executable = $labelExe; sha256Before = $labelExeHash; sha256After = $labelExeAfterHash binaryStable = ($labelExeHash -ceq $labelExeAfterHash); exit = $labelRunExit endedUtc = [DateTime]::UtcNow.ToString('o') interpretation = '0=32 valid probes without candidate findings; 2=padding/corridor finding; 3=invalid coverage/contract probe; other=infrastructure/panic' } $labelReceipt | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $labelRun 'receipt.json') -Encoding utf8 # Capture all produced evidence, even for exit 2/3 or a missing summary. The # manifest itself is excluded naturally because it does not exist until written. $labelOutputManifest = @(Get-LabelArtifactManifest $labelRun -AllFiles) ConvertTo-Json -InputObject $labelOutputManifest -Depth 4 | Set-Content -LiteralPath (Join-Path $labelRun 'output-artifacts.json') -Encoding utf8 if ($labelExeHash -cne $labelExeAfterHash) { throw 'Executable changed during execution; this run is nonacceptance.' } $labelSummary = Join-Path $labelOutput 'summary.txt' if (!(Test-Path -LiteralPath $labelSummary)) { throw 'No complete summary: infrastructure failure or panic, not acceptance.' } if ((Get-Content -LiteralPath $labelSummary -Raw) -notmatch '(?m)^cases=32\r?$') { throw 'Expected exactly 32 completed cases.' } if ($labelRunExit -ne 0) { throw "Evaluator exit $labelRunExit. Preserve metrics/images; diagnose before changing the candidate." }