$ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot $requiredFiles = @( 'App.vue', 'main.js', 'manifest.json', 'pages.json', 'uni.scss', 'styles/global.scss', 'data/mock.js', 'utils/config.js', 'utils/api.js', 'components/AppTabbar.vue', 'components/PageHeader.vue', 'pages/auth/a01-entry.vue', 'pages/auth/a02-login.vue', 'pages/genealogy/g01-my-genealogies.vue', 'pages/genealogy/g03-create-genealogy.vue', 'pages/genealogy/g05-genealogy-overview.vue', 'pages/genealogy/g06-search-genealogies.vue', 'pages/genealogy/g10-application-review.vue', 'pages/tree/t01-tree-overview.vue', 'pages/tree/t03-member-profile.vue', 'pages/family/f01-family-feed.vue', 'pages/family/f02-publish-feed.vue', 'pages/profile/m01-profile-home.vue', 'pages/notification/n01-message-center.vue', 'static/icons/tab-genealogy.png', 'static/icons/tab-family.png', 'static/icons/tab-profile.png' ) $missing = $requiredFiles | Where-Object { -not (Test-Path (Join-Path $root $_)) } if ($missing) { throw "Missing phase-one files: $($missing -join ', ')" } $pages = Get-Content -Raw -Encoding UTF8 (Join-Path $root 'pages.json') | ConvertFrom-Json $paths = @($pages.pages | ForEach-Object { $_.path }) $requiredRoutes = @( 'pages/auth/a01-entry', 'pages/auth/a02-login', 'pages/genealogy/g01-my-genealogies', 'pages/genealogy/g03-create-genealogy', 'pages/genealogy/g05-genealogy-overview', 'pages/genealogy/g06-search-genealogies', 'pages/genealogy/g10-application-review', 'pages/tree/t01-tree-overview', 'pages/tree/t03-member-profile', 'pages/family/f01-family-feed', 'pages/family/f02-publish-feed', 'pages/profile/m01-profile-home', 'pages/notification/n01-message-center' ) $missingRoutes = $requiredRoutes | Where-Object { $_ -notin $paths } if ($missingRoutes) { throw "Missing page routes: $($missingRoutes -join ', ')" } if ($paths -contains 'pages/genealogy/g04-first-ancestor') { throw 'G04 route must be merged into G03' } $tokens = Get-Content -Raw -Encoding UTF8 (Join-Path $root 'uni.scss') foreach ($token in @('$brand-red:', '$ink:', '$paper:', '$gold:')) { if ($tokens -notmatch [regex]::Escape($token)) { throw "Missing design token: $token" } } Add-Type -AssemblyName System.Drawing foreach ($icon in @('tab-genealogy.png', 'tab-family.png', 'tab-profile.png')) { $bitmap = [System.Drawing.Bitmap]::new((Join-Path $root "static/icons/$icon")) try { if (-not [System.Drawing.Image]::IsAlphaPixelFormat($bitmap.PixelFormat)) { throw "Icon must keep an alpha channel: $icon" } if ($bitmap.GetPixel(0, 0).A -ne 0) { throw "Icon corner must be transparent: $icon" } } finally { $bitmap.Dispose() } } Write-Output 'PASS phase-one Uni-App contract'