$ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot $issues = New-Object System.Collections.Generic.List[string] function Read-RequiredFile { param([string]$RelativePath) $path = Join-Path $root $RelativePath if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { $script:issues.Add("missing required G03 file: $RelativePath") return '' } return Get-Content -Raw -Encoding UTF8 -LiteralPath $path } $page = Read-RequiredFile 'pages/genealogy/g03-create-genealogy.vue' $api = Read-RequiredFile 'utils/api.js' $flowContract = Read-RequiredFile 'tests/g03-create-flow-contract.ps1' $flowRuntime = Read-RequiredFile 'tests/g03-create-flow-runtime-smoke.js' foreach ($required in @( 'appApi.createGenealogy', 'finishPage("G01", {}, {', 'entityId: created.id', 'requestController: createController' )) { if (-not $page.Contains($required)) { $issues.Add("G03 real create page missing: $required") } } foreach ($required in @( "url: '/genealogy/app/genealogies'", 'normalizeCreatedGenealogy', 'requestStrict({' )) { if (-not $api.Contains($required)) { $issues.Add("G03 real create API missing: $required") } } foreach ($required in @( 'G03-CREATE-FLOW-CONTRACT PASS', 'G03-CREATE-FLOW-RUNTIME-SMOKE PASS' )) { $source = if ($required -like '*RUNTIME*') { $flowRuntime } else { $flowContract } if (-not $source.Contains($required)) { $issues.Add("G03 verification missing: $required") } } foreach ($forbidden in @( 'createLocalGenealogyPreview', 'updateLocalGenealogyPreview', 'removeLocalGenealogyPreview', 'local-created-', 'setTimeout(', 'genealogies.unshift(created)' )) { if ($page.Contains($forbidden) -or $api.Contains($forbidden)) { $issues.Add("G03 must not retain a local preview path: $forbidden") } } if ($issues.Count -gt 0) { Write-Output 'G03-BOOTSTRAP-CLIENT-RELEASE BLOCKED' foreach ($issue in $issues) { Write-Output "- $issue" } exit 1 } Write-Output 'G03-BOOTSTRAP-CLIENT-RELEASE PASS'