Keep native merge depth windows by reframing unsafe endpoints
This commit is contained in:
@@ -25,14 +25,19 @@ function Orbit([string]$Name,$CurrentBoard,[switch]$Pitch,[int]$YawPixels=120,[i
|
|||||||
throw 'No safe blank orbit start in the actual board view.'
|
throw 'No safe blank orbit start in the actual board view.'
|
||||||
}
|
}
|
||||||
function ZoomOut([int]$Stage,$CurrentBoard) {
|
function ZoomOut([int]$Stage,$CurrentBoard) {
|
||||||
|
$before=Save "stage-$Stage-zoom-out-before"
|
||||||
|
Check "stage-$Stage-current-pinch-projection" (Same $CurrentBoard (Board $before $Stage)) 'The pinch uses the exact current board and manual pose'
|
||||||
$helper=Join-Path $PSScriptRoot 'send-composition-touch.ps1'
|
$helper=Join-Path $PSScriptRoot 'send-composition-touch.ps1'
|
||||||
foreach($contacts in @(@(30,400,999,1024),@(30,400,999,0),@(900,350,1,1024,1500,350,2,1024),@(1050,350,1,1024,1350,350,2,1024),@(1050,350,1,0,1350,350,2,0))){
|
foreach($contacts in @(@(30,400,999,1024),@(30,400,999,0),@(900,350,1,1024,1500,350,2,1024),@(1050,350,1,1024,1350,350,2,1024),@(1050,350,1,0,1350,350,2,0))){
|
||||||
& pwsh -NoProfile -Command "& '$helper' -Contacts $($contacts-join',')"
|
& pwsh -NoProfile -Command "& '$helper' -Contacts $($contacts-join',')"
|
||||||
$code=$LASTEXITCODE;$commands.Add(@{command='native sendTouch pinch-out';contacts=$contacts;exitCode=$code;utc=[DateTime]::UtcNow.ToString('o')});if($code-ne0){throw 'Native pinch failed'};Start-Sleep -Milliseconds 120
|
$code=$LASTEXITCODE;$commands.Add(@{command='native sendTouch pinch-out';contacts=$contacts;exitCode=$code;utc=[DateTime]::UtcNow.ToString('o')});if($code-ne0){throw 'Native pinch failed'};Start-Sleep -Milliseconds 120
|
||||||
}
|
}
|
||||||
Step "stage-$Stage-zoom-out" @() 300
|
Step "stage-$Stage-zoom-out" @() 300
|
||||||
$after=Board (Save "stage-$Stage-zoom-out-state") $Stage
|
$state=Save "stage-$Stage-zoom-out-state";$after=Board $state $Stage
|
||||||
Check "stage-$Stage-pinch-preserves-board" ((Same $CurrentBoard.balls $after.balls)-and(Same $CurrentBoard.groups $after.groups)-and(Same $CurrentBoard.countedBallIds $after.countedBallIds)-and$after.camera.distance-gt$CurrentBoard.camera.distance) 'Actual two-finger zoom-out; no ball, membership or count edits'
|
Check "stage-$Stage-pinch-preserves-board" ((Same $CurrentBoard.balls $after.balls)-and(Same $CurrentBoard.groups $after.groups)-and(Same $CurrentBoard.countedBallIds $after.countedBallIds)-and$after.camera.distance-gt$CurrentBoard.camera.distance) 'Actual two-finger zoom-out; no ball, membership or count edits'
|
||||||
|
$expected=$state|ConvertTo-Json -Depth 20|ConvertFrom-Json
|
||||||
|
(Board $expected $Stage).camera=$CurrentBoard.camera
|
||||||
|
Check "stage-$Stage-pinch-preserves-whole-save" (Same $before $expected) 'Only this board manual camera may change; every independent record remains exact'
|
||||||
return $after
|
return $after
|
||||||
}
|
}
|
||||||
function RevealBall([int]$Stage,[string]$Id,[string]$Name) {
|
function RevealBall([int]$Stage,[string]$Id,[string]$Name) {
|
||||||
@@ -99,6 +104,11 @@ function MergeReal([int]$Stage,[string]$Name,[int]$SourceCount=0,[int]$TargetCou
|
|||||||
$targetPoint=BallPoint $board $candidate.tid
|
$targetPoint=BallPoint $board $candidate.tid
|
||||||
if(WorldSafe @(($targetPoint[0]+$offset),$targetPoint[1])){$pair=$candidate;break}
|
if(WorldSafe @(($targetPoint[0]+$offset),$targetPoint[1])){$pair=$candidate;break}
|
||||||
}
|
}
|
||||||
|
if(!$pair-and$projection-eq0-and$board.camera.distance-lt15){
|
||||||
|
# Keep a visited contact depth plane when its endpoint is outside the UI-safe view.
|
||||||
|
$needsFrame=@($pairs|Where-Object {$point=BallPoint $board $_.tid;$_.depth-lt.9-and(BallClear $board $_.sid)-and!(WorldSafe @(($point[0]+$offset),$point[1]))}).Count-gt0
|
||||||
|
if($needsFrame){$board=ZoomOut $Stage $board;continue}
|
||||||
|
}
|
||||||
if($pair-or$attempt-ne0-or$projection-ne0){break}
|
if($pair-or$attempt-ne0-or$projection-ne0){break}
|
||||||
$routed=LiftMergeRoute $Stage "$Name-upward-route" $board $SourceCount $TargetCount
|
$routed=LiftMergeRoute $Stage "$Name-upward-route" $board $SourceCount $TargetCount
|
||||||
if(!$routed){break}
|
if(!$routed){break}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
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
|
||||||
Reference in New Issue
Block a user