[CmdletBinding()]
param(
    [ValidateRange(1024, 65535)]
    [int]$Port = 9353,

    [string]$Output,

    [string]$Screenshot,

    [string]$ExchangeDirectory,

    [string]$NodePath,

    [ValidateRange(10, 120)]
    [int]$LaunchTimeoutSeconds = 30,

    [ValidateRange(60, 900)]
    [int]$HarnessTimeoutSeconds = 180,

    [switch]$StaticAudit
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$requestedPort = $Port
$requestedOutput = $Output
$requestedScreenshot = $Screenshot
$requestedExchangeDirectory = $ExchangeDirectory
$requestedNodePath = $NodePath
$requestedLaunchTimeout = $LaunchTimeoutSeconds
$requestedHarnessTimeout = $HarnessTimeoutSeconds
$sharedScript = Join-Path $PSScriptRoot 'Invoke-LegacyPackageInputSmoke.ps1'
if (-not [IO.File]::Exists($sharedScript)) {
    throw [InvalidOperationException]::new('The shared package input safety script is missing.')
}

# Reuse the exact Debug AppX package, DryRun, loopback CDP, package identity,
# process ownership, Tornado isolation and neutral normal-close guards. This
# definitions-only import launches nothing.
. $sharedScript `
    -BuildFlavor DebugAppX `
    -Profile ReadOnly `
    -Port $requestedPort `
    -Output $requestedOutput `
    -Screenshot $requestedScreenshot `
    -NodePath $requestedNodePath `
    -LaunchTimeoutSeconds $requestedLaunchTimeout `
    -HarnessTimeoutSeconds $requestedHarnessTimeout `
    -DefinitionsOnly

$Port = $requestedPort
$Output = $requestedOutput
$Screenshot = $requestedScreenshot
$ExchangeDirectory = $requestedExchangeDirectory
$NodePath = $requestedNodePath
$LaunchTimeoutSeconds = $requestedLaunchTimeout
$HarnessTimeoutSeconds = $requestedHarnessTimeout
$HarnessPath = Join-Path $PSScriptRoot 'Test-LegacyPackageAppearanceSmoke.mjs'

Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
using System.Threading;

public static class LegacyAppearanceInputNative
{
    [StructLayout(LayoutKind.Sequential)]
    private struct MouseInput
    {
        public int Dx;
        public int Dy;
        public uint MouseData;
        public uint Flags;
        public uint Time;
        public UIntPtr ExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct KeyboardInput
    {
        public ushort VirtualKey;
        public ushort ScanCode;
        public uint Flags;
        public uint Time;
        public UIntPtr ExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct HardwareInput
    {
        public uint Message;
        public ushort ParameterLow;
        public ushort ParameterHigh;
    }

    [StructLayout(LayoutKind.Explicit)]
    private struct InputUnion
    {
        [FieldOffset(0)] public MouseInput Mouse;
        [FieldOffset(0)] public KeyboardInput Keyboard;
        [FieldOffset(0)] public HardwareInput Hardware;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct Input
    {
        public uint Type;
        public InputUnion Union;
    }

    [DllImport("user32.dll")]
    private static extern uint SendInput(
        uint inputCount,
        Input[] inputs,
        int inputSize);

    [DllImport("user32.dll")]
    private static extern short GetAsyncKeyState(int virtualKey);

    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    private static extern IntPtr GetAncestor(IntPtr window, uint flags);

    [DllImport("user32.dll")]
    private static extern bool IsWindow(IntPtr window);

    private const uint InputKeyboard = 1;
    private const uint KeyUp = 0x0002;
    private const uint GetAncestorRoot = 2;
    private const ushort VirtualKeyHome = 0x24;
    private const ushort VirtualKeyDown = 0x28;
    private const ushort VirtualKeyEnter = 0x0D;

    public static int InputStructureBytes()
    {
        return Marshal.SizeOf(typeof(Input));
    }

    public static int ExpectedInputStructureBytes()
    {
        return IntPtr.Size == 8 ? 40 : 28;
    }

    public static void SendClosedSelectKeys(IntPtr expectedRoot, int optionIndex)
    {
        if (expectedRoot == IntPtr.Zero || !IsWindow(expectedRoot) ||
            optionIndex < 0 || optionIndex > 2 ||
            GetAncestor(GetForegroundWindow(), GetAncestorRoot) != expectedRoot)
        {
            throw new InvalidOperationException(
                "The closed appearance select keyboard contract is invalid.");
        }

        AssertReleased(VirtualKeyHome);
        AssertReleased(VirtualKeyDown);
        AssertReleased(VirtualKeyEnter);
        ushort held = 0;
        try
        {
            SendKey(VirtualKeyHome, false);
            held = VirtualKeyHome;
            Thread.Sleep(45);
            SendKey(VirtualKeyHome, true);
            held = 0;
            Thread.Sleep(60);

            for (int index = 0; index < optionIndex; index++)
            {
                AssertForeground(expectedRoot);
                SendKey(VirtualKeyDown, false);
                held = VirtualKeyDown;
                Thread.Sleep(45);
                SendKey(VirtualKeyDown, true);
                held = 0;
                Thread.Sleep(60);
            }

            AssertForeground(expectedRoot);
            SendKey(VirtualKeyEnter, false);
            held = VirtualKeyEnter;
            Thread.Sleep(45);
            SendKey(VirtualKeyEnter, true);
            held = 0;
            Thread.Sleep(300);
            AssertForeground(expectedRoot);
        }
        finally
        {
            if (held != 0) SendKey(held, true);
            AssertReleased(VirtualKeyHome);
            AssertReleased(VirtualKeyDown);
            AssertReleased(VirtualKeyEnter);
        }
    }

    private static void AssertForeground(IntPtr expectedRoot)
    {
        if (GetAncestor(GetForegroundWindow(), GetAncestorRoot) != expectedRoot)
        {
            throw new InvalidOperationException(
                "The exact package window lost foreground during appearance input.");
        }
    }

    private static void AssertReleased(ushort virtualKey)
    {
        if ((GetAsyncKeyState(virtualKey) & 0x8000) != 0)
        {
            throw new InvalidOperationException(
                "An appearance input key remained held.");
        }
    }

    private static void SendKey(ushort virtualKey, bool keyUp)
    {
        int inputSize = InputStructureBytes();
        if (inputSize != ExpectedInputStructureBytes())
        {
            throw new InvalidOperationException(
                "The Win32 INPUT structure size is not ABI-compatible.");
        }
        Input input = new Input {
            Type = InputKeyboard,
            Union = new InputUnion {
                Keyboard = new KeyboardInput {
                    VirtualKey = virtualKey,
                    Flags = keyUp ? KeyUp : 0
                }
            }
        };
        if (SendInput(1, new Input[] { input }, inputSize) != 1)
        {
            throw new InvalidOperationException(
                "Windows did not accept the one-shot appearance key input.");
        }
    }
}
'@

$script:Phase = 'preflight'
$script:ApplicationProcess = $null
$script:ApplicationWasLaunched = $false
$script:CurrentApplicationClosed = $true
$script:AppearanceRequestCalls = 0
$script:AppearanceAcknowledgementCalls = 0
$script:BaselineSettingsState = $null
$script:BaselineSettingsBytes = $null
$script:BaselineRecoveryPath = $null
$script:BaselineRecoveryCreated = $false
$script:BaselineRecoverySha256 = $null
$script:BaselineRestored = $false
$script:BaselineRestoreAttempted = $false

function Test-ClosedAppearanceValue(
    [string]$Kind,
    [object]$Value) {
    if ($Value -isnot [string]) { return $false }
    switch -CaseSensitive ($Kind) {
        'colorTheme' { return @('system', 'light', 'dark') -ccontains [string]$Value }
        'viewMode' { return @('automatic', 'compact', 'cards') -ccontains [string]$Value }
        'startWorkspace' { return @('stockCut', 'lastWorkspace') -ccontains [string]$Value }
        default { return $false }
    }
}

function New-Appearance(
    [string]$ColorTheme,
    [string]$ViewMode,
    [string]$StartWorkspace) {
    if (-not (Test-ClosedAppearanceValue 'colorTheme' $ColorTheme) -or
        -not (Test-ClosedAppearanceValue 'viewMode' $ViewMode) -or
        -not (Test-ClosedAppearanceValue 'startWorkspace' $StartWorkspace)) {
        Throw-SafeFailure 'An appearance projection is outside the closed schema.'
    }
    return [pscustomobject][ordered]@{
        colorTheme = $ColorTheme
        viewMode = $ViewMode
        startWorkspace = $StartWorkspace
    }
}

function Test-AppearanceEqual([object]$Left, [object]$Right) {
    return $null -ne $Left -and $null -ne $Right -and
        [string]$Left.colorTheme -ceq [string]$Right.colorTheme -and
        [string]$Left.viewMode -ceq [string]$Right.viewMode -and
        [string]$Left.startWorkspace -ceq [string]$Right.startWorkspace
}

function Get-ContextHash(
    [object]$SceneDirectory,
    [object]$ResourceDirectory,
    [object]$BackgroundDirectory,
    [object]$NavigationExpanded) {
    $context = [ordered]@{
        sceneDirectory = $SceneDirectory
        resourceDirectory = $ResourceDirectory
        backgroundDirectory = $BackgroundDirectory
        navigationExpanded = $NavigationExpanded
    }
    $bytes = $Utf8.GetBytes(($context | ConvertTo-Json -Compress))
    return Get-ByteArraySha256 $bytes
}

function Assert-SettingsScalarTypes([object]$Value) {
    foreach ($name in @('sceneDirectory', 'resourceDirectory', 'backgroundDirectory')) {
        $candidate = $Value.$name
        if ($null -ne $candidate -and $candidate -isnot [string]) {
            Throw-SafeFailure 'The operator settings folder projection is not a string or null.'
        }
    }
    if ($Value.navigationExpanded -isnot [bool]) {
        Throw-SafeFailure 'The operator navigation setting is not Boolean.'
    }
}

function Get-OperatorSettingsFileState {
    if (-not [IO.File]::Exists($OperatorSettingsPath)) {
        return [pscustomobject][ordered]@{
            exists = $false
            length = 0
            sha256 = $null
            schemaVersion = 0
            contextSha256 = Get-ContextHash $null $null $null $true
            appearance = New-Appearance 'system' 'automatic' 'stockCut'
        }
    }

    $item = Get-Item -LiteralPath $OperatorSettingsPath -Force
    if ($item.PSIsContainer -or
        ($item.Attributes -band ([IO.FileAttributes]::ReparsePoint -bor
                [IO.FileAttributes]::Device)) -ne 0 -or
        $item.Length -le 0 -or $item.Length -gt 16KB) {
        Throw-SafeFailure 'The operator settings file is not a bounded regular file.'
    }
    $bytes = [IO.File]::ReadAllBytes($OperatorSettingsPath)
    if ($bytes.Length -ne $item.Length) {
        Throw-SafeFailure 'The operator settings file changed while it was read.'
    }
    try {
        $raw = $StrictUtf8.GetString($bytes)
        $value = $raw | ConvertFrom-Json -ErrorAction Stop
    }
    catch {
        Throw-SafeFailure 'The operator settings file is not strict UTF-8 JSON.'
    }
    if ($null -eq $value -or
        (ConvertTo-FiniteNumber $value.schemaVersion 'Operator settings schema version') `
            -notin @(1, 2)) {
        Throw-SafeFailure 'The operator settings schema version is unsupported.'
    }
    $schemaVersion = [int]$value.schemaVersion
    $expectedNames = if ($schemaVersion -eq 1) {
        @('schemaVersion', 'sceneDirectory', 'resourceDirectory',
            'backgroundDirectory', 'navigationExpanded')
    }
    else {
        @('schemaVersion', 'sceneDirectory', 'resourceDirectory',
            'backgroundDirectory', 'navigationExpanded', 'colorTheme',
            'viewMode', 'startWorkspace')
    }
    Assert-ExactJsonPropertyNames $value $expectedNames 'Operator settings JSON'
    foreach ($name in $expectedNames) {
        $escapedName = [regex]::Escape($name)
        if ([regex]::Matches($raw, '"' + $escapedName + '"\s*:').Count -ne 1) {
            Throw-SafeFailure 'The operator settings JSON contains a duplicate property.'
        }
    }
    Assert-SettingsScalarTypes $value
    $appearance = if ($schemaVersion -eq 1) {
        New-Appearance 'system' 'automatic' 'stockCut'
    }
    else {
        New-Appearance `
            ([string]$value.colorTheme) `
            ([string]$value.viewMode) `
            ([string]$value.startWorkspace)
    }
    return [pscustomobject][ordered]@{
        exists = $true
        length = $bytes.Length
        sha256 = Get-ByteArraySha256 $bytes
        schemaVersion = $schemaVersion
        contextSha256 = Get-ContextHash `
            $value.sceneDirectory `
            $value.resourceDirectory `
            $value.backgroundDirectory `
            $value.navigationExpanded
        appearance = $appearance
    }
}

function Wait-OperatorSettingsAppearance(
    [object]$ExpectedAppearance,
    [string]$ExpectedContextSha256,
    [datetime]$Deadline) {
    while ([datetime]::UtcNow -lt $Deadline) {
        try {
            $state = Get-OperatorSettingsFileState
            if ($state.exists -eq $true -and $state.schemaVersion -eq 2 -and
                [string]$state.contextSha256 -ceq $ExpectedContextSha256 -and
                (Test-AppearanceEqual $state.appearance $ExpectedAppearance)) {
                return $state
            }
        }
        catch {
            # The native atomic save can briefly move between generations. The
            # bounded wait only observes; it never reissues input.
        }
        Start-Sleep -Milliseconds 50
    }
    Throw-SafeFailure 'The expected appearance settings file was not observed after one input.'
}

function Initialize-ExactBaselineRecovery([string]$RecoveryPath) {
    $script:BaselineSettingsState = Get-OperatorSettingsFileState
    $script:BaselineSettingsBytes = $null
    $script:BaselineRecoveryPath = $RecoveryPath
    if ($script:BaselineSettingsState.exists -eq $true) {
        $bytes = [IO.File]::ReadAllBytes($OperatorSettingsPath)
        if ((Get-ByteArraySha256 $bytes) -cne
            [string]$script:BaselineSettingsState.sha256) {
            Throw-SafeFailure 'The operator settings baseline changed before backup.'
        }
        $stream = [IO.FileStream]::new(
            $RecoveryPath,
            [IO.FileMode]::CreateNew,
            [IO.FileAccess]::Write,
            [IO.FileShare]::None)
        try {
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        $script:BaselineSettingsBytes = $bytes
        $script:BaselineRecoveryCreated = $true
        $script:BaselineRecoverySha256 = Get-ByteArraySha256 $bytes
    }
    else {
        $marker = $Utf8.GetBytes(
            '{"schemaVersion":1,"operatorSettingsOriginallyAbsent":true}' + "`n")
        $stream = [IO.FileStream]::new(
            $RecoveryPath,
            [IO.FileMode]::CreateNew,
            [IO.FileAccess]::Write,
            [IO.FileShare]::None)
        try {
            $stream.Write($marker, 0, $marker.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        $script:BaselineRecoveryCreated = $true
        $script:BaselineRecoverySha256 = Get-ByteArraySha256 $marker
    }
}

function Restore-ExactBaselineSettings {
    if ($script:BaselineRestoreAttempted) {
        Throw-SafeFailure 'The exact operator settings restoration is one-shot and was already attempted.'
    }
    $script:BaselineRestoreAttempted = $true
    if (@(Get-LegacyApplicationProcesses).Count -ne 0) {
        Throw-SafeFailure 'The exact operator settings baseline cannot be restored while the app runs.'
    }
    $directory = [IO.Path]::GetDirectoryName($OperatorSettingsPath)
    if ([string]::IsNullOrWhiteSpace($directory)) {
        Throw-SafeFailure 'The operator settings restore directory is invalid.'
    }
    $replacementBackupPath = $null
    if ($script:BaselineSettingsState.exists -eq $true) {
        if (-not $script:BaselineRecoveryCreated -or
            -not [IO.File]::Exists($script:BaselineRecoveryPath)) {
            Throw-SafeFailure 'The exact operator settings recovery copy is missing.'
        }
        $recoveryItem = Get-Item -LiteralPath $script:BaselineRecoveryPath -Force
        $recoveryBytes = [IO.File]::ReadAllBytes($script:BaselineRecoveryPath)
        if ($recoveryItem.PSIsContainer -or
            ($recoveryItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
            $recoveryBytes.Length -ne $recoveryItem.Length -or
            (Get-ByteArraySha256 $recoveryBytes) -cne
                [string]$script:BaselineSettingsState.sha256) {
            Throw-SafeFailure 'The exact operator settings recovery copy changed.'
        }
        if (-not [IO.Directory]::Exists($directory)) {
            [void][IO.Directory]::CreateDirectory($directory)
        }
        $temporaryPath = Join-Path $directory (
            '.runtime-folders.local.json.' + [Guid]::NewGuid().ToString('N') + '.restore.tmp')
        try {
            $stream = [IO.FileStream]::new(
                $temporaryPath,
                [IO.FileMode]::CreateNew,
                [IO.FileAccess]::Write,
                [IO.FileShare]::None)
            try {
                $stream.Write($recoveryBytes, 0, $recoveryBytes.Length)
                $stream.Flush($true)
            }
            finally { $stream.Dispose() }
            if ([IO.File]::Exists($OperatorSettingsPath)) {
                $targetItem = Get-Item -LiteralPath $OperatorSettingsPath -Force
                if ($targetItem.PSIsContainer -or
                    ($targetItem.Attributes -band ([IO.FileAttributes]::ReparsePoint -bor
                            [IO.FileAttributes]::Device)) -ne 0) {
                    Throw-SafeFailure 'The operator settings restore target became unsafe.'
                }
                $replacementBackupPath = Join-Path $directory (
                    '.runtime-folders.local.json.' +
                    [Guid]::NewGuid().ToString('N') + '.restore.backup')
                [IO.File]::Replace(
                    $temporaryPath,
                    $OperatorSettingsPath,
                    $replacementBackupPath,
                    $true)
            }
            else {
                [IO.File]::Move($temporaryPath, $OperatorSettingsPath)
            }
            $temporaryPath = $null
        }
        finally {
            if ($null -ne $temporaryPath -and [IO.File]::Exists($temporaryPath)) {
                [IO.File]::Delete($temporaryPath)
            }
        }
    }
    elseif ([IO.File]::Exists($OperatorSettingsPath)) {
        if (-not $script:BaselineRecoveryCreated -or
            -not [IO.File]::Exists($script:BaselineRecoveryPath) -or
            (Get-FileHash -Algorithm SHA256 -LiteralPath `
                $script:BaselineRecoveryPath).Hash -cne
                [string]$script:BaselineRecoverySha256) {
            Throw-SafeFailure 'The original-absence recovery marker changed.'
        }
        $targetItem = Get-Item -LiteralPath $OperatorSettingsPath -Force
        if ($targetItem.PSIsContainer -or
            ($targetItem.Attributes -band ([IO.FileAttributes]::ReparsePoint -bor
                    [IO.FileAttributes]::Device)) -ne 0) {
            Throw-SafeFailure 'The newly created operator settings restore target became unsafe.'
        }
        [IO.File]::Delete($OperatorSettingsPath)
    }

    $restored = Get-OperatorSettingsFileState
    if ($restored.exists -ne $script:BaselineSettingsState.exists -or
        ($restored.exists -eq $true -and
            [string]$restored.sha256 -cne [string]$script:BaselineSettingsState.sha256)) {
        Throw-SafeFailure 'The exact original operator settings bytes were not restored.'
    }
    if (-not $script:BaselineSettingsState.exists -and
        $script:BaselineRecoveryCreated -and
        -not [IO.File]::Exists($OperatorSettingsPath) -and
        (Get-FileHash -Algorithm SHA256 -LiteralPath `
            $script:BaselineRecoveryPath).Hash -cne
            [string]$script:BaselineRecoverySha256) {
        Throw-SafeFailure 'The original-absence recovery marker changed before cleanup.'
    }
    if ($null -ne $replacementBackupPath -and
        [IO.File]::Exists($replacementBackupPath)) {
        $replacementBackup = Get-Item -LiteralPath $replacementBackupPath -Force
        if ($replacementBackup.PSIsContainer -or
            ($replacementBackup.Attributes -band ([IO.FileAttributes]::ReparsePoint -bor
                    [IO.FileAttributes]::Device)) -ne 0) {
            Throw-SafeFailure 'The operator settings replacement backup became unsafe.'
        }
        [IO.File]::Delete($replacementBackupPath)
    }
    if ($script:BaselineRecoveryCreated -and
        [IO.File]::Exists($script:BaselineRecoveryPath)) {
        [IO.File]::Delete($script:BaselineRecoveryPath)
        $script:BaselineRecoveryCreated = $false
    }
    $script:BaselineRestored = $true
    return $restored
}

function Get-AlternateAppearance([object]$Baseline) {
    return New-Appearance `
        $(if ([string]$Baseline.colorTheme -cne 'dark') { 'dark' } else { 'light' }) `
        $(if ([string]$Baseline.viewMode -cne 'cards') { 'cards' } else { 'compact' }) `
        $(if ([string]$Baseline.startWorkspace -cne 'lastWorkspace') {
                'lastWorkspace'
            }
            else { 'stockCut' })
}

function Get-SequenceAppearance(
    [int]$Sequence,
    [object]$Initial,
    [object]$Final,
    [switch]$After) {
    $color = [string]$Initial.colorTheme
    $view = [string]$Initial.viewMode
    $start = [string]$Initial.startWorkspace
    if ($Sequence -ge 2 -and $After) { $color = [string]$Final.colorTheme }
    if ($Sequence -ge 3) { $color = [string]$Final.colorTheme }
    if ($Sequence -ge 3 -and $After) { $view = [string]$Final.viewMode }
    if ($Sequence -ge 4) {
        $color = [string]$Final.colorTheme
        $view = [string]$Final.viewMode
    }
    if ($Sequence -ge 4 -and $After) { $start = [string]$Final.startWorkspace }
    return New-Appearance $color $view $start
}

function Write-AppearanceAcknowledgement(
    [string]$Path,
    [object]$Request,
    [object]$SettingsState) {
    $acknowledgement = [ordered]@{
        schemaVersion = 1
        phase = [string]$Request.phase
        sequence = [int]$Request.sequence
        token = [string]$Request.token
        result = 'PASS'
        operation = [string]$Request.operation
        targetId = [string]$Request.targetId
        appearanceKey = if ($null -eq $Request.appearanceKey) { $null } else {
            [string]$Request.appearanceKey
        }
        targetValue = if ($null -eq $Request.targetValue) { $null } else {
            [string]$Request.targetValue
        }
        optionIndex = if ($null -eq $Request.optionIndex) { $null } else {
            [int]$Request.optionIndex
        }
        packageIdentityValidated = $true
        dryRunValidated = $true
        tornadoConnectionCount = 0
        inputRetryCount = 0
        mouseDownCalls = 1
        mouseUpCalls = 1
        homeKeyCalls = [int]$Request.homeKeyCalls
        arrowDownKeyCalls = [int]$Request.arrowDownKeyCalls
        enterKeyCalls = [int]$Request.enterKeyCalls
        settings = [ordered]@{
            exists = [bool]$SettingsState.exists
            length = [int64]$SettingsState.length
            sha256 = [string]$SettingsState.sha256
            schemaVersion = [int]$SettingsState.schemaVersion
            contextSha256 = [string]$SettingsState.contextSha256
            appearance = $SettingsState.appearance
        }
    }
    $bytes = $Utf8.GetBytes(($acknowledgement | ConvertTo-Json -Depth 8 -Compress) + "`n")
    $temporaryPath = Join-Path ([IO.Path]::GetDirectoryName($Path)) (
        ([IO.Path]::GetFileName($Path)) + '.' + [Guid]::NewGuid().ToString('N') + '.tmp')
    try {
        $stream = [IO.FileStream]::new(
            $temporaryPath,
            [IO.FileMode]::CreateNew,
            [IO.FileAccess]::Write,
            [IO.FileShare]::None)
        try {
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        [IO.File]::Move($temporaryPath, $Path)
        $temporaryPath = $null
    }
    finally {
        if ($null -ne $temporaryPath -and [IO.File]::Exists($temporaryPath)) {
            [IO.File]::Delete($temporaryPath)
        }
    }
    return [pscustomobject]@{
        Bytes = $bytes
        Sha256 = Get-ByteArraySha256 $bytes
    }
}

function Assert-RequestAppearance([object]$Value, [object]$Expected, [string]$Label) {
    Assert-ExactJsonPropertyNames $Value @(
        'colorTheme', 'viewMode', 'startWorkspace') $Label
    if (-not (Test-AppearanceEqual $Value $Expected)) {
        Throw-SafeFailure "$Label does not match the closed phase progression."
    }
}

function Invoke-ExactAppearanceRequest(
    [string]$RequestPath,
    [string]$AcknowledgementPath,
    [int]$ExpectedSequence,
    [string]$ExpectedPhase,
    [object]$PhaseInitial,
    [object]$PhaseFinal,
    [Diagnostics.Process]$Application,
    [string]$ExpectedApplicationPath) {
    $script:AppearanceRequestCalls++
    if ($script:AppearanceRequestCalls -ne $ExpectedSequence -or
        [IO.File]::Exists($AcknowledgementPath)) {
        Throw-SafeFailure 'The appearance input one-shot budget changed.'
    }
    $requestEvidence = Wait-ReadSmallJsonEvidenceFile `
        $RequestPath `
        'Appearance input request' `
        ([datetime]::UtcNow.AddSeconds(3))
    $request = $requestEvidence.Value
    Assert-ExactJsonPropertyNames $request @(
        'schemaVersion', 'phase', 'sequence', 'token', 'targetUrl',
        'operation', 'targetId', 'appearanceKey', 'targetValue',
        'optionIndex', 'expectedBefore', 'expectedAfter', 'point',
        'viewport', 'devicePixelRatio', 'mouseDownCalls', 'mouseUpCalls',
        'homeKeyCalls', 'arrowDownKeyCalls', 'enterKeyCalls',
        'inputRetryCount') 'Appearance input request'
    Assert-ExactJsonPropertyNames $request.viewport @('width', 'height') `
        'Appearance input viewport'
    $token = [string]$request.token
    if ((ConvertTo-FiniteNumber $request.schemaVersion 'Appearance input schema') -ne 1 -or
        (ConvertTo-FiniteNumber $request.sequence 'Appearance input sequence') -ne
            $ExpectedSequence -or
        $request.phase -isnot [string] -or [string]$request.phase -cne $ExpectedPhase -or
        $request.targetUrl -isnot [string] -or
        [string]$request.targetUrl -cne
            'https://legacy-parity.mbn.local/index.html' -or
        $request.token -isnot [string] -or $token -cnotmatch '\A[0-9A-F]{32}\z' -or
        (ConvertTo-FiniteNumber $request.inputRetryCount 'Appearance input retry count') -ne 0 -or
        (ConvertTo-FiniteNumber $request.mouseDownCalls 'Appearance mouse-down count') -ne 1 -or
        (ConvertTo-FiniteNumber $request.mouseUpCalls 'Appearance mouse-up count') -ne 1) {
        Throw-SafeFailure 'The appearance input request violates the common closed contract.'
    }
    $expectedBefore = Get-SequenceAppearance `
        $ExpectedSequence $PhaseInitial $PhaseFinal
    $expectedAfter = Get-SequenceAppearance `
        $ExpectedSequence $PhaseInitial $PhaseFinal -After
    Assert-RequestAppearance $request.expectedBefore $expectedBefore `
        'Appearance expected-before projection'
    Assert-RequestAppearance $request.expectedAfter $expectedAfter `
        'Appearance expected-after projection'

    $plan = switch ($ExpectedSequence) {
        1 { [pscustomobject]@{
                Operation = 'application-click'; TargetId = 'workspace-settings-tab'
                AppearanceKey = $null; TargetValue = $null; OptionIndex = $null
            }; break }
        2 { [pscustomobject]@{
                Operation = 'select-appearance-option'; TargetId = 'operator-color-theme'
                AppearanceKey = 'colorTheme'; TargetValue = [string]$PhaseFinal.colorTheme
                OptionIndex = @('system', 'light', 'dark').IndexOf(
                    [string]$PhaseFinal.colorTheme)
            }; break }
        3 { [pscustomobject]@{
                Operation = 'select-appearance-option'; TargetId = 'operator-view-mode'
                AppearanceKey = 'viewMode'; TargetValue = [string]$PhaseFinal.viewMode
                OptionIndex = @('automatic', 'compact', 'cards').IndexOf(
                    [string]$PhaseFinal.viewMode)
            }; break }
        4 { [pscustomobject]@{
                Operation = 'select-appearance-option'; TargetId = 'operator-start-workspace'
                AppearanceKey = 'startWorkspace'; TargetValue =
                    [string]$PhaseFinal.startWorkspace
                OptionIndex = @('stockCut', 'lastWorkspace').IndexOf(
                    [string]$PhaseFinal.startWorkspace)
            }; break }
        default { Throw-SafeFailure 'The appearance input sequence is outside its four-step plan.' }
    }
    $actualAppearanceKey = if ($null -eq $request.appearanceKey) { $null } else {
        [string]$request.appearanceKey
    }
    $actualTargetValue = if ($null -eq $request.targetValue) { $null } else {
        [string]$request.targetValue
    }
    $actualOptionIndex = if ($null -eq $request.optionIndex) { $null } else {
        [int](ConvertTo-FiniteNumber $request.optionIndex 'Appearance option index')
    }
    $homeCount = ConvertTo-FiniteNumber $request.homeKeyCalls 'Appearance Home count'
    $downCount = ConvertTo-FiniteNumber $request.arrowDownKeyCalls `
        'Appearance ArrowDown count'
    $enterCount = ConvertTo-FiniteNumber $request.enterKeyCalls 'Appearance Enter count'
    if ($request.operation -isnot [string] -or
        [string]$request.operation -cne $Plan.Operation -or
        $request.targetId -isnot [string] -or
        [string]$request.targetId -cne $Plan.TargetId -or
        $actualAppearanceKey -cne $Plan.AppearanceKey -or
        $actualTargetValue -cne $Plan.TargetValue -or
        $actualOptionIndex -ne $Plan.OptionIndex -or
        $homeCount -ne $(if ($ExpectedSequence -eq 1) { 0 } else { 1 }) -or
        $downCount -ne $(if ($ExpectedSequence -eq 1) { 0 } else { $Plan.OptionIndex }) -or
        $enterCount -ne $(if ($ExpectedSequence -eq 1) { 0 } else { 1 })) {
        Throw-SafeFailure 'The appearance input request is outside the exact control plan.'
    }

    $viewportWidth = ConvertTo-FiniteNumber $request.viewport.width `
        'Appearance viewport width'
    $viewportHeight = ConvertTo-FiniteNumber $request.viewport.height `
        'Appearance viewport height'
    $devicePixelRatio = ConvertTo-FiniteNumber $request.devicePixelRatio `
        'Appearance device pixel ratio'
    if ($viewportWidth -lt 1 -or $viewportWidth -gt 16384 -or
        $viewportHeight -lt 1 -or $viewportHeight -gt 16384 -or
        $devicePixelRatio -lt 0.25 -or $devicePixelRatio -gt 5) {
        Throw-SafeFailure 'The appearance viewport contract is invalid.'
    }
    $point = ConvertTo-ExactInputPoint `
        $request.point $viewportWidth $viewportHeight 'Appearance input point'
    $beforeFile = Get-OperatorSettingsFileState
    if ([string]$beforeFile.contextSha256 -cne
            [string]$script:BaselineSettingsState.contextSha256 -or
        -not (Test-AppearanceEqual $beforeFile.appearance $expectedBefore)) {
        Throw-SafeFailure 'The operator settings file changed before physical appearance input.'
    }

    Assert-ExactApplicationStillRunning $Application $ExpectedApplicationPath
    Assert-NoTornadoConnection $Application.Id
    [LegacyPackageInputNative]::SendApplicationClick(
        $Application.MainWindowHandle,
        $Application.Id,
        30001,
        $point.X,
        $point.Y,
        $viewportWidth,
        $viewportHeight,
        $devicePixelRatio,
        $false)
    if ($ExpectedSequence -gt 1) {
        [LegacyPackageInputNative]::AcquireOwnedForeground(
            $Application.MainWindowHandle,
            $Application.MainWindowHandle,
            $Application.Id,
            30001)
        [LegacyAppearanceInputNative]::SendClosedSelectKeys(
            $Application.MainWindowHandle,
            [int]$Plan.OptionIndex)
    }
    Assert-ExactApplicationStillRunning $Application $ExpectedApplicationPath
    Assert-NoTornadoConnection $Application.Id

    $afterFile = if ($ExpectedSequence -eq 1) {
        $observed = Get-OperatorSettingsFileState
        if ($observed.exists -ne $beforeFile.exists -or
            [string]$observed.sha256 -cne [string]$beforeFile.sha256) {
            Throw-SafeFailure 'Opening Settings unexpectedly changed the settings file.'
        }
        $observed
    }
    else {
        Wait-OperatorSettingsAppearance `
            $expectedAfter `
            ([string]$script:BaselineSettingsState.contextSha256) `
            ([datetime]::UtcNow.AddSeconds(15))
    }

    $script:AppearanceAcknowledgementCalls++
    if ($script:AppearanceAcknowledgementCalls -ne $ExpectedSequence) {
        Throw-SafeFailure 'The appearance acknowledgement one-shot budget changed.'
    }
    $acknowledgement = Write-AppearanceAcknowledgement `
        $AcknowledgementPath $request $afterFile
    return [pscustomobject][ordered]@{
        sequence = $ExpectedSequence
        operation = [string]$Plan.Operation
        targetId = [string]$Plan.TargetId
        requestPath = $RequestPath
        requestSha256 = $requestEvidence.Sha256
        acknowledgementPath = $AcknowledgementPath
        acknowledgementSha256 = $acknowledgement.Sha256
        resultingSettingsSha256 = [string]$afterFile.sha256
    }
}

function Invoke-AppearanceHarnessUnderWatch(
    [string]$PhaseName,
    [object]$ExpectedInitial,
    [object]$ExpectedFinal,
    [string]$PhaseOutput,
    [string]$PhaseScreenshot,
    [string]$PhaseExchangeDirectory,
    [Diagnostics.Process]$Application,
    [string]$ExpectedApplicationPath) {
    $arguments = @(
        $HarnessPath,
        '--phase', $PhaseName,
        '--port', [string]$Port,
        '--output', $PhaseOutput,
        '--screenshot', $PhaseScreenshot,
        '--exchange-directory', $PhaseExchangeDirectory,
        '--expected-color-theme', [string]$ExpectedInitial.colorTheme,
        '--expected-view-mode', [string]$ExpectedInitial.viewMode,
        '--expected-start-workspace', [string]$ExpectedInitial.startWorkspace,
        '--final-color-theme', [string]$ExpectedFinal.colorTheme,
        '--final-view-mode', [string]$ExpectedFinal.viewMode,
        '--final-start-workspace', [string]$ExpectedFinal.startWorkspace,
        '--timeout-ms', [string]($HarnessTimeoutSeconds * 1000)
    ) | ForEach-Object { ConvertTo-QuotedProcessArgument ([string]$_) }
    $startInfo = New-Object Diagnostics.ProcessStartInfo
    $startInfo.FileName = $NodePath
    $startInfo.WorkingDirectory = $RepositoryRoot
    $startInfo.Arguments = $arguments -join ' '
    $startInfo.UseShellExecute = $false
    $startInfo.CreateNoWindow = $true
    $startInfo.RedirectStandardInput = $true
    try { $node = [Diagnostics.Process]::Start($startInfo) }
    catch { Throw-SafeFailure 'The appearance input helper could not be started.' }
    if ($null -eq $node) { Throw-SafeFailure 'The appearance input helper did not start.' }

    $script:AppearanceRequestCalls = 0
    $script:AppearanceAcknowledgementCalls = 0
    $nextSequence = 1
    $exchangeEvidence = New-Object 'Collections.Generic.List[object]'
    $deadline = [datetime]::UtcNow.AddSeconds($HarnessTimeoutSeconds + 30)
    $monitoringFailure = $null
    try {
        while (-not $node.HasExited) {
            if ([datetime]::UtcNow -ge $deadline) {
                Throw-SafeFailure 'The appearance helper exceeded its global deadline.'
            }
            Assert-ExactApplicationStillRunning $Application $ExpectedApplicationPath
            Assert-NoTornadoConnection $Application.Id
            if ($nextSequence -le 4) {
                $requestPath = Join-Path $PhaseExchangeDirectory (
                    $nextSequence.ToString('00') + '.request.json')
                $acknowledgementPath = Join-Path $PhaseExchangeDirectory (
                    $nextSequence.ToString('00') + '.ack.json')
                if ([IO.File]::Exists($requestPath)) {
                    $exchange = Invoke-ExactAppearanceRequest `
                        $requestPath `
                        $acknowledgementPath `
                        $nextSequence `
                        $PhaseName `
                        $ExpectedInitial `
                        $ExpectedFinal `
                        $Application `
                        $ExpectedApplicationPath
                    [void]$exchangeEvidence.Add($exchange)
                    $nextSequence++
                }
            }
            Start-Sleep -Milliseconds 75
            $node.Refresh()
        }
        if ($node.ExitCode -ne 0 -or $nextSequence -ne 5 -or
            $exchangeEvidence.Count -ne 4 -or
            $script:AppearanceRequestCalls -ne 4 -or
            $script:AppearanceAcknowledgementCalls -ne 4) {
            Throw-SafeFailure 'The appearance helper did not complete four physical inputs.'
        }
        Assert-ExactApplicationStillRunning $Application $ExpectedApplicationPath
        Assert-NoTornadoConnection $Application.Id
    }
    catch { $monitoringFailure = $_.Exception.Message }

    if ($null -ne $monitoringFailure) {
        $stopped = $node.HasExited
        if (-not $stopped) {
            try {
                $node.StandardInput.WriteLine('CANCEL')
                $node.StandardInput.Flush()
                $stopped = $node.WaitForExit(5000)
            }
            catch { $stopped = $false }
        }
        if (-not $stopped) {
            try {
                # Only the bounded Node helper is stopped. The package is never
                # force-terminated and no appearance input is retried.
                $node.Kill()
                $stopped = $node.WaitForExit(10000)
            }
            catch { $stopped = $false }
        }
        Throw-SafeFailure (
            "$monitoringFailure The appearance helper was stopped if possible; " +
            'the packaged app was left open and no input was retried.')
    }
    return [pscustomobject]@{
        ExitCode = $node.ExitCode
        Exchanges = @($exchangeEvidence.ToArray())
    }
}

function Read-AppearancePhaseEvidence(
    [string]$Path,
    [string]$ScreenshotPath,
    [string]$ExpectedPhase,
    [object]$ExpectedInitial,
    [object]$ExpectedFinal) {
    try {
        $item = Get-Item -LiteralPath $Path -Force
        if ($item.PSIsContainer -or
            ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
            $item.Length -le 0 -or $item.Length -gt 512KB) {
            Throw-SafeFailure 'Appearance phase evidence is not a bounded regular file.'
        }
        $bytes = [IO.File]::ReadAllBytes($Path)
        if ($bytes.Length -ne $item.Length) {
            Throw-SafeFailure 'Appearance phase evidence changed while it was read.'
        }
        $value = $StrictUtf8.GetString($bytes) | ConvertFrom-Json -ErrorAction Stop
        $sealed = [pscustomobject]@{
            Value = $value
            Sha256 = Get-ByteArraySha256 $bytes
        }
    }
    catch [InvalidOperationException] { throw }
    catch { Throw-SafeFailure 'Appearance phase evidence is not strict bounded JSON.' }
    $value = $sealed.Value
    if ([int]$value.schemaVersion -ne 1 -or
        [string]$value.profile -cne 'operator-appearance-persistence' -or
        [string]$value.phase -cne $ExpectedPhase -or
        [string]$value.result -cne 'PASS' -or $null -ne $value.error -or
        [string]$value.target.expectedUrl -cne
            'https://legacy-parity.mbn.local/index.html' -or
        [int]$value.target.port -ne $Port -or
        [string]$value.target.url -cne
            'https://legacy-parity.mbn.local/index.html' -or
        [string]$value.safety.requiredMode -cne 'dryRun' -or
        [string]$value.safety.requiredPhase -cne 'idle' -or
        [int]$value.safety.inputRetryCount -ne 0 -or
        $value.safety.appCloseRequested -ne $false -or
        $value.safety.playoutIntentIssued -ne $false -or
        @($value.safety.blockedOutboundMessages).Count -ne 0 -or
        @($value.safety.stateViolations).Count -ne 0 -or
        -not (Test-AppearanceEqual $value.expectedInitial $ExpectedInitial) -or
        -not (Test-AppearanceEqual $value.expectedFinal $ExpectedFinal) -or
        @($value.exchanges).Count -ne 4 -or
        @($value.selections).Count -ne 3 -or
        ($ExpectedPhase -ceq 'verify-restore' -and
            $value.persistenceVerifiedBeforeInput -ne $true) -or
        ($ExpectedPhase -ceq 'verify-restore' -and
            $value.startWorkspaceBehaviorVerifiedBeforeInput -ne $true) -or
        ($ExpectedPhase -ceq 'mutate' -and
            ($value.persistenceVerifiedBeforeInput -ne $false -or
             $value.startWorkspaceBehaviorVerifiedBeforeInput -ne $false))) {
        Throw-SafeFailure 'The appearance phase evidence violates its sealed contract.'
    }
    $selectionKeys = @('colorTheme', 'viewMode', 'startWorkspace')
    for ($selectionIndex = 0;
        $selectionIndex -lt $selectionKeys.Count;
        $selectionIndex++) {
        $selection = $value.selections[$selectionIndex]
        $selectionKey = $selectionKeys[$selectionIndex]
        $expectedTarget = [string]$ExpectedFinal.$selectionKey
        $expectedDownCount = switch -CaseSensitive ($selectionKey) {
            'colorTheme' { @('system', 'light', 'dark').IndexOf($expectedTarget); break }
            'viewMode' { @('automatic', 'compact', 'cards').IndexOf($expectedTarget); break }
            'startWorkspace' {
                @('stockCut', 'lastWorkspace').IndexOf($expectedTarget); break
            }
        }
        if ([string]$selection.appearanceKey -cne $selectionKey -or
            [string]$selection.targetValue -cne $expectedTarget -or
            $selection.trustedChange -ne $true -or
            [int]$selection.physicalKeyCounts.home -ne 1 -or
            [int]$selection.physicalKeyCounts.arrowDown -ne $expectedDownCount -or
            [int]$selection.physicalKeyCounts.enter -ne 1 -or
            [int]$selection.physicalKeyCounts.total -ne (2 + $expectedDownCount) -or
            [int]$selection.outboundIntentCount -ne 1 -or
            $selection.restartRequired -ne $false) {
            Throw-SafeFailure 'An appearance selection lacks trusted physical input evidence.'
        }
    }
    $phaseExchanges = @($value.exchanges)
    for ($exchangeIndex = 0;
        $exchangeIndex -lt $phaseExchanges.Count;
        $exchangeIndex++) {
        $exchange = $phaseExchanges[$exchangeIndex]
        if ($exchange.physicalInput.pointerDown.isTrusted -ne $true -or
            $exchange.physicalInput.pointerUp.isTrusted -ne $true -or
            [string]$exchange.physicalInput.pointerDown.pointerType -cne 'mouse' -or
            [string]$exchange.physicalInput.pointerUp.pointerType -cne 'mouse') {
            Throw-SafeFailure 'An appearance exchange lacks trusted pointer evidence.'
        }
        if ($exchangeIndex -gt 0) {
            $selection = $value.selections[$exchangeIndex - 1]
            if ($exchange.physicalInput.change.isTrusted -ne $true -or
                [string]$exchange.physicalInput.change.type -cne 'change' -or
                [string]$exchange.physicalInput.change.value -cne
                    [string]$selection.targetValue -or
                [int]$exchange.physicalKeyCounts.home -ne
                    [int]$selection.physicalKeyCounts.home -or
                [int]$exchange.physicalKeyCounts.arrowDown -ne
                    [int]$selection.physicalKeyCounts.arrowDown -or
                [int]$exchange.physicalKeyCounts.enter -ne
                    [int]$selection.physicalKeyCounts.enter) {
                Throw-SafeFailure 'An appearance exchange lacks its trusted change/key seal.'
            }
        }
    }
    $screenshot = Get-Item -LiteralPath $ScreenshotPath -Force
    if ($screenshot.PSIsContainer -or
        ($screenshot.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
        $screenshot.Length -le 0 -or
        [int64]$value.screenshot.bytes -ne $screenshot.Length -or
        [string]$value.screenshot.sha256 -cne
            (Get-FileHash -Algorithm SHA256 -LiteralPath $ScreenshotPath).Hash) {
        Throw-SafeFailure 'The appearance phase screenshot is not sealed exactly.'
    }
    return [pscustomobject]@{
        Value = $value
        Sha256 = $sealed.Sha256
        ScreenshotSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $ScreenshotPath).Hash
    }
}

function Start-ExactAppearanceApplication(
    [pscustomobject]$Registration,
    [int]$LaunchOrdinal) {
    if ($LaunchOrdinal -notin @(1, 2)) {
        Throw-SafeFailure 'The appearance launch ordinal is outside its two-launch budget.'
    }
    Assert-NoExistingApplication
    Assert-PortIsFree $Port
    $application = Start-PackagedDryRunApplication $Registration $Port
    [void](Wait-ExactLoopbackListener `
        $Port `
        $application `
        ([datetime]::UtcNow.AddSeconds($LaunchTimeoutSeconds)))
    Assert-NoTornadoConnection $application.Id
    Wait-StartupIntroDismissed $application $Registration.Executable
    $script:ApplicationProcess = $application
    $script:ApplicationWasLaunched = $true
    $script:CurrentApplicationClosed = $false
    return $application
}

function Close-ExactAppearanceApplication(
    [Diagnostics.Process]$Application,
    [string]$ExpectedPath) {
    if ($script:CloseMainWindowCalls -ne 0 -or $script:PrimaryInvokeCalls -ne 0) {
        Throw-SafeFailure 'The per-launch normal-close budget was not reset.'
    }
    Invoke-ExactNormalClose $Application $ExpectedPath
    Wait-PortReleased $Port ([datetime]::UtcNow.AddSeconds(15))
    if (@(Get-LegacyApplicationProcesses).Count -ne 0 -or
        $script:CloseMainWindowCalls -ne 1 -or $script:PrimaryInvokeCalls -ne 1) {
        Throw-SafeFailure 'The exact appearance package did not complete one normal close.'
    }
    $script:CurrentApplicationClosed = $true
    $script:ApplicationWasLaunched = $false
    $script:CloseMainWindowCalls = 0
    $script:PrimaryInvokeCalls = 0
}

function Write-FinalAppearanceEvidence([string]$Path, [object]$Value) {
    $bytes = $Utf8.GetBytes(($Value | ConvertTo-Json -Depth 10) + "`n")
    $stream = [IO.FileStream]::new(
        $Path,
        [IO.FileMode]::CreateNew,
        [IO.FileAccess]::Write,
        [IO.FileShare]::None)
    try {
        $stream.Write($bytes, 0, $bytes.Length)
        $stream.Flush($true)
    }
    finally { $stream.Dispose() }
}

if ($StaticAudit) {
    [pscustomobject][ordered]@{
        result = 'PASS'
        profile = 'operator-appearance-persistence'
        packageFlavor = 'DebugAppX'
        launchCount = 2
        phaseCount = 2
        physicalSettingsClickCount = 2
        physicalSelectCount = 6
        inputRetryCount = 0
        rawBaselineRecovery = $true
        packageForceTerminationAllowed = $false
        sendInputClickAvailable = $null -ne
            [LegacyPackageInputNative].GetMethod('SendApplicationClick')
        sendInputSelectKeysAvailable = $null -ne
            [LegacyAppearanceInputNative].GetMethod('SendClosedSelectKeys')
        inputStructureBytes = [LegacyAppearanceInputNative]::InputStructureBytes()
        expectedInputStructureBytes =
            [LegacyAppearanceInputNative]::ExpectedInputStructureBytes()
        inputStructureSizeValidated =
            [LegacyAppearanceInputNative]::InputStructureBytes() -eq
                [LegacyAppearanceInputNative]::ExpectedInputStructureBytes()
        harnessPath = $HarnessPath
        harnessSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $HarnessPath).Hash
    } | ConvertTo-Json -Compress
    return
}

$timestamp = [datetime]::UtcNow.ToString('yyyyMMddTHHmmssfffZ')
$Output = Resolve-EvidencePath $Output "legacy-package-appearance-$timestamp.json"
$Screenshot = Resolve-EvidencePath $Screenshot "legacy-package-appearance-$timestamp.png"
if ([string]::IsNullOrWhiteSpace($ExchangeDirectory)) {
    $ExchangeDirectory = Join-Path `
        ([IO.Path]::GetDirectoryName($Output)) `
        ([IO.Path]::GetFileNameWithoutExtension($Output) + '.exchanges')
}
elseif ([IO.Path]::IsPathRooted($ExchangeDirectory)) {
    $ExchangeDirectory = [IO.Path]::GetFullPath($ExchangeDirectory)
}
else {
    $ExchangeDirectory = [IO.Path]::GetFullPath((Join-Path $RepositoryRoot $ExchangeDirectory))
}
$NodePath = Resolve-NodeExecutable $NodePath

$phaseOneDirectory = Join-Path $ExchangeDirectory 'phase-01-input'
$phaseTwoDirectory = Join-Path $ExchangeDirectory 'phase-02-input'
$phaseOneOutput = Join-Path $ExchangeDirectory 'phase-01.json'
$phaseTwoOutput = Join-Path $ExchangeDirectory 'phase-02.json'
$phaseOneScreenshot = Join-Path $ExchangeDirectory 'phase-01.png'
$recoveryPath = Join-Path $ExchangeDirectory '.operator-settings-baseline.recovery'

try {
    if (-not [IO.File]::Exists($HarnessPath)) {
        Throw-SafeFailure 'The tracked appearance harness is missing.'
    }
    Assert-OutputPathAvailable $Output 'Output'
    Assert-OutputPathAvailable $Screenshot 'Screenshot'
    Assert-OutputPathAvailable $ExchangeDirectory 'Exchange directory'
    [void][IO.Directory]::CreateDirectory($ExchangeDirectory)
    [void][IO.Directory]::CreateDirectory($phaseOneDirectory)
    [void][IO.Directory]::CreateDirectory($phaseTwoDirectory)
    if (@(Get-ChildItem -LiteralPath $phaseOneDirectory -Force).Count -ne 0 -or
        @(Get-ChildItem -LiteralPath $phaseTwoDirectory -Force).Count -ne 0) {
        Throw-SafeFailure 'A new appearance exchange directory is not empty.'
    }

    Assert-LocalConfigurationIsDryRun
    Assert-NoUnsafeEnvironment
    $registration = Get-ExactDevelopmentPackage
    Assert-NoExistingApplication
    Assert-PortIsFree $Port
    Initialize-ExactBaselineRecovery $recoveryPath
    $baselineAppearance = $script:BaselineSettingsState.appearance
    $alternateAppearance = Get-AlternateAppearance $baselineAppearance

    $script:Phase = 'first package launch and physical mutation'
    $firstApplication = Start-ExactAppearanceApplication $registration 1
    $firstProcessId = $firstApplication.Id
    $firstHarness = Invoke-AppearanceHarnessUnderWatch `
        'mutate' `
        $baselineAppearance `
        $alternateAppearance `
        $phaseOneOutput `
        $phaseOneScreenshot `
        $phaseOneDirectory `
        $firstApplication `
        $registration.Executable
    $firstEvidence = Read-AppearancePhaseEvidence `
        $phaseOneOutput `
        $phaseOneScreenshot `
        'mutate' `
        $baselineAppearance `
        $alternateAppearance
    $mutatedSettings = Get-OperatorSettingsFileState
    if ($mutatedSettings.schemaVersion -ne 2 -or
        [string]$mutatedSettings.contextSha256 -cne
            [string]$script:BaselineSettingsState.contextSha256 -or
        -not (Test-AppearanceEqual $mutatedSettings.appearance $alternateAppearance)) {
        Throw-SafeFailure 'The alternate appearance was not persisted before relaunch.'
    }

    $script:Phase = 'first normal close'
    Close-ExactAppearanceApplication $firstApplication $registration.Executable

    $script:Phase = 'second package launch and physical restoration'
    $secondApplication = Start-ExactAppearanceApplication $registration 2
    $secondProcessId = $secondApplication.Id
    $secondHarness = Invoke-AppearanceHarnessUnderWatch `
        'verify-restore' `
        $alternateAppearance `
        $baselineAppearance `
        $phaseTwoOutput `
        $Screenshot `
        $phaseTwoDirectory `
        $secondApplication `
        $registration.Executable
    $secondEvidence = Read-AppearancePhaseEvidence `
        $phaseTwoOutput `
        $Screenshot `
        'verify-restore' `
        $alternateAppearance `
        $baselineAppearance
    $logicalRestored = Get-OperatorSettingsFileState
    if ($logicalRestored.schemaVersion -ne 2 -or
        [string]$logicalRestored.contextSha256 -cne
            [string]$script:BaselineSettingsState.contextSha256 -or
        -not (Test-AppearanceEqual $logicalRestored.appearance $baselineAppearance)) {
        Throw-SafeFailure 'The baseline appearance was not restored by physical input.'
    }

    $script:Phase = 'second normal close'
    Close-ExactAppearanceApplication $secondApplication $registration.Executable

    $script:Phase = 'exact raw settings restoration'
    $exactRestored = Restore-ExactBaselineSettings
    $script:Phase = 'seal final evidence'
    $finalEvidence = [ordered]@{
        schemaVersion = 1
        profile = 'operator-appearance-persistence'
        result = 'PASS'
        packageFullName = $PackageFullName
        packageMode = $PackageModeLabel
        playoutMode = 'DryRun'
        cdpAddress = '127.0.0.1'
        cdpPort = $Port
        processIds = @($firstProcessId, $secondProcessId)
        launchCount = 2
        normalCloseCount = 2
        tornadoPortConnections = 0
        inputRetryCount = 0
        baseline = [ordered]@{
            existed = [bool]$script:BaselineSettingsState.exists
            sha256 = [string]$script:BaselineSettingsState.sha256
            schemaVersion = [int]$script:BaselineSettingsState.schemaVersion
            contextSha256 = [string]$script:BaselineSettingsState.contextSha256
            appearance = $baselineAppearance
        }
        alternate = $alternateAppearance
        mutation = [ordered]@{
            physicalSelectCount = 3
            exchangeCount = $firstHarness.Exchanges.Count
            phaseEvidence = $phaseOneOutput
            phaseEvidenceSha256 = $firstEvidence.Sha256
            screenshot = $phaseOneScreenshot
            screenshotSha256 = $firstEvidence.ScreenshotSha256
        }
        relaunch = [ordered]@{
            persistedBeforeInput =
                [bool]$secondEvidence.Value.persistenceVerifiedBeforeInput
            physicalRestoreSelectCount = 3
            exchangeCount = $secondHarness.Exchanges.Count
            phaseEvidence = $phaseTwoOutput
            phaseEvidenceSha256 = $secondEvidence.Sha256
        }
        restoration = [ordered]@{
            logicalAppearanceRestored = $true
            exactOriginalBytesRestored = $true
            finalExists = [bool]$exactRestored.exists
            finalSha256 = [string]$exactRestored.sha256
            recoveryCopyRemoved = -not [IO.File]::Exists($recoveryPath)
        }
        screenshot = $Screenshot
        screenshotSha256 = $secondEvidence.ScreenshotSha256
        exchangeDirectory = $ExchangeDirectory
    }
    Write-FinalAppearanceEvidence $Output $finalEvidence
    $script:Phase = 'complete'
    [pscustomobject]@{
        result = 'PASS'
        packageFullName = $PackageFullName
        packageMode = $PackageModeLabel
        playoutMode = 'DryRun'
        launchCount = 2
        physicalSelectCount = 6
        persistenceVerified = $true
        exactOriginalSettingsRestored = $true
        output = $Output
        outputSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $Output).Hash
        screenshot = $Screenshot
        screenshotSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $Screenshot).Hash
        exchangeDirectory = $ExchangeDirectory
    }
}
catch {
    $message = $_.Exception.Message
    $running = $false
    try { $running = @(Get-LegacyApplicationProcesses).Count -gt 0 }
    catch { $running = $false }

    if (-not $running -and $null -ne $script:BaselineSettingsState -and
        -not $script:BaselineRestored -and -not $script:BaselineRestoreAttempted) {
        try { [void](Restore-ExactBaselineSettings) }
        catch {
            Throw-SafeFailure (
                "Appearance smoke stopped during '$($script:Phase)': $message " +
                'The app is closed, but exact settings restoration also failed. ' +
                "Preserve the recovery evidence at '$ExchangeDirectory'.")
        }
    }
    if ($running) {
        Throw-SafeFailure (
            "Appearance smoke stopped during '$($script:Phase)': $message " +
            'The application was intentionally left open; no input retry, close retry, ' +
            'forced termination, or settings-file overwrite was attempted. The exact ' +
            "recovery copy remains under '$ExchangeDirectory'.")
    }
    if ($script:BaselineRestoreAttempted -and -not $script:BaselineRestored) {
        Throw-SafeFailure (
            "Appearance smoke stopped during '$($script:Phase)': $message " +
            'The one-shot settings restoration had an unclear or failed result and was not ' +
            "retried. Preserve the recovery evidence at '$ExchangeDirectory'.")
    }
    throw
}
