param( [Parameter(Mandatory = $true)][string]$OutputRoot, [string]$SourceFixtureRoot = 'C:\dev\TEMP\local-parity-launch-20260806' ) $ErrorActionPreference = 'Stop' $repoRoot = Split-Path -Parent $PSScriptRoot $releaseRoot = Join-Path $repoRoot 'Launcher.Next.App\bin\x64\Release\net8.0-windows' $output = [IO.Path]::GetFullPath($OutputRoot) $fixture = [IO.Path]::GetFullPath($SourceFixtureRoot) if (-not (Test-Path -LiteralPath (Join-Path $releaseRoot 'Launcher.Next.App.exe'))) { throw 'OWNER_REVIEW_RELEASE_EXE_MISSING' } if (-not (Test-Path -LiteralPath (Join-Path $fixture 'catalog\P_Rec_Annot\0.1.0\package.manifest.json'))) { throw 'OWNER_REVIEW_CATALOG_INPUT_MISSING' } if (Test-Path -LiteralPath $output) { throw 'OWNER_REVIEW_OUTPUT_ALREADY_EXISTS' } $app = Join-Path $output 'app' $controlled = Join-Path $output 'controlled' New-Item -ItemType Directory -Path $app, $controlled, (Join-Path $controlled 'configuration'), (Join-Path $controlled 'project'), (Join-Path $controlled 'evidence') | Out-Null Copy-Item -Path (Join-Path $releaseRoot '*') -Destination $app -Recurse Copy-Item -LiteralPath (Join-Path $fixture 'catalog') -Destination $controlled -Recurse Copy-Item -LiteralPath (Join-Path $fixture 'project\Project.xml') -Destination (Join-Path $controlled 'project\Project.xml') $rosterDirectory = Join-Path $controlled '_System\Plant 3D_2019\Applications' New-Item -ItemType Directory -Path $rosterDirectory | Out-Null Copy-Item -LiteralPath (Join-Path $fixture 'configuration\download_list.xml') -Destination (Join-Path $rosterDirectory 'download_list.xml') Copy-Item -LiteralPath (Join-Path $fixture 'configuration\compatibility-overlay.json') -Destination (Join-Path $controlled 'configuration\compatibility-overlay.json') @' Owner review controlled local PXP-OAowner-review-localPlant 3D_2019Project files |Project.xml|All files (*.*)|*.*%PROJECTDIRECTORY%\..\_System\Plant 3D_2019\Applications\download_list.xmlcontrolled-local-pxp-oaP_Rec_Annotlocal-immutable-package '@ | Set-Content -LiteralPath (Join-Path $controlled 'configuration\Settings.xml') -Encoding utf8 $profile = [ordered]@{ schemaVersion = 1 name = 'Owner Review Controlled Local PXP-OA' root = $controlled settingsPath = (Join-Path $controlled 'configuration\Settings.xml') downloadListPath = (Join-Path $rosterDirectory 'download_list.xml') overlayPath = (Join-Path $controlled 'configuration\compatibility-overlay.json') catalogRoot = (Join-Path $controlled 'catalog') patternName = 'Plant 3D_2019' evidenceRoot = (Join-Path $controlled 'evidence') } $profilePath = Join-Path $controlled 'configuration\owner-review-profile.json' $profile | ConvertTo-Json | Set-Content -LiteralPath $profilePath -Encoding utf8 @{ launcherCommit = (git -C $repoRoot rev-parse HEAD).Trim(); distribution = 'OwnerReviewControlledLocal'; createdUtc = [DateTimeOffset]::UtcNow } | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $app 'owner-review-release.json') -Encoding utf8 @" @echo off "%~dp0Launcher.Next.App.exe" --mode LocalParityLaunch --config "%~dp0..\controlled\configuration\owner-review-profile.json" "@ | Set-Content -LiteralPath (Join-Path $app 'Launch Owner Review.cmd') -Encoding ascii [pscustomobject]@{ DistributionRoot = $output Executable = (Join-Path $app 'Launcher.Next.App.exe') Launcher = (Join-Path $app 'Launch Owner Review.cmd') Profile = $profilePath Project = (Join-Path $controlled 'project\Project.xml') AutomaticRoster = (Join-Path $rosterDirectory 'download_list.xml') } | Format-List