$ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot $page = Get-Content -LiteralPath (Join-Path $root 'pages/tree/t03-member-profile.vue') -Raw -Encoding UTF8 $api = Get-Content -LiteralPath (Join-Path $root 'utils/api.js') -Raw -Encoding UTF8 $issues = [System.Collections.Generic.List[string]]::new() foreach ($required in @( 'appApi.getPerson(', 'createRequestController', 'isRequestCancelled', 'onUnload', 'loadSequence', 'memberState.value = "loading";' )) { if (-not $page.Contains($required)) { $issues.Add("T03 page missing remote read owner: $required") } } if ($page.Contains('@/data/mock.js') -or $page.Contains('findTreeMemberPresentationFixture')) { $issues.Add('T03 must not retain the fixture read after the remote owner lands') } foreach ($required in @( 'const normalizeLineagePersonDetail =', 'LINEAGE_PERSON_RESPONSE_INVALID', 'return normalizeLineagePersonDetail(result, normalizedGenealogyId, normalizedPersonId)' )) { if (-not $api.Contains($required)) { $issues.Add("API owner missing strict T03 contract: $required") } } if ($issues.Count -gt 0) { $lines = [System.Collections.Generic.List[string]]::new() $lines.Add('T03-MEMBER-REMOTE-CONTRACT BLOCKED') foreach ($issue in $issues) { $lines.Add("- $issue") } throw ($lines -join [Environment]::NewLine) } Write-Output 'T03-MEMBER-REMOTE-CONTRACT PASS'