Private/Repair-OSDStageRepositoryCacheResidue.ps1

function Repair-OSDStageRepositoryCacheResidue {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$CachePath,
        [string]$LogPath
    )

    $stagingRoot = Join-Path $CachePath '.staging'
    if (-not (Test-Path -LiteralPath $stagingRoot -PathType Container)) { return }
    $items = @(Get-ChildItem -LiteralPath $stagingRoot -Force -ErrorAction SilentlyContinue)
    $owned = @($items | Where-Object { $_.PSIsContainer -and $_.Name -match '^Sync-[0-9a-f]{32}$' })
    $unknown = @($items | Where-Object { -not ($_.PSIsContainer -and $_.Name -match '^Sync-[0-9a-f]{32}$') })

    foreach ($item in $unknown) {
        $message = "Unrecognized cache staging content was left untouched: $($item.FullName)"
        Write-Warning $message
        if ($LogPath) { Write-OSDStageLog -LogPath $LogPath -Component 'CacheHealth' -Event 'CacheAdvisory' -Level 'Warning' -Message $message -Data @{Path=$item.FullName} }
    }
    if ($owned.Count -eq 0) { return }

    $packagesRoot = Join-Path $CachePath 'Packages'
    $catalogPath = Join-Path $CachePath 'CacheCatalog.json'
    $activeConsistent = $false
    $reason = $null
    try {
        if (Test-Path -LiteralPath $catalogPath -PathType Leaf) {
            $catalog = Get-OSDStageManifest -Path $catalogPath
            if (-not ($catalog.PSObject.Properties.Name -contains 'Packages')) { throw 'CacheCatalog.json is missing Packages.' }
            foreach ($package in @($catalog.Packages)) {
                $id = [string]$package.Id
                if ($id -notmatch '^[A-Za-z0-9][A-Za-z0-9._-]*$' -or $id -match '\.\.') { throw "CacheCatalog.json contains invalid package Id '$id'." }
                $sha = [string]$package.Payload.Sha256
                if ($sha -notmatch '^[A-Fa-f0-9]{64}$') { throw "CacheCatalog.json package '$id' has invalid SHA-256 metadata." }
                $archive = Join-Path $packagesRoot (Join-Path $id 'Package.zip')
                if (-not (Test-OSDStageFileHash -Path $archive -ExpectedSha256 $sha)) { throw "Cached repository package '$id' is missing or does not match CacheCatalog.json." }
            }
            $activeConsistent = $true
        }
        else {
            $physicalPackages = if (Test-Path -LiteralPath $packagesRoot -PathType Container) { @(Get-ChildItem -LiteralPath $packagesRoot -Directory -Force -ErrorAction SilentlyContinue) } else { @() }
            $activeConsistent = $physicalPackages.Count -eq 0
            if (-not $activeConsistent) { $reason = 'Repository package folders exist without CacheCatalog.json.' }
        }
    }
    catch { $reason = $_.Exception.Message; $activeConsistent = $false }

    if (-not $activeConsistent) {
        $message = "OSDStage transaction residue was preserved because the active repository cache could not be proven consistent$(if ($reason) { ': ' + $reason } else { '.' })"
        Write-Warning $message
        if ($LogPath) { Write-OSDStageLog -LogPath $LogPath -Component 'CacheHealth' -Event 'CacheRecoveryPreserved' -Level 'Warning' -Message $message -Data @{CachePath=$CachePath} }
        return
    }

    $removed = 0
    foreach ($directory in $owned) { Remove-Item -LiteralPath $directory.FullName -Recurse -Force -ErrorAction Stop; $removed++ }
    if ($removed -gt 0 -and $LogPath) { Write-OSDStageLog -LogPath $LogPath -Component 'CacheHealth' -Event 'CacheTransactionResidueRemoved' -Message 'Removed stale OSDStage repository transaction directories after validating the active cache.' -Data @{Count=$removed;StagingRoot=$stagingRoot} }
    [pscustomobject]@{CachePath=$CachePath;RemovedCount=$removed;AdvisoryCount=$unknown.Count}
}