$ErrorActionPreference = 'Stop'
function Assert-Contains {
param([string]$Content, [string]$Expected, [string]$Message)
if ($Content -notmatch [regex]::Escape($Expected)) { throw $Message }
}
function Assert-NoCssSurface {
param([string]$Content, [string]$ClassName)
foreach ($property in @('border', 'background', 'border-radius')) {
if ($Content -match "(?s)\\.$ClassName\\s*\\{[^}]*\\b$property\\s*:") {
throw "Application flow must not construct .$ClassName with CSS $property"
}
}
}
$root = Split-Path -Parent $PSScriptRoot
$g08 = Get-Content -LiteralPath (Join-Path $root 'pages/genealogy/g08-join-application.vue') -Raw -Encoding utf8
$g09 = Get-Content -LiteralPath (Join-Path $root 'pages/genealogy/g09-my-applications.vue') -Raw -Encoding utf8
$g10 = Get-Content -LiteralPath (Join-Path $root 'pages/genealogy/g10-application-review.vue') -Raw -Encoding utf8
$catalog = Get-Content -LiteralPath (Join-Path $root 'data/page-catalog.js') -Raw -Encoding utf8
foreach ($page in @($g08, $g09, $g10)) {
if ($page -match '' 'G08-G10 must use the accepted shared genealogy background'
if ($page -match "@/utils/api\.js|\bappApi\b") { throw 'G08-G10 design phase must not connect the API layer' }
}
foreach ($required in @(
"const joinState = ref('form')",
'join-state--form',
'join-state--success',
'join-state--error',
'g03-create-flow-panel.png',
'a01-scroll-primary-v3.png',
'const genealogyPreview',
'query.genealogyId',
"const source = ref('search')",
'const sourceContract = computed(() =>',
'const fieldErrors = reactive({',
'/pages/genealogy/g09-my-applications',
'/pages/genealogy/g01-my-genealogies?genealogyId='
)) { Assert-Contains $g08 $required "Missing G08 join contract: $required" }
foreach ($nativeUi in @('uni.showToast', 'uni.showModal', 'uni.showLoading', 'uni.showActionSheet')) {
if ($g08 -match [regex]::Escape($nativeUi)) { throw "G08 must not use native UniApp UI: $nativeUi" }
}
foreach ($required in @(
"const applicationState = ref('loading')",
'application-state--list',
'application-state--empty',
'application-state--error',
'application-status-card.png',
"'PENDING'",
"'APPROVED'",
"'REJECTED'",
"'WITHDRAWN'",
'const applicationSamples',
'const actionFor = (item) =>',
'const withdrawTarget = ref(null)',
'