$ErrorActionPreference = 'Stop' function Assert-Contains { param([string]$Content, [string]$Expected, [string]$Message) if ($Content -notmatch [regex]::Escape($Expected)) { throw $Message } } $root = Split-Path -Parent $PSScriptRoot $profiles = Get-Content -LiteralPath (Join-Path $root 'styles/adaptive-frame-profiles.scss') -Raw -Encoding utf8 $paths = @( 'pages/tree/t03-member-profile.vue', 'pages/tree/t04-add-relative.vue', 'pages/tree/t05-edit-member.vue', 'pages/tree/t06-edit-relationship.vue', 'pages/tree/t07-member-directory.vue', 'pages/tree/t08-member-states.vue' ) $pages = @{} foreach ($path in $paths) { $content = Get-Content -LiteralPath (Join-Path $root $path) -Raw -Encoding utf8 if ($content -match ')') { throw "$path must not retain ModulePage" } if ($content -match "@/utils/api\.js|\bappApi\b") { throw "$path must not connect the API layer" } $pages[$path] = $content } foreach ($path in @('pages/tree/t03-member-profile.vue', 'pages/tree/t07-member-directory.vue', 'pages/tree/t08-member-states.vue')) { Assert-Contains $pages[$path] 'ModulePageBackground' "$path must use the tree module background" } $t03 = $pages['pages/tree/t03-member-profile.vue'] foreach ($required in @('member-state--detail', 'member-state--error', 'adaptive.adaptive-tree-panel', 'adaptive.adaptive-tree-field', '/pages/tree/t05-edit-member', 'query.personId')) { Assert-Contains $t03 $required "Missing T03 contract: $required" } $specializedForms = @{ 't04-add-relative.vue' = @('add-state--form', 'add-state--success', 'add-relative-form', 'relationOptions') 't05-edit-member.vue' = @('edit-state--form', 'edit-state--success', 'edit-member-form', 'memberFixtures') 't06-edit-relationship.vue' = @('relationship-state--form', 'relationship-state--conflict', 'relationship-form', 'relationshipOptions') } foreach ($entry in $specializedForms.GetEnumerator()) { $content = $pages["pages/tree/$($entry.Key)"] if ($content -match ')|import\s+TreeMemberForm') { throw "$($entry.Key) must own its business workflow instead of TreeMemberForm" } foreach ($required in $entry.Value) { Assert-Contains $content $required "Missing specialized form contract in $($entry.Key): $required" } } $t07 = $pages['pages/tree/t07-member-directory.vue'] foreach ($required in @('directory-state--list', 'directory-state--empty', 'directory-state--error', 'adaptive.adaptive-genealogy-list-card', 'directory-card__status', '/pages/tree/t03-member-profile')) { Assert-Contains $t07 $required "Missing T07 contract: $required" } $t08 = $pages['pages/tree/t08-member-states.vue'] foreach ($required in @('member-status--privacy', 'member-status--deceased', 'member-status--forbidden', 'adaptive.adaptive-tree-panel', 'query.state')) { Assert-Contains $t08 $required "Missing T08 contract: $required" } foreach ($asset in @('t01-state-panel.png', 't07-search-input-frame.png', 'list-slip-frame.png')) { Assert-Contains $profiles $asset "Adaptive tree profile missing: $asset" } $catalog = Get-Content -LiteralPath (Join-Path $root 'data/page-catalog.js') -Raw -Encoding utf8 foreach ($entry in @('t04:', 't05:', 't06:', 't07:', 't08:')) { if ($catalog -match [regex]::Escape($entry)) { throw "Page catalog must remove migrated entry: $entry" } } Write-Output 'T03-T08-MEMBER-FLOW-CONTRACT PASS'