Files
ARCADIA-Studio/harness/experiments/scenario-spacing-gates-c4a2cf6-20260913/diagnostic/run.ps1
T

115 lines
12 KiB
PowerShell

#Requires -Version 7.0
# Diagnostic only. Parent may run this once after review; no Cargo or rebuild.
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference='Stop'
$gate='C:/Users/User/Documents/Git/ARCADIA-Studio/.local/scenario-spacing-gates-attempt2-20260913'
$pin='c4a2cf63f11818cf7fc766acf3a2779768a2a658'
$binaryPath='C:/Users/User/Documents/Git/ARCADIA-Studio/target/debug/deps/arcadia_studio-27db9628b266bf39.exe'
$binaryHash='cf31c674a7ef6c19dbe72f65c660030b5af6127d6450e35117ffc201ef813249'
$binaryBytes=150361088
$environmentPath='C:/Users/User/Documents/Git/ARCADIA-Studio/.local/toolchain/env.ps1'
$environmentHash='be2226f08764bb6961b4be8513ce55bab076890cddd2fef0f54a4031f94a82d4'
$runtimePath='C:/Users/User/Documents/Git/ARCADIA-Studio/.local/toolchain/llvm-mingw-20260908-ucrt-x86_64/bin/libunwind.dll'
$runtimeHash='aa282fa47bb2c4e210cea5e470cdbdca58568f0be0bc73e404d86ab9cd95ef6a'
$receiptHashes=@{list='076b1a00681ba00dc77cc1373da9e7e0f199cfb19ba90176bf2f9e80be6112e4';focused='4be2dccf8d20a785bf36fcb1615fe47419fd02414ed468cdade457b64a421333'}
function Hash([string]$Path){(Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()}
function Read-Json([string]$Path){Get-Content -Raw -LiteralPath $Path|ConvertFrom-Json}
function Write-NewJson([string]$Path,$Value){$stream=[IO.File]::Open($Path,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::Read);try{$bytes=[Text.UTF8Encoding]::new($false).GetBytes(($Value|ConvertTo-Json -Depth 20)+"`n");$stream.Write($bytes,0,$bytes.Length);$stream.Flush($true)}finally{$stream.Dispose()}}
function Names-Equal($Expected,$Actual){$a=@($Expected);$b=@($Actual);return $a.Count -eq $b.Count -and @($a|Sort-Object -Unique).Count -eq $a.Count -and @($b|Sort-Object -Unique).Count -eq $b.Count -and @(Compare-Object $a $b -CaseSensitive).Count -eq 0}
function Binary-Record {
$file=Get-Item -LiteralPath $binaryPath
$hash=Hash $binaryPath
if($file.Length -ne $binaryBytes -or $hash -cne $binaryHash){throw 'Previously compiled exact c4 test executable changed.'}
[ordered]@{path=$file.FullName;bytes=$file.Length;sha256=$hash;mtimeUtc=$file.LastWriteTimeUtc.ToString('o')}
}
function Runtime-Record {
$item=Get-Item -LiteralPath $runtimePath
$hash=Hash $runtimePath
if($hash -cne $runtimeHash){throw 'Known toolchain libunwind runtime changed.'}
[ordered]@{path=$item.FullName;bytes=$item.Length;sha256=$hash}
}
function Gate-Bindings {
$bindings=@{}
foreach($stage in @('list','focused')) {
$name=$stage+'-receipt.json';$path=Join-Path $gate $name
if((Hash $path) -cne $receiptHashes[$stage]){throw 'Closed upstream receipt changed.'}
$bindings[$name]=Hash $path
$r=Read-Json $path
if([IO.Path]::GetFullPath($r.externalEnvironmentPath) -ine [IO.Path]::GetFullPath($environmentPath) -or $r.externalEnvironmentSha256 -cne $environmentHash -or (Hash $environmentPath) -cne $environmentHash){throw 'Closed gate toolchain environment binding differs.'}
$bindings['external_environment:'+$environmentPath]=$environmentHash
if($r.base -cne $pin -or $r.stage -cne $stage -or -not $r.inputsUnchanged -or -not $r.testBinaryBindingValid -or $null -ne $r.postflightFailure -or @($r.testExecutables).Count -ne 1){throw 'Invalid closed source/binary binding.'}
$b=$r.testExecutables[0]
if([IO.Path]::GetFullPath($b.path) -ine [IO.Path]::GetFullPath($binaryPath) -or $b.sha256 -cne $binaryHash -or $b.bytes -ne $binaryBytes){throw 'Wrong upstream executable.'}
if($stage -eq 'list' -and ($r.cargoExitCode -ne 0 -or -not $r.selectionValid)){throw 'Successful closed listing required.'}
if($stage -eq 'focused') {
if($r.cargoExitCode -ne 101 -or $r.selectionValid -or @($r.testResultSummaries).Count -ne 1){throw 'This diagnostic requires the preserved failed focused attempt.'}
$s=$r.testResultSummaries[0]
if($s.passed -ne 286 -or $s.failed -ne 2 -or $s.ignored -ne 0 -or $s.filtered -ne 794 -or $r.priorStage.receiptSha256 -cne $receiptHashes.list){throw 'Wrong prior focused failure/chain.'}
}
foreach($entry in $r.boundScriptAndInputHashes.PSObject.Properties){if((Hash (Join-Path $gate $entry.Name)) -cne $entry.Value){throw "Changed upstream bound input: $($entry.Name)"};$bindings[$entry.Name]=$entry.Value}
foreach($entry in @(@(($stage+'.log'),$r.rawLogSha256),@('toolchain-versions.json',$r.toolchainVersionsSha256),@(('inputs-complete-'+$stage+'-before.json'),$r.beforeCaptureSha256),@(('inputs-complete-'+$stage+'-after.json'),$r.afterCaptureSha256))){if((Hash (Join-Path $gate $entry[0])) -cne $entry[1]){throw "Changed upstream raw receipt input: $($entry[0])"};$bindings[$entry[0]]=$entry[1]}
}
$bindings
}
foreach($name in @('capture-diagnostic.ps1','expected-inputs.json','enumeration.json','external-inputs.json','inputs-complete-before.json','inputs-complete-diagnostic-all-before.json','inputs-complete-diagnostic-all-after.json','diagnostic-all.log','diagnostic-all-receipt.json','provenance-before.json')){if(Test-Path -LiteralPath (Join-Path $PSScriptRoot $name)){throw "Preserve prior diagnostic output: $name"}}
$upstream=Gate-Bindings
$list=Read-Json (Join-Path $gate 'list-receipt.json')
$selection=Read-Json (Join-Path $gate 'expected-tests.json')
$expected=Read-Json (Join-Path $gate 'expected-inputs.json')
if($selection.source_commit -cne $pin -or @($list.listedTests).Count -ne 1082 -or @($selection.ignored_tests).Count -ne 4 -or -not (Names-Equal $selection.desktop_tests $list.listedTests) -or $expected.base -cne $pin -or $expected.count -ne 610 -or @($expected.files).Count -ne 610){throw 'Exact 1082/4/610 diagnostic contract differs.'}
$beforeBinary=Binary-Record
# The already-built gnullvm EXE uses the same bound toolchain runtime PATH as its gate.
# Dot-sourcing affects this diagnostic process only; no DLL is copied.
. $environmentPath
$runtimeBefore=Runtime-Record
$runtimeDirectory=[IO.Path]::GetDirectoryName($runtimePath)
$firstPathRuntime=@($env:PATH.Split(';')|Where-Object {$_}|ForEach-Object {Join-Path $_ 'libunwind.dll'}|Where-Object {Test-Path -LiteralPath $_ -PathType Leaf}|Select-Object -First 1)
if($firstPathRuntime.Count -ne 1 -or [IO.Path]::GetFullPath($firstPathRuntime[0]) -ine [IO.Path]::GetFullPath($runtimePath)){throw 'PATH would resolve a different libunwind runtime.'}
foreach($directory in @([IO.Path]::GetDirectoryName($binaryPath),$expected.workspace,(Join-Path $env:SystemRoot 'System32'),$env:SystemRoot)){if(Test-Path -LiteralPath (Join-Path $directory 'libunwind.dll')){throw 'An earlier DLL-search directory contains an unbound libunwind.dll; stop for explicit provenance.'}}
# Reuse the exact capture helper with one declared change: accept a diagnostic-all prefix.
# Copies and generated captures belong here; the closed gate remains untouched.
$captureSource=Join-Path $gate 'capture.ps1'
$captureText=[IO.File]::ReadAllText($captureSource)
$old='(list|focused|all|clippy|build|diagnostic)-(before|after)'
$new='(list|focused|all|clippy|build|diagnostic|diagnostic-all)-(before|after)'
if(($captureText.Split($old,[StringSplitOptions]::None)).Count -ne 2){throw 'Capture helper adaptation no longer has exactly one known seam.'}
$adapted=$captureText.Replace($old,$new)
$captureLocal=Join-Path $PSScriptRoot 'capture-diagnostic.ps1'
[IO.File]::WriteAllText($captureLocal,$adapted,[Text.UTF8Encoding]::new($false))
foreach($name in @('expected-inputs.json','enumeration.json','external-inputs.json','inputs-complete-before.json')){[IO.File]::Copy((Join-Path $gate $name),(Join-Path $PSScriptRoot $name),$false)}
$scriptHash=Hash $PSCommandPath
$captureHash=Hash $captureLocal
Write-NewJson (Join-Path $PSScriptRoot 'provenance-before.json') ([ordered]@{source_commit=$pin;classification='diagnostic_after_failed_focused_gate';run_script_sha256=$scriptHash;gate=$gate;upstream_bindings=$upstream;external_environment=[ordered]@{path=$environmentPath;sha256=$environmentHash};runtime_before=$runtimeBefore;runtime_path_directory=$runtimeDirectory;effective_path=$env:PATH;capture_original_sha256=(Hash $captureSource);capture_adapted_sha256=$captureHash;capture_change=[ordered]@{from=$old;to=$new};binary_before=$beforeBinary;command=@($binaryPath,'--test-threads=1');source_input_count=610;expected_tests=1082;expected_ignored=@($selection.ignored_tests);waives_failed_focused_gate=$false})
& $captureLocal -Stage diagnostic-all-before
$beforeBinary=Binary-Record
$start=[DateTime]::UtcNow.ToString('o')
$PSNativeCommandUseErrorActionPreference=$false
Push-Location -LiteralPath $expected.workspace
try {& $binaryPath --test-threads=1 2>&1|Tee-Object -FilePath (Join-Path $PSScriptRoot 'diagnostic-all.log');$exit=$LASTEXITCODE}finally{Pop-Location}
$end=[DateTime]::UtcNow.ToString('o')
$raw=Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'diagnostic-all.log')
$executed=@([regex]::Matches($raw,'(?m)^test ([^\r\n]+?) \.\.\. (ok|FAILED|ignored)[^\r\n]*\r?$')|ForEach-Object {[ordered]@{name=$_.Groups[1].Value;result=$_.Groups[2].Value}})
$summaries=@([regex]::Matches($raw,'test result: (ok|FAILED)\. (\d+) passed; (\d+) failed; (\d+) ignored; (\d+) measured; (\d+) filtered out;')|ForEach-Object {[ordered]@{status=$_.Groups[1].Value;passed=[int]$_.Groups[2].Value;failed=[int]$_.Groups[3].Value;ignored=[int]$_.Groups[4].Value;measured=[int]$_.Groups[5].Value;filtered=[int]$_.Groups[6].Value}})
$passed=@($executed|Where-Object {$_.result -eq 'ok'}).Count
$failed=@($executed|Where-Object {$_.result -eq 'FAILED'}|ForEach-Object {$_.name})
$ignored=@($executed|Where-Object {$_.result -eq 'ignored'}|ForEach-Object {$_.name})
$valid=(Names-Equal $list.listedTests @($executed|ForEach-Object {$_.name})) -and (Names-Equal $selection.ignored_tests $ignored) -and $summaries.Count -eq 1
if($valid){$s=$summaries[0];$valid=$s.passed -eq $passed -and $s.failed -eq $failed.Count -and $s.ignored -eq 4 -and $s.measured -eq 0 -and $s.filtered -eq 0 -and (($failed.Count -eq 0 -and $s.status -eq 'ok' -and $exit -eq 0) -or ($failed.Count -gt 0 -and $s.status -eq 'FAILED' -and $exit -ne 0))}
$unchanged=$false;$postflightFailure=$null;$afterBinary=$null;$runtimeAfter=$null
try {
& $captureLocal -Stage diagnostic-all-after
$afterBinary=Binary-Record
$runtimeAfter=Runtime-Record
if($runtimeAfter.bytes -ne $runtimeBefore.bytes -or $runtimeAfter.sha256 -cne $runtimeBefore.sha256){throw 'Runtime changed during diagnostic.'}
$current=Gate-Bindings
foreach($name in $upstream.Keys){if($current[$name] -cne $upstream[$name]){throw 'Upstream evidence changed during diagnostic.'}}
if((Hash $PSCommandPath) -cne $scriptHash -or (Hash $captureLocal) -cne $captureHash){throw 'Diagnostic recipe changed during execution.'}
foreach($name in @('expected-inputs.json','enumeration.json','external-inputs.json','inputs-complete-before.json')){if((Hash (Join-Path $PSScriptRoot $name)) -cne (Hash (Join-Path $gate $name))){throw 'Copied capture input changed.'}}
$unchanged=$true
} catch {$postflightFailure=$_.Exception.Message}
Write-NewJson (Join-Path $PSScriptRoot 'diagnostic-all-receipt.json') ([ordered]@{source_commit=$pin;classification='diagnostic_after_failed_focused_gate';successful_full_gate=$false;waives_failed_focused_gate=$false;compiler_executed=$false;command=@($binaryPath,'--test-threads=1');start_utc=$start;end_utc=$end;test_exit_code=$exit;complete_inventory_valid=$valid;tests_passed=($valid -and $failed.Count -eq 0);inputs_unchanged=$unchanged;postflight_failure=$postflightFailure;binary_before=$beforeBinary;binary_after=$afterBinary;runtime_before=$runtimeBefore;runtime_after=$runtimeAfter;listed_tests=@($list.listedTests);executed_tests=$executed;failed_tests=$failed;ignored_tests=$ignored;test_result_summaries=$summaries;provenance_sha256=(Hash (Join-Path $PSScriptRoot 'provenance-before.json'));raw_log_sha256=(Hash (Join-Path $PSScriptRoot 'diagnostic-all.log'));before_capture_sha256=(Hash (Join-Path $PSScriptRoot 'inputs-complete-diagnostic-all-before.json'));after_capture_sha256=if(Test-Path -LiteralPath (Join-Path $PSScriptRoot 'inputs-complete-diagnostic-all-after.json')){Hash (Join-Path $PSScriptRoot 'inputs-complete-diagnostic-all-after.json')}else{$null};scope='Complete-inventory diagnostic of the unchanged already-built c4 binary. Prior failed focused gate remains failed. Any corrected source needs its own acceptance gates.'})
if(-not $valid -or -not $unchanged){exit 2}
exit $exit