param(
    [ValidateSet("Debug", "Release")]
    [string]$Configuration = "Release",

    [string]$Version = "0.1.0-dev",

    [string]$OutputRoot = "",

    [switch]$SkipBuild,

    [switch]$NoZip,

    [switch]$EnableWebRtc,

    [string]$AccountReleaseConfigPath = "",

    [switch]$AllowUnsignedDevelopmentBootstrap,

    [string]$TrustedBuildCacheRoot = "",

    [switch]$AllowTestBuildCacheRoot,

    [switch]$TestMode
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
. (Join-Path $PSScriptRoot "SyncVisionAccountReleaseConfig.ps1")

function New-SyncVisionPackageName {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Version,

        [switch]$AllowUnsignedDevelopmentBootstrap
    )

    $normalized = $Version.Trim()
    if ([string]::IsNullOrWhiteSpace($normalized)) {
        throw "Package version cannot be empty."
    }
    if ($normalized.IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0) {
        throw "Package version contains characters that are invalid in a file name: $Version"
    }

    $suffix = if ($AllowUnsignedDevelopmentBootstrap) {
        "development-unsigned-bootstrap"
    }
    else {
        "development-unsigned"
    }
    return "SyncVision-$normalized-win-x64-$suffix"
}

function Get-SyncVisionPackageMarkerContent {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet("Debug", "Release")]
        [string]$Configuration,

        [switch]$AllowUnsignedDevelopmentBootstrap
    )

    $marker = [ordered]@{
        schema_version = 2
        product = "SyncVision"
        artifact_kind = "development-package"
        platform = "win-x64"
        configuration = $Configuration
        checksum_manifest = "SHA256SUMS.txt"
        publisher_authentication = "none"
        installation_mode = "manual-verification"
        unsigned_development_bootstrap = [bool]$AllowUnsignedDevelopmentBootstrap
    }
    return ($marker | ConvertTo-Json -Depth 3) + "`n"
}

function New-SyncVisionPackageEntry {
    param(
        [string]$Source = "",

        [string]$Content = "",

        [Parameter(Mandatory = $true)]
        [string]$Destination
    )

    [pscustomobject]@{
        Source = $Source
        Content = $Content
        Destination = $Destination
        Generated = [string]::IsNullOrWhiteSpace($Source)
    }
}

function Get-SyncVisionWebRtcRuntimeDllNames {
    return @(
        "datachannel.dll",
        "srtp2.dll",
        "libssl-3-x64.dll",
        "libcrypto-3-x64.dll"
    )
}

function Get-SyncVisionVcRuntimeDllNames {
    return @(
        "vcruntime140.dll",
        "vcruntime140_1.dll",
        "msvcp140.dll",
        "msvcp140_atomic_wait.dll"
    )
}

function Get-SyncVisionTrustedImportRootNames {
    return @(
        "msbuild_current",
        "vc_targets",
        "vs_extensions",
        "webtools_aspire",
        "vc_auxiliary",
        "vc_tools_auxiliary",
        "vc_tools_bin",
        "windows_sdk_design_time",
        "windows_sdk_bin"
    )
}

function Get-SyncVisionDirectoryTreeSha256 {
    param(
        [Parameter(Mandatory = $true)][string]$Root,
        [string[]]$ExcludedTopLevelNames = @(),
        [string[]]$ExcludedRelativePaths = @()
    )

    if (-not (Test-Path -LiteralPath $Root -PathType Container)) {
        throw "Validated tree root was not found: $Root"
    }
    $resolvedRoot = (Resolve-Path -LiteralPath $Root).Path.TrimEnd('\', '/')
    $rootItem = Get-Item -LiteralPath $resolvedRoot -Force
    if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Validated tree root must not be a reparse point: $resolvedRoot"
    }

    $excludedTopLevel = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($name in $ExcludedTopLevelNames) {
        [void]$excludedTopLevel.Add($name)
    }
    $excludedRelative = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    foreach ($path in $ExcludedRelativePaths) {
        [void]$excludedRelative.Add((($path -replace '\\', '/').Trim('/')))
    }

    $records = New-Object "System.Collections.Generic.List[string]"
    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push($resolvedRoot)
    while ($pending.Count -ne 0) {
        foreach ($item in (Get-ChildItem -LiteralPath $pending.Pop() -Force)) {
            $relativePath = $item.FullName.Substring($resolvedRoot.Length).TrimStart([char[]]@('\', '/')) -replace '\\', '/'
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Validated tree contains a reparse point: $($item.FullName)"
            }
            $separatorIndex = $relativePath.IndexOf('/')
            $topLevelName = if ($separatorIndex -lt 0) { $relativePath } else { $relativePath.Substring(0, $separatorIndex) }
            if ($excludedTopLevel.Contains($topLevelName)) {
                continue
            }
            $isExcluded = $excludedRelative.Contains($relativePath)
            if (-not $isExcluded) {
                foreach ($excludedPath in $excludedRelative) {
                    if ($relativePath.StartsWith("$excludedPath/", [StringComparison]::Ordinal)) {
                        $isExcluded = $true
                        break
                    }
                }
            }
            if ($isExcluded) {
                continue
            }
            if ($item.PSIsContainer) {
                $records.Add("D|$relativePath")
                $pending.Push($item.FullName)
                continue
            }
            $hash = (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
            $records.Add("F|$relativePath|$hash")
        }
    }

    $orderedRecords = $records.ToArray()
    [Array]::Sort($orderedRecords, [StringComparer]::Ordinal)
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes(($orderedRecords -join "`n"))
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        return ([BitConverter]::ToString($sha256.ComputeHash($bytes))).Replace("-", "").ToLowerInvariant()
    }
    finally {
        $sha256.Dispose()
    }
}

function Get-SyncVisionRuntimeExecutableNames {
    return @(
        "SyncVisionClient.exe",
        "SyncVisionServer.exe",
        "SyncVisionLauncher.exe",
        "SyncVisionShare.exe",
        "SyncVisionControl.exe",
        "SyncVisionAgentInstaller.exe",
        "SyncVisionAgentService.exe"
    )
}

function Get-SyncVisionPackagePublicExecutableNames {
    return @(
        "SyncVisionControl.exe",
        "SyncVisionServer.exe"
    )
}

function Get-SyncVisionAgentPayloadExecutableNames {
    return @(
        "SyncVisionClient.exe",
        "SyncVisionShare.exe",
        "SyncVisionAgentInstaller.exe",
        "SyncVisionAgentService.exe"
    )
}

function Get-SyncVisionBuildFlavorManifestPath {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RepoRoot,

        [Parameter(Mandatory = $true)]
        [ValidateSet("Debug", "Release")]
        [string]$Configuration
    )

    return Join-Path $RepoRoot "build\x64\$Configuration\SyncVisionBuildFlavor.json"
}

function ConvertTo-SyncVisionCanonicalJson {
    param([Parameter(Mandatory = $true)][object]$Value, [int]$Depth = 10)
    return ((($Value | ConvertTo-Json -Depth $Depth) -replace "`r`n?", "`n") + "`n")
}

function Assert-SyncVisionExactJsonProperties {
    param(
        [Parameter(Mandatory = $true)][object]$Value,
        [Parameter(Mandatory = $true)][AllowEmptyCollection()][string[]]$ExpectedNames,
        [Parameter(Mandatory = $true)][string]$Context
    )
    if ($Value -isnot [pscustomobject]) { throw "$Context must be a JSON object." }
    $actualNames = @($Value.PSObject.Properties | ForEach-Object { $_.Name })
    $matches = $actualNames.Count -eq $ExpectedNames.Count
    if ($matches) {
        foreach ($name in $ExpectedNames) {
            if ($actualNames -cnotcontains $name) { $matches = $false; break }
        }
    }
    if (-not $matches) {
        throw "$Context must contain the exact JSON properties with exact casing: $($ExpectedNames -join ', ')."
    }
}

function Assert-SyncVisionJsonString {
    param([AllowNull()]$Value, [Parameter(Mandatory = $true)][string]$Context)
    if ($Value -isnot [string]) { throw "$Context must be a string." }
}

function Assert-SyncVisionJsonNonEmptyString {
    param([AllowNull()]$Value, [Parameter(Mandatory = $true)][string]$Context)
    Assert-SyncVisionJsonString -Value $Value -Context $Context
    if ([string]::IsNullOrWhiteSpace($Value)) { throw "$Context must not be empty." }
}

function Assert-SyncVisionJsonBoolean {
    param([AllowNull()]$Value, [Parameter(Mandatory = $true)][string]$Context)
    if ($Value -isnot [bool]) { throw "$Context must be a Boolean." }
}

function Assert-SyncVisionJsonSha256 {
    param([AllowNull()]$Value, [Parameter(Mandatory = $true)][string]$Context)
    Assert-SyncVisionJsonString -Value $Value -Context $Context
    if ($Value -cnotmatch '^[0-9a-f]{64}$') { throw "$Context must be a lowercase SHA-256 string." }
}

function ConvertTo-SyncVisionCanonicalToolIdentityModel {
    param([Parameter(Mandatory = $true)][object]$Value, [Parameter(Mandatory = $true)][string]$Context)

    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @(
        "file_name", "file_version", "file_version_raw", "sha256", "signer_thumbprint", "signer_subject") -Context $Context
    foreach ($propertyName in @("file_name", "file_version", "file_version_raw", "signer_thumbprint", "signer_subject")) {
        Assert-SyncVisionJsonString -Value $Value.$propertyName -Context "$Context $propertyName"
    }
    if ([string]$Value.file_version_raw -cnotmatch '^[0-9]+(?:\.[0-9]+){3}$') {
        throw "$Context file_version_raw must be a four-part numeric file version."
    }
    Assert-SyncVisionJsonSha256 -Value $Value.sha256 -Context "$Context sha256"
    if ($Value.signer_thumbprint -cnotmatch '^[0-9A-F]{40}$' -or
        $Value.signer_subject -notmatch '(^|, )O=Microsoft Corporation(,|$)') {
        throw "$Context must identify the reviewed Microsoft Authenticode signer."
    }
    return [pscustomobject]([ordered]@{
            file_name = $Value.file_name
            file_version = $Value.file_version
            file_version_raw = $Value.file_version_raw
            sha256 = $Value.sha256
            signer_thumbprint = $Value.signer_thumbprint
            signer_subject = $Value.signer_subject
        })
}

function ConvertTo-SyncVisionCanonicalMsBuildIdentityModel {
    param([Parameter(Mandatory = $true)][object]$Value, [Parameter(Mandatory = $true)][string]$Context)

    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @(
        "file_name", "relative_path", "pe_machine", "file_version", "file_version_raw", "sha256",
        "signer_thumbprint", "signer_subject") -Context $Context
    $baseIdentity = ConvertTo-SyncVisionCanonicalToolIdentityModel `
        -Value ([pscustomobject]@{
                file_name = $Value.file_name
                file_version = $Value.file_version
                file_version_raw = $Value.file_version_raw
                sha256 = $Value.sha256
                signer_thumbprint = $Value.signer_thumbprint
                signer_subject = $Value.signer_subject
            }) `
        -Context $Context
    Assert-SyncVisionJsonNonEmptyString -Value $Value.relative_path -Context "$Context relative_path"
    Assert-SyncVisionJsonNonEmptyString -Value $Value.pe_machine -Context "$Context pe_machine"
    if ($Value.relative_path -cne "MSBuild/Current/Bin/amd64/MSBuild.exe") {
        throw "$Context relative_path must be the reviewed amd64 MSBuild entry point."
    }
    if ($Value.pe_machine -cne "0x8664") {
        throw "$Context pe_machine must identify AMD64 (0x8664)."
    }
    return [pscustomobject]([ordered]@{
            file_name = $baseIdentity.file_name
            relative_path = $Value.relative_path
            pe_machine = $Value.pe_machine
            file_version = $baseIdentity.file_version
            file_version_raw = $baseIdentity.file_version_raw
            sha256 = $baseIdentity.sha256
            signer_thumbprint = $baseIdentity.signer_thumbprint
            signer_subject = $baseIdentity.signer_subject
        })
}

function ConvertTo-SyncVisionCanonicalRetiredBuildCacheIdentityModel {
    param([Parameter(Mandatory = $true)][object]$Value, [Parameter(Mandatory = $true)][string]$Context)

    $hashNames = @(
        "receipt_sha256", "dependency_lock_sha256", "source_tree_sha256", "output_tree_sha256",
        "build_flavor_manifest_sha256", "webrtc_output_tree_sha256", "webrtc_manifest_sha256")
    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @($hashNames + "legacy_msbuild") -Context $Context
    $model = [ordered]@{}
    foreach ($name in $hashNames) {
        Assert-SyncVisionJsonSha256 -Value $Value.$name -Context "$Context $name"
        $model[$name] = $Value.$name
    }
    $model.legacy_msbuild = ConvertTo-SyncVisionCanonicalToolIdentityModel `
        -Value $Value.legacy_msbuild `
        -Context "$Context legacy_msbuild"
    return [pscustomobject]$model
}

function ConvertTo-SyncVisionCanonicalTreeIdentityModel {
    param(
        [Parameter(Mandatory = $true)][object]$Value,
        [Parameter(Mandatory = $true)][string]$Context
    )

    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @("relative_path", "tree_sha256") -Context $Context
    Assert-SyncVisionJsonNonEmptyString -Value $Value.relative_path -Context "$Context relative_path"
    Assert-SyncVisionJsonSha256 -Value $Value.tree_sha256 -Context "$Context tree_sha256"
    if ([IO.Path]::IsPathRooted($Value.relative_path) -or
        $Value.relative_path -match '(^|/)\.\.(/|$)' -or
        $Value.relative_path -match '\\') {
        throw "$Context relative_path must be a canonical forward-slash relative path."
    }
    return [pscustomobject]([ordered]@{
            relative_path = $Value.relative_path
            tree_sha256 = $Value.tree_sha256
        })
}

function ConvertTo-SyncVisionCanonicalCMakeRuntimeIdentityModel {
    param([Parameter(Mandatory = $true)][object]$Value, [Parameter(Mandatory = $true)][string]$Context)

    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @(
        "relative_path", "executable_relative_path", "tree_sha256") -Context $Context
    foreach ($propertyName in @("relative_path", "executable_relative_path")) {
        Assert-SyncVisionJsonNonEmptyString -Value $Value.$propertyName -Context "$Context $propertyName"
        if ([IO.Path]::IsPathRooted($Value.$propertyName) -or
            $Value.$propertyName -match '(^|/)\.\.(/|$)' -or
            $Value.$propertyName -match '\\') {
            throw "$Context $propertyName must be a canonical forward-slash relative path."
        }
    }
    Assert-SyncVisionJsonSha256 -Value $Value.tree_sha256 -Context "$Context tree_sha256"
    if ($Value.executable_relative_path -cne "bin/cmake.exe") {
        throw "$Context executable_relative_path must be 'bin/cmake.exe'."
    }
    return [pscustomobject]([ordered]@{
            relative_path = $Value.relative_path
            executable_relative_path = $Value.executable_relative_path
            tree_sha256 = $Value.tree_sha256
        })
}

function ConvertTo-SyncVisionCanonicalFileIdentityModel {
    param(
        [Parameter(Mandatory = $true)][object]$Value,
        [Parameter(Mandatory = $true)][string]$Context
    )

    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @("relative_path", "sha256") -Context $Context
    Assert-SyncVisionJsonNonEmptyString -Value $Value.relative_path -Context "$Context relative_path"
    Assert-SyncVisionJsonSha256 -Value $Value.sha256 -Context "$Context sha256"
    if ([IO.Path]::IsPathRooted($Value.relative_path) -or
        $Value.relative_path -match '(^|/)\.\.(/|$)' -or
        $Value.relative_path -match '\\') {
        throw "$Context relative_path must be a canonical forward-slash relative path."
    }
    return [pscustomobject]([ordered]@{
            relative_path = $Value.relative_path
            sha256 = $Value.sha256
        })
}

function ConvertTo-SyncVisionCanonicalDependencyModel {
    param([Parameter(Mandatory = $true)][object]$Value)
    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @(
        "schema_version", "dependency", "version", "source_commit", "architecture", "configuration",
        "features", "cmake_runtime_tree_sha256", "include_relative_path", "include_tree_sha256", "import_library_relative_path",
        "import_library_sha256", "runtime_relative_path", "runtime_dll_sha256", "output_tree_sha256") -Context "WebRTC dependency manifest"
    if ($Value.schema_version -isnot [int] -or $Value.schema_version -ne 4) {
        throw "WebRTC dependency manifest schema_version must be an integer equal to 4."
    }
    foreach ($propertyName in @("dependency", "version", "source_commit", "architecture", "configuration", "include_relative_path", "import_library_relative_path", "runtime_relative_path")) {
        Assert-SyncVisionJsonString -Value $Value.$propertyName -Context "WebRTC dependency manifest $propertyName"
    }
    foreach ($propertyName in @("cmake_runtime_tree_sha256", "include_tree_sha256", "import_library_sha256", "output_tree_sha256")) {
        Assert-SyncVisionJsonSha256 -Value $Value.$propertyName -Context "WebRTC dependency manifest $propertyName"
    }
    Assert-SyncVisionExactJsonProperties -Value $Value.features -ExpectedNames @("media", "srtp", "shared") -Context "WebRTC dependency manifest features"
    foreach ($propertyName in @("media", "srtp", "shared")) {
        Assert-SyncVisionJsonBoolean -Value $Value.features.$propertyName -Context "WebRTC dependency manifest features.$propertyName"
    }
    $runtimeNames = @(Get-SyncVisionWebRtcRuntimeDllNames)
    Assert-SyncVisionExactJsonProperties -Value $Value.runtime_dll_sha256 -ExpectedNames $runtimeNames -Context "WebRTC dependency manifest runtime_dll_sha256"
    $runtimeModel = [ordered]@{}
    foreach ($name in $runtimeNames) {
        $hash = $Value.runtime_dll_sha256.PSObject.Properties[$name].Value
        Assert-SyncVisionJsonSha256 -Value $hash -Context "WebRTC dependency manifest runtime_dll_sha256.$name"
        $runtimeModel[$name] = $hash
    }
    return [pscustomobject]([ordered]@{
            schema_version = $Value.schema_version
            dependency = $Value.dependency
            version = $Value.version
            source_commit = $Value.source_commit
            architecture = $Value.architecture
            configuration = $Value.configuration
            features = [pscustomobject]([ordered]@{ media = $Value.features.media; srtp = $Value.features.srtp; shared = $Value.features.shared })
            cmake_runtime_tree_sha256 = $Value.cmake_runtime_tree_sha256
            include_relative_path = $Value.include_relative_path
            include_tree_sha256 = $Value.include_tree_sha256
            import_library_relative_path = $Value.import_library_relative_path
            import_library_sha256 = $Value.import_library_sha256
            runtime_relative_path = $Value.runtime_relative_path
            runtime_dll_sha256 = [pscustomobject]$runtimeModel
            output_tree_sha256 = $Value.output_tree_sha256
        })
}

function ConvertTo-SyncVisionCanonicalLockModel {
    param([Parameter(Mandatory = $true)][object]$Value)
    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames @(
        "schema_version", "dependency", "version", "source_commit", "source_tree_sha256",
        "architecture", "features", "toolchain", "configurations") -Context "Repository WebRTC dependency lock"
    if ($Value.schema_version -isnot [int] -or $Value.schema_version -ne 4) {
        throw "Repository WebRTC dependency lock schema_version must be an integer equal to 4."
    }
    foreach ($propertyName in @("dependency", "version", "source_commit", "architecture")) {
        Assert-SyncVisionJsonString -Value $Value.$propertyName -Context "Repository WebRTC dependency lock $propertyName"
    }
    Assert-SyncVisionJsonSha256 -Value $Value.source_tree_sha256 -Context "Repository WebRTC dependency lock source_tree_sha256"
    Assert-SyncVisionExactJsonProperties -Value $Value.features -ExpectedNames @("media", "srtp", "shared") -Context "Repository WebRTC dependency lock features"
    foreach ($propertyName in @("media", "srtp", "shared")) {
        Assert-SyncVisionJsonBoolean -Value $Value.features.$propertyName -Context "Repository WebRTC dependency lock features.$propertyName"
    }
    Assert-SyncVisionExactJsonProperties -Value $Value.toolchain -ExpectedNames @(
        "vcpkg_commit", "vcpkg_triplet", "vcpkg_toolchain_tree_sha256", "vcpkg_installed_tree_sha256",
        "cmake_generator", "visual_studio_installation_version", "vc_tools_version", "windows_sdk_version",
        "import_roots", "framework_xaml", "cmake_runtime", "vswhere", "cmake", "msbuild", "webtools_aspire_msbuild", "cl", "link", "cmd", "powershell") -Context "Repository WebRTC dependency lock toolchain"
    foreach ($propertyName in @("vcpkg_commit", "vcpkg_triplet", "cmake_generator", "visual_studio_installation_version", "vc_tools_version", "windows_sdk_version")) {
        Assert-SyncVisionJsonString -Value $Value.toolchain.$propertyName -Context "Repository WebRTC dependency lock toolchain.$propertyName"
    }
    foreach ($propertyName in @("vcpkg_toolchain_tree_sha256", "vcpkg_installed_tree_sha256")) {
        Assert-SyncVisionJsonSha256 -Value $Value.toolchain.$propertyName -Context "Repository WebRTC dependency lock toolchain.$propertyName"
    }
    $toolchainModel = [ordered]@{
        vcpkg_commit = $Value.toolchain.vcpkg_commit
        vcpkg_triplet = $Value.toolchain.vcpkg_triplet
        vcpkg_toolchain_tree_sha256 = $Value.toolchain.vcpkg_toolchain_tree_sha256
        vcpkg_installed_tree_sha256 = $Value.toolchain.vcpkg_installed_tree_sha256
        cmake_generator = $Value.toolchain.cmake_generator
        visual_studio_installation_version = $Value.toolchain.visual_studio_installation_version
        vc_tools_version = $Value.toolchain.vc_tools_version
        windows_sdk_version = $Value.toolchain.windows_sdk_version
    }
    $importRootNames = @(Get-SyncVisionTrustedImportRootNames)
    Assert-SyncVisionExactJsonProperties -Value $Value.toolchain.import_roots -ExpectedNames $importRootNames -Context "Repository WebRTC dependency lock toolchain.import_roots"
    $importRootModel = [ordered]@{}
    foreach ($rootName in $importRootNames) {
        $importRootModel[$rootName] = ConvertTo-SyncVisionCanonicalTreeIdentityModel `
            -Value $Value.toolchain.import_roots.$rootName `
            -Context "Repository WebRTC dependency lock toolchain.import_roots.$rootName"
    }
    $toolchainModel.import_roots = [pscustomobject]$importRootModel
    $toolchainModel.framework_xaml = ConvertTo-SyncVisionCanonicalFileIdentityModel `
        -Value $Value.toolchain.framework_xaml `
        -Context "Repository WebRTC dependency lock toolchain.framework_xaml"
    $toolchainModel.cmake_runtime = ConvertTo-SyncVisionCanonicalCMakeRuntimeIdentityModel `
        -Value $Value.toolchain.cmake_runtime `
        -Context "Repository WebRTC dependency lock toolchain.cmake_runtime"
    foreach ($toolName in @("vswhere", "cmake")) {
        $toolchainModel[$toolName] = ConvertTo-SyncVisionCanonicalToolIdentityModel -Value $Value.toolchain.$toolName -Context "Repository WebRTC dependency lock toolchain.$toolName"
    }
    $toolchainModel.msbuild = ConvertTo-SyncVisionCanonicalMsBuildIdentityModel `
        -Value $Value.toolchain.msbuild `
        -Context "Repository WebRTC dependency lock toolchain.msbuild"
    $toolchainModel.webtools_aspire_msbuild = ConvertTo-SyncVisionCanonicalToolIdentityModel `
        -Value $Value.toolchain.webtools_aspire_msbuild `
        -Context "Repository WebRTC dependency lock toolchain.webtools_aspire_msbuild"
    foreach ($toolName in @("cl", "link", "cmd", "powershell")) {
        $toolchainModel[$toolName] = ConvertTo-SyncVisionCanonicalToolIdentityModel -Value $Value.toolchain.$toolName -Context "Repository WebRTC dependency lock toolchain.$toolName"
    }
    Assert-SyncVisionExactJsonProperties -Value $Value.configurations -ExpectedNames @("Debug", "Release") -Context "Repository WebRTC dependency lock configurations"
    $configurationModel = [ordered]@{}
    foreach ($configurationName in @("Debug", "Release")) {
        $entry = $Value.configurations.PSObject.Properties[$configurationName].Value
        Assert-SyncVisionExactJsonProperties -Value $entry -ExpectedNames @(
            "configuration", "include_relative_path", "include_tree_sha256", "import_library_relative_path",
            "import_library_sha256", "runtime_relative_path", "runtime_dll_sha256", "output_tree_sha256",
            "rollback_previous_output_tree_sha256", "rollback_previous_manifest_sha256",
            "retired_build_cache_identities") -Context "Repository WebRTC dependency lock $configurationName entry"
        foreach ($propertyName in @("configuration", "include_relative_path", "import_library_relative_path", "runtime_relative_path")) {
            Assert-SyncVisionJsonString -Value $entry.$propertyName -Context "Repository WebRTC dependency lock $configurationName.$propertyName"
        }
        foreach ($propertyName in @("include_tree_sha256", "import_library_sha256", "output_tree_sha256", "rollback_previous_output_tree_sha256", "rollback_previous_manifest_sha256")) {
            Assert-SyncVisionJsonSha256 -Value $entry.$propertyName -Context "Repository WebRTC dependency lock $configurationName.$propertyName"
        }
        $runtimeNames = @(Get-SyncVisionWebRtcRuntimeDllNames)
        Assert-SyncVisionExactJsonProperties -Value $entry.runtime_dll_sha256 -ExpectedNames $runtimeNames -Context "Repository WebRTC dependency lock $configurationName.runtime_dll_sha256"
        $runtimeModel = [ordered]@{}
        foreach ($name in $runtimeNames) {
            $hash = $entry.runtime_dll_sha256.PSObject.Properties[$name].Value
            Assert-SyncVisionJsonSha256 -Value $hash -Context "Repository WebRTC dependency lock $configurationName.runtime_dll_sha256.$name"
            $runtimeModel[$name] = $hash
        }
        $retiredIdentityModel = @()
        foreach ($identity in @($entry.retired_build_cache_identities)) {
            $retiredIdentityModel += ConvertTo-SyncVisionCanonicalRetiredBuildCacheIdentityModel `
                -Value $identity `
                -Context "Repository WebRTC dependency lock $configurationName.retired_build_cache_identities"
        }
        if (($configurationName -ceq "Debug" -and $retiredIdentityModel.Count -ne 0) -or
            ($configurationName -ceq "Release" -and $retiredIdentityModel.Count -ne 1)) {
            throw "Repository WebRTC dependency lock must contain no Debug retirement identity and exactly one Release retirement identity."
        }
        $configurationModel[$configurationName] = [pscustomobject]([ordered]@{
                configuration = $entry.configuration
                include_relative_path = $entry.include_relative_path
                include_tree_sha256 = $entry.include_tree_sha256
                import_library_relative_path = $entry.import_library_relative_path
                import_library_sha256 = $entry.import_library_sha256
                runtime_relative_path = $entry.runtime_relative_path
                runtime_dll_sha256 = [pscustomobject]$runtimeModel
                output_tree_sha256 = $entry.output_tree_sha256
                rollback_previous_output_tree_sha256 = $entry.rollback_previous_output_tree_sha256
                rollback_previous_manifest_sha256 = $entry.rollback_previous_manifest_sha256
                retired_build_cache_identities = @($retiredIdentityModel)
            })
    }
    return [pscustomobject]([ordered]@{
            schema_version = $Value.schema_version
            dependency = $Value.dependency
            version = $Value.version
            source_commit = $Value.source_commit
            source_tree_sha256 = $Value.source_tree_sha256
            architecture = $Value.architecture
            features = [pscustomobject]([ordered]@{ media = $Value.features.media; srtp = $Value.features.srtp; shared = $Value.features.shared })
            toolchain = [pscustomobject]$toolchainModel
            configurations = [pscustomobject]$configurationModel
        })
}

function ConvertTo-SyncVisionCanonicalBuildFlavorModel {
    param([Parameter(Mandatory = $true)][object]$Value)
    $propertyNames = @(
        "schema_version", "configuration", "architecture", "account_enabled",
        "account_release_config_relative_path", "account_release_config_sha256",
        "webrtc_enabled", "webrtc_prepared_root",
        "webrtc_dependency_manifest_sha256", "webrtc_dependency", "webrtc_dependency_lock_relative_path",
        "webrtc_dependency_lock_sha256", "runtime_dll_sha256", "runtime_exe_sha256")
    if ($Value -isnot [pscustomobject] -or $null -eq $Value.PSObject.Properties["schema_version"]) {
        Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames $propertyNames -Context "Build flavor manifest"
    }
    if ($Value.schema_version -isnot [int] -or $Value.schema_version -ne 5) {
        throw "Unsupported build flavor manifest schema_version '$($Value.schema_version)'; schema_version must be an integer equal to 5."
    }
    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames $propertyNames -Context "Build flavor manifest"
    Assert-SyncVisionJsonString -Value $Value.configuration -Context "Build flavor manifest configuration"
    Assert-SyncVisionJsonString -Value $Value.architecture -Context "Build flavor manifest architecture"
    Assert-SyncVisionJsonBoolean -Value $Value.account_enabled -Context "Build flavor manifest account_enabled"
    Assert-SyncVisionJsonBoolean -Value $Value.webrtc_enabled -Context "Build flavor manifest webrtc_enabled"
    if ($Value.account_enabled) {
        Assert-SyncVisionJsonNonEmptyString -Value $Value.account_release_config_relative_path -Context "Build flavor manifest account_release_config_relative_path"
        Assert-SyncVisionJsonSha256 -Value $Value.account_release_config_sha256 -Context "Build flavor manifest account_release_config_sha256"
        if ((Resolve-SyncVisionAccountReleaseConfigRelativePath `
                -RelativePath $Value.account_release_config_relative_path) -cne
            $Value.account_release_config_relative_path) {
            throw "Build flavor manifest account release config path is invalid."
        }
    }
    elseif ($null -ne $Value.account_release_config_relative_path -or
        $null -ne $Value.account_release_config_sha256) {
        throw "Account-disabled build flavor manifest must not contain account release config identity."
    }
    Assert-SyncVisionExactJsonProperties -Value $Value.runtime_exe_sha256 -ExpectedNames @(Get-SyncVisionRuntimeExecutableNames) -Context "Build flavor manifest runtime_exe_sha256"
    $exeModel = [ordered]@{}
    foreach ($name in (Get-SyncVisionRuntimeExecutableNames)) {
        $hash = $Value.runtime_exe_sha256.PSObject.Properties[$name].Value
        Assert-SyncVisionJsonSha256 -Value $hash -Context "Build flavor manifest runtime_exe_sha256.$name"
        $exeModel[$name] = $hash
    }
    $runtimeModel = [ordered]@{}
    $dependencyModel = $null
    if ($Value.webrtc_enabled) {
        foreach ($propertyName in @("webrtc_prepared_root", "webrtc_dependency_manifest_sha256", "webrtc_dependency_lock_relative_path", "webrtc_dependency_lock_sha256")) {
            Assert-SyncVisionJsonString -Value $Value.$propertyName -Context "Build flavor manifest $propertyName"
        }
        Assert-SyncVisionJsonSha256 -Value $Value.webrtc_dependency_manifest_sha256 -Context "Build flavor manifest webrtc_dependency_manifest_sha256"
        Assert-SyncVisionJsonSha256 -Value $Value.webrtc_dependency_lock_sha256 -Context "Build flavor manifest webrtc_dependency_lock_sha256"
        $dependencyModel = ConvertTo-SyncVisionCanonicalDependencyModel -Value $Value.webrtc_dependency
        $runtimeNames = @(Get-SyncVisionWebRtcRuntimeDllNames)
        Assert-SyncVisionExactJsonProperties -Value $Value.runtime_dll_sha256 -ExpectedNames $runtimeNames -Context "Build flavor manifest runtime_dll_sha256"
        foreach ($name in $runtimeNames) {
            $hash = $Value.runtime_dll_sha256.PSObject.Properties[$name].Value
            Assert-SyncVisionJsonSha256 -Value $hash -Context "Build flavor manifest runtime_dll_sha256.$name"
            $runtimeModel[$name] = $hash
        }
    }
    else {
        Assert-SyncVisionExactJsonProperties -Value $Value.runtime_dll_sha256 -ExpectedNames @() -Context "Build flavor manifest runtime_dll_sha256"
        foreach ($propertyName in @("webrtc_prepared_root", "webrtc_dependency_manifest_sha256", "webrtc_dependency", "webrtc_dependency_lock_relative_path", "webrtc_dependency_lock_sha256")) {
            if ($null -ne $Value.$propertyName) { throw "Default build flavor manifest $propertyName must be null." }
        }
    }
    return [pscustomobject]([ordered]@{
            schema_version = $Value.schema_version
            configuration = $Value.configuration
            architecture = $Value.architecture
            account_enabled = $Value.account_enabled
            account_release_config_relative_path = $Value.account_release_config_relative_path
            account_release_config_sha256 = $Value.account_release_config_sha256
            webrtc_enabled = $Value.webrtc_enabled
            webrtc_prepared_root = $Value.webrtc_prepared_root
            webrtc_dependency_manifest_sha256 = $Value.webrtc_dependency_manifest_sha256
            webrtc_dependency = $dependencyModel
            webrtc_dependency_lock_relative_path = $Value.webrtc_dependency_lock_relative_path
            webrtc_dependency_lock_sha256 = $Value.webrtc_dependency_lock_sha256
            runtime_dll_sha256 = [pscustomobject]$runtimeModel
            runtime_exe_sha256 = [pscustomobject]$exeModel
        })
}

function Read-SyncVisionCanonicalJsonFile {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Description,
        [Parameter(Mandatory = $true)][scriptblock]$ModelBuilder
    )
    $raw = Get-Content -LiteralPath $Path -Raw
    try { $parsed = $raw | ConvertFrom-Json }
    catch { throw "$Description is not valid JSON: $Path. $($_.Exception.Message)" }
    $model = & $ModelBuilder $parsed
    if (($raw -replace "`r`n?", "`n") -cne (ConvertTo-SyncVisionCanonicalJson -Value $model -Depth 10)) {
        throw "$Description is not canonical JSON: $Path. Property order, casing, whitespace, and duplicate keys must match the deterministic writer."
    }
    return $model
}

function Read-SyncVisionPreparedDependencyManifest {
    param([Parameter(Mandatory = $true)][string]$Path)
    return Read-SyncVisionCanonicalJsonFile -Path $Path -Description "Prepared WebRTC dependency manifest" -ModelBuilder {
        param($value)
        ConvertTo-SyncVisionCanonicalDependencyModel -Value $value
    }
}

function Read-SyncVisionWebRtcDependencyLock {
    param(
        [Parameter(Mandatory = $true)][string]$RepoRoot,
        [Parameter(Mandatory = $true)][ValidateSet("Debug", "Release")][string]$Configuration
    )

    $relativePath = "msbuild/SyncVisionWebRtcDependency.lock.json"
    $lockPath = Join-Path $RepoRoot ($relativePath -replace '/', '\')
    if (-not (Test-Path -LiteralPath $lockPath -PathType Leaf)) {
        throw "Repository WebRTC dependency lock was not found: $lockPath"
    }
    $lock = Read-SyncVisionCanonicalJsonFile -Path $lockPath -Description "Repository WebRTC dependency lock" -ModelBuilder {
        param($value)
        ConvertTo-SyncVisionCanonicalLockModel -Value $value
    }
    $entry = $lock.configurations.PSObject.Properties[$Configuration].Value
    if ($null -eq $lock -or
        $lock.schema_version -ne 4 -or
        $lock.dependency -cne "libdatachannel" -or
        $lock.version -cne "0.24.5" -or
        $lock.source_commit -cne "188ec93f6a0b01c2032ddb4c8c013118f7f30232" -or
        $lock.toolchain.vcpkg_commit -cne "4f8fe05871555c1798dbcb1957d0d595e94f7b57" -or
        $lock.architecture -cne "x64" -or
        $lock.features.media -ne $true -or
        $lock.features.srtp -ne $true -or
        $lock.features.shared -ne $true -or
        $null -eq $entry -or
        $entry.configuration -cne $Configuration) {
        throw "Repository WebRTC dependency lock does not contain the approved libdatachannel 0.24.5 $Configuration x64 media/SRTP/shared entry: $lockPath"
    }
    return [pscustomobject]@{
        Lock = $lock
        Entry = $entry
        Path = $lockPath
        RelativePath = $relativePath
        Sha256 = (Get-FileHash -LiteralPath $lockPath -Algorithm SHA256).Hash.ToLowerInvariant()
    }
}

function Assert-SyncVisionDependencySnapshotMatchesLock {
    param(
        [Parameter(Mandatory = $true)][object]$Dependency,
        [Parameter(Mandatory = $true)][object]$Approved,
        [Parameter(Mandatory = $true)][ValidateSet("Debug", "Release")][string]$Configuration
    )

    $lock = $Approved.Lock
    $entry = $Approved.Entry
    $requiredDllNames = @(Get-SyncVisionWebRtcRuntimeDllNames)
    $dependencyDllNames = @($Dependency.runtime_dll_sha256.PSObject.Properties.Name)
    $lockDllNames = @($entry.runtime_dll_sha256.PSObject.Properties.Name)
    $matches = $Dependency.schema_version -eq 4 -and
        $Dependency.dependency -ceq $lock.dependency -and
        $Dependency.version -ceq $lock.version -and
        $Dependency.source_commit -ceq $lock.source_commit -and
        $Dependency.architecture -ceq $lock.architecture -and
        $Dependency.configuration -ceq $Configuration -and
        $Dependency.features.media -eq $lock.features.media -and
        $Dependency.features.srtp -eq $lock.features.srtp -and
        $Dependency.features.shared -eq $lock.features.shared -and
        $Dependency.cmake_runtime_tree_sha256 -ceq $lock.toolchain.cmake_runtime.tree_sha256 -and
        $Dependency.include_relative_path -ceq $entry.include_relative_path -and
        $Dependency.include_tree_sha256 -ceq $entry.include_tree_sha256 -and
        $Dependency.import_library_relative_path -ceq $entry.import_library_relative_path -and
        $Dependency.import_library_sha256 -ceq $entry.import_library_sha256 -and
        $Dependency.runtime_relative_path -ceq $entry.runtime_relative_path -and
        $Dependency.output_tree_sha256 -ceq $entry.output_tree_sha256 -and
        $dependencyDllNames.Count -eq $requiredDllNames.Count -and
        $lockDllNames.Count -eq $requiredDllNames.Count -and
        @(Compare-Object -ReferenceObject $requiredDllNames -DifferenceObject $dependencyDllNames).Count -eq 0 -and
        @(Compare-Object -ReferenceObject $requiredDllNames -DifferenceObject $lockDllNames).Count -eq 0
    if ($matches) {
        foreach ($name in $requiredDllNames) {
            if ([string]$Dependency.runtime_dll_sha256.PSObject.Properties[$name].Value -cne
                [string]$entry.runtime_dll_sha256.PSObject.Properties[$name].Value) {
                $matches = $false
                break
            }
        }
    }
    if (-not $matches) {
        throw "WebRTC dependency snapshot does not match the approved $Configuration repository lock entry."
    }
}

function Assert-SyncVisionBuildFlavorManifest {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RepoRoot,

        [Parameter(Mandatory = $true)]
        [ValidateSet("Debug", "Release")]
        [string]$Configuration,

        [switch]$EnableWebRtc,

        [string]$TrustedWebRtcRoot = "",

        [string]$ExpectedRecordedWebRtcRoot = ""
    )

    $manifestPath = Get-SyncVisionBuildFlavorManifestPath -RepoRoot $RepoRoot -Configuration $Configuration
    if (-not (Test-Path -LiteralPath $manifestPath -PathType Leaf)) {
        throw "Build flavor manifest was not found: $manifestPath. Run scripts\build.ps1 for the requested configuration and flavor before packaging."
    }

    $manifest = Read-SyncVisionCanonicalJsonFile -Path $manifestPath -Description "Build flavor manifest" -ModelBuilder {
        param($value)
        ConvertTo-SyncVisionCanonicalBuildFlavorModel -Value $value
    }
    if ($null -eq $manifest) {
        throw "Build flavor manifest is empty: $manifestPath"
    }

    if ($null -eq $manifest.PSObject.Properties["schema_version"]) {
        throw "Build flavor manifest is missing required property 'schema_version': $manifestPath"
    }
    if ($manifest.schema_version -isnot [int] -or $manifest.schema_version -ne 5) {
        throw "Unsupported build flavor manifest schema_version '$($manifest.schema_version)': $manifestPath"
    }

    $requiredPropertyNames = @(
        "configuration",
        "architecture",
        "account_enabled",
        "account_release_config_relative_path",
        "account_release_config_sha256",
        "webrtc_enabled",
        "webrtc_prepared_root",
        "webrtc_dependency_manifest_sha256",
        "webrtc_dependency",
        "webrtc_dependency_lock_relative_path",
        "webrtc_dependency_lock_sha256",
        "runtime_dll_sha256",
        "runtime_exe_sha256"
    )
    foreach ($propertyName in $requiredPropertyNames) {
        if ($null -eq $manifest.PSObject.Properties[$propertyName]) {
            throw "Build flavor manifest is missing required property '$propertyName': $manifestPath"
        }
    }
    if ($manifest.configuration -isnot [string] -or $manifest.configuration -cne $Configuration) {
        throw "Build flavor configuration mismatch: requested '$Configuration', manifest records '$($manifest.configuration)'."
    }
    if ($manifest.architecture -cne "x64") {
        throw "Build flavor architecture mismatch: expected 'x64', manifest records '$($manifest.architecture)'."
    }
    if ($manifest.account_enabled -ne $true) {
        throw "Release packaging requires an account-enabled build flavor. Rebuild with -AccountReleaseConfigPath."
    }
    $accountConfig = Read-SyncVisionAccountReleaseConfig `
        -RepoRoot $RepoRoot `
        -RelativePath $manifest.account_release_config_relative_path
    if ($accountConfig.Sha256 -cne $manifest.account_release_config_sha256) {
        throw "Build flavor account release config hash mismatch. Rebuild before packaging."
    }
    if ($manifest.webrtc_enabled -isnot [bool]) {
        throw "Build flavor manifest property 'webrtc_enabled' must be a Boolean: $manifestPath"
    }
    if ($EnableWebRtc -and -not $manifest.webrtc_enabled) {
        throw "Build flavor mismatch: requested WebRTC packaging, but the manifest records WebRTC disabled."
    }
    if (-not $EnableWebRtc -and $manifest.webrtc_enabled) {
        throw "Build flavor mismatch: requested default packaging, but the manifest records WebRTC enabled."
    }
    if ($null -eq $manifest.runtime_dll_sha256 -or $manifest.runtime_dll_sha256 -isnot [pscustomobject]) {
        throw "Build flavor manifest property 'runtime_dll_sha256' must be a JSON object: $manifestPath"
    }
    if ($null -eq $manifest.runtime_exe_sha256 -or $manifest.runtime_exe_sha256 -isnot [pscustomobject]) {
        throw "Build flavor manifest property 'runtime_exe_sha256' must be a JSON object: $manifestPath"
    }

    $outputDir = Join-Path $RepoRoot "build\x64\$Configuration"
    $requiredExeNames = @(Get-SyncVisionRuntimeExecutableNames)
    $exeHashProperties = @($manifest.runtime_exe_sha256.PSObject.Properties)
    $recordedExeNames = @($exeHashProperties | ForEach-Object { $_.Name })
    $exeHashNameDifferences = @(Compare-Object -ReferenceObject $requiredExeNames -DifferenceObject $recordedExeNames)
    if ($exeHashProperties.Count -ne $requiredExeNames.Count -or $exeHashNameDifferences.Count -ne 0) {
        throw "Build flavor manifest must record SHA-256 for exactly these runtime EXEs: $($requiredExeNames -join ', ')."
    }

    foreach ($name in $requiredExeNames) {
        $recordedHash = [string]$manifest.runtime_exe_sha256.PSObject.Properties[$name].Value
        if ($recordedHash -notmatch '^[0-9a-fA-F]{64}$') {
            throw "Build flavor manifest has an invalid SHA-256 for runtime EXE '$name'."
        }

        $executablePath = Join-Path $outputDir $name
        if (-not (Test-Path -LiteralPath $executablePath -PathType Leaf)) {
            throw "Required SyncVision executable was not found for packaging: $executablePath"
        }
        $actualHash = (Get-FileHash -LiteralPath $executablePath -Algorithm SHA256).Hash
        if (-not [string]::Equals($recordedHash, $actualHash, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Build flavor runtime EXE hash mismatch: $name"
        }
    }

    $hashProperties = @($manifest.runtime_dll_sha256.PSObject.Properties)
    if (-not $EnableWebRtc) {
        if ($hashProperties.Count -ne 0) {
            throw "Default build flavor manifest must not record WebRTC runtime DLL hashes: $manifestPath"
        }
        if ($null -ne $manifest.webrtc_prepared_root -or
            $null -ne $manifest.webrtc_dependency_manifest_sha256 -or
            $null -ne $manifest.webrtc_dependency -or
            $null -ne $manifest.webrtc_dependency_lock_relative_path -or
            $null -ne $manifest.webrtc_dependency_lock_sha256) {
            throw "Default build flavor manifest must record null WebRTC dependency provenance: $manifestPath"
        }
        return $manifest
    }

    if ($manifest.webrtc_prepared_root -isnot [string] -or
        [string]::IsNullOrWhiteSpace($manifest.webrtc_prepared_root) -or
        -not [IO.Path]::IsPathRooted($manifest.webrtc_prepared_root)) {
        throw "WebRTC build flavor manifest property 'webrtc_prepared_root' must be an absolute path: $manifestPath"
    }
    if (-not [string]::IsNullOrWhiteSpace($ExpectedRecordedWebRtcRoot) -and
        -not [string]::Equals(
            [IO.Path]::GetFullPath($manifest.webrtc_prepared_root).TrimEnd('\', '/'),
            [IO.Path]::GetFullPath($ExpectedRecordedWebRtcRoot).TrimEnd('\', '/'),
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "WebRTC build flavor recorded a prepared root outside the trusted cache publication."
    }
    if ($manifest.webrtc_dependency_manifest_sha256 -notmatch '^[0-9a-fA-F]{64}$') {
        throw "WebRTC build flavor manifest has an invalid dependency manifest SHA-256: $manifestPath"
    }
    if ($null -eq $manifest.webrtc_dependency -or $manifest.webrtc_dependency -isnot [pscustomobject]) {
        throw "WebRTC build flavor manifest property 'webrtc_dependency' must be a JSON object: $manifestPath"
    }
    $dependency = $manifest.webrtc_dependency
    $expectedLockRelativePath = "msbuild/SyncVisionWebRtcDependency.lock.json"
    $expectedLockPath = Join-Path $RepoRoot ($expectedLockRelativePath -replace '/', '\')
    if ($manifest.webrtc_dependency_lock_relative_path -cne $expectedLockRelativePath) {
        throw "WebRTC build flavor repository lock path mismatch: expected '$expectedLockRelativePath', manifest records '$($manifest.webrtc_dependency_lock_relative_path)'."
    }
    if ($manifest.webrtc_dependency_lock_sha256 -notmatch '^[0-9a-fA-F]{64}$' -or
        -not [string]::Equals(
            $manifest.webrtc_dependency_lock_sha256,
            (Get-FileHash -LiteralPath $expectedLockPath -Algorithm SHA256).Hash,
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "WebRTC repository lock hash mismatch: $expectedLockPath. Rebuild before packaging; -SkipBuild cannot reuse provenance from different lock bytes."
    }
    $approvedDependency = Read-SyncVisionWebRtcDependencyLock -RepoRoot $RepoRoot -Configuration $Configuration
    Assert-SyncVisionDependencySnapshotMatchesLock `
        -Dependency $dependency `
        -Approved $approvedDependency `
        -Configuration $Configuration
    if ($dependency.schema_version -ne 4 -or
        $dependency.dependency -cne "libdatachannel" -or
        $dependency.version -cne "0.24.5" -or
        $dependency.source_commit -cne "188ec93f6a0b01c2032ddb4c8c013118f7f30232" -or
        $dependency.architecture -cne "x64" -or
        $dependency.configuration -cne $Configuration -or
        $dependency.features.media -ne $true -or
        $dependency.features.srtp -ne $true -or
        $dependency.features.shared -ne $true) {
        throw "WebRTC dependency snapshot does not match pinned libdatachannel 0.24.5 $Configuration x64 media/SRTP requirements."
    }
    $dependencyRoot = if ([string]::IsNullOrWhiteSpace($TrustedWebRtcRoot)) {
        $manifest.webrtc_prepared_root
    }
    else {
        [IO.Path]::GetFullPath($TrustedWebRtcRoot).TrimEnd('\', '/')
    }
    $dependencyManifestPath = Join-Path $dependencyRoot "SyncVisionWebRtcDependency.json"
    if (-not (Test-Path -LiteralPath $dependencyManifestPath -PathType Leaf)) {
        throw "WebRTC dependency manifest recorded by the build was not found: $dependencyManifestPath"
    }
    $actualDependencyManifestHash = (Get-FileHash -LiteralPath $dependencyManifestPath -Algorithm SHA256).Hash
    if (-not [string]::Equals(
            $manifest.webrtc_dependency_manifest_sha256,
            $actualDependencyManifestHash,
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "WebRTC dependency manifest hash mismatch: $dependencyManifestPath"
    }
    $diskDependency = Read-SyncVisionPreparedDependencyManifest -Path $dependencyManifestPath
    $embeddedDependencyJson = ConvertTo-SyncVisionCanonicalJson -Value $dependency -Depth 10
    $diskDependencyJson = ConvertTo-SyncVisionCanonicalJson -Value $diskDependency -Depth 10
    if ($diskDependencyJson -cne $embeddedDependencyJson) {
        throw "WebRTC on-disk dependency manifest does not semantically match the embedded build-flavor dependency snapshot: $dependencyManifestPath"
    }
    Assert-SyncVisionDependencySnapshotMatchesLock `
        -Dependency $diskDependency `
        -Approved $approvedDependency `
        -Configuration $Configuration
    $preparedOutputHash = Get-SyncVisionDirectoryTreeSha256 `
        -Root $dependencyRoot `
        -ExcludedRelativePaths @("SyncVisionWebRtcDependency.json")
    if ($preparedOutputHash -cne $diskDependency.output_tree_sha256 -or
        $preparedOutputHash -cne $approvedDependency.Entry.output_tree_sha256) {
        throw "WebRTC prepared dependency complete output tree hash mismatch: $dependencyRoot"
    }

    $requiredDllNames = @(Get-SyncVisionWebRtcRuntimeDllNames)
    $dependencyDllNames = @($dependency.runtime_dll_sha256.PSObject.Properties | ForEach-Object { $_.Name })
    $dependencyDllDifferences = @(Compare-Object -ReferenceObject $requiredDllNames -DifferenceObject $dependencyDllNames)
    if ($dependencyDllNames.Count -ne $requiredDllNames.Count -or $dependencyDllDifferences.Count -ne 0) {
        throw "WebRTC dependency snapshot must list exactly these runtime DLLs: $($requiredDllNames -join ', ')."
    }
    $recordedDllNames = @($hashProperties | ForEach-Object { $_.Name })
    $hashNameDifferences = @(Compare-Object -ReferenceObject $requiredDllNames -DifferenceObject $recordedDllNames)
    if ($hashProperties.Count -ne $requiredDllNames.Count -or $hashNameDifferences.Count -ne 0) {
        throw "WebRTC build flavor manifest must record SHA-256 for exactly these runtime DLLs: $($requiredDllNames -join ', ')."
    }

    foreach ($name in $requiredDllNames) {
        $recordedHash = [string]$manifest.runtime_dll_sha256.PSObject.Properties[$name].Value
        if ($recordedHash -notmatch '^[0-9a-fA-F]{64}$') {
            throw "WebRTC build flavor manifest has an invalid SHA-256 for runtime DLL '$name'."
        }
        $dependencyHash = [string]$dependency.runtime_dll_sha256.PSObject.Properties[$name].Value
        if (-not [string]::Equals($recordedHash, $dependencyHash, [StringComparison]::OrdinalIgnoreCase)) {
            throw "WebRTC runtime DLL hash does not match the prepared dependency snapshot: $name"
        }

        $sidecarPath = Join-Path $outputDir $name
        if (-not (Test-Path -LiteralPath $sidecarPath -PathType Leaf)) {
            throw "WebRTC runtime DLL was not found for packaging: $sidecarPath"
        }
        $actualHash = (Get-FileHash -LiteralPath $sidecarPath -Algorithm SHA256).Hash
        if (-not [string]::Equals($recordedHash, $actualHash, [StringComparison]::OrdinalIgnoreCase)) {
            throw "WebRTC runtime DLL hash mismatch: $name"
        }
    }

    return $manifest
}

function Get-SyncVisionPackageCurrentUserSid {
    return [Security.Principal.WindowsIdentity]::GetCurrent().User
}

function Get-SyncVisionPackageTrustedSids {
    return @(
        (Get-SyncVisionPackageCurrentUserSid).Value,
        "S-1-5-18",
        "S-1-5-32-544"
    ) | Sort-Object -Unique
}

function New-SyncVisionTrustedPackageDirectorySecurity {
    $acl = New-Object Security.AccessControl.DirectorySecurity
    $acl.SetAccessRuleProtection($true, $false)
    $inheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    $allow = [Security.AccessControl.AccessControlType]::Allow
    $none = [Security.AccessControl.PropagationFlags]::None
    $currentSid = Get-SyncVisionPackageCurrentUserSid
    $acl.SetOwner($currentSid)
    foreach ($sidValue in (Get-SyncVisionPackageTrustedSids)) {
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                [Security.Principal.SecurityIdentifier]::new($sidValue),
                [Security.AccessControl.FileSystemRights]::FullControl,
                $inheritance,
                $none,
                $allow)) | Out-Null
    }
    return $acl
}

function Get-SyncVisionPackageDestructiveRights {
    return [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
}

function Get-SyncVisionPackageMutationRights {
    return [Security.AccessControl.FileSystemRights]::WriteData -bor
        [Security.AccessControl.FileSystemRights]::AppendData -bor
        [Security.AccessControl.FileSystemRights]::WriteExtendedAttributes -bor
        [Security.AccessControl.FileSystemRights]::WriteAttributes -bor
        [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
}

function New-SyncVisionTrustedPackageFileSecurity {
    $acl = New-Object Security.AccessControl.FileSecurity
    $acl.SetAccessRuleProtection($true, $false)
    $currentSid = Get-SyncVisionPackageCurrentUserSid
    $acl.SetOwner($currentSid)
    foreach ($sidValue in (Get-SyncVisionPackageTrustedSids)) {
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                [Security.Principal.SecurityIdentifier]::new($sidValue),
                [Security.AccessControl.FileSystemRights]::FullControl,
                [Security.AccessControl.AccessControlType]::Allow)) | Out-Null
    }
    return $acl
}

function Assert-SyncVisionPackagePathTrustMetadata {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $item = Get-Item -LiteralPath $Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context rejected a reparse point: $($item.FullName)"
    }
    $streams = @(Get-Item -LiteralPath $item.FullName -Stream * -ErrorAction Stop)
    if (@($streams | Where-Object { [string]$_.Stream -cne ':$DATA' }).Count -ne 0) {
        throw "$Context rejected an NTFS named data stream: $($item.FullName)"
    }
    Initialize-SyncVisionPackagePathIdentityType
    if ([SyncVisionTask19PackagePathIdentity]::HasExtendedAttributes($item.FullName)) {
        throw "$Context rejected NTFS extended attributes outside the authenticated package format: $($item.FullName)"
    }
    Get-SyncVisionPackagePathTopology -Path $item.FullName | Out-Null
    return $item
}

function Assert-SyncVisionPackageTreeTrustMetadata {
    param(
        [Parameter(Mandatory = $true)][string]$Root,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $rootItem = Assert-SyncVisionPackagePathTrustMetadata -Path $Root -Context $Context
    if (-not $rootItem.PSIsContainer) {
        return $rootItem.FullName
    }
    Assert-SyncVisionTrustedPackageTreeNoReparse -Root $rootItem.FullName
    foreach ($item in (Get-ChildItem -LiteralPath $rootItem.FullName -Recurse -Force)) {
        Assert-SyncVisionPackagePathTrustMetadata -Path $item.FullName -Context $Context | Out-Null
    }
    return $rootItem.FullName
}

function Assert-SyncVisionProtectedPackagePublicationObject {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyString()][string]$ExpectedSha256 = ""
    )

    $item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    Assert-SyncVisionPackageTreeTrustMetadata `
        -Root $item.FullName `
        -Context "Protected package publication object" | Out-Null
    $trustedSids = @(Get-SyncVisionPackageTrustedSids)
    $objects = @($item)
    if ($item.PSIsContainer) {
        Assert-SyncVisionTrustedPackageTreeNoReparse -Root $item.FullName
        $objects += @(Get-ChildItem -LiteralPath $item.FullName -Recurse -Force)
    }
    foreach ($object in $objects) {
        $acl = Get-Acl -LiteralPath $object.FullName
        $rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
        $actualSids = @($rules | ForEach-Object { $_.IdentityReference.Value } | Sort-Object -Unique)
        if (-not $acl.AreAccessRulesProtected -or
            $trustedSids -notcontains $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value -or
            $rules.Count -ne $trustedSids.Count -or
            @(Compare-Object -CaseSensitive -ReferenceObject $trustedSids -DifferenceObject $actualSids).Count -ne 0) {
            throw "Package publication object lacks an exact protected ACL: $($object.FullName)"
        }
        foreach ($rule in $rules) {
            if ($rule.IsInherited -or
                $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
                $rule.FileSystemRights -ne [Security.AccessControl.FileSystemRights]::FullControl) {
                throw "Package publication object has a non-exact ACL rule: $($object.FullName)"
            }
        }
    }
    if (-not [string]::IsNullOrWhiteSpace($ExpectedSha256)) {
        $actual = if ($item.PSIsContainer) {
            Get-SyncVisionDirectoryTreeSha256 -Root $item.FullName
        }
        else {
            (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
        }
        if ($actual -cne $ExpectedSha256) {
            throw "Protected package publication object identity mismatch. Expected $ExpectedSha256, got $actual`: $($item.FullName)"
        }
    }
    return $item.FullName
}

function Protect-SyncVisionPackagePublicationObject {
    param([Parameter(Mandatory = $true)][string]$Path)

    $item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    Assert-SyncVisionPackageTreeTrustMetadata `
        -Root $item.FullName `
        -Context "Package publication protection" | Out-Null
    $topologyBefore = if ($item.PSIsContainer) {
        Get-SyncVisionPackageTreeTopologySha256 -Root $item.FullName
    }
    else {
        $topology = Get-SyncVisionPackagePathTopology -Path $item.FullName
        "$($topology.FileId):$($topology.LinkCount)"
    }
    if ($item.PSIsContainer) {
        Assert-SyncVisionTrustedPackageTreeNoReparse -Root $item.FullName
        foreach ($file in (Get-ChildItem -LiteralPath $item.FullName -File -Recurse -Force)) {
            Set-Acl -LiteralPath $file.FullName -AclObject (New-SyncVisionTrustedPackageFileSecurity)
        }
        foreach ($directory in @((Get-ChildItem -LiteralPath $item.FullName -Directory -Recurse -Force) | Sort-Object { $_.FullName.Length } -Descending)) {
            Set-Acl -LiteralPath $directory.FullName -AclObject (New-SyncVisionTrustedPackageDirectorySecurity)
        }
        Set-Acl -LiteralPath $item.FullName -AclObject (New-SyncVisionTrustedPackageDirectorySecurity)
    }
    else {
        Set-Acl -LiteralPath $item.FullName -AclObject (New-SyncVisionTrustedPackageFileSecurity)
    }
    $topologyAfter = if ($item.PSIsContainer) {
        Get-SyncVisionPackageTreeTopologySha256 -Root $item.FullName
    }
    else {
        $topology = Get-SyncVisionPackagePathTopology -Path $item.FullName
        "$($topology.FileId):$($topology.LinkCount)"
    }
    if ($topologyAfter -cne $topologyBefore) {
        throw "Package publication hard-link topology changed while ACL protection was applied: $($item.FullName)"
    }
    return Assert-SyncVisionProtectedPackagePublicationObject -Path $item.FullName
}

function Assert-SyncVisionTrustedPackageAtomicParent {
    param([Parameter(Mandatory = $true)][string]$Path)

    $trustedSids = @(Get-SyncVisionPackageTrustedSids)
    $dangerous = Get-SyncVisionPackageDestructiveRights
    $current = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    while ($null -ne $current) {
        if ($current -isnot [IO.DirectoryInfo] -or
            ($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Trusted package atomic-creation chain contains a reparse point: $($current.FullName)"
        }
        $acl = Get-Acl -LiteralPath $current.FullName
        $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if ($trustedSids -notcontains $ownerSid -and
            $ownerSid -ne "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464") {
            throw "Trusted package atomic-creation chain has untrusted owner $ownerSid."
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($applies -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $dangerous) -ne 0) {
                throw "Trusted package atomic-creation chain grants unprivileged delete or ACL-control rights."
            }
        }
        $current = if ($current -is [IO.DirectoryInfo]) { $current.Parent } else { $current.Directory }
    }
}

function Assert-SyncVisionTrustedPackageDirectory {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
        throw "$Context was not found: $Path"
    }
    $item = Get-Item -LiteralPath $Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context must not be a reparse point."
    }
    $acl = Get-Acl -LiteralPath $item.FullName
    $trustedSids = @(Get-SyncVisionPackageTrustedSids)
    if (-not $acl.AreAccessRulesProtected -or
        $trustedSids -notcontains $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value) {
        throw "$Context owner or ACL inheritance is not protected."
    }
    $rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    $expectedInheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    if ($rules.Count -ne $trustedSids.Count) {
        throw "$Context must grant exactly current user, SYSTEM, and Administrators."
    }
    foreach ($rule in $rules) {
        if ($trustedSids -notcontains $rule.IdentityReference.Value -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.FileSystemRights -ne [Security.AccessControl.FileSystemRights]::FullControl -or
            $rule.InheritanceFlags -ne $expectedInheritance -or
            $rule.PropagationFlags -ne [Security.AccessControl.PropagationFlags]::None -or
            $rule.IsInherited) {
            throw "$Context contains a non-exact ACL rule."
        }
    }
    return $item.FullName
}

function Assert-SyncVisionTrustedPackageTreeNoReparse {
    param([Parameter(Mandatory = $true)][string]$Root)

    $rootItem = Get-Item -LiteralPath $Root -Force
    if (-not $rootItem.PSIsContainer -or
        ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Trusted package tree must start at a non-reparse directory."
    }
    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push($rootItem.FullName)
    while ($pending.Count -ne 0) {
        foreach ($item in (Get-ChildItem -LiteralPath $pending.Pop() -Force)) {
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Trusted package tree contains a reparse point: $($item.FullName)"
            }
            if ($item.PSIsContainer) { $pending.Push($item.FullName) }
        }
    }
}

function Get-SyncVisionTrustedPackageBasePath {
    $programData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)
    if ([string]::IsNullOrWhiteSpace($programData)) {
        throw "Trusted package staging could not resolve CommonApplicationData."
    }
    return Join-Path $programData "SyncVisionTrustedPackage"
}

function Get-SyncVisionDefaultPackageOutputRoot {
    return Join-Path (Get-SyncVisionTrustedPackageBasePath) "release"
}

function Initialize-SyncVisionTrustedPackageBase {
    $base = Get-SyncVisionTrustedPackageBasePath
    $parent = Split-Path -Parent $base
    Assert-SyncVisionTrustedPackageAtomicParent -Path $parent
    if (-not (Test-Path -LiteralPath $base)) {
        [IO.Directory]::CreateDirectory($base, (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
    }
    $resolved = Assert-SyncVisionTrustedPackageDirectory -Path $base -Context "Trusted package base"
    Assert-SyncVisionTrustedPackageAtomicParent -Path $parent
    return $resolved
}

function Copy-SyncVisionTrustedPackageTreeExact {
    param(
        [Parameter(Mandatory = $true)][string]$SourceRoot,
        [Parameter(Mandatory = $true)][string]$DestinationRoot
    )

    $source = (Resolve-Path -LiteralPath $SourceRoot).Path.TrimEnd('\', '/')
    $destination = (Resolve-Path -LiteralPath $DestinationRoot).Path.TrimEnd('\', '/')
    if (@(Get-ChildItem -LiteralPath $destination -Force).Count -ne 0) {
        throw "Trusted package snapshot destination must be empty."
    }
    $pending = New-Object "System.Collections.Generic.Stack[object]"
    $pending.Push([pscustomobject]@{ Source = $source; Destination = $destination })
    while ($pending.Count -ne 0) {
        $pair = $pending.Pop()
        foreach ($item in (Get-ChildItem -LiteralPath $pair.Source -Force)) {
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Trusted package snapshot rejected a reparse point: $($item.FullName)"
            }
            $relative = $item.FullName.Substring($source.Length).TrimStart([char[]]@('\', '/'))
            $target = Join-Path $destination $relative
            if ($item.PSIsContainer) {
                [IO.Directory]::CreateDirectory($target) | Out-Null
                $pending.Push([pscustomobject]@{ Source = $item.FullName; Destination = $target })
            }
            else {
                [IO.File]::Copy($item.FullName, $target, $false)
            }
        }
    }
}

function ConvertTo-SyncVisionTrustedBuildReceiptModel {
    param([Parameter(Mandatory = $true)][object]$Value)

    $names = @(
        "schema_version", "configuration", "architecture", "account_enabled",
        "account_release_config_relative_path", "account_release_config_sha256", "webrtc_enabled",
        "source_relative_path", "source_tree_sha256", "output_relative_path", "output_tree_sha256",
        "build_flavor_manifest_relative_path", "build_flavor_manifest_sha256",
        "dependency_lock_relative_path", "dependency_lock_sha256", "webrtc_relative_path",
        "webrtc_output_tree_sha256", "webrtc_manifest_sha256")
    Assert-SyncVisionExactJsonProperties -Value $Value -ExpectedNames $names -Context "Trusted build receipt"
    if ($Value.schema_version -isnot [int] -or $Value.schema_version -ne 2 -or
        $Value.configuration -notin @("Debug", "Release") -or
        $Value.architecture -cne "x64" -or
        $Value.account_enabled -isnot [bool] -or
        $Value.webrtc_enabled -isnot [bool]) {
        throw "Trusted build receipt header is invalid."
    }
    foreach ($name in @("source_tree_sha256", "output_tree_sha256", "build_flavor_manifest_sha256", "dependency_lock_sha256")) {
        Assert-SyncVisionJsonSha256 -Value $Value.$name -Context "Trusted build receipt $name"
    }
    if ($Value.account_enabled) {
        Assert-SyncVisionJsonNonEmptyString -Value $Value.account_release_config_relative_path -Context "Trusted build receipt account_release_config_relative_path"
        Assert-SyncVisionJsonSha256 -Value $Value.account_release_config_sha256 -Context "Trusted build receipt account_release_config_sha256"
        if ((Resolve-SyncVisionAccountReleaseConfigRelativePath `
                -RelativePath $Value.account_release_config_relative_path) -cne
            $Value.account_release_config_relative_path) {
            throw "Trusted build receipt account release config path is invalid."
        }
    }
    elseif ($null -ne $Value.account_release_config_relative_path -or
        $null -ne $Value.account_release_config_sha256) {
        throw "Account-disabled trusted build receipt contains account release config identity."
    }
    $outputRelative = "source/build/x64/$($Value.configuration)"
    if ($Value.source_relative_path -cne "source" -or
        $Value.output_relative_path -cne $outputRelative -or
        $Value.build_flavor_manifest_relative_path -cne "$outputRelative/SyncVisionBuildFlavor.json" -or
        $Value.dependency_lock_relative_path -cne "source/msbuild/SyncVisionWebRtcDependency.lock.json") {
        throw "Trusted build receipt contains an unexpected relative path."
    }
    if ($Value.webrtc_enabled) {
        if ($Value.webrtc_relative_path -cne "webrtc") { throw "Trusted build receipt WebRTC path is invalid." }
        Assert-SyncVisionJsonSha256 -Value $Value.webrtc_output_tree_sha256 -Context "Trusted build receipt WebRTC output"
        Assert-SyncVisionJsonSha256 -Value $Value.webrtc_manifest_sha256 -Context "Trusted build receipt WebRTC manifest"
    }
    elseif ($null -ne $Value.webrtc_relative_path -or $null -ne $Value.webrtc_output_tree_sha256 -or $null -ne $Value.webrtc_manifest_sha256) {
        throw "Default trusted build receipt contains WebRTC identities."
    }
    return [pscustomobject]([ordered]@{
        schema_version = 2; configuration = $Value.configuration; architecture = "x64"
        account_enabled = [bool]$Value.account_enabled
        account_release_config_relative_path = $Value.account_release_config_relative_path
        account_release_config_sha256 = $Value.account_release_config_sha256
        webrtc_enabled = [bool]$Value.webrtc_enabled
        source_relative_path = $Value.source_relative_path; source_tree_sha256 = $Value.source_tree_sha256
        output_relative_path = $Value.output_relative_path; output_tree_sha256 = $Value.output_tree_sha256
        build_flavor_manifest_relative_path = $Value.build_flavor_manifest_relative_path; build_flavor_manifest_sha256 = $Value.build_flavor_manifest_sha256
        dependency_lock_relative_path = $Value.dependency_lock_relative_path; dependency_lock_sha256 = $Value.dependency_lock_sha256
        webrtc_relative_path = $Value.webrtc_relative_path; webrtc_output_tree_sha256 = $Value.webrtc_output_tree_sha256
        webrtc_manifest_sha256 = $Value.webrtc_manifest_sha256
    })
}

function Assert-SyncVisionTrustedBuildCache {
    param([Parameter(Mandatory = $true)][string]$CacheRoot)

    $root = Assert-SyncVisionTrustedPackageDirectory -Path $CacheRoot -Context "Trusted build cache or snapshot"
    Assert-SyncVisionTrustedPackageTreeNoReparse -Root $root
    $receiptPath = Join-Path $root "SyncVisionTrustedBuildReceipt.json"
    $receipt = Read-SyncVisionCanonicalJsonFile -Path $receiptPath -Description "Trusted build receipt" -ModelBuilder {
        param($value)
        ConvertTo-SyncVisionTrustedBuildReceiptModel -Value $value
    }
    $source = Join-Path $root "source"
    $output = Join-Path $root ($receipt.output_relative_path -replace '/', '\')
    $lockPath = Join-Path $root ($receipt.dependency_lock_relative_path -replace '/', '\')
    $flavorPath = Join-Path $root ($receipt.build_flavor_manifest_relative_path -replace '/', '\')
    if (-not (Test-Path -LiteralPath $flavorPath -PathType Leaf)) {
        throw "Build flavor manifest was not found in the trusted build cache: $flavorPath"
    }
    if ((Get-SyncVisionDirectoryTreeSha256 -Root $source -ExcludedTopLevelNames @("build")) -cne $receipt.source_tree_sha256 -or
        (Get-SyncVisionDirectoryTreeSha256 -Root $output) -cne $receipt.output_tree_sha256 -or
        (Get-FileHash -LiteralPath $lockPath -Algorithm SHA256).Hash.ToLowerInvariant() -cne $receipt.dependency_lock_sha256 -or
        (Get-FileHash -LiteralPath $flavorPath -Algorithm SHA256).Hash.ToLowerInvariant() -cne $receipt.build_flavor_manifest_sha256) {
        throw "Trusted build cache differs from its canonical receipt."
    }
    if ($receipt.account_enabled) {
        $accountConfig = Read-SyncVisionAccountReleaseConfig `
            -RepoRoot $source `
            -RelativePath $receipt.account_release_config_relative_path
        if ($accountConfig.Sha256 -cne $receipt.account_release_config_sha256) {
            throw "Trusted build cache account release config differs from its receipt."
        }
    }
    $webRtcPath = $null
    if ($receipt.webrtc_enabled) {
        $webRtcPath = Join-Path $root "webrtc"
        $webRtcManifestPath = Join-Path $webRtcPath "SyncVisionWebRtcDependency.json"
        if ((Get-SyncVisionDirectoryTreeSha256 -Root $webRtcPath -ExcludedRelativePaths @("SyncVisionWebRtcDependency.json")) -cne $receipt.webrtc_output_tree_sha256 -or
            (Get-FileHash -LiteralPath $webRtcManifestPath -Algorithm SHA256).Hash.ToLowerInvariant() -cne $receipt.webrtc_manifest_sha256) {
            throw "Trusted build cache WebRTC snapshot differs from its receipt."
        }
    }
    return [pscustomobject]@{
        RootPath = $root
        SourcePath = $source
        OutputPath = $output
        WebRtcPath = $webRtcPath
        ReceiptPath = $receiptPath
        Receipt = $receipt
    }
}

function Get-SyncVisionTrustedBuildCachePath {
    param([Parameter(Mandatory = $true)][ValidateSet("Debug", "Release")][string]$Configuration)

    $programData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)
    return Join-Path (Join-Path $programData "SyncVisionTrustedBuild") ("cache-" + $Configuration.ToLowerInvariant())
}

function Resolve-SyncVisionPackageBuildCacheRoot {
    param(
        [Parameter(Mandatory = $true)][ValidateSet("Debug", "Release")][string]$Configuration,
        [AllowEmptyString()][string]$RequestedRoot = "",
        [switch]$AllowTestBuildCacheRoot
    )

    $canonical = [IO.Path]::GetFullPath(
        (Get-SyncVisionTrustedBuildCachePath -Configuration $Configuration)).TrimEnd('\', '/')
    if ([string]::IsNullOrWhiteSpace($RequestedRoot)) {
        return $canonical
    }
    $requested = [IO.Path]::GetFullPath($RequestedRoot).TrimEnd('\', '/')
    if ([string]::Equals($requested, $canonical, [StringComparison]::OrdinalIgnoreCase)) {
        return $canonical
    }
    if (-not $AllowTestBuildCacheRoot) {
        throw "Production packaging requires the canonical protected trusted-build cache '$canonical'; alternate roots are test-only."
    }
    return $requested
}

function Enter-SyncVisionBuildCacheMutex {
    param(
        [Parameter(Mandatory = $true)][ValidateSet("Debug", "Release")][string]$Configuration,
        [ValidateRange(1, 3600000)][int]$TimeoutMs = 30000
    )

    $name = "Global\SyncVision.Task19.TrustedBuild.$($Configuration.ToLowerInvariant())"
    $mutexSecurity = [Security.AccessControl.MutexSecurity]::new()
    $mutexSecurity.SetAccessRuleProtection($true, $false)
    $allow = [Security.AccessControl.AccessControlType]::Allow
    $currentSid = [Security.Principal.WindowsIdentity]::GetCurrent().User
    $mutexSecurity.SetOwner($currentSid)
    $systemSid = [Security.Principal.SecurityIdentifier]::new([Security.Principal.WellKnownSidType]::LocalSystemSid, $null)
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new([Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid, $null)
    foreach ($sid in @($currentSid, $systemSid, $administratorsSid)) {
        $mutexSecurity.AddAccessRule([Security.AccessControl.MutexAccessRule]::new(
                $sid,
                [Security.AccessControl.MutexRights]::FullControl,
                $allow)) | Out-Null
    }
    $createdNew = $false
    $mutex = [Threading.Mutex]::new($false, $name, [ref]$createdNew, $mutexSecurity)
    try {
        $trustedSids = @($currentSid.Value, $systemSid.Value, $administratorsSid.Value) | Sort-Object -Unique
        $actualSecurity = $mutex.GetAccessControl()
        $rules = @($actualSecurity.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
        $actualSids = @($rules | ForEach-Object { $_.IdentityReference.Value } | Sort-Object -Unique)
        if (-not $actualSecurity.AreAccessRulesProtected -or
            $trustedSids -notcontains $actualSecurity.GetOwner([Security.Principal.SecurityIdentifier]).Value -or
            $rules.Count -ne $trustedSids.Count -or
            @(Compare-Object -CaseSensitive -ReferenceObject $trustedSids -DifferenceObject $actualSids).Count -ne 0) {
            throw "Trusted build cache mutex must have a trusted owner, protected DACL, and exact nonempty principal set."
        }
        foreach ($rule in $rules) {
            if ($rule.IsInherited -or
                $rule.AccessControlType -ne $allow -or
                $rule.MutexRights -ne [Security.AccessControl.MutexRights]::FullControl) {
                throw "Trusted build cache mutex has an untrusted or insufficient ACL."
            }
        }
        try { $acquired = $mutex.WaitOne($TimeoutMs) }
        catch [Threading.AbandonedMutexException] { $acquired = $true }
        if (-not $acquired) { throw "Trusted build mutex timed out after $TimeoutMs ms for configuration $Configuration." }
        return [pscustomobject]@{ Mutex = $mutex; Acquired = $true; Name = $name }
    }
    catch {
        $mutex.Dispose()
        throw
    }
}

function Exit-SyncVisionBuildCacheMutex {
    param([AllowNull()]$Context)

    if ($null -eq $Context) { return }
    try { if ($Context.Acquired) { $Context.Mutex.ReleaseMutex() } }
    finally { $Context.Mutex.Dispose() }
}

function New-SyncVisionTrustedPackageSnapshot {
    param(
        [Parameter(Mandatory = $true)][string]$BuildCacheRoot,
        [Parameter(Mandatory = $true)][ValidateSet("Debug", "Release")][string]$Configuration,
        [switch]$AllowTestBuildCacheRoot
    )

    $sourceRoot = Resolve-SyncVisionPackageBuildCacheRoot `
        -Configuration $Configuration `
        -RequestedRoot $BuildCacheRoot `
        -AllowTestBuildCacheRoot:$AllowTestBuildCacheRoot
    $base = Initialize-SyncVisionTrustedPackageBase
    $prefix = "snapshot-"
    $root = Join-Path $base ($prefix + [Guid]::NewGuid().ToString("N"))
    [IO.Directory]::CreateDirectory($root, (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
    $mutex = $null
    try {
        $mutex = Enter-SyncVisionBuildCacheMutex -Configuration $Configuration
        Assert-SyncVisionTrustedPackageAtomicParent -Path (Split-Path -Parent $sourceRoot)
        $validatedSource = Assert-SyncVisionTrustedBuildCache -CacheRoot $sourceRoot
        Copy-SyncVisionTrustedPackageTreeExact -SourceRoot $validatedSource.RootPath -DestinationRoot $root
        Assert-SyncVisionTrustedBuildCache -CacheRoot $sourceRoot | Out-Null
        $validated = Assert-SyncVisionTrustedBuildCache -CacheRoot $root
        return [pscustomobject]@{
            BasePath = $base
            RootPath = $validated.RootPath
            RootPrefix = $prefix
            SourcePath = $validated.SourcePath
            OutputPath = $validated.OutputPath
            WebRtcPath = $validated.WebRtcPath
            ReceiptPath = $validated.ReceiptPath
            Receipt = $validated.Receipt
            OriginalCacheRoot = $sourceRoot
        }
    }
    catch {
        if (Test-Path -LiteralPath $root) {
            Assert-SyncVisionTrustedPackageTreeNoReparse -Root $root
            Remove-Item -LiteralPath $root -Recurse -Force -ErrorAction SilentlyContinue
        }
        throw
    }
    finally {
        Exit-SyncVisionBuildCacheMutex -Context $mutex
    }
}

function Remove-SyncVisionTrustedPackageSnapshot {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    if (-not (Test-Path -LiteralPath $Snapshot.RootPath)) { return }
    $root = Assert-SyncVisionTrustedPackageDirectory -Path $Snapshot.RootPath -Context "Trusted package snapshot cleanup"
    if (-not [string]::Equals((Split-Path -Parent $root), $Snapshot.BasePath, [StringComparison]::OrdinalIgnoreCase) -or
        -not (Split-Path -Leaf $root).StartsWith([string]$Snapshot.RootPrefix, [StringComparison]::Ordinal)) {
        throw "Refusing to remove an unexpected trusted package snapshot."
    }
    Assert-SyncVisionTrustedPackageTreeNoReparse -Root $root
    Remove-Item -LiteralPath $root -Recurse -Force -ErrorAction Stop
}

function New-SyncVisionTrustedPackagePlan {
    param(
        [Parameter(Mandatory = $true)][string]$BuildCacheRoot,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string]$Version,
        [ValidateSet("Debug", "Release")][string]$Configuration = "Release",
        [switch]$EnableWebRtc,
        [switch]$AllowUnsignedDevelopmentBootstrap,
        [switch]$AllowTestBuildCacheRoot
    )

    $snapshot = New-SyncVisionTrustedPackageSnapshot `
        -BuildCacheRoot $BuildCacheRoot `
        -Configuration $Configuration `
        -AllowTestBuildCacheRoot:$AllowTestBuildCacheRoot
    try {
        if ([bool]$snapshot.Receipt.webrtc_enabled -ne [bool]$EnableWebRtc -or
            $snapshot.Receipt.configuration -cne $Configuration) {
            $requestedFlavor = if ($EnableWebRtc) { "requested WebRTC packaging" } else { "requested default packaging" }
            $recordedFlavor = if ($snapshot.Receipt.webrtc_enabled) { "WebRTC enabled" } else { "WebRTC disabled" }
            throw "Trusted build receipt flavor mismatch: $requestedFlavor, but the receipt records $recordedFlavor/$($snapshot.Receipt.configuration)."
        }
        $manifest = Assert-SyncVisionBuildFlavorManifest `
            -RepoRoot $snapshot.SourcePath `
            -Configuration $Configuration `
            -EnableWebRtc:$EnableWebRtc `
            -TrustedWebRtcRoot $(if ($EnableWebRtc) { $snapshot.WebRtcPath } else { "" })
        if ($snapshot.Receipt.account_enabled -ne $true -or
            $manifest.account_enabled -ne $true -or
            $snapshot.Receipt.account_release_config_relative_path -cne $manifest.account_release_config_relative_path -or
            $snapshot.Receipt.account_release_config_sha256 -cne $manifest.account_release_config_sha256) {
            throw "Trusted build receipt and flavor manifest do not identify the same account-enabled release config."
        }
        $plan = New-SyncVisionPackagePlan `
            -RepoRoot $snapshot.SourcePath `
            -OutputRoot $OutputRoot `
            -Version $Version `
            -Configuration $Configuration `
            -EnableWebRtc:$EnableWebRtc `
            -AllowUnsignedDevelopmentBootstrap:$AllowUnsignedDevelopmentBootstrap `
            -BuildFlavorManifest $manifest
        return [pscustomobject]@{ Snapshot = $snapshot; Plan = $plan; BuildFlavorManifest = $manifest }
    }
    catch {
        Remove-SyncVisionTrustedPackageSnapshot -Snapshot $snapshot
        throw
    }
}

function Get-SyncVisionExampleContent {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Destination
    )

    switch ($Destination) {
        "examples\server.public.conf.example" {
            return @"
listen=0.0.0.0:38580
token_file=server.token.example
# Optional per-device hardening: device_tokens_file=device.tokens.example
transport_encryption=required
transport_secret_file=transport.secret.example
discovery_listen=0.0.0.0:38581
discovery_enabled=false
allow_unsafe_public_relay=true
first_frame_timeout_ms=5000
idle_timeout_ms=15000
heartbeat_ttl_ms=30000
max_sessions=128
max_pending_first_frames=64
"@
        }
        "examples\server.lan.conf.example" {
            return @"
listen=0.0.0.0:38580
token_file=server.token.example
# Optional per-device hardening: device_tokens_file=device.tokens.example
discovery_listen=0.0.0.0:38581
advertise=<lan-ip-or-hostname>:38580
discovery_enabled=true
allow_unsafe_public_relay=true
first_frame_timeout_ms=5000
idle_timeout_ms=15000
heartbeat_ttl_ms=30000
max_sessions=128
max_pending_first_frames=64
"@
        }
        "examples\client.public.conf.example" {
            return @"
server=<relay-host-or-ip>:38580
token_file=<path-to-file-containing-shared-token>
# Optional per-device hardening: device_token_file=<path-to-file-containing-this-device-token>
transport_encryption=required
transport_secret_file=<path-to-file-containing-transport-secret>
reconnect_attempts=3
reconnect_delay_ms=1000
reconnect_max_delay_ms=5000
"@
        }
        "examples\install-public-relay.example.ps1" {
            return @"
`$expectedManifestSha256 = Read-Host "Paste the publisher-provided 64-character manifest SHA-256 obtained through an independently trusted channel"
if (`$expectedManifestSha256 -notmatch '^[0-9a-fA-F]{64}$') {
  throw "Expected manifest digest must be a 64-character hexadecimal SHA-256 value from the publisher-provided external manifest digest."
}

powershell -ExecutionPolicy Bypass -File .\scripts\install-server.ps1 ``
  -SkipBuild ``
  -ExpectedManifestSha256 `$expectedManifestSha256 ``
  -Configuration Release ``
  -Listen 0.0.0.0:38580 ``
  -NoDiscovery ``
  -AllowUnsafePublicRelay ``
  -TransportEncryption required ``
  -ConfigureFirewall ``
  -FirewallRemoteAddress "<trusted-client-cidr-or-ip>" ``
  -ServiceAccount NetworkService ``
  -Start ``
  -VerifyInstall
"@
        }
        "examples\install-lan-relay.example.ps1" {
            return @"
`$expectedManifestSha256 = Read-Host "Paste the publisher-provided 64-character manifest SHA-256 obtained through an independently trusted channel"
if (`$expectedManifestSha256 -notmatch '^[0-9a-fA-F]{64}$') {
  throw "Expected manifest digest must be a 64-character hexadecimal SHA-256 value from the publisher-provided external manifest digest."
}

powershell -ExecutionPolicy Bypass -File .\scripts\install-server.ps1 ``
  -SkipBuild ``
  -ExpectedManifestSha256 `$expectedManifestSha256 ``
  -Configuration Release ``
  -Listen 0.0.0.0:38580 ``
  -Lan ``
  -AllowUnsafePublicRelay ``
  -ConfigureFirewall ``
  -FirewallRemoteAddress LocalSubnet ``
  -ServiceAccount NetworkService ``
  -Start ``
  -VerifyInstall
"@
        }
        "examples\new-client-config.example.ps1" {
            return @"
powershell -ExecutionPolicy Bypass -File .\scripts\new-client-config.ps1 ``
  -Server <relay-public-host-or-ip>:38580 ``
  -TokenFile "<path-to-server.token>" ``
  -OutputDir ".\client-config" ``
  -HostDevice host-001 ``
  -ViewerDevice viewer-001 ``
  -TransportEncryption required ``
  -TransportSecretFile "<path-to-transport.secret>" ``
  -IncludeDeviceTokenTemplates
"@
        }
        "examples\start-host.example.ps1" {
            return @"
powershell -ExecutionPolicy Bypass -File .\scripts\start-host.ps1 ``
  -Configuration Release ``
  -ClientConfig ".\examples\client.public.conf.example" ``
  -DeviceTokenFile "<path-to-this-host-device-token>" ``
  -Device <host-device-id> ``
  -AllowViewer <viewer-device-id> ``
  -GrantInputTo <viewer-device-id> ``
  -CaptureBackend auto ``
  -ReceiveDir ".\received"
"@
        }
        "examples\start-viewer.example.ps1" {
            return @"
powershell -ExecutionPolicy Bypass -File .\scripts\start-viewer.ps1 ``
  -Configuration Release ``
  -ClientConfig ".\examples\client.public.conf.example" ``
  -DeviceTokenFile "<path-to-this-viewer-device-token>" ``
  -Device <viewer-device-id> ``
  -Target <host-device-id>
"@
        }
        "examples\verify-public-relay.example.ps1" {
            return @"
# Run this from an allowed external client network, not from the relay server itself.
powershell -ExecutionPolicy Bypass -File .\scripts\verify-public-relay.ps1 ``
  -Server <relay-public-host-or-ip>:38580 ``
  -TokenFile "<path-to-file-containing-shared-token>" ``
  -TransportEncryption required ``
  -TransportSecretFile "<path-to-transport.secret>" ``
  -MinHosts 0 ``
  -MinViewers 0
"@
        }
        "examples\device.tokens.example" {
            return @"
# Optional per-device registration secrets.
# Use one device_id=token line per allowed host/viewer. Keep the real file private.
host-001=<host-device-token>
viewer-001=<viewer-device-token>
"@
        }
        default {
            throw "Unknown SyncVision release example destination: $Destination"
        }
    }
}

function Get-SyncVisionPrerequisitesContent {
    return @'
# Tongping Expert Release Prerequisites

This binary package is built for Windows x64.

## Bundled Runtime

The package includes the Microsoft Visual C++ x64 Redistributable runtime DLLs required by the packaged `SyncVisionControl.exe`, `SyncVisionServer.exe`, and private Agent payloads:

- `vcruntime140.dll`
- `vcruntime140_1.dll`
- `msvcp140.dll`
- `msvcp140_atomic_wait.dll`

These Microsoft-signed app-local files are listed in `SHA256SUMS.txt`, are placed beside both the public executables and the private Agent payloads, and are copied with an installed relay service. The packaged programs do not depend on an older copy under `System32`.

## Package Layout

- Group-control entry: `build\x64\Release\SyncVisionControl.exe`
- LAN relay binary: `build\x64\Release\SyncVisionServer.exe`
- Internal Agent-generation payloads: `build\x64\Release\private-runtime\`
  Do not launch or copy these files individually. Open the group-control console, generate `SyncVisionAgentSetup.exe`, then copy that single generated installer to the controlled PC.
- Build identity manifest: `build\x64\Release\SyncVisionBuildFlavor.json`
- The four Microsoft VC runtime DLLs are packaged at both runtime boundaries; WebRTC DLLs, when enabled, are additionally authenticated by the build flavor dependency manifest.
- Service installer: `scripts\install-server.ps1`
- Install examples: `examples\install-public-relay.example.ps1`
- External public reachability probe: `scripts\verify-public-relay.ps1`

Use `-SkipBuild` when installing from this package so the installer uses the packaged Release binary. `SyncVisionPackage.json` identifies the package and `SHA256SUMS.txt` is the complete package tree contract, excluding only the manifest itself, after the manifest digest is trusted.

internal checksums provide integrity after trusted delivery; commercial distribution must publish the manifest digest through an independently trusted channel (or replace this mechanism with Authenticode/signed manifests when a production certificate is available). Current unsigned artifacts are not publisher-authenticated.
'@
}

function Get-SyncVisionShareCommandContent {
    param(
        [ValidateSet("Debug", "Release")]
        [string]$Configuration = "Release"
    )

    return @"
@echo off
setlocal
cd /d "%~dp0"
set "SYNCVISION_SHARE=%~dp0build\x64\$Configuration\SyncVisionShare.exe"
if not exist "%SYNCVISION_SHARE%" (
  echo SyncVisionShare.exe was not found.
  echo Please extract the whole Tongping Expert package before starting sharing.
  pause
  exit /b 1
)

start "" "%SYNCVISION_SHARE%"
exit /b 0
"@
}

function Get-SyncVisionControlCommandContent {
    param(
        [ValidateSet("Debug", "Release")]
        [string]$Configuration = "Release"
    )

    return @"
@echo off
setlocal
cd /d "%~dp0"
set "SYNCVISION_CONTROL=%~dp0build\x64\$Configuration\SyncVisionControl.exe"
if not exist "%SYNCVISION_CONTROL%" (
  echo SyncVisionControl.exe was not found.
  echo Please extract the whole Tongping Expert package before opening the group console.
  pause
  exit /b 1
)

start "" "%SYNCVISION_CONTROL%"
exit /b 0
"@
}

function Get-SyncVisionStartCommandContent {
    return @'
@echo off
setlocal
cd /d "%~dp0"
set "SYNCVISION_LAUNCHER=%~dp0build\x64\Release\SyncVisionLauncher.exe"
if not exist "%SYNCVISION_LAUNCHER%" (
  echo SyncVisionLauncher.exe was not found.
  echo Please extract the whole Tongping Expert package before starting it.
  pause
  exit /b 1
)

if "%~1"=="" (
  start "" "%SYNCVISION_LAUNCHER%"
  exit /b 0
)

"%SYNCVISION_LAUNCHER%" %*
exit /b %ERRORLEVEL%
'@
}

function Get-SyncVisionLanInstallerElevatedBootstrapContent {
    return @'
param(
    [Parameter(Mandatory = $true)]
    [string]$Root,

    [Parameter(Mandatory = $true)]
    [string]$ExpectedManifestSha256,

    [Parameter(Mandatory = $true)]
    [string[]]$InstallArguments
)

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

function Get-SyncVisionPackageBootstrapSha256 {
    param(
        [Parameter(Mandatory = $true)]
        [byte[]]$Bytes
    )

    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        return [BitConverter]::ToString($sha256.ComputeHash($Bytes)).Replace("-", "").ToLowerInvariant()
    }
    finally {
        $sha256.Dispose()
    }
}

function ConvertTo-SyncVisionPackageBootstrapRelativePath {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RelativePath
    )

    $normalized = $RelativePath.Trim().TrimStart("*") -replace "/", "\\"
    if ([string]::IsNullOrWhiteSpace($normalized) -or
        [IO.Path]::IsPathRooted($normalized) -or
        $normalized.StartsWith("\\")) {
        throw "Package bootstrap rejected an invalid manifest path: $RelativePath"
    }

    $segments = @($normalized -split "\\\\")
    if (@($segments | Where-Object {
                [string]::IsNullOrWhiteSpace($_) -or $_ -eq "." -or $_ -eq ".."
            }).Count -ne 0) {
        throw "Package bootstrap rejected a non-canonical manifest path: $RelativePath"
    }

    return ($segments -join "\\")
}

function New-SyncVisionPackageBootstrapDirectorySecurity {
    $security = [Security.AccessControl.DirectorySecurity]::new()
    $security.SetAccessRuleProtection($true, $false)
    $inheritance = [Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [Security.AccessControl.InheritanceFlags]::ObjectInherit
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::LocalSystemSid,
        $null)
    $security.SetOwner($administratorsSid)
    foreach ($sid in @($administratorsSid, $systemSid)) {
        $security.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $sid,
                [Security.AccessControl.FileSystemRights]::FullControl,
                $inheritance,
                [Security.AccessControl.PropagationFlags]::None,
                [Security.AccessControl.AccessControlType]::Allow)) | Out-Null
    }
    return $security
}

function Assert-SyncVisionPackageBootstrapTree {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RootPath,

        [Parameter(Mandatory = $true)]
        [string]$ManifestPath,

        [Parameter(Mandatory = $true)]
        [object]$ManifestEntries
    )

    $resolvedRoot = (Resolve-Path -LiteralPath $RootPath).Path.TrimEnd("\", "/")
    $rootItem = Get-Item -LiteralPath $resolvedRoot -Force
    if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Package bootstrap rejects a reparse-point package root: $resolvedRoot"
    }

    $resolvedManifest = [IO.Path]::GetFullPath($ManifestPath)
    $rootPrefix = $resolvedRoot + "\"
    $observedEntries = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $pendingDirectories = New-Object "System.Collections.Generic.Stack[string]"
    $pendingDirectories.Push($resolvedRoot)
    while ($pendingDirectories.Count -ne 0) {
        $directoryPath = $pendingDirectories.Pop()
        foreach ($item in (Get-ChildItem -LiteralPath $directoryPath -Force)) {
            $itemPath = $item.FullName
            if (-not $itemPath.StartsWith($rootPrefix, [StringComparison]::OrdinalIgnoreCase)) {
                throw "Package bootstrap rejected an item outside the package root: $itemPath"
            }
            if ($item.PSIsContainer) {
                if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                    throw "Package bootstrap rejects a reparse-point package directory: $itemPath"
                }
                $pendingDirectories.Push($itemPath)
                continue
            }
            if ($itemPath -ieq $resolvedManifest) {
                continue
            }
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Package bootstrap rejected a reparse-point package file: $itemPath"
            }

            $relativePath = ConvertTo-SyncVisionPackageBootstrapRelativePath -RelativePath $itemPath.Substring($rootPrefix.Length)
            if (-not $ManifestEntries.ContainsKey($relativePath)) {
                throw "Package bootstrap rejected an unmanifested package file: $relativePath"
            }
            $actualHash = (Get-FileHash -LiteralPath $itemPath -Algorithm SHA256).Hash.ToLowerInvariant()
            if ($actualHash -ne $ManifestEntries[$relativePath]) {
                throw "Checksum mismatch for $relativePath. Expected $($ManifestEntries[$relativePath]), got $actualHash."
            }
            [void]$observedEntries.Add($relativePath)
        }
    }

    foreach ($relativePath in $ManifestEntries.Keys) {
        if (-not $observedEntries.Contains($relativePath)) {
            throw "Package bootstrap manifest entry is missing from the package: $relativePath"
        }
    }
}

function Assert-SyncVisionPackageBootstrapAncestorChain {
    param([Parameter(Mandatory = $true)][string]$Path)

    $trustedSids = @(
        "S-1-5-18",
        "S-1-5-32-544",
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
    )
    $dangerousRights = [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
    $current = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    while ($null -ne $current) {
        if (($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package bootstrap trusted staging rejected a reparse-point ancestor: $($current.FullName)"
        }

        $acl = Get-Acl -LiteralPath $current.FullName
        $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).ToString()
        if ($trustedSids -notcontains $ownerSid) {
            throw "Package bootstrap trusted staging rejected owner $ownerSid at $($current.FullName)."
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $appliesToDirectory = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($appliesToDirectory -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $dangerousRights) -ne 0) {
                throw "Package bootstrap trusted staging rejected untrusted delete or ACL control on ancestor $($current.FullName)."
            }
        }
        $current = $current.Parent
    }
}

function Assert-SyncVisionPackageBootstrapDirectory {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $item = Get-Item -LiteralPath $Path -Force
    if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Package bootstrap trusted staging requires a non-reparse $Context directory: $Path"
    }

    $acl = Get-Acl -LiteralPath $item.FullName
    $expectedSids = @("S-1-5-18", "S-1-5-32-544")
    $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).ToString()
    if (-not $acl.AreAccessRulesProtected -or $expectedSids -notcontains $ownerSid) {
        throw "Package bootstrap trusted staging rejected the $Context owner or ACL protection: $($item.FullName)"
    }

    $rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    $expectedInheritance = [Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [Security.AccessControl.InheritanceFlags]::ObjectInherit
    $observedSids = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    if ($rules.Count -ne 2) {
        throw "Package bootstrap trusted staging requires exactly two $Context ACL rules."
    }
    foreach ($rule in $rules) {
        if (-not $observedSids.Add($rule.IdentityReference.Value) -or
            $expectedSids -notcontains $rule.IdentityReference.Value -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.FileSystemRights -ne [Security.AccessControl.FileSystemRights]::FullControl -or
            $rule.InheritanceFlags -ne $expectedInheritance -or
            $rule.PropagationFlags -ne [Security.AccessControl.PropagationFlags]::None -or
            $rule.IsInherited) {
            throw "Package bootstrap trusted staging rejected a non-exact $Context ACL rule."
        }
    }
    return $item.FullName
}

function Initialize-SyncVisionPackageBootstrapStagingBase {
    $commonApplicationData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)
    if ([string]::IsNullOrWhiteSpace($commonApplicationData)) {
        throw "Package bootstrap trusted staging could not resolve CommonApplicationData."
    }

    $basePath = Join-Path $commonApplicationData "SyncVisionPackageStaging"
    Assert-SyncVisionPackageBootstrapAncestorChain -Path (Split-Path -Parent $basePath)
    if (Test-Path -LiteralPath $basePath) {
        if (-not (Test-Path -LiteralPath $basePath -PathType Container)) {
            throw "Package bootstrap trusted staging base is not a directory: $basePath"
        }
    }
    else {
        [IO.Directory]::CreateDirectory($basePath, (New-SyncVisionPackageBootstrapDirectorySecurity)) | Out-Null
    }

    $resolvedBase = Assert-SyncVisionPackageBootstrapDirectory -Path $basePath -Context "base"
    Assert-SyncVisionPackageBootstrapAncestorChain -Path $resolvedBase
    return $resolvedBase
}

function Assert-SyncVisionPackageBootstrapStagingPath {
    param(
        [Parameter(Mandatory = $true)][string]$BasePath,
        [Parameter(Mandatory = $true)][string]$StagingPath
    )

    $resolvedBase = Assert-SyncVisionPackageBootstrapDirectory -Path $BasePath -Context "base"
    Assert-SyncVisionPackageBootstrapAncestorChain -Path $resolvedBase
    $resolvedStage = Assert-SyncVisionPackageBootstrapDirectory -Path $StagingPath -Context "leaf"
    if (-not [string]::Equals((Split-Path -Parent $resolvedStage), $resolvedBase, [StringComparison]::OrdinalIgnoreCase)) {
        throw "Package bootstrap trusted staging leaf is not a direct child of its base."
    }
    return $resolvedStage
}

$rootPath = (Resolve-Path -LiteralPath $Root).Path.TrimEnd("\\", "/")
$rootItem = Get-Item -LiteralPath $rootPath -Force
if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
    throw "Package bootstrap rejects a reparse-point package root: $rootPath"
}
$manifestPath = Join-Path $rootPath "SHA256SUMS.txt"
if (-not (Test-Path -LiteralPath $manifestPath -PathType Leaf)) {
    throw "Package bootstrap could not find SHA256SUMS.txt: $manifestPath"
}
if ($ExpectedManifestSha256 -notmatch "^[0-9a-fA-F]{64}$") {
    throw "Expected manifest digest must be a 64-character hexadecimal SHA-256 value from the publisher-provided external manifest digest."
}

$manifestBytes = [IO.File]::ReadAllBytes($manifestPath)
$actualManifestSha256 = Get-SyncVisionPackageBootstrapSha256 -Bytes $manifestBytes
if (-not [string]::Equals($actualManifestSha256, $ExpectedManifestSha256, [StringComparison]::OrdinalIgnoreCase)) {
    throw "Package bootstrap trusted manifest SHA-256 mismatch. Expected $ExpectedManifestSha256, got $actualManifestSha256."
}

$manifestEntries = New-Object "System.Collections.Generic.Dictionary[string,string]" ([StringComparer]::OrdinalIgnoreCase)
$manifestText = [Text.UTF8Encoding]::new($false).GetString($manifestBytes)
foreach ($line in ($manifestText -split "`r?`n")) {
    $trimmed = $line.Trim()
    if ([string]::IsNullOrWhiteSpace($trimmed)) {
        continue
    }
    if ($trimmed -notmatch "^([0-9a-fA-F]{64})\\s+(.+)$") {
        throw "Package bootstrap rejected an invalid SHA256SUMS.txt entry: $line"
    }

    $relativePath = ConvertTo-SyncVisionPackageBootstrapRelativePath -RelativePath $Matches[2]
    if ($relativePath -ieq "SHA256SUMS.txt" -or $manifestEntries.ContainsKey($relativePath)) {
        throw "Package bootstrap rejected a duplicate or self-referential manifest entry: $relativePath"
    }
    $manifestEntries.Add($relativePath, $Matches[1].ToLowerInvariant())
}

Assert-SyncVisionPackageBootstrapTree -RootPath $rootPath -ManifestPath $manifestPath -ManifestEntries $manifestEntries

$stageBase = Initialize-SyncVisionPackageBootstrapStagingBase
$stageRoot = Join-Path $stageBase ("stage-" + [Guid]::NewGuid().ToString("N"))
[IO.Directory]::CreateDirectory($stageRoot, (New-SyncVisionPackageBootstrapDirectorySecurity)) | Out-Null
$stageRoot = Assert-SyncVisionPackageBootstrapStagingPath -BasePath $stageBase -StagingPath $stageRoot
$stagePackageRoot = Join-Path $stageRoot "package"
[IO.Directory]::CreateDirectory($stagePackageRoot) | Out-Null

try {
    Assert-SyncVisionPackageBootstrapTree -RootPath $rootPath -ManifestPath $manifestPath -ManifestEntries $manifestEntries
    foreach ($relativePath in @($manifestEntries.Keys | Sort-Object)) {
        $sourcePath = Join-Path $rootPath $relativePath
        $stagePath = Join-Path $stagePackageRoot $relativePath
        $stageDirectory = Split-Path -Parent $stagePath
        [IO.Directory]::CreateDirectory($stageDirectory) | Out-Null
        [IO.File]::Copy($sourcePath, $stagePath, $true)

        $stagedHash = (Get-FileHash -LiteralPath $stagePath -Algorithm SHA256).Hash.ToLowerInvariant()
        if ($stagedHash -ne $manifestEntries[$relativePath]) {
            throw "Checksum mismatch for staged package file $relativePath. Expected $($manifestEntries[$relativePath]), got $stagedHash."
        }
    }
    [IO.File]::WriteAllBytes((Join-Path $stagePackageRoot "SHA256SUMS.txt"), $manifestBytes)
    Assert-SyncVisionPackageBootstrapTree -RootPath $rootPath -ManifestPath $manifestPath -ManifestEntries $manifestEntries
    Assert-SyncVisionPackageBootstrapTree `
        -RootPath $stagePackageRoot `
        -ManifestPath (Join-Path $stagePackageRoot "SHA256SUMS.txt") `
        -ManifestEntries $manifestEntries

    $stagedInstaller = Join-Path $stagePackageRoot "scripts\\install-server.ps1"
    if (-not (Test-Path -LiteralPath $stagedInstaller -PathType Leaf)) {
        throw "Package bootstrap could not stage scripts\\install-server.ps1."
    }
    Assert-SyncVisionPackageBootstrapStagingPath -BasePath $stageBase -StagingPath $stageRoot | Out-Null

    Push-Location $stagePackageRoot
    try {
        & $stagedInstaller `
            -SkipBuild `
            -ExpectedManifestSha256 $ExpectedManifestSha256 `
            @InstallArguments
    }
    finally {
        Pop-Location
    }
}
finally {
    if (-not [string]::IsNullOrWhiteSpace($stageRoot) -and (Test-Path -LiteralPath $stageRoot)) {
        try {
            Assert-SyncVisionPackageBootstrapStagingPath -BasePath $stageBase -StagingPath $stageRoot | Out-Null
            Remove-Item -LiteralPath $stageRoot -Recurse -Force -ErrorAction Stop
        }
        catch {
            Write-Warning "Package bootstrap trusted staging cleanup was refused: $($_.Exception.Message)"
        }
    }
}
'@
}

function ConvertTo-SyncVisionGzipBase64 {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Content
    )

    $contentBytes = [Text.UTF8Encoding]::new($false).GetBytes($Content)
    $memory = [IO.MemoryStream]::new()
    try {
        $gzip = [IO.Compression.GzipStream]::new(
            $memory,
            [IO.Compression.CompressionMode]::Compress,
            $true)
        try {
            $gzip.Write($contentBytes, 0, $contentBytes.Length)
        }
        finally {
            $gzip.Dispose()
        }
        return [Convert]::ToBase64String($memory.ToArray())
    }
    finally {
        $memory.Dispose()
    }
}

function Get-SyncVisionLanInstallerCommandContent {
    $bootstrapPayload = ConvertTo-SyncVisionGzipBase64 -Content (Get-SyncVisionLanInstallerElevatedBootstrapContent)
    $commandTemplate = @'
@echo off
setlocal
cd /d "%~dp0"
set "SYNCVISION_ROOT=%~dp0"
set "SYNCVISION_LAN_BOOTSTRAP_PAYLOAD=__SYNCVISION_LAN_BOOTSTRAP_PAYLOAD__"
if not exist "%SYNCVISION_ROOT%scripts\install-server.ps1" (
  echo SyncVision install-server.ps1 was not found.
  echo Please extract the whole SyncVision package before installing the LAN server.
  pause
  exit /b 1
)

echo SyncVision will ask Windows for administrator permission.
echo This installs the LAN relay service and opens the firewall only for LocalSubnet.
if not exist "%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" (
  echo The system Windows PowerShell executable was not found.
  pause
  exit /b 1
)
"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; $q=[char]34; $root=$env:SYNCVISION_ROOT; $expected=$env:SYNCVISION_EXPECTED_MANIFEST_SHA256; $payload=$env:SYNCVISION_LAN_BOOTSTRAP_PAYLOAD; $systemPowerShell=Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'; $script=Join-Path $root 'scripts\install-server.ps1'; $manifestPath=Join-Path $root 'SHA256SUMS.txt'; if ([string]::IsNullOrWhiteSpace($payload)) { throw 'The trusted elevated bootstrap payload was not provided.' }; if (!(Test-Path -LiteralPath $systemPowerShell -PathType Leaf)) { throw 'The system Windows PowerShell executable was not found.' }; if (!(Test-Path -LiteralPath $script -PathType Leaf)) { throw 'install-server.ps1 was not found.' }; if ([string]::IsNullOrWhiteSpace($expected)) { $expected=Read-Host 'Paste the 64-character publisher-provided manifest SHA-256 obtained through an independently trusted channel' }; if ($expected -notmatch '^[0-9a-fA-F]{64}$') { throw 'Expected manifest digest must be a 64-character hexadecimal SHA-256 value from the publisher-provided external manifest digest.' }; if (!(Test-Path -LiteralPath $manifestPath -PathType Leaf)) { throw 'SHA256SUMS.txt was not found.' }; $manifestBytes=[IO.File]::ReadAllBytes($manifestPath); $manifestHasher=[Security.Cryptography.SHA256]::Create(); try { $actualManifestSha256=[BitConverter]::ToString($manifestHasher.ComputeHash($manifestBytes)).Replace('-','').ToLowerInvariant() } finally { $manifestHasher.Dispose() }; if (-not [string]::Equals($actualManifestSha256,$expected,[StringComparison]::OrdinalIgnoreCase)) { throw ('Trusted manifest SHA-256 mismatch. Expected ' + $expected + ', got ' + $actualManifestSha256 + '.') }; $scriptExpectedHash=$null; foreach($line in ([Text.UTF8Encoding]::new($false).GetString($manifestBytes) -split '\r?\n')) { $trimmed=$line.Trim(); if([string]::IsNullOrWhiteSpace($trimmed)){continue}; if($trimmed -notmatch '^([0-9a-fA-F]{64})\s+(.+)$'){throw ('Invalid SHA256SUMS.txt entry: ' + $line)}; $relativePath=$Matches[2].Trim().TrimStart('*') -replace '/','\'; if([string]::Equals($relativePath,'scripts\install-server.ps1',[StringComparison]::OrdinalIgnoreCase)){if($null -ne $scriptExpectedHash){throw 'SHA256SUMS.txt contains duplicate scripts\install-server.ps1 entries.'};$scriptExpectedHash=$Matches[1].ToLowerInvariant()} }; if([string]::IsNullOrWhiteSpace($scriptExpectedHash)){throw 'SHA256SUMS.txt does not contain scripts\install-server.ps1.'}; $scriptBytes=[IO.File]::ReadAllBytes($script); $scriptHasher=[Security.Cryptography.SHA256]::Create(); try { $actualScriptHash=[BitConverter]::ToString($scriptHasher.ComputeHash($scriptBytes)).Replace('-','').ToLowerInvariant() } finally { $scriptHasher.Dispose() }; if($actualScriptHash -ne $scriptExpectedHash){throw ('Checksum mismatch for scripts\install-server.ps1. Expected ' + $scriptExpectedHash + ', got ' + $actualScriptHash + '.')}; $elevatedCommand='$ErrorActionPreference=''Stop''; $payloadBytes=[Convert]::FromBase64String(''' + $payload + '''); $payloadStream=[IO.MemoryStream]::new($payloadBytes); $gzip=[IO.Compression.GzipStream]::new($payloadStream,[IO.Compression.CompressionMode]::Decompress,$false); $reader=[IO.StreamReader]::new($gzip,[Text.UTF8Encoding]::new($false)); try { $PackageBootstrap=[scriptblock]::Create($reader.ReadToEnd()) } finally { $reader.Dispose(); $gzip.Dispose(); $payloadStream.Dispose() }; $installArguments=@(''-Configuration'',''Release'',''-Listen'',''0.0.0.0:38580'',''-Lan'',''-AllowUnsafePublicRelay'',''-ConfigureFirewall'',''-FirewallRemoteAddress'',''LocalSubnet'',''-ServiceAccount'',''NetworkService'',''-Start'',''-VerifyInstall''); & $PackageBootstrap -Root $env:SYNCVISION_ROOT -ExpectedManifestSha256 ' + $expected.ToLowerInvariant() + ' -InstallArguments $installArguments'; $arguments=@('-NoProfile','-ExecutionPolicy','Bypass','-Command',($q + $elevatedCommand + $q)) -join ' '; $process=Start-Process -FilePath $systemPowerShell -Verb RunAs -Wait -PassThru -ArgumentList $arguments; if ($process.ExitCode -ne 0) { throw ('Elevated LAN server installation failed with exit code ' + $process.ExitCode + '.') }"
if errorlevel 1 (
  echo LAN server installation did not complete.
  pause
  exit /b 1
)

echo LAN server installation finished.
pause
'@

    return $commandTemplate.Replace('__SYNCVISION_LAN_BOOTSTRAP_PAYLOAD__', $bootstrapPayload)
}

function Get-SyncVisionBeginnerQuickStartContent {
    param([switch]$AllowUnsignedDevelopmentBootstrap)

    if ($AllowUnsignedDevelopmentBootstrap) {
        return @'
Tongping Expert Quick Start

UNSIGNED DEVELOPMENT BOOTSTRAP INCLUDED
This output is for local development and manual verification only. The CMD is not publisher-authenticated and is not a commercial one-click installer.

1. Extract the whole Tongping Expert zip folder.
2. On the group-control PC, double-click Open Group Console.cmd.
3. Leave the connection fields blank to let the control console start the bundled LAN relay automatically.
4. Generate SyncVisionAgentSetup.exe in the group-control console, copy that one file to each controlled PC, and run it there.
5. For a separately installed LAN relay only, independently verify the external manifest digest before double-clicking Install LAN Server as Administrator.cmd. Treat the unsigned CMD as untrusted development material before approving UAC.

Local and LAN:
- Leaving the connection fields blank is the simplest LAN path. The control console starts the bundled relay automatically.
- The unsigned wrapper exists only because package creation explicitly opted in with -AllowUnsignedDevelopmentBootstrap.

Public relay:
- Public internet use needs a reachable Windows server address, a non-default token file, firewall/NAT rules, and the package examples under examples\.
- Do not publish the default dev-token on a public address.
- Commercial one-click distribution requires a native Authenticode-signed bootstrap or MSI and a production signing certificate.
'@
    }

    return @'
Tongping Expert Quick Start

UNSIGNED DEVELOPMENT PACKAGE - MANUAL VERIFICATION REQUIRED
This output is not publisher-authenticated and intentionally contains no package-local administrator CMD.

1. Verify SHA256SUMS.txt against the external .SHA256SUMS.sha256 sidecar obtained through an independently trusted channel.
2. Extract the whole Tongping Expert zip folder.
3. On the group-control PC, double-click Open Group Console.cmd.
4. Leave the connection fields blank to let the control console start the bundled LAN relay automatically.
5. Generate SyncVisionAgentSetup.exe in the group-control console, copy that one file to each controlled PC, and run it there.

LAN relay manual verification:
- Open an administrator PowerShell session yourself only after independently verifying the package.
- Run scripts\install-server.ps1 with -SkipBuild and -ExpectedManifestSha256 using the externally verified digest.
- This development package does not provide a one-click elevation entrypoint.

Public relay:
- Public internet use needs a reachable Windows server address, a non-default token file, firewall/NAT rules, and the package examples under examples\.
- Do not publish the default dev-token on a public address.
- Commercial one-click distribution requires a native Authenticode-signed bootstrap or MSI and a production signing certificate.
'@
}

function Get-SyncVisionPackageEntries {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RepoRoot,

        [ValidateSet("Debug", "Release")]
        [string]$Configuration = "Release",

        [switch]$EnableWebRtc,

        [switch]$AllowUnsignedDevelopmentBootstrap,

        [AllowNull()]
        [object]$BuildFlavorManifest
    )

    $entries = New-Object System.Collections.Generic.List[object]
    $entries.Add((New-SyncVisionPackageEntry `
        -Content (Get-SyncVisionPackageMarkerContent `
            -Configuration $Configuration `
            -AllowUnsignedDevelopmentBootstrap:$AllowUnsignedDevelopmentBootstrap) `
        -Destination "SyncVisionPackage.json"))

    $releaseDir = Join-Path $RepoRoot "build\x64\$Configuration"
    $entries.Add((New-SyncVisionPackageEntry `
        -Source (Get-SyncVisionBuildFlavorManifestPath -RepoRoot $RepoRoot -Configuration $Configuration) `
        -Destination (Join-Path "build\x64\$Configuration" "SyncVisionBuildFlavor.json")))
    $accountEnabledProperty = if ($null -eq $BuildFlavorManifest) {
        $null
    }
    else {
        $BuildFlavorManifest.PSObject.Properties["account_enabled"]
    }
    if ($null -ne $accountEnabledProperty -and $accountEnabledProperty.Value -eq $true) {
        $accountConfigRelativePath = Resolve-SyncVisionAccountReleaseConfigRelativePath `
            -RelativePath $BuildFlavorManifest.account_release_config_relative_path
        $entries.Add((New-SyncVisionPackageEntry `
            -Source (Join-Path $RepoRoot ($accountConfigRelativePath -replace '/', '\')) `
            -Destination ($accountConfigRelativePath -replace '/', '\')))
    }

    foreach ($name in (Get-SyncVisionPackagePublicExecutableNames)) {
        $entries.Add((New-SyncVisionPackageEntry `
            -Source (Join-Path $releaseDir $name) `
            -Destination (Join-Path "build\x64\$Configuration" $name)))
    }

    foreach ($name in (Get-SyncVisionAgentPayloadExecutableNames)) {
        $entries.Add((New-SyncVisionPackageEntry `
            -Source (Join-Path $releaseDir $name) `
            -Destination (Join-Path "build\x64\$Configuration\private-runtime" $name)))
    }

    foreach ($name in (Get-SyncVisionVcRuntimeDllNames)) {
        $source = Join-Path $releaseDir $name
        $entries.Add((New-SyncVisionPackageEntry `
            -Source $source `
            -Destination (Join-Path "build\x64\$Configuration" $name)))
        $entries.Add((New-SyncVisionPackageEntry `
            -Source $source `
            -Destination (Join-Path "build\x64\$Configuration\private-runtime" $name)))
    }

    if ($EnableWebRtc) {
        if ($null -eq $BuildFlavorManifest) {
            $buildFlavorManifestPath = Get-SyncVisionBuildFlavorManifestPath `
                -RepoRoot $RepoRoot `
                -Configuration $Configuration
            $BuildFlavorManifest = Get-Content -LiteralPath $buildFlavorManifestPath -Raw | ConvertFrom-Json
        }
        $webRtcRuntimeDllNames = @(
            $BuildFlavorManifest.runtime_dll_sha256.PSObject.Properties |
                ForEach-Object { $_.Name })
        foreach ($name in $webRtcRuntimeDllNames) {
            $entries.Add((New-SyncVisionPackageEntry `
                -Source (Join-Path $releaseDir $name) `
                -Destination (Join-Path "build\x64\$Configuration" $name)))
            $entries.Add((New-SyncVisionPackageEntry `
                -Source (Join-Path $releaseDir $name) `
                -Destination (Join-Path "build\x64\$Configuration\private-runtime" $name)))
        }
    }

    $scriptNames = @(
        "SyncVisionAccountReleaseConfig.ps1",
        "install-server.ps1",
        "new-client-config.ps1",
        "package-release.ps1",
        "start-host.ps1",
        "start-server.ps1",
        "start-viewer.ps1",
        "status-server.ps1",
        "uninstall-server.ps1",
        "run-public-relay-e2e-smoke.ps1",
        "verify-public-relay.ps1"
    )
    foreach ($name in $scriptNames) {
        $entries.Add((New-SyncVisionPackageEntry `
            -Source (Join-Path (Join-Path $RepoRoot "scripts") $name) `
            -Destination (Join-Path "scripts" $name)))
    }

    $docNames = @(
        "README.md",
        "docs\runbooks\cpp-local-smoke.md",
        "docs\runbooks\cpp-server-deployment.md",
        "docs\runbooks\webrtc-build.md"
    )
    foreach ($name in $docNames) {
        $entries.Add((New-SyncVisionPackageEntry `
            -Source (Join-Path $RepoRoot $name) `
            -Destination $name))
    }

    $entries.Add((New-SyncVisionPackageEntry `
        -Content (Get-SyncVisionControlCommandContent -Configuration $Configuration) `
        -Destination "Open Group Console.cmd"))

    if ($AllowUnsignedDevelopmentBootstrap) {
        $entries.Add((New-SyncVisionPackageEntry `
            -Content (Get-SyncVisionLanInstallerCommandContent) `
            -Destination "Install LAN Server as Administrator.cmd"))
    }

    $entries.Add((New-SyncVisionPackageEntry `
        -Content (Get-SyncVisionBeginnerQuickStartContent `
            -AllowUnsignedDevelopmentBootstrap:$AllowUnsignedDevelopmentBootstrap) `
        -Destination "Tongping Expert Quick Start.txt"))

    $entries.Add((New-SyncVisionPackageEntry `
        -Content (Get-SyncVisionPrerequisitesContent) `
        -Destination "docs\runbooks\release-prerequisites.md"))

    $exampleNames = @(
        "examples\server.public.conf.example",
        "examples\server.lan.conf.example",
        "examples\client.public.conf.example",
        "examples\install-public-relay.example.ps1",
        "examples\install-lan-relay.example.ps1",
        "examples\new-client-config.example.ps1",
        "examples\start-host.example.ps1",
        "examples\start-viewer.example.ps1",
        "examples\device.tokens.example",
        "examples\verify-public-relay.example.ps1"
    )
    foreach ($name in $exampleNames) {
        $entries.Add((New-SyncVisionPackageEntry `
            -Content (Get-SyncVisionExampleContent -Destination $name) `
            -Destination $name))
    }

    return $entries
}

function New-SyncVisionPackagePlan {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RepoRoot,

        [Parameter(Mandatory = $true)]
        [string]$OutputRoot,

        [Parameter(Mandatory = $true)]
        [string]$Version,

        [ValidateSet("Debug", "Release")]
        [string]$Configuration = "Release",

        [switch]$EnableWebRtc,

        [switch]$AllowUnsignedDevelopmentBootstrap,

        [AllowNull()]
        [object]$BuildFlavorManifest
    )

    $packageName = New-SyncVisionPackageName `
        -Version $Version `
        -AllowUnsignedDevelopmentBootstrap:$AllowUnsignedDevelopmentBootstrap
    $packageRoot = Join-Path $OutputRoot $packageName

    [pscustomobject]@{
        PackageName = $packageName
        PublicationOutputRoot = [IO.Path]::GetFullPath($OutputRoot)
        PackageRoot = $packageRoot
        ZipPath = Join-Path $OutputRoot "$packageName.zip"
        ManifestPath = Join-Path $packageRoot "SHA256SUMS.txt"
        ManifestDigestPath = Join-Path $OutputRoot "$packageName.SHA256SUMS.sha256"
        EnableWebRtc = [bool]$EnableWebRtc
        AllowUnsignedDevelopmentBootstrap = [bool]$AllowUnsignedDevelopmentBootstrap
        Entries = @(Get-SyncVisionPackageEntries `
            -RepoRoot $RepoRoot `
            -Configuration $Configuration `
            -EnableWebRtc:$EnableWebRtc `
            -AllowUnsignedDevelopmentBootstrap:$AllowUnsignedDevelopmentBootstrap `
            -BuildFlavorManifest $BuildFlavorManifest)
    }
}

function Assert-SyncVisionPackageInputs {
    param(
        [Parameter(Mandatory = $true)]
        [object[]]$Entries
    )

    foreach ($entry in $Entries) {
        if ($entry.Generated) {
            continue
        }
        if (-not (Test-Path -LiteralPath $entry.Source -PathType Leaf)) {
            throw "Release package input was not found: $($entry.Source)"
        }
    }
}

function Copy-SyncVisionPackageEntries {
    param(
        [Parameter(Mandatory = $true)]
        [string]$PackageRoot,

        [Parameter(Mandatory = $true)]
        [object[]]$Entries
    )

    if (-not (Test-Path -LiteralPath $PackageRoot)) {
        New-Item -ItemType Directory -Path $PackageRoot | Out-Null
    }
    $rootItem = Get-Item -LiteralPath $PackageRoot -Force
    if (-not $rootItem.PSIsContainer -or
        ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
        @(Get-ChildItem -LiteralPath $PackageRoot -Force).Count -ne 0) {
        throw "Release package construction root must be a fresh empty non-reparse directory: $PackageRoot"
    }

    foreach ($entry in $Entries) {
        $target = Join-Path $PackageRoot $entry.Destination
        $targetDir = Split-Path -Parent $target
        New-Item -ItemType Directory -Force -Path $targetDir | Out-Null
        if ($entry.Generated) {
            [IO.File]::WriteAllText($target, ($entry.Content.TrimEnd() + [Environment]::NewLine), [Text.UTF8Encoding]::new($false))
        }
        else {
            Copy-Item -LiteralPath $entry.Source -Destination $target -Force
        }
    }
}

function Write-SyncVisionChecksumManifest {
    param(
        [Parameter(Mandatory = $true)]
        [string]$PackageRoot,

        [Parameter(Mandatory = $true)]
        [string]$ManifestPath
    )

    $rootPath = (Resolve-Path -LiteralPath $PackageRoot).Path
    $manifestLeaf = Split-Path -Leaf $ManifestPath
    $files = Get-ChildItem -LiteralPath $rootPath -File -Recurse |
        Where-Object { $_.Name -ne $manifestLeaf } |
        Sort-Object FullName

    $lines = foreach ($file in $files) {
        $relative = $file.FullName.Substring($rootPath.Length).TrimStart('\') -replace '\\', '/'
        $hash = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
        "$hash  $relative"
    }

    [IO.File]::WriteAllText($ManifestPath, (($lines -join [Environment]::NewLine) + [Environment]::NewLine), [Text.UTF8Encoding]::new($false))
}

function Write-SyncVisionManifestDigestSidecar {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ManifestPath,

        [Parameter(Mandatory = $true)]
        [string]$ManifestDigestPath
    )

    $manifestHash = (Get-FileHash -LiteralPath $ManifestPath -Algorithm SHA256).Hash.ToLowerInvariant()
    [IO.File]::WriteAllText($ManifestDigestPath, $manifestHash + [Environment]::NewLine, [Text.UTF8Encoding]::new($false))
}

function Assert-SyncVisionPackagePublicationBoundary {
    param([Parameter(Mandatory = $true)][string]$OutputRoot)

    $root = [IO.Path]::GetFullPath($OutputRoot).TrimEnd('\', '/')
    if (-not (Test-Path -LiteralPath $root -PathType Container)) {
        throw "Package publication output root was not found: $root"
    }
    $trustedSids = @(Get-SyncVisionPackageTrustedSids) + @(
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464")
    $mutation = Get-SyncVisionPackageMutationRights
    $destructive = Get-SyncVisionPackageDestructiveRights
    $current = Get-Item -LiteralPath (Resolve-Path -LiteralPath $root).Path -Force
    $isOutputRoot = $true
    while ($null -ne $current) {
        if ($current -isnot [IO.DirectoryInfo] -or
            ($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package publication boundary contains a non-directory or reparse point: $($current.FullName)"
        }
        $acl = Get-Acl -LiteralPath $current.FullName
        $owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if ($trustedSids -notcontains $owner) {
            throw "Package publication boundary has an untrusted owner SID $owner at $($current.FullName)."
        }
        $rejectedRights = if ($isOutputRoot) { $mutation } else { $destructive }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            if (-not $isOutputRoot -and
                ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -ne 0) {
                continue
            }
            if ($rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $rejectedRights) -ne 0) {
                if ($isOutputRoot) {
                    throw "Package publication output root grants an untrusted SID content, metadata, inheritable, delete, or ACL mutation rights at $($current.FullName)."
                }
                throw "Package publication ancestor grants an untrusted SID delete, ACL-control, or replacement rights at $($current.FullName)."
            }
        }
        $isOutputRoot = $false
        $current = $current.Parent
    }
    return $root
}

function Initialize-SyncVisionPackagePublicationRoot {
    param([Parameter(Mandatory = $true)][string]$OutputRoot)

    $root = [IO.Path]::GetFullPath($OutputRoot).TrimEnd('\', '/')
    $volumeRoot = [IO.Path]::GetPathRoot($root).TrimEnd('\', '/')
    if ([string]::Equals($root, $volumeRoot, [StringComparison]::OrdinalIgnoreCase)) {
        throw "Package publication output root must be a non-root directory path: $root"
    }
    if (Test-Path -LiteralPath $root) {
        return Assert-SyncVisionPackagePublicationBoundary -OutputRoot $root
    }

    $missing = New-Object "System.Collections.Generic.Stack[string]"
    $existing = $root
    while (-not (Test-Path -LiteralPath $existing)) {
        $missing.Push($existing)
        $parent = Split-Path -Parent $existing
        if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $existing) {
            throw "Package publication output root has no existing directory ancestor: $root"
        }
        $existing = $parent
    }
    if (-not (Test-Path -LiteralPath $existing -PathType Container)) {
        throw "Package publication output root ancestor is not a directory: $existing"
    }
    Assert-SyncVisionPackagePublicationBoundary -OutputRoot $existing | Out-Null

    while ($missing.Count -ne 0) {
        $nextPath = $missing.Pop()
        $parent = Split-Path -Parent $nextPath
        Assert-SyncVisionPackagePublicationBoundary -OutputRoot $parent | Out-Null
        if (-not (Test-Path -LiteralPath $nextPath)) {
            [IO.Directory]::CreateDirectory(
                $nextPath,
                (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
        }
        Assert-SyncVisionTrustedPackageDirectory `
            -Path $nextPath `
            -Context "Protected package publication output root" | Out-Null
        Assert-SyncVisionPackagePublicationBoundary -OutputRoot $nextPath | Out-Null
    }

    return Assert-SyncVisionPackagePublicationBoundary -OutputRoot $root
}

function New-SyncVisionCanonicalPackageArchive {
    param(
        [Parameter(Mandatory = $true)][string]$PackageRoot,
        [Parameter(Mandatory = $true)][string]$ZipPath,
        [Parameter(Mandatory = $true)][string]$ArchiveRootName
    )

    try {
        if ($null -eq ("System.IO.Compression.ZipArchive" -as [type])) {
            Microsoft.PowerShell.Utility\Add-Type -AssemblyName System.IO.Compression
        }
    }
    catch {
        throw "The structured ZIP creation assembly could not be loaded. $($_.Exception.Message)"
    }

    $root = (Resolve-Path -LiteralPath $PackageRoot).Path.TrimEnd('\', '/')
    if ([string]::IsNullOrWhiteSpace($ArchiveRootName) -or
        $ArchiveRootName.IndexOfAny([char[]]@('\', '/')) -ge 0) {
        throw "Package archive root name is invalid: $ArchiveRootName"
    }
    if (Test-Path -LiteralPath $ZipPath) {
        throw "Package archive destination already exists: $ZipPath"
    }

    $zipStream = $null
    $archive = $null
    try {
        $zipStream = [IO.File]::Open(
            $ZipPath,
            [IO.FileMode]::CreateNew,
            [IO.FileAccess]::ReadWrite,
            [IO.FileShare]::None)
        $archive = [IO.Compression.ZipArchive]::new(
            $zipStream,
            [IO.Compression.ZipArchiveMode]::Create,
            $true)

        $archive.CreateEntry(
            "$ArchiveRootName/",
            [IO.Compression.CompressionLevel]::NoCompression) | Out-Null
        foreach ($item in (Get-ChildItem -LiteralPath $root -Recurse -Force | Sort-Object -Property FullName)) {
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Package archive source tree contains a reparse point: $($item.FullName)"
            }
            $relativePath = $item.FullName.Substring($root.Length).TrimStart([char[]]@('\', '/')) -replace '\\', '/'
            if ([string]::IsNullOrWhiteSpace($relativePath)) {
                throw "Package archive source tree contains an empty relative path."
            }
            $entryName = "$ArchiveRootName/$relativePath"
            if ($item.PSIsContainer) {
                $archive.CreateEntry(
                    "$entryName/",
                    [IO.Compression.CompressionLevel]::NoCompression) | Out-Null
                continue
            }

            $entry = $archive.CreateEntry(
                $entryName,
                [IO.Compression.CompressionLevel]::Optimal)
            $sourceStream = $null
            $entryStream = $null
            try {
                $sourceStream = [IO.File]::Open(
                    $item.FullName,
                    [IO.FileMode]::Open,
                    [IO.FileAccess]::Read,
                    [IO.FileShare]::Read)
                $entryStream = $entry.Open()
                $sourceStream.CopyTo($entryStream)
            }
            finally {
                if ($null -ne $entryStream) { $entryStream.Dispose() }
                if ($null -ne $sourceStream) { $sourceStream.Dispose() }
            }
        }
    }
    catch {
        if ($null -ne $archive) {
            $archive.Dispose()
            $archive = $null
        }
        if ($null -ne $zipStream) {
            $zipStream.Dispose()
            $zipStream = $null
        }
        if (Test-Path -LiteralPath $ZipPath -PathType Leaf) {
            [IO.File]::Delete($ZipPath)
        }
        throw
    }
    finally {
        if ($null -ne $archive) { $archive.Dispose() }
        if ($null -ne $zipStream) { $zipStream.Dispose() }
    }
}

function ConvertTo-SyncVisionCanonicalPackageArchiveEntry {
    param(
        [Parameter(Mandatory = $true)][string]$EntryName,
        [Parameter(Mandatory = $true)][string]$ArchiveRootName
    )

    if ([string]::IsNullOrWhiteSpace($EntryName)) {
        throw "Package archive contains an unsafe empty entry name."
    }
    if ($EntryName.Contains("\")) {
        throw "Package archive entry uses a non-standard path separator: $EntryName"
    }
    $isDirectory = $EntryName.EndsWith("/", [StringComparison]::Ordinal)
    $normalized = $EntryName
    if ($normalized.StartsWith("/", [StringComparison]::Ordinal)) {
        throw "Package archive contains an unsafe rooted entry: $EntryName"
    }
    $path = if ($isDirectory) {
        $normalized.Substring(0, $normalized.Length - 1)
    }
    else {
        $normalized
    }
    if ([string]::IsNullOrWhiteSpace($path) -or $path.EndsWith("/", [StringComparison]::Ordinal)) {
        throw "Package archive contains an unsafe non-canonical entry: $EntryName"
    }

    $segments = @($path.Split('/'))
    foreach ($segment in $segments) {
        if ([string]::IsNullOrWhiteSpace($segment) -or
            $segment -eq "." -or
            $segment -eq ".." -or
            $segment.EndsWith(" ", [StringComparison]::Ordinal) -or
            $segment.EndsWith(".", [StringComparison]::Ordinal) -or
            $segment -match '[\x00-\x1f<>:"|?*]' -or
            $segment -match '^(?i:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)' -or
            $segment.Normalize([Text.NormalizationForm]::FormC) -cne $segment) {
            throw "Package archive contains an unsafe or non-canonical entry: $EntryName"
        }
    }
    if ($segments[0] -cne $ArchiveRootName) {
        throw "Package archive entry is outside the intended archive root '$ArchiveRootName': $EntryName"
    }
    return [pscustomobject]@{ Path = $path; IsDirectory = $isDirectory }
}

function Assert-SyncVisionPackageArchiveMatchesTree {
    param(
        [Parameter(Mandatory = $true)][string]$PackageRoot,
        [Parameter(Mandatory = $true)][string]$ZipPath,
        [Parameter(Mandatory = $true)][string]$ArchiveRootName
    )

    try {
        if ($null -eq ("System.IO.Compression.ZipArchive" -as [type])) {
            Microsoft.PowerShell.Utility\Add-Type -AssemblyName System.IO.Compression
        }
        if ($null -eq ("System.IO.Compression.ZipFile" -as [type])) {
            Microsoft.PowerShell.Utility\Add-Type -AssemblyName System.IO.Compression.FileSystem
        }
    }
    catch {
        throw "The structured ZIP validation assemblies could not be loaded. $($_.Exception.Message)"
    }

    $root = (Resolve-Path -LiteralPath $PackageRoot).Path.TrimEnd('\', '/')
    $expectedFiles = New-Object "System.Collections.Generic.Dictionary[string,object]" ([StringComparer]::Ordinal)
    $expectedDirectories = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    [void]$expectedDirectories.Add($ArchiveRootName)
    foreach ($item in (Get-ChildItem -LiteralPath $root -Recurse -Force)) {
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package archive source tree contains a reparse point: $($item.FullName)"
        }
        $relativePath = $item.FullName.Substring($root.Length).TrimStart([char[]]@('\', '/')) -replace '\\', '/'
        $archivePath = "$ArchiveRootName/$relativePath"
        if ($item.PSIsContainer) {
            [void]$expectedDirectories.Add($archivePath)
        }
        else {
            $expectedFiles.Add($archivePath, [pscustomobject]@{
                    Length = [Int64]$item.Length
                    Sha256 = (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
                })
        }
    }

    $seenEntries = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $observedFiles = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    $representedDirectories = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    $archive = $null
    try {
        $archive = [IO.Compression.ZipFile]::OpenRead($ZipPath)
        foreach ($entry in $archive.Entries) {
            $canonical = ConvertTo-SyncVisionCanonicalPackageArchiveEntry `
                -EntryName $entry.FullName `
                -ArchiveRootName $ArchiveRootName
            if (-not $seenEntries.Add($canonical.Path)) {
                throw "Package archive contains a duplicate entry identity: $($entry.FullName)"
            }
            $unixFileType = (([int]$entry.ExternalAttributes -shr 16) -band 0xf000)
            if ($unixFileType -eq 0xa000) {
                throw "Package archive contains an unsafe symbolic-link entry: $($entry.FullName)"
            }

            if ($canonical.IsDirectory) {
                if ($entry.Length -ne 0 -or -not $expectedDirectories.Contains($canonical.Path)) {
                    throw "Package archive directory entry does not match the sealed package tree: $($entry.FullName)"
                }
                $directoryPath = $canonical.Path
                while (-not [string]::IsNullOrWhiteSpace($directoryPath)) {
                    [void]$representedDirectories.Add($directoryPath)
                    $separatorIndex = $directoryPath.LastIndexOf('/')
                    $directoryPath = if ($separatorIndex -lt 0) { "" } else { $directoryPath.Substring(0, $separatorIndex) }
                }
                continue
            }

            if (-not $expectedFiles.ContainsKey($canonical.Path)) {
                throw "Package archive file entry does not match the sealed package tree: $($entry.FullName)"
            }
            $expected = $expectedFiles[$canonical.Path]
            if ([Int64]$entry.Length -ne [Int64]$expected.Length) {
                throw "Package archive file length mismatch for $($entry.FullName). Expected $($expected.Length), got $($entry.Length)."
            }
            try {
                $stream = $entry.Open()
                try {
                    $sha256 = [Security.Cryptography.SHA256]::Create()
                    try {
                        $actualHash = ([BitConverter]::ToString($sha256.ComputeHash($stream))).Replace("-", "").ToLowerInvariant()
                    }
                    finally { $sha256.Dispose() }
                }
                finally { $stream.Dispose() }
            }
            catch {
                throw "Package archive entry could not be read safely: $($entry.FullName). $($_.Exception.Message)"
            }
            if ($actualHash -cne [string]$expected.Sha256) {
                throw "Package archive file hash mismatch for $($entry.FullName). Expected $($expected.Sha256), got $actualHash."
            }
            [void]$observedFiles.Add($canonical.Path)

            $separatorIndex = $canonical.Path.LastIndexOf('/')
            $directoryPath = if ($separatorIndex -lt 0) { "" } else { $canonical.Path.Substring(0, $separatorIndex) }
            while (-not [string]::IsNullOrWhiteSpace($directoryPath)) {
                [void]$representedDirectories.Add($directoryPath)
                $separatorIndex = $directoryPath.LastIndexOf('/')
                $directoryPath = if ($separatorIndex -lt 0) { "" } else { $directoryPath.Substring(0, $separatorIndex) }
            }
        }
    }
    catch {
        if ($_.Exception.Message -match '^Package archive ') { throw }
        throw "Package archive is not a readable structured ZIP: $ZipPath. $($_.Exception.Message)"
    }
    finally {
        if ($null -ne $archive) { $archive.Dispose() }
    }

    if ($observedFiles.Count -ne $expectedFiles.Count) {
        $missingFiles = @($expectedFiles.Keys | Where-Object { -not $observedFiles.Contains($_) })
        throw "Package archive file entry set does not match the sealed package tree. Missing: $($missingFiles -join ', ')"
    }
    $missingDirectories = @($expectedDirectories | Where-Object { -not $representedDirectories.Contains($_) })
    if ($missingDirectories.Count -ne 0) {
        throw "Package archive directory entry set does not match the sealed package tree. Missing: $($missingDirectories -join ', ')"
    }
    return [pscustomobject]@{ FileCount = $observedFiles.Count; DirectoryCount = $representedDirectories.Count }
}

function Assert-SyncVisionConstructedPackage {
    param(
        [Parameter(Mandatory = $true)][string]$PackageRoot,
        [Parameter(Mandatory = $true)][string]$ManifestPath,
        [Parameter(Mandatory = $true)][string]$ManifestDigestPath,
        [AllowEmptyString()][string]$ZipPath = "",
        [AllowEmptyString()][string]$ArchiveRootName = ""
    )

    Assert-SyncVisionPackageTreeTrustMetadata `
        -Root $PackageRoot `
        -Context "Constructed package tree" | Out-Null
    if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf) -or
        -not (Test-Path -LiteralPath $ManifestDigestPath -PathType Leaf)) {
        throw "Constructed package is missing its manifest or external digest sidecar."
    }
    foreach ($path in @($ManifestPath, $ManifestDigestPath)) {
        Assert-SyncVisionPackagePathTrustMetadata `
            -Path $path `
            -Context "Constructed package identity file" | Out-Null
    }
    $manifestHash = (Get-FileHash -LiteralPath $ManifestPath -Algorithm SHA256).Hash.ToLowerInvariant()
    $recordedHash = (Get-Content -LiteralPath $ManifestDigestPath -Raw).Trim()
    if ($recordedHash -cne $manifestHash) {
        throw "Constructed package manifest digest sidecar mismatch. Expected $manifestHash, got $recordedHash."
    }
    if (-not [string]::IsNullOrWhiteSpace($ZipPath)) {
        if (-not (Test-Path -LiteralPath $ZipPath -PathType Leaf) -or
            (((Get-Item -LiteralPath $ZipPath -Force).Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0)) {
            throw "Constructed package ZIP is missing or is a reparse point: $ZipPath"
        }
        Assert-SyncVisionPackagePathTrustMetadata `
            -Path $ZipPath `
            -Context "Constructed package ZIP" | Out-Null
        if ([string]::IsNullOrWhiteSpace($ArchiveRootName)) {
            $ArchiveRootName = Split-Path -Leaf ([IO.Path]::GetFullPath($PackageRoot).TrimEnd('\', '/'))
        }
        Assert-SyncVisionPackageArchiveMatchesTree `
            -PackageRoot $PackageRoot `
            -ZipPath $ZipPath `
            -ArchiveRootName $ArchiveRootName | Out-Null
    }
    return [pscustomobject]@{
        PackageTreeSha256 = Get-SyncVisionDirectoryTreeSha256 -Root $PackageRoot
        ManifestSha256 = $manifestHash
        ManifestDigestFileSha256 = (Get-FileHash -LiteralPath $ManifestDigestPath -Algorithm SHA256).Hash.ToLowerInvariant()
        ZipSha256 = if ([string]::IsNullOrWhiteSpace($ZipPath)) { $null } else { (Get-FileHash -LiteralPath $ZipPath -Algorithm SHA256).Hash.ToLowerInvariant() }
    }
}

function Assert-SyncVisionSealedPackageIdentityUnchanged {
    param(
        [Parameter(Mandatory = $true)][object]$Expected,
        [Parameter(Mandatory = $true)][object]$Actual,
        [Parameter(Mandatory = $true)][string]$Context
    )

    foreach ($propertyName in @("PackageTreeSha256", "ManifestSha256", "ManifestDigestFileSha256")) {
        if ([string]$Expected.$propertyName -cne [string]$Actual.$propertyName) {
            throw "$Context changed sealed package identity: $propertyName"
        }
    }
    return $Actual
}

function Remove-SyncVisionPackagePublicationPath {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string[]]$AllowedLeafPrefixes
    )

    if (-not (Test-Path -LiteralPath $Path)) { return }
    $full = (Resolve-Path -LiteralPath $Path).Path
    $parent = Split-Path -Parent $full
    $leaf = Split-Path -Leaf $full
    if (-not [string]::Equals($parent, $OutputRoot, [StringComparison]::OrdinalIgnoreCase) -or
        @($AllowedLeafPrefixes | Where-Object { $leaf.StartsWith($_, [StringComparison]::Ordinal) }).Count -eq 0) {
        throw "Refusing to remove an unexpected package publication path: $full"
    }
    $item = Get-Item -LiteralPath $full -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Refusing to remove a reparse-point package publication path: $full"
    }
    if ($item.PSIsContainer) {
        Assert-SyncVisionTrustedPackageTreeNoReparse -Root $full
        Remove-Item -LiteralPath $full -Recurse -Force -ErrorAction Stop
    }
    else {
        Remove-Item -LiteralPath $full -Force -ErrorAction Stop
    }
}

function Resolve-SyncVisionPackageTrustedWindowsPowerShell {
    param([Parameter(Mandatory = $true)][object]$ExpectedIdentity)

    $windowsRoot = [IO.Directory]::GetParent([Environment]::SystemDirectory).FullName.TrimEnd('\', '/')
    $path = Join-Path $windowsRoot "System32\WindowsPowerShell\v1.0\powershell.exe"
    $trustedSids = @(
        "S-1-5-18",
        "S-1-5-32-544",
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
    )
    $mutation = [Security.AccessControl.FileSystemRights]::WriteData -bor
        [Security.AccessControl.FileSystemRights]::AppendData -bor
        [Security.AccessControl.FileSystemRights]::WriteExtendedAttributes -bor
        [Security.AccessControl.FileSystemRights]::WriteAttributes -bor
        [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
    $destructive = [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
    $current = Get-Item -LiteralPath (Resolve-Path -LiteralPath $path).Path -Force
    while ($null -ne $current) {
        if (($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Windows PowerShell trust boundary contains a reparse point: $($current.FullName)"
        }
        $acl = Get-Acl -LiteralPath $current.FullName
        $owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if ($trustedSids -notcontains $owner) {
            throw "Windows PowerShell trust boundary has an untrusted owner SID $owner at $($current.FullName)."
        }
        $normalized = $current.FullName.TrimEnd('\', '/')
        $reject = if ($normalized.StartsWith($windowsRoot + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase) -or
            [string]::Equals($normalized, $windowsRoot, [StringComparison]::OrdinalIgnoreCase)) { $mutation } else { $destructive }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($applies -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $reject) -ne 0) {
                throw "Windows PowerShell trust boundary grants an untrusted SID mutation rights at $($current.FullName)."
            }
        }
        $current = if ($current -is [IO.DirectoryInfo]) { $current.Parent } else { $current.Directory }
    }
    $item = Get-Item -LiteralPath $path -Force
    $actualVersion = [string]$item.VersionInfo.FileVersion
    $actualVersionRaw = [string]$item.VersionInfo.FileVersionRaw
    $actualHash = (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
    $signature = Get-AuthenticodeSignature -LiteralPath $item.FullName
    if ($actualVersionRaw -cne [string]$ExpectedIdentity.file_version_raw) {
        throw "Windows PowerShell raw file version mismatch. Expected '$($ExpectedIdentity.file_version_raw)', got '$actualVersionRaw'."
    }
    if ($item.Name -cne $ExpectedIdentity.file_name -or
        $actualHash -cne $ExpectedIdentity.sha256 -or
        $signature.Status -ne [Management.Automation.SignatureStatus]::Valid -or
        $null -eq $signature.SignerCertificate -or
        $signature.SignerCertificate.Thumbprint.ToUpperInvariant() -cne $ExpectedIdentity.signer_thumbprint -or
        $signature.SignerCertificate.Subject -cne $ExpectedIdentity.signer_subject -or
        $signature.SignerCertificate.Subject -notmatch '(^|, )O=Microsoft Corporation(,|$)') {
        throw "Windows PowerShell identity differs from the reviewed dependency lock."
    }
    return [pscustomobject]@{ Path = $item.FullName; Hash = $actualHash; Version = $actualVersion; VersionRaw = $actualVersionRaw }
}

function Initialize-SyncVisionPackagePathIdentityType {
    if ("SyncVisionTask19PackagePathIdentity" -as [type]) { return }
    Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public static class SyncVisionTask19PackagePathIdentity
{
    private const uint FILE_READ_EA = 0x00000008u;
    private const uint FILE_SHARE_READ = 0x00000001u;
    private const uint FILE_SHARE_WRITE = 0x00000002u;
    private const uint FILE_SHARE_DELETE = 0x00000004u;
    private const uint OPEN_EXISTING = 3u;
    private const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000u;
    private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000u;
    private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400u;
    private const uint MOVEFILE_REPLACE_EXISTING = 0x00000001u;
    private const uint MOVEFILE_WRITE_THROUGH = 0x00000008u;

    [StructLayout(LayoutKind.Sequential)]
    private struct BY_HANDLE_FILE_INFORMATION
    {
        public uint FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public uint VolumeSerialNumber;
        public uint FileSizeHigh;
        public uint FileSizeLow;
        public uint NumberOfLinks;
        public uint FileIndexHigh;
        public uint FileIndexLow;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern SafeFileHandle CreateFile(
        string fileName, uint desiredAccess, uint shareMode, IntPtr securityAttributes,
        uint creationDisposition, uint flagsAndAttributes, IntPtr templateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetFileInformationByHandle(
        SafeFileHandle handle, out BY_HANDLE_FILE_INFORMATION information);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool MoveFileEx(string existingName, string newName, uint flags);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool ReplaceFile(
        string replacedFileName,
        string replacementFileName,
        string backupFileName,
        uint replaceFlags,
        IntPtr exclude,
        IntPtr reserved);

    [StructLayout(LayoutKind.Sequential)]
    private struct IO_STATUS_BLOCK
    {
        public IntPtr Status;
        public IntPtr Information;
    }

    [DllImport("ntdll.dll")]
    private static extern int NtQueryEaFile(
        SafeFileHandle fileHandle,
        out IO_STATUS_BLOCK ioStatusBlock,
        IntPtr buffer,
        uint length,
        [MarshalAs(UnmanagedType.U1)] bool returnSingleEntry,
        IntPtr eaList,
        uint eaListLength,
        IntPtr eaIndex,
        [MarshalAs(UnmanagedType.U1)] bool restartScan);

    private static BY_HANDLE_FILE_INFORMATION GetInformation(string path)
    {
        using (SafeFileHandle handle = CreateFile(
            path,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateFile for package output identity failed.");
            }
            BY_HANDLE_FILE_INFORMATION information;
            if (!GetFileInformationByHandle(handle, out information))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "GetFileInformationByHandle failed.");
            }
            if ((information.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
            {
                throw new InvalidOperationException("Package path identity rejected a reparse point.");
            }
            return information;
        }
    }

    public static string Get(string path)
    {
        BY_HANDLE_FILE_INFORMATION information = GetInformation(path);
        return information.VolumeSerialNumber.ToString("x8") + ":" +
            information.FileIndexHigh.ToString("x8") + information.FileIndexLow.ToString("x8");
    }

    public static string GetHandleIdentity(SafeFileHandle handle)
    {
        if (handle == null || handle.IsInvalid)
        {
            throw new ArgumentException("Package identity requires a valid file handle.", "handle");
        }
        BY_HANDLE_FILE_INFORMATION information;
        if (!GetFileInformationByHandle(handle, out information))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "GetFileInformationByHandle failed.");
        }
        if ((information.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
        {
            throw new InvalidOperationException("Package handle identity rejected a reparse point.");
        }
        return information.VolumeSerialNumber.ToString("x8") + ":" +
            information.FileIndexHigh.ToString("x8") + information.FileIndexLow.ToString("x8");
    }

    public static uint GetLinkCount(string path)
    {
        return GetInformation(path).NumberOfLinks;
    }

    public static bool HasExtendedAttributes(string path)
    {
        const int STATUS_NO_EAS_ON_FILE = unchecked((int)0xC0000052u);
        const int STATUS_NO_MORE_EAS = unchecked((int)0x80000012u);
        const int STATUS_BUFFER_OVERFLOW = unchecked((int)0x80000005u);
        const int STATUS_BUFFER_TOO_SMALL = unchecked((int)0xC0000023u);
        using (SafeFileHandle handle = CreateFile(
            path,
            FILE_READ_EA,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateFile for package extended-attribute inspection failed.");
            }
            IntPtr buffer = Marshal.AllocHGlobal(65536);
            try
            {
                IO_STATUS_BLOCK statusBlock;
                int status = NtQueryEaFile(
                    handle, out statusBlock, buffer, 65536u, false,
                    IntPtr.Zero, 0u, IntPtr.Zero, true);
                if (status == STATUS_NO_EAS_ON_FILE || status == STATUS_NO_MORE_EAS)
                {
                    return false;
                }
                if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)
                {
                    return true;
                }
                if (status < 0)
                {
                    throw new Win32Exception(status, "NtQueryEaFile failed while inspecting package metadata.");
                }
                return statusBlock.Information.ToInt64() != 0;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
    }

    public static void MoveNoReplace(string sourcePath, string destinationPath)
    {
        if (!MoveFileEx(sourcePath, destinationPath, MOVEFILE_WRITE_THROUGH))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "Durable package publication move failed.");
        }
    }

    public static void Replace(string sourcePath, string destinationPath)
    {
        if (!MoveFileEx(
            sourcePath,
            destinationPath,
            MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "Durable package journal replacement failed.");
        }
    }

    public static void ReplaceWithBackup(
        string replacementPath,
        string destinationPath,
        string backupPath)
    {
        if (!ReplaceFile(destinationPath, replacementPath, backupPath, 0u, IntPtr.Zero, IntPtr.Zero))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "Atomic package generation pointer replacement failed.");
        }
    }
}
'@
}

function Get-SyncVisionPackagePathIdentity {
    param([Parameter(Mandatory = $true)][string]$Path)

    $resolved = (Resolve-Path -LiteralPath $Path).Path
    Initialize-SyncVisionPackagePathIdentityType
    return [SyncVisionTask19PackagePathIdentity]::Get($resolved)
}

function Get-SyncVisionPackagePathTopology {
    param([Parameter(Mandatory = $true)][string]$Path)

    $item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    Initialize-SyncVisionPackagePathIdentityType
    $linkCount = [UInt32][SyncVisionTask19PackagePathIdentity]::GetLinkCount($item.FullName)
    if (-not $item.PSIsContainer -and $linkCount -ne 1) {
        $fileId = [SyncVisionTask19PackagePathIdentity]::Get($item.FullName)
        throw "Package trust boundary rejected hard-link topology at '$($item.FullName)': FileId=$fileId LinkCount=$linkCount."
    }
    return [pscustomobject]@{
        FileId = [SyncVisionTask19PackagePathIdentity]::Get($item.FullName)
        LinkCount = $linkCount
        IsDirectory = [bool]$item.PSIsContainer
    }
}

function Get-SyncVisionPackageTreeTopologySha256 {
    param([Parameter(Mandatory = $true)][string]$Root)

    $rootItem = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Root).Path -Force
    if (-not $rootItem.PSIsContainer -or
        ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Package topology root must be a non-reparse directory: $Root"
    }
    $rootPath = $rootItem.FullName.TrimEnd('\', '/')
    $items = @($rootItem) + @(Get-ChildItem -LiteralPath $rootPath -Recurse -Force)
    $lines = New-Object "System.Collections.Generic.List[string]"
    foreach ($item in $items) {
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package topology rejected a reparse point: $($item.FullName)"
        }
        $topology = Get-SyncVisionPackagePathTopology -Path $item.FullName
        $relative = if ([string]::Equals($item.FullName.TrimEnd('\', '/'), $rootPath, [StringComparison]::OrdinalIgnoreCase)) {
            "."
        }
        else {
            $item.FullName.Substring($rootPath.Length).TrimStart('\', '/') -replace '\\', '/'
        }
        $relativeBase64 = [Convert]::ToBase64String([Text.UTF8Encoding]::new($false).GetBytes($relative))
        $kind = if ($topology.IsDirectory) { "D" } else { "F" }
        $lines.Add("$kind|$relativeBase64|$($topology.FileId)|$($topology.LinkCount)")
    }
    $ordered = $lines.ToArray()
    [Array]::Sort($ordered, [StringComparer]::Ordinal)
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes(($ordered -join "`n") + "`n")
    return Get-SyncVisionPackagePublicationJournalSha256 -Bytes $bytes
}

function Get-SyncVisionPackageOutputIdentity {
    param([Parameter(Mandatory = $true)][string]$OutputRoot)

    return Get-SyncVisionPackagePathIdentity -Path $OutputRoot
}

function New-SyncVisionPackageMutexSecurity {
    $security = [Security.AccessControl.MutexSecurity]::new()
    $security.SetAccessRuleProtection($true, $false)
    $currentSid = Get-SyncVisionPackageCurrentUserSid
    $security.SetOwner($currentSid)
    foreach ($sidValue in (Get-SyncVisionPackageTrustedSids)) {
        $security.AddAccessRule([Security.AccessControl.MutexAccessRule]::new(
                [Security.Principal.SecurityIdentifier]::new($sidValue),
                [Security.AccessControl.MutexRights]::FullControl,
                [Security.AccessControl.AccessControlType]::Allow)) | Out-Null
    }
    return $security
}

function Assert-SyncVisionPackageMutexSecurity {
    param(
        [Parameter(Mandatory = $true)][Threading.Mutex]$Mutex,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $trustedSids = @(Get-SyncVisionPackageTrustedSids)
    $security = $Mutex.GetAccessControl()
    $owner = $security.GetOwner([Security.Principal.SecurityIdentifier]).Value
    $rules = @($security.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    $actualSids = @($rules | ForEach-Object { $_.IdentityReference.Value } | Sort-Object -Unique)
    if (-not $security.AreAccessRulesProtected -or
        $trustedSids -notcontains $owner -or
        $rules.Count -ne $trustedSids.Count -or
        $trustedSids.Count -eq 0 -or
        @(Compare-Object -CaseSensitive -ReferenceObject $trustedSids -DifferenceObject $actualSids).Count -ne 0) {
        throw "$Context must have a trusted owner, protected DACL, and exact nonempty principal set."
    }
    foreach ($rule in $rules) {
        if ($rule.IsInherited -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.MutexRights -ne [Security.AccessControl.MutexRights]::FullControl) {
            throw "$Context contains a non-exact mutex access rule."
        }
    }
    return [pscustomobject]@{ OwnerSid = $owner; DaclProtected = $true; PrincipalCount = $rules.Count }
}

function Get-SyncVisionPackagePublicationMutexName {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    $resource = "Output|$(Get-SyncVisionPackageOutputIdentity -OutputRoot $OutputRoot)|$($PackageName.ToUpperInvariant())"
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        $hash = ([BitConverter]::ToString(
                $sha256.ComputeHash([Text.UTF8Encoding]::new($false).GetBytes($resource)))).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
    return "Global\SyncVision.Task19.PackageOutput.$hash"
}

function Enter-SyncVisionPackagePublicationMutex {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string]$PackageName,
        [ValidateRange(1, 3600000)][int]$TimeoutMs = 30000
    )

    $name = Get-SyncVisionPackagePublicationMutexName -OutputRoot $OutputRoot -PackageName $PackageName
    $createdNew = $false
    $mutex = [Threading.Mutex]::new($false, $name, [ref]$createdNew, (New-SyncVisionPackageMutexSecurity))
    try {
        $identity = Assert-SyncVisionPackageMutexSecurity -Mutex $mutex -Context "Package publication mutex"
        $acquired = $false
        $wasAbandoned = $false
        try { $acquired = $mutex.WaitOne($TimeoutMs) }
        catch [Threading.AbandonedMutexException] {
            $acquired = $true
            $wasAbandoned = $true
        }
        if (-not $acquired) {
            throw "Package publication mutex timed out after $TimeoutMs ms for output '$OutputRoot' and package '$PackageName'."
        }
        return [pscustomobject]@{
            Mutex = $mutex
            Acquired = $true
            Name = $name
            OwnerSid = $identity.OwnerSid
            DaclProtected = $identity.DaclProtected
            PrincipalCount = $identity.PrincipalCount
            WasAbandoned = $wasAbandoned
        }
    }
    catch {
        $mutex.Dispose()
        throw
    }
}

function Exit-SyncVisionPackagePublicationMutex {
    param([AllowNull()]$Context)

    if ($null -eq $Context) { return }
    try { if ($Context.Acquired) { $Context.Mutex.ReleaseMutex() } }
    finally { $Context.Mutex.Dispose() }
}

function Get-SyncVisionPackagePlanOutputRoot {
    param([Parameter(Mandatory = $true)][object]$Plan)

    foreach ($propertyName in @("PublicationOutputRoot", "OutputRoot")) {
        $property = $Plan.PSObject.Properties[$propertyName]
        if ($null -ne $property -and -not [string]::IsNullOrWhiteSpace([string]$property.Value)) {
            return [IO.Path]::GetFullPath([string]$property.Value).TrimEnd('\', '/')
        }
    }
    $packageRoot = [IO.Path]::GetFullPath([string]$Plan.PackageRoot).TrimEnd('\', '/')
    return (Split-Path -Parent $packageRoot).TrimEnd('\', '/')
}

function Set-SyncVisionPackagePlanGenerationPaths {
    param(
        [Parameter(Mandatory = $true)][object]$Plan,
        [Parameter(Mandatory = $true)][object]$Generation
    )

    $values = [ordered]@{
        PublicationOutputRoot = [string]$Generation.OutputRoot
        PackageRoot = [string]$Generation.PackageRoot
        ManifestPath = [string]$Generation.ManifestPath
        ManifestDigestPath = [string]$Generation.ManifestDigestPath
        ZipPath = [string]$Generation.ZipPath
        GenerationPointerPath = [string]$Generation.PointerPath
        GenerationId = [string]$Generation.Pointer.TransactionId
    }
    foreach ($entry in $values.GetEnumerator()) {
        if ($null -eq $Plan.PSObject.Properties[$entry.Key]) {
            $Plan | Add-Member -NotePropertyName $entry.Key -NotePropertyValue $entry.Value
        }
        else {
            $Plan.$($entry.Key) = $entry.Value
        }
    }
    return $Plan
}

function Get-SyncVisionPackagePublicationJournalPaths {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    if ([string]::IsNullOrWhiteSpace($PackageName) -or
        -not [string]::Equals((Split-Path -Leaf $PackageName), $PackageName, [StringComparison]::Ordinal) -or
        $PackageName.IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0) {
        throw "Package publication journal requires a valid package leaf name."
    }
    $journal = Join-Path $OutputRoot "$PackageName.release-transaction.journal"
    return [pscustomobject]@{
        Journal = [IO.Path]::GetFullPath($journal)
        Temporary = [IO.Path]::GetFullPath("$journal.tmp")
    }
}

function Get-SyncVisionPackagePublicationLayout {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string]$PackageName,
        [Parameter(Mandatory = $true)][string]$TransactionId
    )

    if ($TransactionId -cnotmatch '^[0-9a-f]{32}$') {
        throw "Package publication layout requires a canonical transaction ID."
    }
    $root = [IO.Path]::GetFullPath($OutputRoot).TrimEnd('\', '/')
    $trustedBase = Initialize-SyncVisionTrustedPackageBase
    $stageLeaf = "publication-$TransactionId"
    $candidateLeaf = "$PackageName.release-candidate-$TransactionId"
    $generationLeaf = "$PackageName.release-generation-$TransactionId"
    $pointerLeaf = "$PackageName.release-current"
    $pointerCandidateLeaf = "$PackageName.release-pointer-$TransactionId.candidate"
    $pointerBackupLeaf = "$PackageName.release-pointer-$TransactionId.previous"
    return [pscustomobject]@{
        StageLeaf = $stageLeaf
        Stage = Join-Path $trustedBase $stageLeaf
        StageTombstone = Join-Path $trustedBase "$stageLeaf.tombstone"
        CandidateLeaf = $candidateLeaf
        Candidate = Join-Path $root $candidateLeaf
        CandidateTombstone = Join-Path $root "$candidateLeaf.tombstone"
        GenerationLeaf = $generationLeaf
        Generation = Join-Path $root $generationLeaf
        GenerationTombstone = Join-Path $root "$generationLeaf.tombstone"
        PointerLeaf = $pointerLeaf
        Pointer = Join-Path $root $pointerLeaf
        PointerCandidateLeaf = $pointerCandidateLeaf
        PointerCandidate = Join-Path $root $pointerCandidateLeaf
        PointerCandidateTombstone = Join-Path $root "$pointerCandidateLeaf.tombstone"
        PointerBackupLeaf = $pointerBackupLeaf
        PointerBackup = Join-Path $root $pointerBackupLeaf
        PointerBackupTombstone = Join-Path $root "$pointerBackupLeaf.tombstone"
        TrustedBase = $trustedBase
        OutputRoot = $root
    }
}

function Get-SyncVisionPackagePublicationObjectHash {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][ValidateSet("Directory", "File")][string]$Kind
    )

    if ($Kind -ceq "Directory") {
        return Get-SyncVisionDirectoryTreeSha256 -Root $Path
    }
    return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}

function ConvertTo-SyncVisionPackagePublicationBase64 {
    param([AllowEmptyString()][string]$Value = "")

    return [Convert]::ToBase64String([Text.UTF8Encoding]::new($false).GetBytes($Value))
}

function ConvertFrom-SyncVisionPackagePublicationBase64 {
    param(
        [Parameter(Mandatory = $true)][AllowEmptyString()][string]$Value,
        [Parameter(Mandatory = $true)][string]$Context
    )

    try {
        $bytes = [Convert]::FromBase64String($Value)
        $decoded = [Text.UTF8Encoding]::new($false, $true).GetString($bytes)
    }
    catch {
        throw "$Context is not canonical UTF-8 Base64."
    }
    if ((ConvertTo-SyncVisionPackagePublicationBase64 -Value $decoded) -cne $Value -or
        $decoded.IndexOf([char]0) -ge 0) {
        throw "$Context is not canonical UTF-8 Base64."
    }
    return $decoded
}

function Get-SyncVisionPackagePublicationJournalSha256 {
    param([Parameter(Mandatory = $true)][byte[]]$Bytes)

    $sha256 = [Security.Cryptography.SHA256]::Create()
    try { return ([BitConverter]::ToString($sha256.ComputeHash($Bytes))).Replace("-", "").ToLowerInvariant() }
    finally { $sha256.Dispose() }
}

function ConvertTo-SyncVisionPackagePublicationEnvelope {
    param(
        [Parameter(Mandatory = $true)][string]$Header,
        [Parameter(Mandatory = $true)][int]$Version,
        [Parameter(Mandatory = $true)][string]$Payload
    )

    $payloadBytes = [Text.UTF8Encoding]::new($false).GetBytes($Payload)
    return @(
        $Header
        "version=$Version"
        "payload_b64=$(ConvertTo-SyncVisionPackagePublicationBase64 -Value $Payload)"
        "payload_sha256=$(Get-SyncVisionPackagePublicationJournalSha256 -Bytes $payloadBytes)"
        ""
    ) -join "`n"
}

function ConvertFrom-SyncVisionPackagePublicationEnvelope {
    param(
        [Parameter(Mandatory = $true)][string]$Text,
        [Parameter(Mandatory = $true)][string]$Header,
        [Parameter(Mandatory = $true)][int]$Version,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if ($Text.Length -le 0 -or $Text.Length -gt 1048576 -or
        $Text[0] -eq [char]0xfeff -or $Text.IndexOf("`r") -ge 0 -or
        $Text.IndexOf([char]0) -ge 0 -or -not $Text.EndsWith("`n", [StringComparison]::Ordinal)) {
        throw "$Context encoding or size is invalid."
    }
    [string[]]$lines = $Text.Split([char]10)
    if ($lines.Count -ne 5 -or $lines[0] -cne $Header -or
        $lines[1] -cne "version=$Version" -or $lines[4] -cne "" -or
        -not $lines[2].StartsWith("payload_b64=", [StringComparison]::Ordinal) -or
        $lines[3] -cnotmatch '^payload_sha256=([0-9a-f]{64})$') {
        throw "$Context envelope is invalid."
    }
    $expectedSha256 = $Matches[1]
    $payloadBase64 = $lines[2].Substring("payload_b64=".Length)
    $payload = ConvertFrom-SyncVisionPackagePublicationBase64 -Value $payloadBase64 -Context "$Context payload"
    $payloadBytes = [Text.UTF8Encoding]::new($false).GetBytes($payload)
    if ((Get-SyncVisionPackagePublicationJournalSha256 -Bytes $payloadBytes) -cne $expectedSha256) {
        throw "$Context payload digest mismatch."
    }
    return $payload
}

function Read-SyncVisionPackageProtectedTextFile {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        throw "$Context was not found: $Path"
    }
    $validatedPath = Assert-SyncVisionProtectedPackagePublicationObject -Path $Path
    $fileId = Get-SyncVisionPackagePathIdentity -Path $validatedPath
    $share = [IO.FileShare]::Read -bor [IO.FileShare]::Delete
    $stream = [IO.File]::Open($validatedPath, [IO.FileMode]::Open, [IO.FileAccess]::Read, $share)
    try {
        $handleFileId = [SyncVisionTask19PackagePathIdentity]::GetHandleIdentity($stream.SafeFileHandle)
        if ($handleFileId -cne $fileId) {
            throw "$Context File ID changed before its validated handle was opened."
        }
        if ($stream.Length -le 0 -or $stream.Length -gt 1048576) {
            throw "$Context size is invalid: $($stream.Length)"
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "$Context read ended early." }
            $offset += $read
        }
        try { $text = [Text.UTF8Encoding]::new($false, $true).GetString($bytes) }
        catch { throw "$Context is not strict UTF-8." }
        if ([SyncVisionTask19PackagePathIdentity]::GetHandleIdentity($stream.SafeFileHandle) -cne $fileId) {
            throw "$Context File ID changed while its handle was read."
        }
        return [pscustomobject]@{
            Path = $validatedPath
            FileId = $fileId
            Sha256 = Get-SyncVisionPackagePublicationJournalSha256 -Bytes $bytes
            Text = $text
        }
    }
    finally { $stream.Dispose() }
}

function Assert-SyncVisionPackageGenerationPointer {
    param(
        [Parameter(Mandatory = $true)][object]$Pointer,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    Assert-SyncVisionExactJsonProperties -Value $Pointer -ExpectedNames @(
        "SchemaVersion", "TransactionId", "PackageName", "GenerationLeaf", "IncludeZip",
        "PackageTreeSha256", "ManifestSha256", "ManifestDigestFileSha256", "ZipSha256",
        "GenerationSha256", "GenerationTopologySha256") -Context "Package generation pointer"
    $transactionId = [string]$Pointer.TransactionId
    if ($Pointer.SchemaVersion -isnot [int] -or [int]$Pointer.SchemaVersion -ne 1 -or
        $transactionId -cnotmatch '^[0-9a-f]{32}$' -or
        [string]$Pointer.PackageName -cne $PackageName -or
        [string]$Pointer.GenerationLeaf -cne "$PackageName.release-generation-$transactionId" -or
        $Pointer.IncludeZip -isnot [bool]) {
        throw "Package generation pointer identity or schema is invalid."
    }
    foreach ($propertyName in @(
            "PackageTreeSha256", "ManifestSha256", "ManifestDigestFileSha256",
            "GenerationSha256", "GenerationTopologySha256")) {
        if ([string]$Pointer.$propertyName -cnotmatch '^[0-9a-f]{64}$') {
            throw "Package generation pointer has an invalid $propertyName."
        }
    }
    $zipSha256 = [string]$Pointer.ZipSha256
    if (([bool]$Pointer.IncludeZip -and $zipSha256 -cnotmatch '^[0-9a-f]{64}$') -or
        (-not [bool]$Pointer.IncludeZip -and -not [string]::IsNullOrEmpty($zipSha256))) {
        throw "Package generation pointer ZIP identity is invalid."
    }
    return [pscustomobject]@{
        SchemaVersion = 1
        TransactionId = $transactionId
        PackageName = [string]$Pointer.PackageName
        GenerationLeaf = [string]$Pointer.GenerationLeaf
        IncludeZip = [bool]$Pointer.IncludeZip
        PackageTreeSha256 = [string]$Pointer.PackageTreeSha256
        ManifestSha256 = [string]$Pointer.ManifestSha256
        ManifestDigestFileSha256 = [string]$Pointer.ManifestDigestFileSha256
        ZipSha256 = $zipSha256
        GenerationSha256 = [string]$Pointer.GenerationSha256
        GenerationTopologySha256 = [string]$Pointer.GenerationTopologySha256
    }
}

function ConvertTo-SyncVisionPackageGenerationPointerPayload {
    param(
        [Parameter(Mandatory = $true)][object]$Pointer,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    $state = Assert-SyncVisionPackageGenerationPointer -Pointer $Pointer -PackageName $PackageName
    return ([ordered]@{
            SchemaVersion = $state.SchemaVersion
            TransactionId = $state.TransactionId
            PackageName = $state.PackageName
            GenerationLeaf = $state.GenerationLeaf
            IncludeZip = $state.IncludeZip
            PackageTreeSha256 = $state.PackageTreeSha256
            ManifestSha256 = $state.ManifestSha256
            ManifestDigestFileSha256 = $state.ManifestDigestFileSha256
            ZipSha256 = $state.ZipSha256
            GenerationSha256 = $state.GenerationSha256
            GenerationTopologySha256 = $state.GenerationTopologySha256
        } | ConvertTo-Json -Compress)
}

function ConvertTo-SyncVisionPackageGenerationPointerText {
    param(
        [Parameter(Mandatory = $true)][object]$Pointer,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    $payload = ConvertTo-SyncVisionPackageGenerationPointerPayload -Pointer $Pointer -PackageName $PackageName
    return ConvertTo-SyncVisionPackagePublicationEnvelope `
        -Header "SYNCVISION_PACKAGE_GENERATION_POINTER" `
        -Version 1 `
        -Payload $payload
}

function ConvertFrom-SyncVisionPackageGenerationPointerText {
    param(
        [Parameter(Mandatory = $true)][string]$Text,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    $payload = ConvertFrom-SyncVisionPackagePublicationEnvelope `
        -Text $Text `
        -Header "SYNCVISION_PACKAGE_GENERATION_POINTER" `
        -Version 1 `
        -Context "Package generation pointer"
    try { $document = $payload | ConvertFrom-Json -ErrorAction Stop }
    catch { throw "Package generation pointer JSON is invalid: $($_.Exception.Message)" }
    $state = Assert-SyncVisionPackageGenerationPointer -Pointer $document -PackageName $PackageName
    if ((ConvertTo-SyncVisionPackageGenerationPointerPayload -Pointer $state -PackageName $PackageName) -cne $payload) {
        throw "Package generation pointer JSON is not in exact canonical form."
    }
    return $state
}

function Read-SyncVisionPackageGenerationPointerFile {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    $file = Read-SyncVisionPackageProtectedTextFile -Path $Path -Context "Package generation pointer"
    $pointer = ConvertFrom-SyncVisionPackageGenerationPointerText -Text $file.Text -PackageName $PackageName
    return [pscustomobject]@{
        Pointer = $pointer
        Path = $file.Path
        FileId = $file.FileId
        Sha256 = $file.Sha256
        Text = $file.Text
    }
}

function Write-SyncVisionPackageGenerationPointerCandidate {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][object]$Pointer,
        [Parameter(Mandatory = $true)][string]$PackageName,
        [AllowNull()][scriptblock]$TestPhaseHook,
        [AllowNull()][object]$Journal
    )

    if (Test-Path -LiteralPath $Path) {
        throw "Package generation pointer candidate already exists: $Path"
    }
    $text = ConvertTo-SyncVisionPackageGenerationPointerText -Pointer $Pointer -PackageName $PackageName
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes($text)
    $stream = [IO.File]::Create(
        $Path,
        4096,
        [IO.FileOptions]::WriteThrough,
        (New-SyncVisionTrustedPackageFileSecurity))
    try {
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterPointerCandidateFileCreated" $Journal
        }
        $stream.Write($bytes, 0, $bytes.Length)
        $stream.Flush($true)
    }
    finally { $stream.Dispose() }
    $persisted = Read-SyncVisionPackageGenerationPointerFile -Path $Path -PackageName $PackageName
    if ($persisted.Text -cne $text) {
        throw "Package generation pointer candidate changed after its durable write."
    }
    return $persisted
}

function Assert-SyncVisionPublishedPackageGeneration {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Pointer
    )

    $root = [IO.Path]::GetFullPath($OutputRoot).TrimEnd('\', '/')
    $generationRoot = Join-Path $root $Pointer.GenerationLeaf
    if (-not [string]::Equals(
            (Split-Path -Parent ([IO.Path]::GetFullPath($generationRoot))).TrimEnd('\', '/'),
            $root,
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "Package generation pointer escaped its output root."
    }
    Assert-SyncVisionProtectedPackagePublicationObject `
        -Path $generationRoot `
        -ExpectedSha256 $Pointer.GenerationSha256 | Out-Null
    $topologySha256 = Get-SyncVisionPackageTreeTopologySha256 -Root $generationRoot
    if ($topologySha256 -cne $Pointer.GenerationTopologySha256) {
        throw "Published package generation hard-link topology changed."
    }
    $packageRoot = Join-Path $generationRoot $Pointer.PackageName
    $manifestPath = Join-Path $packageRoot "SHA256SUMS.txt"
    $manifestDigestPath = Join-Path $generationRoot "$($Pointer.PackageName).SHA256SUMS.sha256"
    $zipPath = Join-Path $generationRoot "$($Pointer.PackageName).zip"
    $identity = Assert-SyncVisionConstructedPackage `
        -PackageRoot $packageRoot `
        -ManifestPath $manifestPath `
        -ManifestDigestPath $manifestDigestPath `
        -ZipPath $(if ($Pointer.IncludeZip) { $zipPath } else { "" }) `
        -ArchiveRootName $Pointer.PackageName
    if ($identity.PackageTreeSha256 -cne $Pointer.PackageTreeSha256 -or
        $identity.ManifestSha256 -cne $Pointer.ManifestSha256 -or
        $identity.ManifestDigestFileSha256 -cne $Pointer.ManifestDigestFileSha256 -or
        ($Pointer.IncludeZip -and $identity.ZipSha256 -cne $Pointer.ZipSha256) -or
        (-not $Pointer.IncludeZip -and (Test-Path -LiteralPath $zipPath))) {
        throw "Published package generation differs from its atomic pointer identity."
    }
    return [pscustomobject]@{
        OutputRoot = $root
        GenerationRoot = $generationRoot
        PackageRoot = $packageRoot
        ManifestPath = $manifestPath
        ManifestDigestPath = $manifestDigestPath
        ZipPath = $zipPath
        Identity = $identity
    }
}

function Resolve-SyncVisionPublishedPackageGeneration {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan,
        [switch]$AllowMissing
    )

    $root = [IO.Path]::GetFullPath($OutputRoot).TrimEnd('\', '/')
    $pointerPath = Join-Path $root "$($Plan.PackageName).release-current"
    $pointerFile = $null
    for ($attempt = 0; $attempt -lt 32; ++$attempt) {
        if (-not (Test-Path -LiteralPath $pointerPath)) {
            if ($AllowMissing -and $attempt -eq 0) { return $null }
            if ($attempt -lt 31) {
                [Threading.Thread]::Sleep(2)
                continue
            }
            throw "Published package generation pointer was not found: $pointerPath"
        }
        try {
            $pointerFile = Read-SyncVisionPackageGenerationPointerFile `
                -Path $pointerPath `
                -PackageName $Plan.PackageName
            break
        }
        catch {
            $retryable = $_.CategoryInfo.Category -eq [Management.Automation.ErrorCategory]::ObjectNotFound -or
                $_.Exception.Message -match 'File ID changed before its validated handle was opened'
            if (-not $retryable -or $attempt -ge 31) { throw }
            [Threading.Thread]::Sleep(2)
        }
    }
    if ($null -eq $pointerFile) {
        throw "Published package generation pointer could not be read after bounded atomic-switch retries."
    }
    $generation = Assert-SyncVisionPublishedPackageGeneration `
        -OutputRoot $root `
        -Pointer $pointerFile.Pointer
    return [pscustomobject]@{
        OutputRoot = $root
        PointerPath = $pointerPath
        Pointer = $pointerFile.Pointer
        PointerFileId = $pointerFile.FileId
        PointerSha256 = $pointerFile.Sha256
        GenerationRoot = $generation.GenerationRoot
        PackageRoot = $generation.PackageRoot
        ManifestPath = $generation.ManifestPath
        ManifestDigestPath = $generation.ManifestDigestPath
        ZipPath = $generation.ZipPath
        Identity = $generation.Identity
    }
}

function Assert-SyncVisionNoLegacyPackagePublicationFinals {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][string]$PackageName
    )

    $legacyPaths = @(
        (Join-Path $OutputRoot $PackageName),
        (Join-Path $OutputRoot "$PackageName.SHA256SUMS.sha256"),
        (Join-Path $OutputRoot "$PackageName.zip"))
    foreach ($legacyPath in $legacyPaths) {
        if (-not (Test-Path -LiteralPath $legacyPath)) { continue }
        Assert-SyncVisionPackageTreeTrustMetadata `
            -Root $legacyPath `
            -Context "Legacy existing package final" | Out-Null
        throw "Refusing to modify or take ownership of an existing legacy package final in place: $legacyPath"
    }
}

function Assert-SyncVisionPackagePublicationJournal {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    Assert-SyncVisionExactJsonProperties -Value $Journal -ExpectedNames @(
        "SchemaVersion", "TransactionId", "Phase", "PhaseIndex", "OutputIdentity",
        "PackageName", "IncludeZip", "StageLeaf", "CandidateLeaf", "GenerationLeaf",
        "PointerLeaf", "PointerCandidateLeaf", "PointerBackupLeaf", "OldPointerExists",
        "OldPointerSha256", "OldPointerFileId", "OldGenerationLeaf",
        "NewGenerationSha256", "NewGenerationFileId", "NewGenerationTopologySha256",
        "NewPointerSha256", "NewPointerFileId") -Context "Package publication transaction intent"
    $root = (Resolve-Path -LiteralPath $OutputRoot).Path.TrimEnd('\', '/')
    $transactionId = [string]$Journal.TransactionId
    if ($Journal.SchemaVersion -isnot [int] -or [int]$Journal.SchemaVersion -ne 2 -or
        $transactionId -cnotmatch '^[0-9a-f]{32}$' -or
        [string]$Journal.OutputIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$' -or
        [string]$Journal.OutputIdentity -cne (Get-SyncVisionPackageOutputIdentity -OutputRoot $root) -or
        [string]$Journal.PackageName -cne [string]$Plan.PackageName -or
        $Journal.IncludeZip -isnot [bool]) {
        throw "Package publication transaction intent identity or schema is invalid."
    }
    $layout = Get-SyncVisionPackagePublicationLayout `
        -OutputRoot $root `
        -PackageName $Plan.PackageName `
        -TransactionId $transactionId
    foreach ($propertyName in @(
            "StageLeaf", "CandidateLeaf", "GenerationLeaf", "PointerLeaf",
            "PointerCandidateLeaf", "PointerBackupLeaf")) {
        if ([string]$Journal.$propertyName -cne [string]$layout.$propertyName) {
            throw "Package publication transaction intent has an invalid $propertyName."
        }
    }

    $phase = [string]$Journal.Phase
    $cleanupPhases = @(
        "RollbackTombstonePending", "RollbackTombstoned",
        "CommitTombstonePending", "CommitTombstoned")
    $ordinaryPhases = @(
        "Intent", "CandidateReady", "GenerationMovePending",
        "GenerationReady", "SwitchPending", "Committed")
    if (($ordinaryPhases + $cleanupPhases) -cnotcontains $phase -or
        (($ordinaryPhases -ccontains $phase) -and [int]$Journal.PhaseIndex -ne -1) -or
        (($cleanupPhases -ccontains $phase) -and
            ([int]$Journal.PhaseIndex -lt 0 -or [int]$Journal.PhaseIndex -gt 4))) {
        throw "Package publication transaction intent phase is invalid: $phase/$($Journal.PhaseIndex)"
    }

    if ($Journal.OldPointerExists -isnot [bool]) {
        throw "Package publication transaction intent old-pointer presence is invalid."
    }
    if ([bool]$Journal.OldPointerExists) {
        if ([string]$Journal.OldPointerSha256 -cnotmatch '^[0-9a-f]{64}$' -or
            [string]$Journal.OldPointerFileId -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$' -or
            [string]$Journal.OldGenerationLeaf -cnotmatch "^$([regex]::Escape($Plan.PackageName))\.release-generation-[0-9a-f]{32}$") {
            throw "Package publication transaction intent old-pointer identity is invalid."
        }
    }
    elseif (-not [string]::IsNullOrEmpty([string]$Journal.OldPointerSha256) -or
        -not [string]::IsNullOrEmpty([string]$Journal.OldPointerFileId) -or
        -not [string]::IsNullOrEmpty([string]$Journal.OldGenerationLeaf)) {
        throw "Package publication transaction intent records an absent old pointer identity."
    }

    $newGenerationValues = @(
        [string]$Journal.NewGenerationSha256,
        [string]$Journal.NewGenerationFileId,
        [string]$Journal.NewGenerationTopologySha256)
    $hasNewGeneration = @($newGenerationValues | Where-Object { -not [string]::IsNullOrEmpty($_) }).Count -ne 0
    if ($hasNewGeneration -and
        ($newGenerationValues[0] -cnotmatch '^[0-9a-f]{64}$' -or
            $newGenerationValues[1] -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$' -or
            $newGenerationValues[2] -cnotmatch '^[0-9a-f]{64}$')) {
        throw "Package publication transaction intent new-generation identity is incomplete or invalid."
    }
    $newPointerValues = @([string]$Journal.NewPointerSha256, [string]$Journal.NewPointerFileId)
    $hasNewPointer = @($newPointerValues | Where-Object { -not [string]::IsNullOrEmpty($_) }).Count -ne 0
    if ($hasNewPointer -and
        ($newPointerValues[0] -cnotmatch '^[0-9a-f]{64}$' -or
            $newPointerValues[1] -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$')) {
        throw "Package publication transaction intent new-pointer identity is incomplete or invalid."
    }
    if ($phase -in @("CandidateReady", "GenerationMovePending", "GenerationReady", "SwitchPending", "Committed") -and
        -not $hasNewGeneration) {
        throw "Package publication transaction intent phase requires a sealed generation identity."
    }
    if ($phase -in @("SwitchPending", "Committed") -and -not $hasNewPointer) {
        throw "Package publication transaction intent phase requires a sealed pointer identity."
    }
    if ($phase.StartsWith("Commit", [StringComparison]::Ordinal) -and
        (-not $hasNewGeneration -or -not $hasNewPointer)) {
        throw "Committed package cleanup requires complete new-generation and pointer identities."
    }

    return [pscustomobject]@{
        SchemaVersion = 2
        TransactionId = $transactionId
        Phase = $phase
        PhaseIndex = [int]$Journal.PhaseIndex
        OutputIdentity = [string]$Journal.OutputIdentity
        PackageName = [string]$Journal.PackageName
        IncludeZip = [bool]$Journal.IncludeZip
        StageLeaf = [string]$Journal.StageLeaf
        CandidateLeaf = [string]$Journal.CandidateLeaf
        GenerationLeaf = [string]$Journal.GenerationLeaf
        PointerLeaf = [string]$Journal.PointerLeaf
        PointerCandidateLeaf = [string]$Journal.PointerCandidateLeaf
        PointerBackupLeaf = [string]$Journal.PointerBackupLeaf
        OldPointerExists = [bool]$Journal.OldPointerExists
        OldPointerSha256 = [string]$Journal.OldPointerSha256
        OldPointerFileId = [string]$Journal.OldPointerFileId
        OldGenerationLeaf = [string]$Journal.OldGenerationLeaf
        NewGenerationSha256 = $newGenerationValues[0]
        NewGenerationFileId = $newGenerationValues[1]
        NewGenerationTopologySha256 = $newGenerationValues[2]
        NewPointerSha256 = $newPointerValues[0]
        NewPointerFileId = $newPointerValues[1]
    }
}

function ConvertTo-SyncVisionPackagePublicationJournalPayload {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $state = Assert-SyncVisionPackagePublicationJournal -Journal $Journal -OutputRoot $OutputRoot -Plan $Plan
    return ([ordered]@{
            SchemaVersion = $state.SchemaVersion
            TransactionId = $state.TransactionId
            Phase = $state.Phase
            PhaseIndex = $state.PhaseIndex
            OutputIdentity = $state.OutputIdentity
            PackageName = $state.PackageName
            IncludeZip = $state.IncludeZip
            StageLeaf = $state.StageLeaf
            CandidateLeaf = $state.CandidateLeaf
            GenerationLeaf = $state.GenerationLeaf
            PointerLeaf = $state.PointerLeaf
            PointerCandidateLeaf = $state.PointerCandidateLeaf
            PointerBackupLeaf = $state.PointerBackupLeaf
            OldPointerExists = $state.OldPointerExists
            OldPointerSha256 = $state.OldPointerSha256
            OldPointerFileId = $state.OldPointerFileId
            OldGenerationLeaf = $state.OldGenerationLeaf
            NewGenerationSha256 = $state.NewGenerationSha256
            NewGenerationFileId = $state.NewGenerationFileId
            NewGenerationTopologySha256 = $state.NewGenerationTopologySha256
            NewPointerSha256 = $state.NewPointerSha256
            NewPointerFileId = $state.NewPointerFileId
        } | ConvertTo-Json -Compress)
}

function ConvertTo-SyncVisionPackagePublicationJournalText {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $payload = ConvertTo-SyncVisionPackagePublicationJournalPayload `
        -Journal $Journal `
        -OutputRoot $OutputRoot `
        -Plan $Plan
    return ConvertTo-SyncVisionPackagePublicationEnvelope `
        -Header "SYNCVISION_PACKAGE_PUBLICATION_INTENT" `
        -Version 2 `
        -Payload $payload
}

function ConvertFrom-SyncVisionPackagePublicationJournalText {
    param(
        [Parameter(Mandatory = $true)][string]$Text,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $payload = ConvertFrom-SyncVisionPackagePublicationEnvelope `
        -Text $Text `
        -Header "SYNCVISION_PACKAGE_PUBLICATION_INTENT" `
        -Version 2 `
        -Context "Package publication transaction intent"
    try { $document = $payload | ConvertFrom-Json -ErrorAction Stop }
    catch { throw "Package publication transaction intent JSON is invalid: $($_.Exception.Message)" }
    $state = Assert-SyncVisionPackagePublicationJournal -Journal $document -OutputRoot $OutputRoot -Plan $Plan
    if ((ConvertTo-SyncVisionPackagePublicationJournalPayload `
            -Journal $state `
            -OutputRoot $OutputRoot `
            -Plan $Plan) -cne $payload) {
        throw "Package publication transaction intent JSON is not in exact canonical form."
    }
    return $state
}

function Test-SyncVisionPackagePublicationJournalStaticMatch {
    param(
        [Parameter(Mandatory = $true)][object]$Left,
        [Parameter(Mandatory = $true)][object]$Right,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $a = Assert-SyncVisionPackagePublicationJournal -Journal $Left -OutputRoot $OutputRoot -Plan $Plan
    $b = Assert-SyncVisionPackagePublicationJournal -Journal $Right -OutputRoot $OutputRoot -Plan $Plan
    foreach ($name in @(
            "SchemaVersion", "TransactionId", "OutputIdentity", "PackageName", "IncludeZip",
            "StageLeaf", "CandidateLeaf", "GenerationLeaf", "PointerLeaf",
            "PointerCandidateLeaf", "PointerBackupLeaf", "OldPointerExists",
            "OldPointerSha256", "OldPointerFileId", "OldGenerationLeaf")) {
        if ($a.$name -cne $b.$name) { return $false }
    }
    foreach ($name in @(
            "NewGenerationSha256", "NewGenerationFileId", "NewGenerationTopologySha256",
            "NewPointerSha256", "NewPointerFileId")) {
        if (-not [string]::IsNullOrEmpty([string]$a.$name) -and $a.$name -cne $b.$name) {
            return $false
        }
    }
    return $true
}

function Read-SyncVisionPackagePublicationJournalFile {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $file = Read-SyncVisionPackageProtectedTextFile -Path $Path -Context "Package publication transaction intent"
    return [pscustomobject]@{
        Journal = ConvertFrom-SyncVisionPackagePublicationJournalText `
            -Text $file.Text `
            -OutputRoot $OutputRoot `
            -Plan $Plan
        FileId = $file.FileId
        Sha256 = $file.Sha256
        Text = $file.Text
    }
}

function Assert-SyncVisionPackagePublicationDirectChild {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Parent,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $full = [IO.Path]::GetFullPath($Path)
    $parentFull = [IO.Path]::GetFullPath($Parent).TrimEnd('\', '/')
    if (-not [string]::Equals(
            (Split-Path -Parent $full).TrimEnd('\', '/'),
            $parentFull,
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "$Context escaped its trusted parent: $full"
    }
    return $full
}

function Remove-SyncVisionPackagePublicationObjectExact {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][ValidateSet("Directory", "File")][string]$Kind,
        [AllowEmptyString()][string]$ExpectedFileId = "",
        [AllowEmptyString()][string]$ExpectedSha256 = "",
        [AllowEmptyString()][string]$ExpectedTopologySha256 = ""
    )

    if (-not (Test-Path -LiteralPath $Path)) { return }
    $full = Assert-SyncVisionPackagePublicationDirectChild `
        -Path $Path `
        -Parent $OutputRoot `
        -Context "Package publication exact removal"
    $item = Get-Item -LiteralPath $full -Force
    if (($Kind -ceq "Directory" -and -not $item.PSIsContainer) -or
        ($Kind -ceq "File" -and $item.PSIsContainer)) {
        throw "Package publication exact removal found an unexpected object type: $full"
    }
    Assert-SyncVisionProtectedPackagePublicationObject -Path $full | Out-Null
    if (-not [string]::IsNullOrEmpty($ExpectedFileId) -and
        (Get-SyncVisionPackagePathIdentity -Path $full) -cne $ExpectedFileId) {
        throw "Refusing package publication removal because the File ID changed: $full"
    }
    if (-not [string]::IsNullOrEmpty($ExpectedSha256) -and
        (Get-SyncVisionPackagePublicationObjectHash -Path $full -Kind $Kind) -cne $ExpectedSha256) {
        throw "Refusing package publication removal because the authenticated content changed: $full"
    }
    if ($Kind -ceq "Directory" -and -not [string]::IsNullOrEmpty($ExpectedTopologySha256) -and
        (Get-SyncVisionPackageTreeTopologySha256 -Root $full) -cne $ExpectedTopologySha256) {
        throw "Refusing package publication removal because the hard-link topology changed: $full"
    }
    Remove-SyncVisionPackagePublicationPath `
        -Path $full `
        -OutputRoot ([IO.Path]::GetFullPath($OutputRoot).TrimEnd('\', '/')) `
        -AllowedLeafPrefixes @((Split-Path -Leaf $full))
    if (Test-Path -LiteralPath $full) {
        throw "Package publication exact removal left its validated path present: $full"
    }
}

function Move-SyncVisionPackagePublicationObjectExact {
    param(
        [Parameter(Mandatory = $true)][string]$Source,
        [Parameter(Mandatory = $true)][string]$Destination,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][ValidateSet("Directory", "File")][string]$Kind,
        [AllowEmptyString()][string]$ExpectedFileId = "",
        [AllowEmptyString()][string]$ExpectedSha256 = "",
        [AllowEmptyString()][string]$ExpectedTopologySha256 = ""
    )

    $sourceFull = Assert-SyncVisionPackagePublicationDirectChild `
        -Path $Source -Parent $OutputRoot -Context "Package publication durable move source"
    $destinationFull = Assert-SyncVisionPackagePublicationDirectChild `
        -Path $Destination -Parent $OutputRoot -Context "Package publication durable move destination"
    if (-not (Test-Path -LiteralPath $sourceFull) -or (Test-Path -LiteralPath $destinationFull)) {
        throw "Package publication durable move requires an exact source and absent destination: $sourceFull -> $destinationFull"
    }
    $item = Get-Item -LiteralPath $sourceFull -Force
    if (($Kind -ceq "Directory" -and -not $item.PSIsContainer) -or
        ($Kind -ceq "File" -and $item.PSIsContainer)) {
        throw "Package publication durable move source type changed: $sourceFull"
    }
    Assert-SyncVisionProtectedPackagePublicationObject -Path $sourceFull | Out-Null
    $fileId = Get-SyncVisionPackagePathIdentity -Path $sourceFull
    $sha256 = Get-SyncVisionPackagePublicationObjectHash -Path $sourceFull -Kind $Kind
    $topologySha256 = if ($Kind -ceq "Directory") {
        Get-SyncVisionPackageTreeTopologySha256 -Root $sourceFull
    }
    else { "" }
    if (-not [string]::IsNullOrEmpty($ExpectedFileId) -and $fileId -cne $ExpectedFileId) {
        throw "Package publication durable move source File ID changed: $sourceFull"
    }
    if (-not [string]::IsNullOrEmpty($ExpectedSha256) -and $sha256 -cne $ExpectedSha256) {
        throw "Package publication durable move source content changed: $sourceFull"
    }
    if (-not [string]::IsNullOrEmpty($ExpectedTopologySha256) -and
        $topologySha256 -cne $ExpectedTopologySha256) {
        throw "Package publication durable move source hard-link topology changed: $sourceFull"
    }
    Initialize-SyncVisionPackagePathIdentityType
    [SyncVisionTask19PackagePathIdentity]::MoveNoReplace($sourceFull, $destinationFull)
    if (Test-Path -LiteralPath $sourceFull) {
        throw "Package publication durable move left its source present: $sourceFull"
    }
    Assert-SyncVisionProtectedPackagePublicationObject -Path $destinationFull | Out-Null
    if ((Get-SyncVisionPackagePathIdentity -Path $destinationFull) -cne $fileId -or
        (Get-SyncVisionPackagePublicationObjectHash -Path $destinationFull -Kind $Kind) -cne $sha256 -or
        ($Kind -ceq "Directory" -and
            (Get-SyncVisionPackageTreeTopologySha256 -Root $destinationFull) -cne $topologySha256)) {
        throw "Package publication durable move changed object identity: $destinationFull"
    }
    return [pscustomobject]@{
        FileId = $fileId
        Sha256 = $sha256
        TopologySha256 = $topologySha256
    }
}

function Write-SyncVisionPackagePublicationJournal {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $state = Assert-SyncVisionPackagePublicationJournal -Journal $Journal -OutputRoot $OutputRoot -Plan $Plan
    $paths = Get-SyncVisionPackagePublicationJournalPaths -OutputRoot $OutputRoot -PackageName $state.PackageName
    if (Test-Path -LiteralPath $paths.Temporary) {
        throw "Package publication intent temporary file already exists; recovery must inspect it first."
    }
    $current = if (Test-Path -LiteralPath $paths.Journal) {
        Read-SyncVisionPackagePublicationJournalFile `
            -Path $paths.Journal `
            -OutputRoot $OutputRoot `
            -Plan $Plan
    }
    else { $null }
    if ($null -ne $current -and -not (Test-SyncVisionPackagePublicationJournalStaticMatch `
            -Left $current.Journal `
            -Right $state `
            -OutputRoot $OutputRoot `
            -Plan $Plan)) {
        throw "Refusing to replace a package intent that changed transaction identity or sealed object identity."
    }

    $text = ConvertTo-SyncVisionPackagePublicationJournalText `
        -Journal $state `
        -OutputRoot $OutputRoot `
        -Plan $Plan
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes($text)
    try {
        $stream = [IO.File]::Create(
            $paths.Temporary,
            4096,
            [IO.FileOptions]::WriteThrough,
            (New-SyncVisionTrustedPackageFileSecurity))
        try {
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        Assert-SyncVisionProtectedPackagePublicationObject -Path $paths.Temporary | Out-Null
        Initialize-SyncVisionPackagePathIdentityType
        if ($null -eq $current) {
            [SyncVisionTask19PackagePathIdentity]::MoveNoReplace($paths.Temporary, $paths.Journal)
        }
        else {
            [SyncVisionTask19PackagePathIdentity]::Replace($paths.Temporary, $paths.Journal)
        }
        $persisted = Read-SyncVisionPackagePublicationJournalFile `
            -Path $paths.Journal `
            -OutputRoot $OutputRoot `
            -Plan $Plan
        if ($persisted.Text -cne $text) {
            throw "Package publication transaction intent changed during durable replacement."
        }
        return $persisted.Journal
    }
    finally {
        if (Test-Path -LiteralPath $paths.Temporary) {
            $temporary = Read-SyncVisionPackageProtectedTextFile `
                -Path $paths.Temporary `
                -Context "Package publication intent temporary file"
            Remove-SyncVisionPackagePublicationObjectExact `
                -Path $paths.Temporary `
                -OutputRoot $OutputRoot `
                -Kind File `
                -ExpectedFileId $temporary.FileId `
                -ExpectedSha256 $temporary.Sha256
        }
    }
}

function Set-SyncVisionPackagePublicationJournalPhase {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)]
        [ValidateSet(
            "Intent", "CandidateReady", "GenerationMovePending", "GenerationReady",
            "SwitchPending", "Committed", "RollbackTombstonePending",
            "RollbackTombstoned", "CommitTombstonePending", "CommitTombstoned")]
        [string]$Phase,
        [int]$PhaseIndex = -1,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $Journal.Phase = $Phase
    $Journal.PhaseIndex = $PhaseIndex
    return Write-SyncVisionPackagePublicationJournal -Journal $Journal -OutputRoot $OutputRoot -Plan $Plan
}

function Remove-SyncVisionPackagePublicationJournal {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $paths = Get-SyncVisionPackagePublicationJournalPaths -OutputRoot $OutputRoot -PackageName $Plan.PackageName
    if (-not (Test-Path -LiteralPath $paths.Journal)) { return }
    $current = Read-SyncVisionPackagePublicationJournalFile `
        -Path $paths.Journal `
        -OutputRoot $OutputRoot `
        -Plan $Plan
    if (-not (Test-SyncVisionPackagePublicationJournalStaticMatch `
            -Left $current.Journal `
            -Right $Journal `
            -OutputRoot $OutputRoot `
            -Plan $Plan) -or
        $current.Journal.Phase -cne $Journal.Phase -or
        $current.Journal.PhaseIndex -ne $Journal.PhaseIndex) {
        throw "Refusing to remove a package intent whose transaction or phase changed."
    }
    Remove-SyncVisionPackagePublicationObjectExact `
        -Path $paths.Journal `
        -OutputRoot $OutputRoot `
        -Kind File `
        -ExpectedFileId $current.FileId `
        -ExpectedSha256 $current.Sha256
}

function Assert-SyncVisionPackagePublicationResiduesKnown {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan,
        [AllowNull()][object]$Journal
    )

    $known = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $journalPaths = Get-SyncVisionPackagePublicationJournalPaths -OutputRoot $OutputRoot -PackageName $Plan.PackageName
    if ($null -ne $Journal) {
        $layout = Get-SyncVisionPackagePublicationLayout `
            -OutputRoot $OutputRoot `
            -PackageName $Plan.PackageName `
            -TransactionId $Journal.TransactionId
        foreach ($path in @(
                $journalPaths.Journal, $journalPaths.Temporary,
                $layout.Candidate, $layout.CandidateTombstone,
                $layout.GenerationTombstone,
                $layout.PointerCandidate, $layout.PointerCandidateTombstone,
                $layout.PointerBackup, $layout.PointerBackupTombstone)) {
            [void]$known.Add((Split-Path -Leaf $path))
        }
    }
    $packageName = [string]$Plan.PackageName
    $legacyLeaves = @($packageName, "$packageName.SHA256SUMS.sha256", "$packageName.zip")
    foreach ($item in (Get-ChildItem -LiteralPath $OutputRoot -Force)) {
        $name = $item.Name
        $transactionLike =
            [string]::Equals($name, (Split-Path -Leaf $journalPaths.Journal), [StringComparison]::OrdinalIgnoreCase) -or
            [string]::Equals($name, (Split-Path -Leaf $journalPaths.Temporary), [StringComparison]::OrdinalIgnoreCase) -or
            $name.StartsWith("$packageName.release-candidate-", [StringComparison]::OrdinalIgnoreCase) -or
            ($name.StartsWith("$packageName.release-generation-", [StringComparison]::OrdinalIgnoreCase) -and
                $name.EndsWith(".tombstone", [StringComparison]::OrdinalIgnoreCase)) -or
            $name.StartsWith("$packageName.release-pointer-", [StringComparison]::OrdinalIgnoreCase)
        foreach ($legacyLeaf in $legacyLeaves) {
            if ($name.StartsWith("$legacyLeaf.candidate-", [StringComparison]::OrdinalIgnoreCase) -or
                $name.StartsWith("$legacyLeaf.previous-", [StringComparison]::OrdinalIgnoreCase)) {
                $transactionLike = $true
                break
            }
        }
        if ($transactionLike -and -not $known.Contains($name)) {
            throw "Package publication recovery rejected an unknown transaction residue: $($item.FullName)"
        }
    }
}

function Resolve-SyncVisionPackagePublicationJournal {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan
    )

    $paths = Get-SyncVisionPackagePublicationJournalPaths -OutputRoot $OutputRoot -PackageName $Plan.PackageName
    $current = if (Test-Path -LiteralPath $paths.Journal) {
        Read-SyncVisionPackagePublicationJournalFile -Path $paths.Journal -OutputRoot $OutputRoot -Plan $Plan
    }
    else { $null }
    if (Test-Path -LiteralPath $paths.Temporary) {
        $temporary = $null
        try {
            $temporary = Read-SyncVisionPackagePublicationJournalFile `
                -Path $paths.Temporary `
                -OutputRoot $OutputRoot `
                -Plan $Plan
        }
        catch {
            if ($null -eq $current) { throw }
            $temporaryItem = Get-Item -LiteralPath $paths.Temporary -Force
            if ($temporaryItem.PSIsContainer) {
                throw "Package publication recovery found a directory at the intent temporary-file path."
            }
            $temporaryPath = Assert-SyncVisionProtectedPackagePublicationObject -Path $paths.Temporary
            Remove-SyncVisionPackagePublicationObjectExact `
                -Path $temporaryPath `
                -OutputRoot $OutputRoot `
                -Kind File `
                -ExpectedFileId (Get-SyncVisionPackagePathIdentity -Path $temporaryPath) `
                -ExpectedSha256 ((Get-FileHash -LiteralPath $temporaryPath -Algorithm SHA256).Hash.ToLowerInvariant())
        }
        if ($null -eq $temporary) {
            Assert-SyncVisionPackagePublicationResiduesKnown `
                -OutputRoot $OutputRoot `
                -Plan $Plan `
                -Journal $current.Journal
            return $current.Journal
        }
        if ($null -eq $current) {
            if ($temporary.Journal.Phase -cne "Intent" -or $temporary.Journal.PhaseIndex -ne -1) {
                throw "Package publication recovery rejected an unpaired non-intent temporary file."
            }
            Move-SyncVisionPackagePublicationObjectExact `
                -Source $paths.Temporary `
                -Destination $paths.Journal `
                -OutputRoot $OutputRoot `
                -Kind File `
                -ExpectedFileId $temporary.FileId `
                -ExpectedSha256 $temporary.Sha256 | Out-Null
            $current = Read-SyncVisionPackagePublicationJournalFile `
                -Path $paths.Journal `
                -OutputRoot $OutputRoot `
                -Plan $Plan
        }
        else {
            if (-not (Test-SyncVisionPackagePublicationJournalStaticMatch `
                    -Left $current.Journal `
                    -Right $temporary.Journal `
                    -OutputRoot $OutputRoot `
                    -Plan $Plan)) {
                throw "Package publication recovery rejected a temporary intent from an unknown transaction."
            }
            Remove-SyncVisionPackagePublicationObjectExact `
                -Path $paths.Temporary `
                -OutputRoot $OutputRoot `
                -Kind File `
                -ExpectedFileId $temporary.FileId `
                -ExpectedSha256 $temporary.Sha256
        }
    }
    Assert-SyncVisionPackagePublicationResiduesKnown `
        -OutputRoot $OutputRoot `
        -Plan $Plan `
        -Journal $(if ($null -eq $current) { $null } else { $current.Journal })
    return $(if ($null -eq $current) { $null } else { $current.Journal })
}

function Get-SyncVisionPackagePointerTransactionState {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][object]$Journal,
        [switch]$AllowIntentOwned
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        return [pscustomobject]@{
            Exists = $false
            FileId = ""
            Sha256 = ""
            MatchesOld = $false
            MatchesNew = $false
            Pointer = $null
        }
    }
    try {
        $file = Read-SyncVisionPackageGenerationPointerFile -Path $Path -PackageName $Journal.PackageName
    }
    catch {
        if (-not $AllowIntentOwned) { throw }
        $validatedPath = Assert-SyncVisionProtectedPackagePublicationObject -Path $Path
        return [pscustomobject]@{
            Exists = $true
            FileId = Get-SyncVisionPackagePathIdentity -Path $validatedPath
            Sha256 = (Get-FileHash -LiteralPath $validatedPath -Algorithm SHA256).Hash.ToLowerInvariant()
            MatchesOld = $false
            MatchesNew = $false
            Pointer = $null
        }
    }
    return [pscustomobject]@{
        Exists = $true
        FileId = $file.FileId
        Sha256 = $file.Sha256
        MatchesOld = ([bool]$Journal.OldPointerExists -and
            $file.FileId -ceq $Journal.OldPointerFileId -and
            $file.Sha256 -ceq $Journal.OldPointerSha256)
        MatchesNew = (-not [string]::IsNullOrEmpty([string]$Journal.NewPointerFileId) -and
            $file.FileId -ceq $Journal.NewPointerFileId -and
            $file.Sha256 -ceq $Journal.NewPointerSha256)
        Pointer = $file.Pointer
    }
}

function Get-SyncVisionPackageGenerationTransactionState {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][object]$Journal,
        [switch]$AllowIntentOwned
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        return [pscustomobject]@{
            Exists = $false
            FileId = ""
            Sha256 = ""
            TopologySha256 = ""
            MatchesNew = $false
        }
    }
    $item = Get-Item -LiteralPath $Path -Force
    if (-not $item.PSIsContainer) {
        throw "Package publication recovery found a non-directory generation residue: $Path"
    }
    if ($AllowIntentOwned) {
        Assert-SyncVisionOwnedPackageTransactionTree -Root $Path | Out-Null
    }
    else {
        Assert-SyncVisionProtectedPackagePublicationObject -Path $Path | Out-Null
    }
    $fileId = Get-SyncVisionPackagePathIdentity -Path $Path
    $sha256 = Get-SyncVisionPackagePublicationObjectHash -Path $Path -Kind Directory
    $topologySha256 = Get-SyncVisionPackageTreeTopologySha256 -Root $Path
    $hasExpected = -not [string]::IsNullOrEmpty([string]$Journal.NewGenerationFileId)
    return [pscustomobject]@{
        Exists = $true
        FileId = $fileId
        Sha256 = $sha256
        TopologySha256 = $topologySha256
        MatchesNew = ($hasExpected -and
            $fileId -ceq $Journal.NewGenerationFileId -and
            $sha256 -ceq $Journal.NewGenerationSha256 -and
            $topologySha256 -ceq $Journal.NewGenerationTopologySha256)
    }
}

function Assert-SyncVisionOwnedPackageTransactionTree {
    param([Parameter(Mandatory = $true)][string]$Root)

    $rootPath = Assert-SyncVisionTrustedPackageDirectory `
        -Path $Root `
        -Context "Transaction-owned package tree"
    Assert-SyncVisionTrustedPackageTreeNoReparse -Root $rootPath
    $trustedSids = @(Get-SyncVisionPackageTrustedSids)
    $objects = @((Get-Item -LiteralPath $rootPath -Force)) +
        @(Get-ChildItem -LiteralPath $rootPath -Recurse -Force)
    foreach ($object in $objects) {
        Get-SyncVisionPackagePathTopology -Path $object.FullName | Out-Null
        $acl = Get-Acl -LiteralPath $object.FullName
        if ($trustedSids -notcontains $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value) {
            throw "Transaction-owned package tree has an untrusted owner: $($object.FullName)"
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            if ($trustedSids -notcontains $rule.IdentityReference.Value -or
                $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
                $rule.FileSystemRights -ne [Security.AccessControl.FileSystemRights]::FullControl) {
                throw "Transaction-owned package tree has a non-trusted ACL rule: $($object.FullName)"
            }
        }
    }
    return [pscustomobject]@{
        Path = $rootPath
        FileId = Get-SyncVisionPackagePathIdentity -Path $rootPath
        TopologySha256 = Get-SyncVisionPackageTreeTopologySha256 -Root $rootPath
    }
}

function Move-SyncVisionOwnedPackageTransactionTreeToTombstone {
    param(
        [Parameter(Mandatory = $true)][string]$Source,
        [Parameter(Mandatory = $true)][string]$Destination,
        [Parameter(Mandatory = $true)][string]$TrustedBase
    )

    $sourcePath = Assert-SyncVisionPackagePublicationDirectChild `
        -Path $Source -Parent $TrustedBase -Context "Transaction-owned tree move source"
    $destinationPath = Assert-SyncVisionPackagePublicationDirectChild `
        -Path $Destination -Parent $TrustedBase -Context "Transaction-owned tree tombstone"
    if (-not (Test-Path -LiteralPath $sourcePath) -or (Test-Path -LiteralPath $destinationPath)) {
        throw "Transaction-owned tree move requires one exact source and an absent tombstone."
    }
    $before = Assert-SyncVisionOwnedPackageTransactionTree -Root $sourcePath
    Initialize-SyncVisionPackagePathIdentityType
    [SyncVisionTask19PackagePathIdentity]::MoveNoReplace($sourcePath, $destinationPath)
    $after = Assert-SyncVisionOwnedPackageTransactionTree -Root $destinationPath
    if ($after.FileId -cne $before.FileId -or
        $after.TopologySha256 -cne $before.TopologySha256) {
        throw "Transaction-owned tree identity changed while it was tombstoned."
    }
}

function Remove-SyncVisionOwnedPackageTransactionTreeTombstone {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$TrustedBase
    )

    if (-not (Test-Path -LiteralPath $Path)) { return }
    $full = Assert-SyncVisionPackagePublicationDirectChild `
        -Path $Path -Parent $TrustedBase -Context "Transaction-owned tree tombstone removal"
    Assert-SyncVisionOwnedPackageTransactionTree -Root $full | Out-Null
    Remove-SyncVisionPackagePublicationPath `
        -Path $full `
        -OutputRoot ([IO.Path]::GetFullPath($TrustedBase).TrimEnd('\', '/')) `
        -AllowedLeafPrefixes @((Split-Path -Leaf $full))
    if (Test-Path -LiteralPath $full) {
        throw "Transaction-owned tree tombstone remained after exact removal."
    }
}

function Get-SyncVisionPackageTransactionCleanupSpecs {
    param(
        [Parameter(Mandatory = $true)][ValidateSet("Rollback", "Commit")][string]$Action,
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][object]$Layout
    )

    $specs = New-Object "System.Collections.Generic.List[object]"
    $specs.Add([pscustomobject]@{
            Index = 0; Source = $Layout.Candidate; Tombstone = $Layout.CandidateTombstone
            Parent = $Layout.OutputRoot; Kind = "Directory"
            FileId = $Journal.NewGenerationFileId; Sha256 = $Journal.NewGenerationSha256
            TopologySha256 = $Journal.NewGenerationTopologySha256
        })
    if ($Action -ceq "Rollback") {
        $specs.Add([pscustomobject]@{
                Index = 1; Source = $Layout.Generation; Tombstone = $Layout.GenerationTombstone
                Parent = $Layout.OutputRoot; Kind = "Directory"
                FileId = $Journal.NewGenerationFileId; Sha256 = $Journal.NewGenerationSha256
                TopologySha256 = $Journal.NewGenerationTopologySha256
            })
    }
    $specs.Add([pscustomobject]@{
            Index = 2; Source = $Layout.PointerCandidate; Tombstone = $Layout.PointerCandidateTombstone
            Parent = $Layout.OutputRoot; Kind = "File"
            FileId = $Journal.NewPointerFileId; Sha256 = $Journal.NewPointerSha256
            TopologySha256 = ""
        })
    $specs.Add([pscustomobject]@{
            Index = 3; Source = $Layout.PointerBackup; Tombstone = $Layout.PointerBackupTombstone
            Parent = $Layout.OutputRoot; Kind = "File"
            FileId = $Journal.OldPointerFileId; Sha256 = $Journal.OldPointerSha256
            TopologySha256 = ""
        })
    $specs.Add([pscustomobject]@{
            Index = 4; Source = $Layout.Stage; Tombstone = $Layout.StageTombstone
            Parent = $Layout.TrustedBase; Kind = "Directory"
            FileId = ""; Sha256 = ""; TopologySha256 = ""
        })
    return $specs.ToArray()
}

function Invoke-SyncVisionPackageTransactionResidueCleanup {
    param(
        [Parameter(Mandatory = $true)][ValidateSet("Rollback", "Commit")][string]$Action,
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $layout = Get-SyncVisionPackagePublicationLayout `
        -OutputRoot $OutputRoot `
        -PackageName $Plan.PackageName `
        -TransactionId $Journal.TransactionId
    foreach ($spec in (Get-SyncVisionPackageTransactionCleanupSpecs `
            -Action $Action `
            -Journal $Journal `
            -Layout $layout)) {
        $sourceExists = Test-Path -LiteralPath $spec.Source
        $tombstoneExists = Test-Path -LiteralPath $spec.Tombstone
        if ($sourceExists -and $tombstoneExists) {
            throw "Package publication cleanup found both residue and tombstone for index $($spec.Index)."
        }
        if (-not $sourceExists -and -not $tombstoneExists) { continue }

        $pendingPhase = "${Action}TombstonePending"
        $tombstonedPhase = "${Action}Tombstoned"
        $Journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $Journal `
            -Phase $pendingPhase `
            -PhaseIndex $spec.Index `
            -OutputRoot $OutputRoot `
            -Plan $Plan
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "Before${Action}Tombstone:$($spec.Index)" $Journal }

        $intentOwnedTree = $spec.Index -eq 4 -or
            ($spec.Index -eq 0 -and [string]::IsNullOrEmpty([string]$spec.FileId))
        if ($sourceExists) {
            if ($intentOwnedTree) {
                Move-SyncVisionOwnedPackageTransactionTreeToTombstone `
                    -Source $spec.Source `
                    -Destination $spec.Tombstone `
                    -TrustedBase $spec.Parent
            }
            else {
                Move-SyncVisionPackagePublicationObjectExact `
                    -Source $spec.Source `
                    -Destination $spec.Tombstone `
                    -OutputRoot $spec.Parent `
                    -Kind $spec.Kind `
                    -ExpectedFileId $spec.FileId `
                    -ExpectedSha256 $spec.Sha256 `
                    -ExpectedTopologySha256 $spec.TopologySha256 | Out-Null
            }
        }
        else {
            if ($intentOwnedTree) {
                Assert-SyncVisionOwnedPackageTransactionTree -Root $spec.Tombstone | Out-Null
            }
            else {
                Assert-SyncVisionProtectedPackagePublicationObject -Path $spec.Tombstone | Out-Null
            }
        }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "After${Action}Tombstone:$($spec.Index)" $Journal }

        $Journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $Journal `
            -Phase $tombstonedPhase `
            -PhaseIndex $spec.Index `
            -OutputRoot $OutputRoot `
            -Plan $Plan
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "Before${Action}Delete:$($spec.Index)" $Journal }
        if (Test-Path -LiteralPath $spec.Tombstone) {
            if ($intentOwnedTree) {
                Remove-SyncVisionOwnedPackageTransactionTreeTombstone `
                    -Path $spec.Tombstone `
                    -TrustedBase $spec.Parent
            }
            else {
                Remove-SyncVisionPackagePublicationObjectExact `
                    -Path $spec.Tombstone `
                    -OutputRoot $spec.Parent `
                    -Kind $spec.Kind `
                    -ExpectedFileId $spec.FileId `
                    -ExpectedSha256 $spec.Sha256 `
                    -ExpectedTopologySha256 $spec.TopologySha256
            }
        }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "After${Action}Delete:$($spec.Index)" $Journal }
    }
    return $Journal
}

function Invoke-SyncVisionPackagePublicationRecovery {
    param(
        [Parameter(Mandatory = $true)][string]$OutputRoot,
        [Parameter(Mandatory = $true)][object]$Plan,
        [AllowEmptyString()][string]$ExpectedTransactionId = "",
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $root = Assert-SyncVisionPackagePublicationBoundary -OutputRoot $OutputRoot
    $journal = Resolve-SyncVisionPackagePublicationJournal -OutputRoot $root -Plan $Plan
    if ($null -eq $journal) {
        return [pscustomobject]@{ Recovered = $false; Action = "None"; TransactionId = "" }
    }
    if (-not [string]::IsNullOrEmpty($ExpectedTransactionId) -and
        $journal.TransactionId -cne $ExpectedTransactionId) {
        throw "Package publication recovery intent belongs to an unknown transaction."
    }
    $layout = Get-SyncVisionPackagePublicationLayout `
        -OutputRoot $root `
        -PackageName $Plan.PackageName `
        -TransactionId $journal.TransactionId
    $currentPointer = Get-SyncVisionPackagePointerTransactionState -Path $layout.Pointer -Journal $journal
    $pointerCandidate = Get-SyncVisionPackagePointerTransactionState `
        -Path $layout.PointerCandidate `
        -Journal $journal `
        -AllowIntentOwned:([string]::IsNullOrEmpty([string]$journal.NewPointerFileId))
    $pointerBackup = Get-SyncVisionPackagePointerTransactionState -Path $layout.PointerBackup -Journal $journal
    $candidate = Get-SyncVisionPackageGenerationTransactionState `
        -Path $layout.Candidate `
        -Journal $journal `
        -AllowIntentOwned:([string]::IsNullOrEmpty([string]$journal.NewGenerationFileId))
    $generation = Get-SyncVisionPackageGenerationTransactionState -Path $layout.Generation -Journal $journal

    if (($candidate.Exists -and $generation.Exists) -or
        ($candidate.Exists -and -not [string]::IsNullOrEmpty($journal.NewGenerationFileId) -and -not $candidate.MatchesNew) -or
        ($generation.Exists -and -not [string]::IsNullOrEmpty($journal.NewGenerationFileId) -and -not $generation.MatchesNew) -or
        ($pointerCandidate.Exists -and -not [string]::IsNullOrEmpty($journal.NewPointerFileId) -and -not $pointerCandidate.MatchesNew) -or
        ($pointerBackup.Exists -and -not $pointerBackup.MatchesOld)) {
        throw "Package publication recovery rejected mixed or unknown transaction residue."
    }
    if ($pointerCandidate.Exists -and $null -ne $pointerCandidate.Pointer -and
        [string]$pointerCandidate.Pointer.TransactionId -cne $journal.TransactionId) {
        throw "Package publication recovery rejected a pointer candidate for another transaction."
    }

    $committed = $currentPointer.MatchesNew
    $rolledBack = if ($journal.OldPointerExists) {
        $currentPointer.MatchesOld
    }
    else {
        -not $currentPointer.Exists
    }
    if (-not $committed -and -not $rolledBack) {
        throw "Package publication recovery rejected a current pointer outside the old/new transaction identities."
    }
    if ($committed) {
        if (-not $generation.MatchesNew -or
            [string]$currentPointer.Pointer.TransactionId -cne $journal.TransactionId) {
            throw "Package publication recovery found a committed pointer without its exact immutable generation."
        }
        Assert-SyncVisionPublishedPackageGeneration `
            -OutputRoot $root `
            -Pointer $currentPointer.Pointer | Out-Null
        if ($journal.Phase.StartsWith("Rollback", [StringComparison]::Ordinal)) {
            throw "Package publication recovery found a committed pointer during rollback cleanup."
        }
        $journal = Invoke-SyncVisionPackageTransactionResidueCleanup `
            -Action Commit `
            -Journal $journal `
            -OutputRoot $root `
            -Plan $Plan `
            -TestPhaseHook $TestPhaseHook
        $action = "ForwardCommitted"
    }
    else {
        if ($pointerBackup.Exists) {
            throw "Package publication recovery found an old-pointer backup before the atomic commit point."
        }
        if ($journal.Phase -eq "Committed" -or
            $journal.Phase.StartsWith("Commit", [StringComparison]::Ordinal)) {
            throw "Package publication recovery found the old pointer after a durable commit decision."
        }
        $journal = Invoke-SyncVisionPackageTransactionResidueCleanup `
            -Action Rollback `
            -Journal $journal `
            -OutputRoot $root `
            -Plan $Plan `
            -TestPhaseHook $TestPhaseHook
        $action = "RolledBack"
    }

    Remove-SyncVisionPackagePublicationJournal -Journal $journal -OutputRoot $root -Plan $Plan
    Assert-SyncVisionPackagePublicationResiduesKnown -OutputRoot $root -Plan $Plan -Journal $null
    if ($committed) {
        $published = Resolve-SyncVisionPublishedPackageGeneration -OutputRoot $root -Plan $Plan
        if ($published.Pointer.TransactionId -cne $journal.TransactionId) {
            throw "Package publication committed cleanup changed the current generation pointer."
        }
    }
    elseif ($journal.OldPointerExists) {
        $published = Resolve-SyncVisionPublishedPackageGeneration -OutputRoot $root -Plan $Plan
        if ($published.Pointer.TransactionId -cne $currentPointer.Pointer.TransactionId) {
            throw "Package publication rollback changed the old generation pointer."
        }
    }
    elseif (Test-Path -LiteralPath $layout.Pointer) {
        throw "Package publication rollback unexpectedly created a current generation pointer."
    }
    return [pscustomobject]@{
        Recovered = $true
        Action = $action
        TransactionId = $journal.TransactionId
    }
}
function New-SyncVisionReleasePackage {
    param(
        [Parameter(Mandatory = $true)]
        $Plan,

        [switch]$NoZip,

        [AllowNull()][scriptblock]$TestPhaseHook
    )

    Assert-SyncVisionPackageInputs -Entries $Plan.Entries
    $requestedOutputRoot = Get-SyncVisionPackagePlanOutputRoot -Plan $Plan
    $outputRoot = Initialize-SyncVisionPackagePublicationRoot -OutputRoot $requestedOutputRoot
    if ($null -eq $Plan.PSObject.Properties["PublicationOutputRoot"]) {
        $Plan | Add-Member -NotePropertyName PublicationOutputRoot -NotePropertyValue $outputRoot
    }
    else {
        $Plan.PublicationOutputRoot = $outputRoot
    }

    $publicationMutex = Enter-SyncVisionPackagePublicationMutex `
        -OutputRoot $outputRoot `
        -PackageName $Plan.PackageName
    $nonce = ""
    try {
        Invoke-SyncVisionPackagePublicationRecovery -OutputRoot $outputRoot -Plan $Plan | Out-Null
        Assert-SyncVisionNoLegacyPackagePublicationFinals `
            -OutputRoot $outputRoot `
            -PackageName $Plan.PackageName
        $oldGeneration = Resolve-SyncVisionPublishedPackageGeneration `
            -OutputRoot $outputRoot `
            -Plan $Plan `
            -AllowMissing

        $nonce = [Guid]::NewGuid().ToString("N")
        $layout = Get-SyncVisionPackagePublicationLayout `
            -OutputRoot $outputRoot `
            -PackageName $Plan.PackageName `
            -TransactionId $nonce
        foreach ($reservedPath in @(
                $layout.Stage, $layout.StageTombstone,
                $layout.Candidate, $layout.CandidateTombstone,
                $layout.Generation, $layout.GenerationTombstone,
                $layout.PointerCandidate, $layout.PointerCandidateTombstone,
                $layout.PointerBackup, $layout.PointerBackupTombstone)) {
            if (Test-Path -LiteralPath $reservedPath) {
                throw "Package publication transaction path was preempted before durable intent: $reservedPath"
            }
        }

        $journal = Write-SyncVisionPackagePublicationJournal `
            -Journal ([pscustomobject]@{
                    SchemaVersion = 2
                    TransactionId = $nonce
                    Phase = "Intent"
                    PhaseIndex = -1
                    OutputIdentity = Get-SyncVisionPackageOutputIdentity -OutputRoot $outputRoot
                    PackageName = $Plan.PackageName
                    IncludeZip = (-not $NoZip)
                    StageLeaf = $layout.StageLeaf
                    CandidateLeaf = $layout.CandidateLeaf
                    GenerationLeaf = $layout.GenerationLeaf
                    PointerLeaf = $layout.PointerLeaf
                    PointerCandidateLeaf = $layout.PointerCandidateLeaf
                    PointerBackupLeaf = $layout.PointerBackupLeaf
                    OldPointerExists = ($null -ne $oldGeneration)
                    OldPointerSha256 = $(if ($null -eq $oldGeneration) { "" } else { $oldGeneration.PointerSha256 })
                    OldPointerFileId = $(if ($null -eq $oldGeneration) { "" } else { $oldGeneration.PointerFileId })
                    OldGenerationLeaf = $(if ($null -eq $oldGeneration) { "" } else { $oldGeneration.Pointer.GenerationLeaf })
                    NewGenerationSha256 = ""
                    NewGenerationFileId = ""
                    NewGenerationTopologySha256 = ""
                    NewPointerSha256 = ""
                    NewPointerFileId = ""
                }) `
            -OutputRoot $outputRoot `
            -Plan $Plan
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterIntent" $journal }

        [IO.Directory]::CreateDirectory(
            $layout.Stage,
            (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
        $stageRoot = Assert-SyncVisionTrustedPackageDirectory `
            -Path $layout.Stage `
            -Context "Protected package publication staging root"
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterStageCreated" $journal }

        $stagePackageRoot = Join-Path $stageRoot $Plan.PackageName
        [IO.Directory]::CreateDirectory(
            $stagePackageRoot,
            (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
        $stageManifestPath = Join-Path $stagePackageRoot "SHA256SUMS.txt"
        $stageDigestPath = Join-Path $stageRoot "$($Plan.PackageName).SHA256SUMS.sha256"
        $stageZipPath = if ($NoZip) { "" } else { Join-Path $stageRoot "$($Plan.PackageName).zip" }

        Copy-SyncVisionPackageEntries -PackageRoot $stagePackageRoot -Entries $Plan.Entries
        Assert-SyncVisionPackageTreeTrustMetadata `
            -Root $stagePackageRoot `
            -Context "Release package construction" | Out-Null
        Write-SyncVisionChecksumManifest -PackageRoot $stagePackageRoot -ManifestPath $stageManifestPath
        Write-SyncVisionManifestDigestSidecar `
            -ManifestPath $stageManifestPath `
            -ManifestDigestPath $stageDigestPath
        $sealedBeforeArchive = Assert-SyncVisionConstructedPackage `
            -PackageRoot $stagePackageRoot `
            -ManifestPath $stageManifestPath `
            -ManifestDigestPath $stageDigestPath
        if (-not $NoZip) {
            New-SyncVisionCanonicalPackageArchive `
                -PackageRoot $stagePackageRoot `
                -ZipPath $stageZipPath `
                -ArchiveRootName $Plan.PackageName
        }
        $sealed = Assert-SyncVisionConstructedPackage `
            -PackageRoot $stagePackageRoot `
            -ManifestPath $stageManifestPath `
            -ManifestDigestPath $stageDigestPath `
            -ZipPath $stageZipPath `
            -ArchiveRootName $Plan.PackageName
        Assert-SyncVisionSealedPackageIdentityUnchanged `
            -Expected $sealedBeforeArchive `
            -Actual $sealed `
            -Context "Package archive creation" | Out-Null

        [IO.Directory]::CreateDirectory(
            $layout.Candidate,
            (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
        $candidatePackageRoot = Join-Path $layout.Candidate $Plan.PackageName
        [IO.Directory]::CreateDirectory(
            $candidatePackageRoot,
            (New-SyncVisionTrustedPackageDirectorySecurity)) | Out-Null
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCandidateDirectoryCreated" $journal }
        $candidateManifestPath = Join-Path $candidatePackageRoot "SHA256SUMS.txt"
        $candidateDigestPath = Join-Path $layout.Candidate "$($Plan.PackageName).SHA256SUMS.sha256"
        $candidateZipPath = Join-Path $layout.Candidate "$($Plan.PackageName).zip"
        Copy-SyncVisionTrustedPackageTreeExact `
            -SourceRoot $stagePackageRoot `
            -DestinationRoot $candidatePackageRoot
        [IO.File]::Copy($stageDigestPath, $candidateDigestPath, $false)
        if (-not $NoZip) {
            [IO.File]::Copy($stageZipPath, $candidateZipPath, $false)
        }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCandidateCopiedBeforeProtection" $journal }
        Protect-SyncVisionPackagePublicationObject -Path $layout.Candidate | Out-Null
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCandidateCreated" $journal }

        $candidateIdentity = Assert-SyncVisionConstructedPackage `
            -PackageRoot $candidatePackageRoot `
            -ManifestPath $candidateManifestPath `
            -ManifestDigestPath $candidateDigestPath `
            -ZipPath $(if ($NoZip) { "" } else { $candidateZipPath }) `
            -ArchiveRootName $Plan.PackageName
        if ($candidateIdentity.PackageTreeSha256 -cne $sealed.PackageTreeSha256 -or
            $candidateIdentity.ManifestSha256 -cne $sealed.ManifestSha256 -or
            $candidateIdentity.ManifestDigestFileSha256 -cne $sealed.ManifestDigestFileSha256 -or
            (-not $NoZip -and $candidateIdentity.ZipSha256 -cne $sealed.ZipSha256)) {
            throw "Caller-visible immutable generation differs from the protected sealed package."
        }
        $journal.NewGenerationSha256 = Get-SyncVisionPackagePublicationObjectHash `
            -Path $layout.Candidate `
            -Kind Directory
        $journal.NewGenerationFileId = Get-SyncVisionPackagePathIdentity -Path $layout.Candidate
        $journal.NewGenerationTopologySha256 = Get-SyncVisionPackageTreeTopologySha256 -Root $layout.Candidate
        $journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $journal `
            -Phase CandidateReady `
            -OutputRoot $outputRoot `
            -Plan $Plan
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCandidateReady" $journal }

        $journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $journal `
            -Phase GenerationMovePending `
            -OutputRoot $outputRoot `
            -Plan $Plan
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "BeforeGenerationMove" $journal }
        Move-SyncVisionPackagePublicationObjectExact `
            -Source $layout.Candidate `
            -Destination $layout.Generation `
            -OutputRoot $outputRoot `
            -Kind Directory `
            -ExpectedFileId $journal.NewGenerationFileId `
            -ExpectedSha256 $journal.NewGenerationSha256 `
            -ExpectedTopologySha256 $journal.NewGenerationTopologySha256 | Out-Null
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterGenerationMove" $journal }
        $journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $journal `
            -Phase GenerationReady `
            -OutputRoot $outputRoot `
            -Plan $Plan

        $pointer = [pscustomobject]@{
            SchemaVersion = 1
            TransactionId = $nonce
            PackageName = $Plan.PackageName
            GenerationLeaf = $layout.GenerationLeaf
            IncludeZip = (-not $NoZip)
            PackageTreeSha256 = $candidateIdentity.PackageTreeSha256
            ManifestSha256 = $candidateIdentity.ManifestSha256
            ManifestDigestFileSha256 = $candidateIdentity.ManifestDigestFileSha256
            ZipSha256 = $(if ($NoZip) { "" } else { [string]$candidateIdentity.ZipSha256 })
            GenerationSha256 = $journal.NewGenerationSha256
            GenerationTopologySha256 = $journal.NewGenerationTopologySha256
        }
        Assert-SyncVisionPublishedPackageGeneration `
            -OutputRoot $outputRoot `
            -Pointer $pointer | Out-Null
        $pointerCandidate = Write-SyncVisionPackageGenerationPointerCandidate `
            -Path $layout.PointerCandidate `
            -Pointer $pointer `
            -PackageName $Plan.PackageName `
            -TestPhaseHook $TestPhaseHook `
            -Journal $journal
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterPointerCandidateCreated" $journal }
        $journal.NewPointerSha256 = $pointerCandidate.Sha256
        $journal.NewPointerFileId = $pointerCandidate.FileId
        $journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $journal `
            -Phase SwitchPending `
            -OutputRoot $outputRoot `
            -Plan $Plan

        if ($null -ne $oldGeneration) {
            $oldBeforeSwitch = Resolve-SyncVisionPublishedPackageGeneration `
                -OutputRoot $outputRoot `
                -Plan $Plan
            if ($oldBeforeSwitch.PointerFileId -cne $journal.OldPointerFileId -or
                $oldBeforeSwitch.PointerSha256 -cne $journal.OldPointerSha256 -or
                $oldBeforeSwitch.Pointer.GenerationLeaf -cne $journal.OldGenerationLeaf) {
                throw "Existing published generation changed before the atomic pointer switch."
            }
        }
        elseif (Test-Path -LiteralPath $layout.Pointer) {
            throw "Package current pointer was preempted before its first atomic publication."
        }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "BeforePointerSwitch" $journal }
        Initialize-SyncVisionPackagePathIdentityType
        if ($null -eq $oldGeneration) {
            [SyncVisionTask19PackagePathIdentity]::MoveNoReplace(
                $layout.PointerCandidate,
                $layout.Pointer)
        }
        else {
            [SyncVisionTask19PackagePathIdentity]::ReplaceWithBackup(
                $layout.PointerCandidate,
                $layout.Pointer,
                $layout.PointerBackup)
        }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterPointerSwitch" $journal }

        $currentPointer = Read-SyncVisionPackageGenerationPointerFile `
            -Path $layout.Pointer `
            -PackageName $Plan.PackageName
        if ($currentPointer.FileId -cne $journal.NewPointerFileId -or
            $currentPointer.Sha256 -cne $journal.NewPointerSha256 -or
            $currentPointer.Pointer.TransactionId -cne $nonce) {
            throw "Atomic package generation pointer switch changed the sealed pointer identity."
        }
        if ($null -ne $oldGeneration) {
            $backupPointer = Read-SyncVisionPackageGenerationPointerFile `
                -Path $layout.PointerBackup `
                -PackageName $Plan.PackageName
            if ($backupPointer.FileId -cne $journal.OldPointerFileId -or
                $backupPointer.Sha256 -cne $journal.OldPointerSha256) {
                throw "Atomic package generation pointer switch did not preserve the exact predecessor pointer."
            }
        }
        Assert-SyncVisionPublishedPackageGeneration `
            -OutputRoot $outputRoot `
            -Pointer $currentPointer.Pointer | Out-Null

        $journal = Set-SyncVisionPackagePublicationJournalPhase `
            -Journal $journal `
            -Phase Committed `
            -OutputRoot $outputRoot `
            -Plan $Plan
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCommit" $journal }
        Invoke-SyncVisionPackagePublicationRecovery `
            -OutputRoot $outputRoot `
            -Plan $Plan `
            -ExpectedTransactionId $nonce `
            -TestPhaseHook $TestPhaseHook | Out-Null

        $published = Resolve-SyncVisionPublishedPackageGeneration `
            -OutputRoot $outputRoot `
            -Plan $Plan
        Set-SyncVisionPackagePlanGenerationPaths -Plan $Plan -Generation $published | Out-Null
        return $Plan
    }
    catch {
        $publicationError = $_
        $journalPaths = Get-SyncVisionPackagePublicationJournalPaths `
            -OutputRoot $outputRoot `
            -PackageName $Plan.PackageName
        if ((Test-Path -LiteralPath $journalPaths.Journal) -or
            (Test-Path -LiteralPath $journalPaths.Temporary)) {
            try {
                Invoke-SyncVisionPackagePublicationRecovery `
                    -OutputRoot $outputRoot `
                    -Plan $Plan `
                    -ExpectedTransactionId $nonce | Out-Null
            }
            catch {
                throw "Package publication failed and durable recovery was incomplete. Failure: $($publicationError.Exception.Message) Recovery: $($_.Exception.Message)"
            }
        }
        throw $publicationError
    }
    finally {
        Exit-SyncVisionPackagePublicationMutex -Context $publicationMutex
    }
}
if ($TestMode) {
    return
}

$scriptDir = Split-Path -Parent $PSCommandPath
$repoRoot = (Resolve-Path -LiteralPath (Join-Path $scriptDir "..")).Path
if ([string]::IsNullOrWhiteSpace($OutputRoot)) {
    $OutputRoot = Get-SyncVisionDefaultPackageOutputRoot
}
$buildScript = Join-Path $scriptDir "build.ps1"
$requestedAccountReleaseConfigPath = Resolve-SyncVisionAccountReleaseConfigRelativePath `
    -RelativePath $AccountReleaseConfigPath

Push-Location $repoRoot
$trustedPackageContext = $null
try {
    if (-not $SkipBuild) {
        if ([string]::IsNullOrEmpty($requestedAccountReleaseConfigPath)) {
            throw "Release packaging requires -AccountReleaseConfigPath."
        }
        $approvedBuild = Read-SyncVisionWebRtcDependencyLock -RepoRoot $repoRoot -Configuration $Configuration
        $powerShell = Resolve-SyncVisionPackageTrustedWindowsPowerShell `
            -ExpectedIdentity $approvedBuild.Lock.toolchain.powershell
        $buildArguments = @(
            "-NoProfile",
            "-ExecutionPolicy", "Bypass",
            "-File", $buildScript,
            "-Configuration", $Configuration,
            "-AccountReleaseConfigPath", $requestedAccountReleaseConfigPath,
            "-TrustedCacheOnly"
        )
        if ($EnableWebRtc) {
            $buildArguments += "-EnableWebRtc"
        }
        & $powerShell.Path @buildArguments
        if ($LASTEXITCODE -ne 0) {
            exit $LASTEXITCODE
        }
    }

    $trustedBuildCache = Resolve-SyncVisionPackageBuildCacheRoot `
        -Configuration $Configuration `
        -RequestedRoot $TrustedBuildCacheRoot `
        -AllowTestBuildCacheRoot:$AllowTestBuildCacheRoot
    $trustedPackageContext = New-SyncVisionTrustedPackagePlan `
        -BuildCacheRoot $trustedBuildCache `
        -OutputRoot $OutputRoot `
        -Version $Version `
        -Configuration $Configuration `
        -EnableWebRtc:$EnableWebRtc `
        -AllowUnsignedDevelopmentBootstrap:$AllowUnsignedDevelopmentBootstrap `
        -AllowTestBuildCacheRoot:$AllowTestBuildCacheRoot
    if (-not [string]::IsNullOrEmpty($requestedAccountReleaseConfigPath) -and
        $trustedPackageContext.BuildFlavorManifest.account_release_config_relative_path -cne
            $requestedAccountReleaseConfigPath) {
        throw "Trusted build account release config path does not match -AccountReleaseConfigPath."
    }
    $plan = $trustedPackageContext.Plan

    New-SyncVisionReleasePackage -Plan $plan -NoZip:$NoZip | Out-Null

    Write-Host "SyncVision unsigned development package created for manual verification."
    if ($AllowUnsignedDevelopmentBootstrap) {
        Write-Warning "This package includes an explicitly requested unsigned development elevation wrapper. It is not suitable for commercial distribution."
    }
    Write-Host "PackageRoot: $($plan.PackageRoot)"
    Write-Host "Manifest: $($plan.ManifestPath)"
    Write-Host "ManifestDigestSidecar: $($plan.ManifestDigestPath)"
    if (-not $NoZip) {
        Write-Host "Zip: $($plan.ZipPath)"
    }
}
finally {
    if ($null -ne $trustedPackageContext) {
        try { Remove-SyncVisionTrustedPackageSnapshot -Snapshot $trustedPackageContext.Snapshot }
        catch { Write-Warning "Trusted package snapshot cleanup was refused: $($_.Exception.Message)" }
    }
    Pop-Location
}
