Private/Compile/Write-ResolvedGovernance.ps1

function Write-ResolvedGovernance {
    <#
        .SYNOPSIS
        Serialises the resolved desired-state model to the given build output
        path (a generated artifact, never committed).
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][object]$Resolved,
        [Parameter(Mandatory)][string]$OutputPath
    )

    $outputDir = Split-Path -Parent $OutputPath
    if ($outputDir -and -not (Test-Path $outputDir)) {
        New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
    }

    $header = @(
        "# resolved.yaml"
        "# GENERATED by build.ps1 build — do not edit by hand, do not commit."
        ''
    ) -join "`n"

    $yaml = ConvertTo-Yaml $Resolved
    Set-Content -Path $OutputPath -Value ($header + $yaml) -Encoding utf8

    return $OutputPath
}

function Test-ResolvedGovernance {
    <#
        .SYNOPSIS
        Validates the resolved model against Azure DevOps limits and the
        governance rules (unique shorts, resolvable owner refs, area-path
        constraints). Returns an array of issue strings; empty = valid.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory)][object]$Resolved)

    $issues = [System.Collections.Generic.List[string]]::new()
    $forbidden        = '[\\/:*?"<>|#$&+]'
    $forbiddenInTeams = '[,"/\\[\]:!|<>+=;?*@~''&$#]'   # ADO team name forbidden chars

    # Project declaration: process is free-form (custom templates allowed), but
    # visibility and sourceControl must be values az devops project create accepts.
    if ($Resolved.project) {
        if ($Resolved.project.visibility -notin @('private', 'public')) {
            $issues.Add("Project visibility must be 'private' or 'public', got '$($Resolved.project.visibility)'")
        }
        if ($Resolved.project.sourceControl -notin @('git', 'tfvc')) {
            $issues.Add("Project sourceControl must be 'git' or 'tfvc', got '$($Resolved.project.sourceControl)'")
        }
    }

    # Unique code chains (the global ownership keys, e.g. PTL-FND). Leaf shorts may
    # repeat across products; the product-qualified code must be unique.
    $codes = @($Resolved.areaPaths | Where-Object { $_.code } | ForEach-Object { $_.code })
    $dupes = $codes | Group-Object | Where-Object Count -gt 1
    foreach ($d in $dupes) { $issues.Add("Duplicate code '$($d.Name)' used $($d.Count) times") }

    foreach ($area in $Resolved.areaPaths) {
        $segments = $area.path.TrimStart('\') -split '\\'
        if ($segments.Count -ge 14) {
            $issues.Add("Area path exceeds 14 levels: $($area.path)")
        }
        foreach ($segment in $segments) {
            if ($segment.Length -gt 255) { $issues.Add("Area path segment > 255 chars: $segment") }
            if ($segment -match $forbidden) { $issues.Add("Area path segment contains forbidden characters: $segment") }
        }
    }

    foreach ($team in $Resolved.teams) {
        if ($team.name -match $forbiddenInTeams) {
            $issues.Add("Team name contains ADO-forbidden characters: '$($team.name)'")
        }
    }

    return $issues.ToArray()
}