param( [string[]] $Files = @( "docs/technical/architecture/port-registry.md", "docs/technical/architecture/webservice-catalog.md" ) ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" function Get-RepositoryRoot { param([string] $Start) $current = Resolve-Path $Start while ($null -ne $current) { if (Test-Path (Join-Path $current "docs")) { return $current } $parent = Split-Path -Parent $current if ($parent -eq $current) { break } $current = $parent } throw "Could not locate repository root from '$Start'." } $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $repoRoot = Get-RepositoryRoot -Start $scriptDir $pathViolations = [System.Collections.Generic.List[string]]::new() $hostViolations = [System.Collections.Generic.List[string]]::new() $pathPattern = [regex]'`(?src/[^`]+)`' $urlPattern = [regex]'https?://(?[A-Za-z0-9.-]+)' $legacyHostPattern = [regex]'\b(?[a-z0-9.-]+\.stellaops\.local)\b' foreach ($relativeFile in $Files) { $normalizedRelative = $relativeFile.Replace('\\', '/').Trim() $absoluteFile = Join-Path $repoRoot $normalizedRelative if (-not (Test-Path $absoluteFile)) { throw "Validation file not found: $normalizedRelative" } $lineNumber = 0 foreach ($line in Get-Content $absoluteFile) { $lineNumber++ foreach ($match in $pathPattern.Matches($line)) { $pathValue = $match.Groups['path'].Value.Trim() $absolutePath = Join-Path $repoRoot ($pathValue.Replace('/', [IO.Path]::DirectorySeparatorChar)) if (-not (Test-Path $absolutePath)) { $pathViolations.Add("${normalizedRelative}:$lineNumber unresolved path '$pathValue'") } } foreach ($match in $urlPattern.Matches($line)) { $hostValue = $match.Groups['host'].Value.ToLowerInvariant() if ($hostValue -eq "localhost") { continue } if ($hostValue.StartsWith("127.")) { continue } if ($hostValue -eq "stella-ops.local" -or $hostValue.EndsWith(".stella-ops.local")) { continue } $hostViolations.Add("${normalizedRelative}:$lineNumber non-canonical runtime host '$hostValue'") } foreach ($match in $legacyHostPattern.Matches($line)) { $hostValue = $match.Groups['host'].Value.ToLowerInvariant() if ($hostValue -eq "hosts.stellaops.local") { continue } $hostViolations.Add("${normalizedRelative}:$lineNumber forbidden legacy hostname '$hostValue' (expected .stella-ops.local)") } } } if ($pathViolations.Count -eq 0 -and $hostViolations.Count -eq 0) { Write-Output "PASS validate-webservice-docs: files=$($Files.Count), pathViolations=0, hostViolations=0" exit 0 } Write-Output "FAIL validate-webservice-docs" foreach ($violation in $pathViolations) { Write-Output "PATH: $violation" } foreach ($violation in $hostViolations) { Write-Output "HOST: $violation" } exit 1