Private/Write-RaidinessRunContext.ps1

<#
    What the run could not collect, written next to what it could.

    "Not measured" is an honest answer only when the reason is recoverable.
    The reasons used to live in a string array that Invoke-Raidiness reduced
    to a count, so a report that said "not measured" could not say why. This
    envelope travels with the evidence: the assessment engine reads it as run
    diagnostics (it carries no measurements and enables no module) and the
    report can show the reason next to the check.
#>

# psrunner-lint allow: New-Item — creates the local data directory when every module was skipped; never a tenant object
function Write-RaidinessRunContext {
    [CmdletBinding()]
    param(
        # The data folder the evidence was written to.
        [Parameter(Mandatory = $true)]
        [string] $Path,

        [string] $TenantId,

        # {Key, Kind, Endpoint, Reason} rows from the collectors and modules.
        [object[]] $Skipped = @(),

        [string[]] $Notes = @()
    )

    $envelope = [ordered]@{
        raidinessRunContext = [ordered]@{
            version     = '1.0'
            generatedAt = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
        }
        skipped             = @($Skipped | ForEach-Object {
                # A module skip has no endpoint, and Set-StrictMode refuses a
                # property that is not there, so ask before reading.
                $row = [ordered]@{ key = $_.Key; kind = $_.Kind }
                if ($_.PSObject.Properties['Endpoint']) { $row.endpoint = $_.Endpoint }
                if ($_.PSObject.Properties['TimeoutSeconds']) { $row.timeoutSeconds = $_.TimeoutSeconds }
                $row.reason = $_.Reason
                $row
            })
        notes               = @($Notes)
    }
    if ($TenantId) { $envelope.raidinessRunContext.tenantId = $TenantId }

    # A run where every module was skipped never reached the collector that
    # creates this directory, and that run is exactly the one whose reasons
    # matter most.
    New-Item -ItemType Directory -Path $Path -Force | Out-Null

    $file = Join-Path $Path 'raidiness-run.json'
    ConvertTo-Json -InputObject $envelope -Depth 8 | Out-File -FilePath $file -Encoding utf8
    $file
}