$ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot function Read-Page([string]$path) { Get-Content -LiteralPath (Join-Path $root $path) -Raw -Encoding UTF8 } $contracts = [ordered]@{ 'pages/records/r03-gift-list.vue' = @('giftBooks','openGiftBook','createGift','gift-state--empty','gift-state--loading','gift-state--error','/pages/records/r04-gift-editor?mode=create','/pages/records/r04-gift-editor?mode=view&giftId=') 'pages/records/r04-gift-editor.vue' = @('giftForm','validateGift','saveGift','confirmDelete','giftId','gift-editor-state--saving','gift-editor-state--error','saveResult','/pages/records/r03-gift-list') 'pages/records/r05-ritual-list.vue' = @('rituals','openRitual','createRitual','ritual-state--empty','ritual-state--loading','ritual-state--error','/pages/records/r06-ritual-detail?ritualId=','/pages/records/r07-ritual-editor?mode=create') 'pages/records/r06-ritual-detail.vue' = @('ritualDetail','participants','editRitual','ritual-state--expired','ritual-state--privacy','ritual-state--error','/pages/records/r07-ritual-editor?mode=edit&ritualId=') 'pages/records/r07-ritual-editor.vue' = @('ritualForm','validateRitual','saveRitual','confirmDelete','ritualId','ritual-editor-state--saving','ritual-editor-state--error','saveResult','/pages/records/r05-ritual-list') 'pages/records/r08-growth-journal.vue' = @('growthRecords','recordGrowth','personName','timeline-state--empty','timeline-state--loading','timeline-state--error','growthForm','saveGrowth') 'pages/records/r09-life-events.vue' = @('lifeEvents','createLifeEvent','personName','timeline-state--empty','timeline-state--loading','timeline-state--error','lifeEventForm','saveLifeEvent') 'pages/records/r10-memo-list.vue' = @('memos','toggleMemo','createMemo','memo-state--empty','memo-state--loading','memo-state--error','memoForm','saveMemo') 'pages/records/r11-merit-records.vue' = @('meritRecords','createMerit','totalContribution','merit-state--empty','merit-state--loading','merit-state--error','meritForm','saveMerit') } foreach ($entry in $contracts.GetEnumerator()) { $source = Read-Page $entry.Key foreach ($token in $entry.Value) { if (-not $source.Contains($token)) { throw "$($entry.Key) missing R business anchor: $token" } } foreach ($shared in @('ModulePageBackground','PageHeader','AppButton','AppLoading')) { if (-not $source.Contains($shared)) { throw "$($entry.Key) missing shared primitive: $shared" } } if ($source -match ')|import\s+ModulePage\s+from') { throw "$($entry.Key) must own its business page" } if ($source -match 'uni\.(showToast|showModal|showLoading|showActionSheet)') { throw "$($entry.Key) must use project feedback primitives" } if ($source -match '(?im)(?