[CmdletBinding()] param( [string] $LegacyProjectRoot, [string] $ManifestPath ) $ErrorActionPreference = 'Stop' if ([string]::IsNullOrWhiteSpace($LegacyProjectRoot)) { $LegacyProjectRoot = Join-Path $PSScriptRoot '..\..\MBN_STOCK_N\MBN_STOCK_N' } if ([string]::IsNullOrWhiteSpace($ManifestPath)) { $ManifestPath = Join-Path $PSScriptRoot '..\docs\legacy-scene-source-hashes.json' } $legacyRoot = [IO.Path]::GetFullPath($LegacyProjectRoot) $manifestFile = [IO.Path]::GetFullPath($ManifestPath) if (-not (Test-Path -LiteralPath $legacyRoot -PathType Container)) { throw 'The read-only legacy project root was not found.' } if (-not (Test-Path -LiteralPath $manifestFile -PathType Leaf)) { throw 'The legacy scene hash manifest was not found.' } $manifest = Get-Content -LiteralPath $manifestFile -Raw -Encoding UTF8 | ConvertFrom-Json if ($manifest.schemaVersion -ne 1 -or $manifest.algorithm -ne 'SHA-256' -or $manifest.builders.Count -ne 35) { throw 'The legacy scene hash manifest is invalid.' } $seen = [Collections.Generic.HashSet[string]]::new([StringComparer]::Ordinal) foreach ($entry in $manifest.builders) { if (-not $seen.Add([string] $entry.builder)) { throw 'The legacy scene hash manifest contains a duplicate builder.' } $relativePath = ([string] $entry.sourceFile).Replace('/', [IO.Path]::DirectorySeparatorChar) $sourceFile = [IO.Path]::GetFullPath((Join-Path $legacyRoot $relativePath)) $rootPrefix = $legacyRoot.TrimEnd([IO.Path]::DirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar if (-not $sourceFile.StartsWith($rootPrefix, [StringComparison]::OrdinalIgnoreCase) -or -not (Test-Path -LiteralPath $sourceFile -PathType Leaf)) { throw "Legacy source is missing for $($entry.builder)." } $actual = (Get-FileHash -LiteralPath $sourceFile -Algorithm SHA256).Hash if (-not $actual.Equals([string] $entry.sha256, [StringComparison]::OrdinalIgnoreCase)) { throw "Legacy source baseline changed for $($entry.builder)." } } Write-Output "LEGACY_SCENE_BASELINE: PASS ($($seen.Count)/35)"