param([Parameter(Mandatory)][string]$EvidenceDir,[Parameter(Mandatory)][string]$FixtureDir,[string]$ProgressionSource=(Join-Path $PSScriptRoot 'exercise-final-progression.ps1')) $ErrorActionPreference='Stop' New-Item -ItemType Directory $EvidenceDir -Force|Out-Null $checks=[Collections.Generic.List[object]]::new();$script:inputs=[Collections.Generic.List[object]]::new() function Record($Id,$Passed,$Actual){$checks.Add(@{id=$Id;passed=[bool]$Passed;actual=$Actual})} function Load($Path,$Name){ $ast=[Management.Automation.Language.Parser]::ParseFile($Path,[ref]$null,[ref]$null) $f=$ast.Find({param($n)$n-is[Management.Automation.Language.FunctionDefinitionAst]-and$n.Name-eq$Name},$true) if(!$f){throw "Missing function $Name"} $expected=$f.Extent.Text.Replace("function $Name","function global:$Name").Replace('$PSScriptRoot',"'$PSScriptRoot'") . ([scriptblock]::Create($expected)) Record "$Name-production-body" ((Get-Command $Name).ScriptBlock.Ast.Extent.Text-ceq$expected) $Path } function Clone($Value){return $Value|ConvertTo-Json -Depth 30|ConvertFrom-Json} function Adb {return 'Physical size: 1080x2400'} function Check($Id,$Passed,$Actual){if(!$Passed){throw "$Id : $Actual"}} function Start-Sleep {} # External input leaves are inert. Geometry below is counterfactual framing, never native proof. function pwsh {$script:inputs.Add('pinch-leaf');$global:LASTEXITCODE=0} function NativePointer {} function Step {} function global:LiftMergeRoute {return $null} $commands=[Collections.Generic.List[object]]::new() $script:current=$null;$script:zoomed=$false;$script:badZoom=$false;$script:caseState=$null function Save([string]$Name){ if($Name-match'-before-(\d+)$'){$script:current=if($script:caseState){Clone $script:caseState}else{Get-Content (Join-Path $FixtureDir "stage-16-merge-4-before-$($Matches[1]).json") -Raw|ConvertFrom-Json};$script:zoomed=$false} if($Name-match'zoom-out-state'){ $script:current=Clone $script:current (Board $script:current 16).camera.distance=15 if($script:badZoom){$script:current.completedStageIds+=16} $script:zoomed=$true } return Clone $script:current } function global:NativeMoveAndHold($Name,$Board,$Id,$End){ if(!(BallClear $Board $Id)-or!(WorldSafe $End)){throw 'unsafe-counterfactual-input'} $script:inputs.Add(@{id=$Id;end=$End;distance=$Board.camera.distance;zoomed=$script:zoomed}) throw 'safe-framed-drop-selected' } try{ foreach($n in @('BallPoint','WorldSafe','BallClear','Same')){Load (Join-Path $PSScriptRoot 'final-common.ps1') $n} foreach($n in @('Board','Orbit','ZoomOut','MergeReal')){Load $ProgressionSource $n} $errorText=$null;try{MergeReal 16 'offline-merge16'|Out-Null}catch{$errorText=$_.Exception.Message} $drops=@($script:inputs|Where-Object {$_-isnot[string]}) Record 'actual-depth-window-reframes-and-reprojects-within-original-bound' ($errorText-eq'safe-framed-drop-selected'-and$drops.Count-eq1-and$drops[0].zoomed-and$drops[0].distance-eq15) @{error=$errorText;inputs=$script:inputs.ToArray();scope='Offline decision/input-leaf replay only; no merge success inferred'} # A native pinch must not mask an independent completion record change. $script:badZoom=$true;$script:inputs.Clear();$errorText=$null try{MergeReal 16 'bad-zoom'|Out-Null}catch{$errorText=$_.Exception.Message} Record 'pinch-independent-record-corruption-rejected-before-ball-input' ($errorText-match'pinch-preserves-whole-save'-and@($script:inputs|Where-Object {$_-isnot[string]}).Count-eq0) $errorText $script:badZoom=$false foreach($kind in @('already-safe-pair','no-eligible-depth','no-source-first-hit','maximum-distance','no-eligible-source-size','offset-only-unsafe')){ $index=if($kind-eq'no-eligible-depth'){0}elseif($kind-eq'maximum-distance'){11}else{2} $script:caseState=Get-Content (Join-Path $FixtureDir "stage-16-merge-4-before-$index.json") -Raw|ConvertFrom-Json $b=Board $script:caseState 16;$sourceCount=1;$targetCount=5 switch($kind){ 'already-safe-pair'{$b.camera.distance=15} 'no-source-first-hit'{foreach($ball in $b.balls){$ball.position=Clone $b.balls[0].position}} 'maximum-distance'{foreach($ball in $b.balls){$ball.position.x*=15/8;$ball.position.y=1.25+($ball.position.y-1.25)*15/8;$ball.position.z*=15/8};$b.camera.distance=15} 'no-eligible-source-size'{$sourceCount=2} 'offset-only-unsafe'{ $b.camera.rotation=[pscustomobject]@{x=0;y=0;z=0;w=1} foreach($ball in $b.balls){$ball.position=[pscustomobject]@{x=-8;y=2.5;z=0}} @($b.balls|Where-Object id -eq 's16-b04')[0].position=[pscustomobject]@{x=0;y=1.25;z=0} @($b.balls|Where-Object id -eq 's16-b05')[0].position=[pscustomobject]@{x=-5.94;y=2.5;z=0} $point=BallPoint $b 's16-b05' Record 'offset-control-center-safe-endpoint-unsafe' ((WorldSafe $point)-and!(WorldSafe @(($point[0]-35),$point[1]))) $point } } $script:inputs.Clear();$errorText=$null;try{MergeReal 16 "control-$kind" $sourceCount $targetCount|Out-Null}catch{$errorText=$_.Exception.Message} $pinches=@($script:inputs|Where-Object {$_-is[string]}).Count $drops=@($script:inputs|Where-Object {$_-isnot[string]}) if($kind-eq'offset-only-unsafe'){$ok=$pinches-eq5-and$errorText-eq'safe-framed-drop-selected'-and$drops.Count-eq1-and$drops[0].zoomed} elseif($kind-eq'already-safe-pair'){$ok=$pinches-eq0-and$errorText-eq'safe-framed-drop-selected'-and$drops.Count-eq1-and!$drops[0].zoomed} else{$ok=$pinches-eq0-and$drops.Count-eq0-and$errorText-match'Native merge bound reached'} Record "branch-control-$kind" $ok @{pinchLeaves=$pinches;drops=$drops;error=$errorText;scope='Explicitly counterfactual boundary control'} } }catch{Record 'evaluation' $false $_.Exception.Message} $passed=$checks.Count-gt0-and@($checks|Where-Object passed -ne $true).Count-eq0 @{passed=$passed;scope='Offline frozen failed execution replay; mocked native leaves and explicitly counterfactual distance15; not Android completion';progressionSha256=(Get-FileHash $ProgressionSource).Hash;fixtures=@(0..15|ForEach-Object {$p=Join-Path $FixtureDir "stage-16-merge-4-before-$_.json";@{path=$p;sha256=(Get-FileHash $p).Hash}});checks=$checks.ToArray()}|ConvertTo-Json -Depth 12|Set-Content (Join-Path $EvidenceDir 'merge-framing-result.json') if(!$passed){exit 1};exit 0