From 20184ad35a7cce044e36bafca94fd3c2abd1b638 Mon Sep 17 00:00:00 2001 From: NINI Date: Tue, 6 Oct 2026 23:08:55 +0900 Subject: [PATCH] Verify native navigation and pause cancel stale Korean speech --- tools/android/check-canceled-audio.ps1 | 11 ++++++++ tools/android/exercise-final-boundaries.ps1 | 30 +++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tools/android/check-canceled-audio.ps1 diff --git a/tools/android/check-canceled-audio.ps1 b/tools/android/check-canceled-audio.ps1 new file mode 100644 index 0000000..9f94fe2 --- /dev/null +++ b/tools/android/check-canceled-audio.ps1 @@ -0,0 +1,11 @@ +param([Parameter(Mandatory)][string]$CapturedPath,[Parameter(Mandatory)][string]$OutputPath) +$ErrorActionPreference='Stop' +$bytes=[IO.File]::ReadAllBytes((Resolve-Path $CapturedPath).Path) +$rate=[BitConverter]::ToInt32($bytes,24);$count=($bytes.Length-44)/2 +if([BitConverter]::ToInt16($bytes,20)-ne1-or[BitConverter]::ToInt16($bytes,22)-ne1-or[BitConverter]::ToInt16($bytes,34)-ne16-or[Text.Encoding]::ASCII.GetString($bytes,36,4)-ne'data'){throw 'Canonical actual monoPCM16 required'} +$startEnergy=0.0;$tailEnergy=0.0;$tailSamples=0;$frontSamples=0 +for($i=0;$i-lt$count;$i++){$v=[double][BitConverter]::ToInt16($bytes,44+$i*2);if($i-lt$rate*3){$startEnergy+=$v*$v;$frontSamples++};if($i-ge$count-$rate*3){$tailEnergy+=$v*$v;$tailSamples++}} +$frontRms=[Math]::Sqrt($startEnergy/$frontSamples);$tailRms=[Math]::Sqrt($tailEnergy/$tailSamples) +$passed=$count/$rate-ge8-and$frontRms-gt32-and$tailRms-le32 +@{passed=$passed;duration=$count/$rate;first3secondsRms=$frontRms;last3secondsRms=$tailRms;thresholdRms=32;capturedSha256=(Get-FileHash $CapturedPath).Hash}|ConvertTo-Json|Set-Content -LiteralPath $OutputPath +if(!$passed){exit 1};exit 0 diff --git a/tools/android/exercise-final-boundaries.ps1 b/tools/android/exercise-final-boundaries.ps1 index cfdc378..b33908d 100644 --- a/tools/android/exercise-final-boundaries.ps1 +++ b/tools/android/exercise-final-boundaries.ps1 @@ -17,6 +17,17 @@ function ReturnOne([string]$Name) { } throw 'Whole-group return did not confirm through real native selection' } +function CanceledSpeech([string]$Name,[string]$Id) { + $recorder=@($recorders|Where-Object name -eq $Name)[0].process + Check "cancel-recorder-$Name" ($recorder.WaitForExit(30000)) 'Actual recorder finished';$recorder.Refresh() + Check "cancel-recorder-exit-$Name" ($recorder.ExitCode-eq0) "$($recorder.ExitCode)" + $comparison=Join-Path $EvidenceDir "$Name-$Id-incomplete-match.json" + & pwsh -NoProfile -File (Join-Path $PSScriptRoot 'compare-audio.ps1') -ReferencePath (Join-Path $projectRoot "Assets/MagnetismHeroes/UnityRuntime/Presentation/Audio/Voice/$Id.wav") -CapturedPath (Join-Path $EvidenceDir "$Name.wav") -OutputPath $comparison -RequireFullSpeech + $code=$LASTEXITCODE;$match=Get-Content $comparison -Raw|ConvertFrom-Json + Check "cancel-clip-not-completed-$Name-$Id" ($code-eq1-and!$match.passed) 'Actual native interrupted clip does not falsely pass complete-speech comparison' + & pwsh -NoProfile -File (Join-Path $PSScriptRoot 'check-canceled-audio.ps1') -CapturedPath (Join-Path $EvidenceDir "$Name.wav") -OutputPath (Join-Path $EvidenceDir "$Name-no-stale.json") + Check "cancel-positive-start-silent-home-tail-$Name" ($LASTEXITCODE-eq0) 'Actual PCM starts non-silent; final3seconds after navigation/pause/startup are silent' +} try { $result.scope='Separate native boundaries after real30 completion; deliberate corrupt-file tests labelled, no fabricated completion or board injection' Check 'clean-source' (!$result.sourceDirty) $result.sourceCommit @@ -34,6 +45,25 @@ try { $empty=Save 'free-empty';Check 'free-empty-allowed' ($empty.latestFreePlay.balls.Count-eq0-and$empty.latestFreePlay.groups.Count-eq0) 'All whole groups natively returned, empty state accepted' Step 'free-empty-refill-one' @('shell','input','tap','2064','756');$one=Save 'free-empty-refilled' Check 'free-empty-refills-one' ($one.latestFreePlay.balls.Count-eq1-and$one.latestFreePlay.groups.Count-eq1-and(Same $one.completedStageIds $original.completedStageIds)-and(Same $one.puzzleStates $original.puzzleStates)) 'Refill changes only latest Free board, all records/puzzles unchanged' + Step 'cancel-guide-home' @('shell','input','tap','312','108');Step 'cancel-guide-selection' @('shell','input','tap','1200','616') + StartAudio 'audio-guide-navigation-cancel' 9 + $stageOne=StagePoint 1;Step 'cancel-guide-enter1' @('shell','input','tap',"$($stageOne[0])","$($stageOne[1])") 450 + Step 'cancel-guide-to-home' @('shell','input','tap','312','108') 3500 + CanceledSpeech 'audio-guide-navigation-cancel' 'guide_collect' + SelectStage 'cancel-count-enter2' 2 + $two=Save 'cancel-count-two-initial';$board=@($two.puzzleStates|Where-Object stageId -eq2)[0] + $s=BallPoint $board $board.groups[0].ballIds[0];$t=BallPoint $board $board.groups[1].ballIds[0] + Step 'cancel-count-two-merge' @('shell','input','swipe',"$($s[0])","$($s[1])","$($t[0]-35)","$($t[1])",'500') 3000 + $two=Save 'cancel-count-two-collected';$board=@($two.puzzleStates|Where-Object stageId -eq2)[0] + Check 'cancel-count-real2-collected' ($board.groups.Count-eq1-and$board.collectedBallIds.Count-eq2) 'Actual replay2 collected before numeric cancellation' + $p=BallPoint $board $board.balls[0].id + StartAudio 'audio-numeric-pause-cancel' 12 + Adb @('shell','input','tap',"$($p[0])","$($p[1])")|Out-Null + Start-Sleep -Milliseconds 130 + Adb @('shell','input','keyevent','3')|Out-Null;Start-Sleep -Milliseconds 500;Adb @('shell','am','force-stop',$package)|Out-Null + StartHome 'numeric-cancel-restart-home' + CanceledSpeech 'audio-numeric-pause-cancel' 'count_01' + Step 'cancel-free-return' @('shell','input','tap','1200','810');$one=Save 'cancel-free-before-pinch' # Genuine two-contact zoom, followed by out-of-window release cancellation of a friend drag. Touch @(30,400,999,100);Touch @(30,400,999,0);Start-Sleep -Milliseconds 100 Touch @(1100,500,101,100,1400,500,102,100);Start-Sleep -Milliseconds 150