param([Parameter(Mandatory=$true)][string]$OutputRoot)
$ErrorActionPreference='Stop'
$root=Join-Path $OutputRoot ('synthetic-t-'+[guid]::NewGuid().ToString('N').Substring(0,8))
$s=Join-Path $root 'S';$c=Join-Path $root 'C';$old=Join-Path $root 'old-reader'
foreach($path in @($s,$c,$old)){New-Item -ItemType Directory -Path $path | Out-Null}
function Save($Value,[string]$Path){$Value | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $Path -Encoding utf8}
function Assert([bool]$Condition,[string]$Message){if(-not$Condition){throw $Message}}
$run=@{syntheticUnitFixture=$true;failures=0;configuration='Release';version='synthetic-not-a-product-version'}
foreach($path in @($s,$c,$old)){Save $run (Join-Path $path 'run.json')}
$manifest=@(0..61 | ForEach-Object {@{index=$_;grid=@(0..100)}})
$contract=@{syntheticUnitFixture=$true;manifest=$manifest;factories=@(0..3);seeded10000Actions=@(0..9999)}
$cases=@(0..710 | ForEach-Object {@{id="synthetic-case$_";metrics=$(if($_ -lt 669){@{synthetic=$true}}else{$null})}})
$samples=[single[]]@(.125,-.125);$bytes=New-Object byte[] 8;[Buffer]::BlockCopy($samples,0,$bytes,0,8)
foreach($path in @($s,$c)){
    New-Item -ItemType Directory -Path (Join-Path $path 'raw'),(Join-Path $path 'states') | Out-Null
    Save $contract (Join-Path $path 'contract.json');Save $cases (Join-Path $path 'cases.json')
    foreach($name in @('envelopes','oscillators','filters','gain-chain')){Save @{syntheticUnitFixture=$true} (Join-Path $path "$name.json")}
    foreach($prefix in @(2,6,16,24,29,32,40,44,62)){
        foreach($extension in @('state','json')){Save @{syntheticUnitFixture=$true;prefix=$prefix} (Join-Path $path "states/prefix-$prefix.$extension")}
    }
    foreach($case in $cases){[IO.File]::WriteAllBytes((Join-Path $path "raw/$($case.id).f32"),$bytes)}
}
Save @{fixtures=9;failures=0;input=$s;syntheticUnitFixture=$true} (Join-Path $c 'cross-state.json')
Save @{fixtures=9;failures=0;input=$c;syntheticUnitFixture=$true} (Join-Path $old 'cross-state.json')
& (Join-Path $PSScriptRoot 'CompareCPUTone.ps1') -Reference $s -Candidate $c -OldReader $old -Output (Join-Path $root 'positive')
$result=Get-Content -LiteralPath (Join-Path $root 'positive/tone-null.json') -Raw | ConvertFrom-Json
Assert ($result.syntheticUnitFixture -and $result.corpusCases -eq 711 -and $result.comparedFrames -eq 711 -and -not$result.fullMilestonePass) 'Synthetic comparison must not be milestone evidence'
# Small independent files test the raw reader, without mutating any positive
# fixture, real audio file or hard-linked baseline evidence.
$good=Join-Path $root 'good.f32';[IO.File]::WriteAllBytes($good,$bytes)
foreach($kind in @('NaN','Inf','difference','truncated')){
    $bad=Join-Path $root "$kind.f32"
    $value=switch($kind){'NaN'{[single]::NaN};'Inf'{[single]::PositiveInfinity};'difference'{[single].25};'truncated'{[single].125}}
    $changed=[single[]]@($value,-.125);$changedBytes=New-Object byte[] 8;[Buffer]::BlockCopy($changed,0,$changedBytes,0,8)
    if($kind -eq 'truncated'){$changedBytes=[byte[]]$changedBytes[0..6]}
    [IO.File]::WriteAllBytes($bad,$changedBytes)
    $failed=$false
    try{[void][DeepPluckStrictRawNull]::Compare($good,$bad)}catch{$failed=$true}
    Assert $failed "Raw negative fixture incorrectly passed: $kind"
}
Save @{syntheticUnitFixture=$true;passed=$true;fullMilestonePass=$false} (Join-Path $root 'unit-test-result.json')
Write-Host 'PASS: synthetic tone-comparison reader and NaN/Inf/length/byte-difference rejection'
