param( [string]$Root = (Split-Path -Parent $PSScriptRoot) ) $ErrorActionPreference = 'Stop' $failures = [System.Collections.Generic.List[string]]::new() $warnings = [System.Collections.Generic.List[string]]::new() $targetsDir = Join-Path $Root 'targets' $targetIndex = Join-Path $targetsDir 'README.md' $targetFiles = Get-ChildItem -LiteralPath $targetsDir -File | Where-Object { $_.Name -match '^\d\d-.*\.md$' } | Sort-Object Name $activeTargets = [System.Collections.Generic.List[object]]::new() $statusPattern = '' foreach ($file in $targetFiles) { $content = Get-Content -Raw -Encoding UTF8 -LiteralPath $file.FullName $matches = [regex]::Matches($content, $statusPattern) if ($matches.Count -ne 1) { $failures.Add("$($file.Name): expected exactly one target status marker, found $($matches.Count)") continue } if ($matches[0].Groups[1].Value -eq 'ACTIVE') { $activeTargets.Add($file) } } if ($activeTargets.Count -ne 1) { $failures.Add("Expected exactly one ACTIVE target, found $($activeTargets.Count)") } if (-not (Test-Path -LiteralPath $targetIndex)) { $failures.Add('targets/README.md is missing') } else { $indexContent = Get-Content -Raw -Encoding UTF8 -LiteralPath $targetIndex $currentMatch = [regex]::Match($indexContent, '(?s)## Current target\s+`(M\d\d)`[^\r\n]*\[[^\]]+\]\(([^)]+)\)') if (-not $currentMatch.Success) { $failures.Add('Could not parse Current target from targets/README.md') } elseif ($activeTargets.Count -eq 1) { $expectedId = $currentMatch.Groups[1].Value $expectedFile = $currentMatch.Groups[2].Value $activeFile = $activeTargets[0].Name $activeId = 'M' + $activeFile.Substring(0, 2) if ($expectedId -ne $activeId -or $expectedFile -ne $activeFile) { $failures.Add("Current target points to $expectedId/$expectedFile but ACTIVE is $activeId/$activeFile") } } } $claimsDir = Join-Path $Root 'coordination\claims' $claimIds = @{} $claimPattern = '' if (Test-Path -LiteralPath $claimsDir) { $claimFiles = Get-ChildItem -LiteralPath $claimsDir -Filter '*.md' -File | Where-Object { $_.Name -ne 'README.md' } foreach ($file in $claimFiles) { $content = Get-Content -Raw -Encoding UTF8 -LiteralPath $file.FullName $matches = [regex]::Matches($content, $claimPattern) if ($matches.Count -ne 1) { $failures.Add("coordination/claims/$($file.Name): expected exactly one valid OPENWC_CLAIM marker") continue } $claimId = $matches[0].Groups[1].Value if ($claimIds.ContainsKey($claimId)) { $failures.Add("Duplicate claim ID $claimId in $($claimIds[$claimId]) and $($file.Name)") } else { $claimIds[$claimId] = $file.Name } $expiryText = $matches[0].Groups[3].Value $expiry = [datetime]::ParseExact($expiryText, 'yyyy-MM-dd', [Globalization.CultureInfo]::InvariantCulture) if ($expiry.Date -lt (Get-Date).ToUniversalTime().Date) { $warnings.Add("Claim $claimId expired on $expiryText") } } } foreach ($warning in $warnings) { Write-Warning $warning } if ($failures.Count -gt 0) { foreach ($failure in $failures) { Write-Error $failure } exit 1 } Write-Output "Coordination check passed: targets=$($targetFiles.Count) active=$($activeTargets.Count) fallback_claims=$($claimIds.Count) warnings=$($warnings.Count)" exit 0