Retry a real upward route after an unchanged native merge drop

This commit is contained in:
NINI
2026-10-10 14:16:35 +09:00
parent 8bd6c426a8
commit 3bfcac8a58
2 changed files with 77 additions and 3 deletions
@@ -121,6 +121,8 @@ function MergeReal([int]$Stage,[string]$Name,[int]$SourceCount=0,[int]$TargetCou
$oldCount=$board.groups.Count $oldCount=$board.groups.Count
if($pair) { if($pair) {
$end=BallPoint $board $pair.tid $end=BallPoint $board $pair.tid
$dragBefore=Save "$Name-drag-$attempt-before"
Check "$Name-current-pair-projection-$attempt" (Same $board (Board $dragBefore $Stage)) 'Actual pair IDs and UI-safe endpoints use the current saved board'
# Try a short lateral contact offset, then orbit to expose another depth plane if blocked. # Try a short lateral contact offset, then orbit to expose another depth plane if blocked.
$after=NativeMoveAndHold "$Name-drag-$attempt" $board $pair.sid @(($end[0]+$offset),$end[1]);$newBoard=Board $after $Stage $after=NativeMoveAndHold "$Name-drag-$attempt" $board $pair.sid @(($end[0]+$offset),$end[1]);$newBoard=Board $after $Stage
if($null-eq$newBoard-or$newBoard.groups.Count-lt$oldCount){ if($null-eq$newBoard-or$newBoard.groups.Count-lt$oldCount){
@@ -128,6 +130,33 @@ function MergeReal([int]$Stage,[string]$Name,[int]$SourceCount=0,[int]$TargetCou
AssertNativeMerge "$Name-actual-$attempt" $board $actual $pair.sid $TargetCount AssertNativeMerge "$Name-actual-$attempt" $board $actual $pair.sid $TargetCount
return $after return $after
} }
if(Same $board $newBoard){
Check "$Name-blocked-drop-whole-save-$attempt" (Same $dragBefore $after) 'An unchanged drop preserves every independent record before a real upward retry'
$routed=LiftMergeRoute $Stage "$Name-blocked-route-$attempt" $newBoard $SourceCount $TargetCount
if($routed){
$revealed=$newBoard|ConvertTo-Json -Depth 20|ConvertFrom-Json;$revealed.camera=$routed.Before.camera
Check "$Name-blocked-route-reveal-board-$attempt" (Same $revealed $routed.Before) 'Revealing the intended ID changes only its manual view'
$routedBoard=Board $routed.State $Stage
$expected=$after|ConvertTo-Json -Depth 20|ConvertFrom-Json
if($routedBoard){$expected.puzzleStates=@($expected.puzzleStates|ForEach-Object{if($_.stageId-eq$Stage){$routedBoard}else{$_}})}
else{
Check "$Name-blocked-route-completed-stage-$attempt" ($routed.State.completedStageIds-contains$Stage-and$routed.State.latestFreePlay.sourceStageId-eq$Stage) 'A missing puzzle requires actual completion and its own free-play board'
$expected.puzzleStates=@($expected.puzzleStates|Where-Object stageId -ne $Stage)
$expected.completedStageIds=@($expected.completedStageIds+@($Stage)|Sort-Object -Unique)
$expected.latestFreePlay=$routed.State.latestFreePlay
}
Check "$Name-blocked-route-independent-records-$attempt" (Same $expected $routed.State) 'Only the actual current board and its own strict completion may change'
if($routedBoard){Check "$Name-blocked-route-not-counted-$attempt" (Same $routed.Before.countedBallIds $routedBoard.countedBallIds) 'An upward retry never counts a friend'}
if($routed.Outcome-eq'MissedGrabOrbit'){
Check "$Name-blocked-route-first-hit-miss-$attempt" (IsNativeOrbitMiss $routed.BeforeState $routed.State $Stage) 'A background orbit is never a grabbed route or merge'
}elseif(!$routedBoard-or$routedBoard.groups.Count-lt$routed.Before.groups.Count){
$actual=if($routedBoard){$routedBoard}else{$routed.State.latestFreePlay}
AssertNativeMerge "$Name-blocked-route-actual-$attempt" $routed.Before $actual $routed.SourceId $TargetCount
return $routed.State
}
$newBoard=$routedBoard
}
}
$board=$newBoard $board=$newBoard
} }
$fineYaw=0 $fineYaw=0
+48 -3
View File
@@ -1,4 +1,4 @@
param([Parameter(Mandatory)][string]$EvidenceDir,[Parameter(Mandatory)][string]$Fixture,[string]$CommonSource=(Join-Path $PSScriptRoot 'final-common.ps1'),[string]$ProgressionSource=(Join-Path $PSScriptRoot 'exercise-final-progression.ps1'),[string]$BlockedFixture,[string]$LiftBefore,[string]$LiftAfter,[string]$FineFixture,[string]$OrbitMissBefore,[string]$OrbitMissAfter) param([Parameter(Mandatory)][string]$EvidenceDir,[Parameter(Mandatory)][string]$Fixture,[string]$CommonSource=(Join-Path $PSScriptRoot 'final-common.ps1'),[string]$ProgressionSource=(Join-Path $PSScriptRoot 'exercise-final-progression.ps1'),[string]$BlockedFixture,[string]$LiftBefore,[string]$LiftAfter,[string]$FineFixture,[string]$OrbitMissBefore,[string]$OrbitMissAfter,[string]$RecurrenceBefore,[string]$RecurrenceAfter)
$ErrorActionPreference='Stop' $ErrorActionPreference='Stop'
New-Item -ItemType Directory -Path $EvidenceDir -Force|Out-Null New-Item -ItemType Directory -Path $EvidenceDir -Force|Out-Null
$checks=[Collections.Generic.List[object]]::new() $checks=[Collections.Generic.List[object]]::new()
@@ -97,7 +97,8 @@ try{
function global:LiftMergeRoute([int]$Stage,[string]$Name,$Board,[int]$SourceCount=0,[int]$TargetCount=0){$script:routeCalls++;$commands.Add(@{route=$true});return [pscustomobject]@{State=$raw;Before=$Board;SourceId='s18-b04'}} function global:LiftMergeRoute([int]$Stage,[string]$Name,$Board,[int]$SourceCount=0,[int]$TargetCount=0){$script:routeCalls++;$commands.Add(@{route=$true});return [pscustomobject]@{State=$raw;Before=$Board;SourceId='s18-b04'}}
$bound=$false;try{MergeReal 18 'replay-actual-blocked18'|Out-Null}catch{$bound=$_.Exception.Message-match'Native merge bound reached'} $bound=$false;try{MergeReal 18 'replay-actual-blocked18'|Out-Null}catch{$bound=$_.Exception.Message-match'Native merge bound reached'}
$orbits=@($commands|Where-Object {$_.arguments.Count-ge7-and$_.arguments[2]-eq'swipe'}) $orbits=@($commands|Where-Object {$_.arguments.Count-ge7-and$_.arguments[2]-eq'swipe'})
Record 'actual-blocked18-uses-one-detour-with-original-attempt-bound' ($bound-and$script:routeCalls-eq1-and$orbits.Count-eq16-and$commands[0].route) @{boundedFailureRetained=$bound;detours=$script:routeCalls;orbitAttempts=$orbits.Count;routeBeforeFirstOrbit=$commands[0].route} $held=@($commands|Where-Object {$_.nativeHeldMove}).Count
Record 'actual-blocked18-retries-only-unchanged-drops-with-original-attempt-bound' ($bound-and$script:routeCalls-eq(1+$held)-and$orbits.Count-eq16-and$commands[0].route) @{boundedFailureRetained=$bound;detours=$script:routeCalls;unchangedDropRetries=$held;orbitAttempts=$orbits.Count;routeBeforeFirstOrbit=$commands[0].route}
foreach($kind in @('missing-board-wrong-free','missing-board-without-completion','merged-without-contact')){ foreach($kind in @('missing-board-wrong-free','missing-board-without-completion','merged-without-contact')){
$routeState=$raw|ConvertTo-Json -Depth 20|ConvertFrom-Json $routeState=$raw|ConvertTo-Json -Depth 20|ConvertFrom-Json
if($kind-eq'merged-without-contact'){ if($kind-eq'merged-without-contact'){
@@ -264,7 +265,51 @@ try{
$errorText=$null;try{MergeReal $stage 'corrupted-reveal-caller'|Out-Null}catch{$errorText=$_.Exception.Message} $errorText=$null;try{MergeReal $stage 'corrupted-reveal-caller'|Out-Null}catch{$errorText=$_.Exception.Message}
Record 'caller-detects-record-corruption-before-pointer-snapshot' ($errorText-match'miss-global-records-unmodified') $errorText Record 'caller-detects-record-corruption-before-pointer-snapshot' ($errorText-match'miss-global-records-unmodified') $errorText
} }
if($RecurrenceBefore){
if(!$RecurrenceAfter){throw 'Requires actual blocked Stage4 before and strict native upward-contact drop saves'}
ReadFunction $ProgressionSource 'MergeReal'
ReadFunction $CommonSource 'AssertNativeMerge'
ReadFunction $CommonSource 'AssertNativeTranslation'
$raw=Get-Content -LiteralPath $RecurrenceBefore -Raw|ConvertFrom-Json
$contact=Get-Content -LiteralPath $RecurrenceAfter -Raw|ConvertFrom-Json
$stage=@($raw.puzzleStates|Where-Object {$_.balls.id-contains's04-b04'})[0].stageId
$script:heldCalls=0;$script:retryCalls=0;$script:routeState=$null;$script:routeBefore=$null;$script:dropState=$null
function Save([string]$Name){return $raw|ConvertTo-Json -Depth 20|ConvertFrom-Json}
function global:NativeMoveAndHold { $script:heldCalls++;return $script:dropState|ConvertTo-Json -Depth 20|ConvertFrom-Json }
function global:LiftMergeRoute { $script:retryCalls++;return [pscustomobject]@{State=($script:routeState|ConvertTo-Json -Depth 20|ConvertFrom-Json);Before=($script:routeBefore|ConvertTo-Json -Depth 20|ConvertFrom-Json);SourceId='s04-b04'} }
function global:Orbit {}
foreach($kind in @('actual-contact','drop-completed','reveal-ball','completed','other-puzzle','free-play','tutorial','counted','deep-contact','foreign-moved','manual-changed','missing-ID','wrong-free','missing-without-completion')){
$script:heldCalls=0;$script:retryCalls=0
$script:dropState=$raw|ConvertTo-Json -Depth 20|ConvertFrom-Json
$script:routeState=$contact|ConvertTo-Json -Depth 20|ConvertFrom-Json
$script:routeBefore=Board ($raw|ConvertTo-Json -Depth 20|ConvertFrom-Json) $stage
$b=Board $script:routeState $stage
switch($kind){
'drop-completed'{$script:dropState.completedStageIds+= $stage}
'reveal-ball'{$script:routeBefore.balls[0].position.x+=.1}
'completed'{$script:routeState.completedStageIds+= $stage}
'other-puzzle'{$script:routeState.puzzleStates[0].balls[0].position.x+=.1}
'free-play'{$script:routeState.latestFreePlay.camera.distance+=.1}
'tutorial'{$script:routeState.seenTutorialIds+= 'unobserved'}
'counted'{$b.countedBallIds+= 's04-b04'}
'deep-contact'{@($b.balls|Where-Object id -eq 's04-b04')[0].position.z+=3}
'foreign-moved'{$b.balls[0].position.x+=.1}
'manual-changed'{$b.camera.distance+=.1}
'missing-ID'{$b.balls=@($b.balls|Where-Object id -ne 's04-b04')}
'wrong-free'{$script:routeState.puzzleStates=@($script:routeState.puzzleStates|Where-Object stageId -ne $stage);$script:routeState.completedStageIds+= $stage}
'missing-without-completion'{$script:routeState.puzzleStates=@($script:routeState.puzzleStates|Where-Object stageId -ne $stage)}
}
$value=$null;$errorText=$null
try{$value=MergeReal $stage "recurrence-$kind"}catch{$errorText=$_.Exception.Message}
if($kind-eq'actual-contact'){
Record 'actual-no-op-drop-retries-upward-and-requires-strict-contact' (!$errorText-and$script:heldCalls-eq1-and$script:retryCalls-eq1-and(Same $value $contact)) @{heldDrops=$script:heldCalls;upwardRetries=$script:retryCalls;error=$errorText;scope='Actual source raw geometry replay with input leaf mocks; native qualification belongs to ROOT'}
}else{
$guard=switch($kind){'drop-completed'{'blocked-drop-whole-save'};'reveal-ball'{'blocked-route-reveal-board'};'counted'{'blocked-route-not-counted'};{$_-in@('completed','other-puzzle','free-play','tutorial')}{'blocked-route-independent-records'};{$_-in@('wrong-free','missing-without-completion')}{'blocked-route-completed-stage'};default{'blocked-route-actual'}}
Record 'corrupted-blocked-route-or-unconfirmed-contact-is-rejected' ($null-eq$value-and$errorText-match$guard) @{kind=$kind;error=$errorText;expectedGuard=$guard}
}
}
}
}catch{Record 'production-function-evaluation' $false $_.Exception.Message} }catch{Record 'production-function-evaluation' $false $_.Exception.Message}
$passed=$checks.Count-gt0-and@($checks|Where-Object passed -ne $true).Count-eq0 $passed=$checks.Count-gt0-and@($checks|Where-Object passed -ne $true).Count-eq0
@{passed=$passed;scope='Offline actual failed save replay and native-input/assertion negative controls; no ADB, no Unity, no native success claim';fixture=$Fixture;fixtureSha256=(Get-FileHash -LiteralPath $Fixture).Hash;routeFixtures=@(@($BlockedFixture,$LiftBefore,$LiftAfter,$FineFixture,$OrbitMissBefore,$OrbitMissAfter)|Where-Object {$_}|ForEach-Object {@{path=$_;sha256=(Get-FileHash -LiteralPath $_).Hash}});commonSource=$CommonSource;commonSha256=(Get-FileHash -LiteralPath $CommonSource).Hash;progressionSource=$ProgressionSource;progressionSha256=(Get-FileHash -LiteralPath $ProgressionSource).Hash;checks=$checks.ToArray()}|ConvertTo-Json -Depth 12|Set-Content -LiteralPath (Join-Path $EvidenceDir 'live-drag-result.json') @{passed=$passed;scope='Offline actual failed save replay and native-input/assertion negative controls; no ADB, no Unity, no native success claim';fixture=$Fixture;fixtureSha256=(Get-FileHash -LiteralPath $Fixture).Hash;routeFixtures=@(@($BlockedFixture,$LiftBefore,$LiftAfter,$FineFixture,$OrbitMissBefore,$OrbitMissAfter,$RecurrenceBefore,$RecurrenceAfter)|Where-Object {$_}|ForEach-Object {@{path=$_;sha256=(Get-FileHash -LiteralPath $_).Hash}});commonSource=$CommonSource;commonSha256=(Get-FileHash -LiteralPath $CommonSource).Hash;progressionSource=$ProgressionSource;progressionSha256=(Get-FileHash -LiteralPath $ProgressionSource).Hash;checks=$checks.ToArray()}|ConvertTo-Json -Depth 12|Set-Content -LiteralPath (Join-Path $EvidenceDir 'live-drag-result.json')
if(!$passed){exit 1};exit 0 if(!$passed){exit 1};exit 0