diff --git a/tools/android/exercise-playground.ps1 b/tools/android/exercise-playground.ps1 index b4e08f3..01a6413 100644 --- a/tools/android/exercise-playground.ps1 +++ b/tools/android/exercise-playground.ps1 @@ -166,7 +166,7 @@ function ApproachDepth([string]$Name,$Source){ for($attempt=0;$attempt-lt5;$attempt++){ $current=if($attempt-eq0){$before}else{Save "$Name-before-attempt-$attempt"};$board=$current.latestFreePlay $point=BallPoint $board 'native-depth-front';Check "$Name-first-hit-safe-$attempt" (WorldSafe $point) ($point-join',') - $pointer=@($point[0]+20,$point[1]);NativeTouch @($point[0],$point[1],73,1024);NativeTouch @($pointer[0],$pointer[1],73,1024);Start-Sleep -Milliseconds 800 + $pointer=@(($point[0]+20),$point[1]);NativeTouch @($point[0],$point[1],73,1024);NativeTouch @($pointer[0],$pointer[1],73,1024);Start-Sleep -Milliseconds 800 for($step=0;$step-lt45;$step++){ $label="$Name-live-$attempt-$step";Step $label @() 0;$friends=@(BlueFriends (Join-Path $EvidenceDir "$label.png")) $commands.Add(@{command='Observe actual live blue friends for input steering';png="$label.png";friends=$friends;pointer=$pointer;utc=[DateTime]::UtcNow.ToString('o')}) @@ -234,8 +234,8 @@ try { $stopped=@($thin.expected.balls|Where-Object id -eq $thin.ballId)[0].position;$reversed=@($after.latestFreePlay.balls|Where-Object id -eq $thin.ballId)[0].position Check 'thin-fast-reverse-opposite-immediate-safe-drop' ($reversed.x-lt$stopped.x-.05-and(SameMembership $thin.source $after.latestFreePlay)-and(InBounds $after.latestFreePlay 1)-and(Same $thin.source.camera $after.latestFreePlay.camera)) 'Actual opposite move from blocked last-safe point reacts immediately and drops with both exact groups preserved' $depth=Clone $fixtures.restores[0].freeSource;$depth.sourceStageId=1;$depth.camera=[pscustomobject][ordered]@{target=[pscustomobject][ordered]@{x=0;y=2.35;z=0};rotation=[pscustomobject][ordered]@{x=0;y=0;z=0;w=1};distance=14} - $depth.balls=@(@{id='native-depth-front';position=@{x=-1;y=3;z=0}},@{id='native-depth-back';position=@{x=1;y=3;z=4}}) - $depth.groups=@(@{id='native-depth-front-group';ballIds=@('native-depth-front')},@{id='native-depth-back-group';ballIds=@('native-depth-back')}) + $depth.balls=@([pscustomobject][ordered]@{id='native-depth-back';position=[pscustomobject][ordered]@{x=1;y=3;z=4}},[pscustomobject][ordered]@{id='native-depth-front';position=[pscustomobject][ordered]@{x=-1;y=3;z=0}}) + $depth.groups=@([pscustomobject][ordered]@{id='native-depth-back-group';ballIds=@('native-depth-back')},[pscustomobject][ordered]@{id='native-depth-front-group';ballIds=@('native-depth-front')}) $short=$null foreach($hold in @(150,2500)){ $state=FixtureState $depth 'free' 1;$before=LoadFixture "stationary-$hold" $state 'free' 1;$point=BallPoint $before.latestFreePlay 'native-depth-front' @@ -246,7 +246,7 @@ try { $before=LoadFixture 'pause-cancel' (FixtureState $depth 'free' 1) 'free' 1;$point=BallPoint $before.latestFreePlay 'native-depth-front' $after=HoldDrag 'pause-cancel' $before.latestFreePlay 'native-depth-front' ($point[0]+80) $point[1] 1200 -Cancel Check 'pause-cancel-restores-board-manual-camera' (Same $before $after) 'Native HOME interrupts actual assisted drag, board and manual camera restored' - $depth.balls[0].position=@{x=-1.5;y=2;z=-1};$depth.balls[1].position=@{x=.5;y=2;z=2.2} + (@($depth.balls|Where-Object {$_.id-ceq'native-depth-front'})[0]).position=[pscustomobject][ordered]@{x=-1.5;y=2;z=-1};(@($depth.balls|Where-Object {$_.id-ceq'native-depth-back'})[0]).position=[pscustomobject][ordered]@{x=.5;y=2;z=2.2} ApproachDepth 'actual-deep-contact' $depth $required=@('six-scenes-ground-prop-feet-arch-hole','front-prop-occlusion-all-original-ids-search','stable-candidate-display-live-assist-and-visible-manual-return','six-scenes-variants-all-five-boundaries-free-source','phone-tablet-readable-ui-numbers-gaps','matched-baseline-native-presentation-memory-observation') if(Test-Path -LiteralPath $observationPath){ diff --git a/tools/android/test-playground-contracts.ps1 b/tools/android/test-playground-contracts.ps1 index afa3f6f..2223625 100644 --- a/tools/android/test-playground-contracts.ps1 +++ b/tools/android/test-playground-contracts.ps1 @@ -1,4 +1,4 @@ -param([Parameter(Mandatory)][string]$EvidenceDir,[string]$FinalSource=(Join-Path $PSScriptRoot 'exercise-final.ps1'),[string]$PlaygroundSource=(Join-Path $PSScriptRoot 'exercise-playground.ps1'),[string]$PreservationFixtureDir,[string]$BoardReadyPng,[string]$HomePng,[string]$ReentryFixtureDir,[string]$DepthFixtureDir) +param([Parameter(Mandatory)][string]$EvidenceDir,[string]$FinalSource=(Join-Path $PSScriptRoot 'exercise-final.ps1'),[string]$PlaygroundSource=(Join-Path $PSScriptRoot 'exercise-playground.ps1'),[string]$PreservationFixtureDir,[string]$BoardReadyPng,[string]$HomePng,[string]$ReentryFixtureDir,[string]$DepthFixtureDir,[string]$PauseFixtureDir) $ErrorActionPreference='Stop' New-Item -ItemType Directory -Path $EvidenceDir -Force|Out-Null $checks=[Collections.Generic.List[object]]::new() @@ -121,6 +121,52 @@ exit ([int]$env:PLAYGROUND_CONTROL_TOUCH_EXIT) Probe 'actual-native-depth-fixture-camera-exact' (Same $depth.camera $dropped.latestFreePlay.camera) @{assignment=$depthCamera.Extent.Text;dropped=$droppedPath;droppedSha256=(Get-FileHash -LiteralPath $droppedPath).Hash;scope='Actual assignment versus NativePreflight7 raw save; replay only, no live native run'} Probe 'actual-native-depth-entry-drop-camera-exact' (Same $entered.latestFreePlay.camera $dropped.latestFreePlay.camera) @{entered=$enteredPath;enteredSha256=(Get-FileHash -LiteralPath $enteredPath).Hash;dropped=$droppedPath;droppedSha256=(Get-FileHash -LiteralPath $droppedPath).Hash} } + $depthSetup=@($gestureAst.FindAll({param($node)$node-is[Management.Automation.Language.AssignmentStatementAst]-and$node.Left.Extent.Text-cin@('$depth','$depth.sourceStageId','$depth.camera','$depth.balls','$depth.groups')},$true)|Sort-Object {$_.Extent.StartOffset}) + if($depthSetup.Count-ne5){throw 'Missing exact five depth-fixture setup assignments'} + $setupText=($depthSetup.Extent.Text-join"`n");$fixtures=@{restores=@(@{freeSource=Clone $floatSource.latestFreePlay})} + . ([scriptblock]::Create($setupText)) + Probe 'actual-depth-producer-ordinal-ball-group-order' (($depth.balls.id-join',')-ceq'native-depth-back,native-depth-front'-and($depth.groups.id-join',')-ceq'native-depth-back-group,native-depth-front-group') @{statements=$setupText;balls=@($depth.balls.id);groups=@($depth.groups.id);scope='Actual full fixture setup AST, no mirrored producer'} + $front=@($depth.balls|Where-Object {$_.id-ceq'native-depth-front'})[0];$back=@($depth.balls|Where-Object {$_.id-ceq'native-depth-back'})[0] + Probe 'actual-depth-producer-original-id-positions' ($depth.sourceStageId-eq1-and$front.position.x-eq-1-and$front.position.y-eq3-and$front.position.z-eq0-and$back.position.x-eq1-and$back.position.y-eq3-and$back.position.z-eq4) 'Original world positions remain attached to their exact IDs' + $positionAssignments=@($gestureAst.FindAll({param($node)$node-is[Management.Automation.Language.AssignmentStatementAst]-and$node.Left.Extent.Text.Contains('$depth.balls')-and$node.Left.Extent.Text.EndsWith('.position')},$true)|Sort-Object {$_.Extent.StartOffset}) + if($positionAssignments.Count-ne2){throw 'Missing exact two deep-contact position assignments'} + $positionText=($positionAssignments.Extent.Text-join"`n");$producer=Clone $depth + foreach($reverse in @($false,$true)){ + $depth=Clone $producer;if($reverse){$depth.balls=@($depth.balls[1],$depth.balls[0])} + . ([scriptblock]::Create($positionText)) + $front=@($depth.balls|Where-Object {$_.id-ceq'native-depth-front'})[0];$back=@($depth.balls|Where-Object {$_.id-ceq'native-depth-back'})[0] + Probe "actual-deep-contact-position-assignments-reverse-$reverse" ($front.position.x-eq-1.5-and$front.position.y-eq2-and$front.position.z-eq-1-and$back.position.x-eq.5-and$back.position.y-eq2-and$back.position.z-eq2.2) @{statements=$positionText;scope='Actual position assignment AST must address IDs independently of array order'} + } + if($PauseFixtureDir){ + $enteredPath=Join-Path $PauseFixtureDir 'pause-cancel-entered.json';$droppedPath=Join-Path $PauseFixtureDir 'pause-cancel-dropped.json' + $entered=Get-Content -LiteralPath $enteredPath -Raw|ConvertFrom-Json;$dropped=Get-Content -LiteralPath $droppedPath -Raw|ConvertFrom-Json + $fixtures=@{restores=@(@{freeSource=Clone $entered.latestFreePlay})};. ([scriptblock]::Create($setupText)) + Probe 'actual-native-pause-canonical-producer-exact' (Same $depth $dropped.latestFreePlay) @{enteredSha256=(Get-FileHash -LiteralPath $enteredPath).Hash;droppedSha256=(Get-FileHash -LiteralPath $droppedPath).Hash;scope='Actual full producer AST against raw NativeLifecycle1 pause save; replay only'} + Probe 'actual-native-original-pause-array-order-still-rejected' (!(Same $entered $dropped)) 'Strict Same retains the original native failure; no array normalization' + $pauseCheck=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.CommandAst]-and$node.GetCommandName()-eq'Check'-and$node.Extent.Text-like"*'pause-cancel-restores-board-manual-camera'*"},$true) + if(!$pauseCheck){throw 'Missing actual pause cancellation Check'} + $before=Clone $entered;$before.latestFreePlay=Clone $depth + foreach($kind in @('valid','position-one-ulp','group-id','ball-id','membership','balls-order','groups-order','camera-one-ulp')){ + $after=Clone $dropped + switch($kind){ + 'position-one-ulp'{$after.latestFreePlay.balls[0].position.x=[double][MathF]::BitIncrement([single]$after.latestFreePlay.balls[0].position.x)} + 'group-id'{$after.latestFreePlay.groups[0].id='changed-group'} + 'ball-id'{$after.latestFreePlay.balls[0].id='NATIVE-DEPTH-BACK'} + 'membership'{$after.latestFreePlay.groups[0].ballIds=@('native-depth-front')} + 'balls-order'{$after.latestFreePlay.balls=@($after.latestFreePlay.balls[1],$after.latestFreePlay.balls[0])} + 'groups-order'{$after.latestFreePlay.groups=@($after.latestFreePlay.groups[1],$after.latestFreePlay.groups[0])} + 'camera-one-ulp'{$after.latestFreePlay.camera.distance=[double][MathF]::BitIncrement([single]$after.latestFreePlay.camera.distance)} + } + $accepted=$false;try{& ([scriptblock]::Create($pauseCheck.Extent.Text));$accepted=$true}catch{} + Probe "actual-pause-cancellation-check-$kind" ($accepted-eq($kind-eq'valid')) @{accepted=$accepted;statement=$pauseCheck.Extent.Text;scope='Actual production cancellation Check with actual raw save and producer board; no native rerun'} + } + } + $approach=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'ApproachDepth'},$true) + $pointerAssignment=$approach.Body.Find({param($node)$node-is[Management.Automation.Language.AssignmentStatementAst]-and$node.Left.Extent.Text-ceq'$pointer'},$true) + if(!$pointerAssignment){throw 'Missing actual deep-contact pointer assignment'} + $point=@([int]1096,[int]609);$pointer=$null;$pointerError=$null + try{. ([scriptblock]::Create($pointerAssignment.Extent.Text))}catch{$pointerError=$_.Exception.Message} + Probe 'actual-deep-contact-pointer-exact-native-point' ($null-eq$pointerError-and$pointer-is[array]-and$pointer.Count-eq2-and$pointer[0]-is[int]-and$pointer[1]-is[int]-and$pointer[0]-eq1116-and$pointer[1]-eq609) @{statement=$pointerAssignment.Extent.Text;actualPoint=$point;pointer=$pointer;error=$pointerError;scope='Actual ApproachDepth assignment with observed native first-hit point; no native input'} $reentry=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'SameProgress'},$true) if($reentry){. ([scriptblock]::Create($reentry.Extent.Text))} Probe 'actual-reentry-comparator-present' ($null-ne$reentry) 'Only outer puzzleStates order may be canonicalized; Same remains strict'