g-health.ps1

# Unified health report: gap sweep (360 states), workflow coverage, per-script inventory.
# Default output is pretty (colors + Unicode bars). Auto-switches to plain when stdout is
# redirected (CI). Pass -Plain to force plain text explicitly.
# -Cov adds per-script gap coverage score; -Uni adds uniqueness score; -CapV lists capability names.

param([switch]$Plain, [switch]$Cov, [switch]$Uni, [switch]$CapV)
. (Join-Path $PSScriptRoot 'g-error-vectors.ps1')

$pretty    = -not $Plain -and -not [System.Console]::IsOutputRedirected
$threshold = 0.04
$sep       = ([string][char]0x2500) * 54   # ─ * 54

# Write colored segment. Always no-newline; caller adds Write-Host '' for EOL.
function pw {
    param([string]$text, [string]$color = 'Gray')
    Write-Host $text -ForegroundColor $color -NoNewline
}

function Get-Bar {
    param([double]$score)
    $filled = [Math]::Min(5, [Math]::Round($score / 0.10 * 5))
    return ([string][char]0x2588) * $filled + ([string][char]0x2591) * (5 - $filled)
}

function Get-ScoreColor {
    param([double]$score, [int]$caps)
    if ($caps -eq 0)             { return 'DarkGray' }
    if ($score -ge 0.08)         { return 'Green'    }
    if ($score -ge $threshold)   { return 'Yellow'   }
    return 'Red'
}

function Get-CovColor {
    param([double]$score)
    if ($score -ge 1.0) { return 'Green'  }
    if ($score -gt 0)   { return 'Yellow' }
    return 'DarkGray'
}

function Get-UniColor {
    param([double]$score)
    if ($score -ge 0.5) { return 'Green'  }
    if ($score -gt 0)   { return 'Yellow' }
    return 'DarkGray'
}

# --- [1] Gap sweep (360 states) ---

$gapData = foreach ($cl in 'B','F','W') { foreach ($di in 'c','d1','s1') {
    foreach ($ah in 'a0','a1') { foreach ($be in 'b0','b1') {
        foreach ($pu in 'P','U') { foreach ($pr in 'PR-','PRD','PRO','PRX','PRA') {
            $r = Resolve-MatrixAction -Hash "$cl|$di|$ah|$be|$pu|$pr"
            if ($r -and $r.Dim) {
                $req     = $GapRequirements[$r.Dim]
                $covered = $req -and (@($req | Where-Object { $_ -in $AllCapabilities }).Count -eq $req.Count)
                if (-not $covered) {
                    " $(Format-GapLabel -Class $r.Class -Dim $r.Dim -Ahead $r.Ahead -Behind $r.Behind -Pr $r.Pr)"
                }
            }
        } } } } } }
$gaps = @($gapData | ForEach-Object { $_.Trim() } | Select-Object -Unique | Sort-Object)

# --- [2] Workflow coverage ---

$wfRows = foreach ($wfName in $WorkflowRegistry.Keys) {
    $wFlags = $WorkflowRegistry[$wfName]
    if ($wFlags -cnotmatch '[a-z]') { continue }   # skip diagnostic-only aliases (e.g. health=H); -c for case-sensitive
    $allCaps = [System.Collections.Generic.HashSet[string]]::new()
    foreach ($f in $wFlags.ToCharArray()) {
        $fc = $FlagCapabilities["$f"]
        if ($fc) { foreach ($cap in $fc) { [void]$allCaps.Add($cap) } }
    }
    $covered = @(foreach ($dim in ($GapRequirements.Keys | Sort-Object)) {
        $req = $GapRequirements[$dim]
        if (@($req | Where-Object { $_ -in $allCaps }).Count -eq $req.Count) { $dim }
    })
    [pscustomobject]@{ Name = $wfName; Flags = $wFlags; Dims = $covered }
}

# --- [3] Script inventory ---

$scripts = Get-ChildItem -Path $PSScriptRoot -Filter 'g-*.ps1' |
    Where-Object { $_.Name -notin @('g-capabilities.ps1','g-error-vectors.ps1',
                                    'g-registry.ps1','g-health.ps1','g-optimization.ps1',
                                    'g-matrix-resolve.ps1') } |
    Sort-Object Name

$totalDims = $GapRequirements.Keys.Count

$scriptRows = foreach ($s in $scripts) {
    $caps  = Get-ScriptCapabilities -Path $s.FullName
    $lines = @(Get-Content $s.FullName | Where-Object { $_.Trim() -and $_.Trim() -notmatch '^#' }).Count
    $score = if ($lines -gt 0 -and $caps.Count -gt 0) { [Math]::Round($caps.Count / $lines, 3) } else { 0 }
    $dimsCovered = @(foreach ($dim in ($GapRequirements.Keys | Sort-Object)) {
        $req = $GapRequirements[$dim]
        if (@($req | Where-Object { $_ -in $caps }).Count -eq $req.Count) { $dim }
    })
    $covScore = if ($totalDims -gt 0) { [Math]::Round($dimsCovered.Count / $totalDims, 3) } else { 0 }
    [pscustomobject]@{
        Name        = $s.Name
        Short       = ($s.Name -replace '^g-' -replace '\.ps1$')
        Caps        = $caps
        Lines       = $lines
        Score       = $score
        Dims        = $dimsCovered
        CovScore    = $covScore
        LowDensity  = ($caps.Count -gt 0 -and $score -lt $threshold)
    }
}

# --- Uniqueness scores (cross-script cap frequency; cap present in exactly one script = unique) ---

if ($Uni) {
    $capFreq = @{}
    foreach ($row in $scriptRows) { foreach ($cap in $row.Caps) { $capFreq[$cap] = ($capFreq[$cap] ?? 0) + 1 } }
    foreach ($row in $scriptRows) {
        $uniq     = @($row.Caps | Where-Object { $capFreq[$_] -eq 1 }).Count
        $uniScore = if ($row.Caps.Count -gt 0) { [Math]::Round($uniq / $row.Caps.Count, 3) } else { 0 }
        Add-Member -InputObject $row -NotePropertyName UniScore -NotePropertyValue $uniScore
    }
}

$lowDensityCount = @($scriptRows | Where-Object LowDensity).Count

# --- Footer stats ---

$coveredDims = @($GapRequirements.Keys | Where-Object {
    $req = $GapRequirements[$_]
    (@($req | Where-Object { $_ -in $AllCapabilities }).Count -eq $req.Count)
}).Count
$overallCov = if ($totalDims -gt 0) { [Math]::Round($coveredDims / $totalDims, 3) } else { 0 }
$scoredRows = @($scriptRows | Where-Object { $_.Score -gt 0 })
$avgDensity = if ($scoredRows.Count -gt 0) { [Math]::Round(($scoredRows | Measure-Object Score -Average).Average, 3) } else { 0 }
$composite  = [Math]::Round($avgDensity * $overallCov, 3)

# --- Summary badge ---

$badge = if ($gaps.Count -gt 0) {
    @{ Text = ([char]0x2717 + " $($gaps.Count) gap$(if ($gaps.Count -ne 1){'s'})"); Color = 'Red' }
} elseif ($lowDensityCount -gt 0) {
    @{ Text = ([char]0x26A0 + " $lowDensityCount low-density"); Color = 'Yellow' }
} else {
    @{ Text = ([char]0x2713 + ' no gaps'); Color = 'Green' }
}

# ══════════════════════════ OUTPUT ══════════════════════════

if ($pretty) {
    # Title
    $pad = ' ' * [Math]::Max(2, 48 - 'Gitbox Health'.Length)
    pw ' Gitbox Health' 'White'; pw $pad; pw $badge.Text $badge.Color; Write-Host ''
    Write-Host ''

    # ── Gaps ──
    $gapStatus      = if ($gaps.Count -gt 0) { [char]0x2717 + " $($gaps.Count) gap$(if($gaps.Count-ne 1){'s'})" } else { [char]0x2713 + ' clean' }
    $gapStatusColor = if ($gaps.Count -gt 0) { 'Red' } else { 'Green' }
    pw ' Gaps ' 'White'; pw '(360 states)' 'DarkGray'
    pw (' ' * [Math]::Max(2, 28 - '(360 states)'.Length)); pw " $gapStatus" $gapStatusColor; Write-Host ''
    pw " $sep" 'DarkGray'; Write-Host ''
    if ($gaps.Count -gt 0) {
        foreach ($gap in $gaps) { pw " $gap" 'Red'; Write-Host '' }
    }
    Write-Host ''

    # ── Workflows ──
    pw ' Workflows' 'White'; Write-Host ''
    pw " $sep" 'DarkGray'; Write-Host ''
    pw (' {0,-10} {1,-7} ' -f 'name','flags') 'DarkGray'; pw 'dims' 'DarkGray'; Write-Host ''
    foreach ($row in $wfRows) {
        pw ' '; pw ('{0,-10}' -f $row.Name) 'White'
        pw ' '; pw ('{0,-7}' -f $row.Flags) 'White'
        pw ' '
        if ($row.Dims.Count) {
            foreach ($dim in $row.Dims) { pw $dim 'Cyan'; pw ' ' }
        } else { pw ([char]0x2014) 'DarkGray' }
        Write-Host ''
    }
    Write-Host ''

    # ── Scripts ──
    pw ' Scripts' 'White'; Write-Host ''
    pw " $sep" 'DarkGray'; Write-Host ''
    $hdr = ' {0,-18} {1,4} {2,-5} {3,-5}' -f 'script','caps','bar','score'
    if ($Cov) { $hdr += ' {0,-5}' -f 'cov' }
    if ($Uni) { $hdr += ' {0,-5}' -f 'uni' }
    $hdr += ' '
    pw $hdr 'DarkGray'; pw 'dims' 'DarkGray'; Write-Host ''
    foreach ($row in $scriptRows) {
        $sc = Get-ScoreColor $row.Score $row.Caps.Count
        $nc = if ($row.Caps.Count -eq 0) { 'DarkGray' } else { 'White' }
        pw ' '; pw ('{0,-18}' -f $row.Short) $nc; pw ' '
        if ($row.Caps.Count -gt 0) {
            pw ('{0,4}' -f $row.Caps.Count) 'White'; pw ' '
            pw (Get-Bar $row.Score) $sc; pw ' '
            pw ('{0:0.000}' -f $row.Score) $sc
            if ($Cov) { pw ' '; pw ('{0:0.000}' -f $row.CovScore) (Get-CovColor $row.CovScore) }
            if ($Uni) { pw ' '; pw ('{0:0.000}' -f $row.UniScore) (Get-UniColor $row.UniScore) }
        } else {
            pw ('{0,4}' -f ([char]0x2014)) 'DarkGray'; pw ' '
            pw (([string][char]0x2591) * 5) 'DarkGray'; pw ' '
            pw ([char]0x2014) 'DarkGray'
            if ($Cov) { pw ' '; pw ([char]0x2014) 'DarkGray' }
            if ($Uni) { pw ' '; pw ([char]0x2014) 'DarkGray' }
        }
        pw ' '
        if ($row.Dims.Count) {
            foreach ($dim in $row.Dims) { pw $dim 'Cyan'; pw ' ' }
        } else { pw ([char]0x2014) 'DarkGray' }
        if ($row.LowDensity) { pw (" " + [char]0x26A0 + " low density") 'Yellow' }
        Write-Host ''
        if ($CapV -and $row.Caps.Count -gt 0) {
            pw ' '; pw ($row.Caps -join ' ') 'DarkGray'; Write-Host ''
        }
    }

    # ── Footer ──
    Write-Host ''
    pw " $sep" 'DarkGray'; Write-Host ''
    $covColor  = if ($overallCov -ge 1.0) { 'Green' } elseif ($overallCov -gt 0) { 'Yellow' } else { 'Red' }
    $compColor = if ($composite -ge 0.05) { 'Green' } elseif ($composite -gt 0) { 'Yellow' } else { 'Red' }
    pw ' '; pw 'coverage ' 'DarkGray'; pw "$coveredDims/$totalDims" $covColor
    pw ' '; pw 'avg density ' 'DarkGray'; pw ('{0:0.000}' -f $avgDensity) 'White'
    pw ' '; pw 'composite ' 'DarkGray'; pw ('{0:0.000}' -f $composite) $compColor
    Write-Host ''

} else {
    # ── Plain output ──
    Write-Host 'Gaps (360 states)'
    if ($gaps.Count -gt 0) {
        foreach ($gap in $gaps) { Write-Host " $gap" }
    } else { Write-Host ' no gaps found' }
    Write-Host ''

    Write-Host 'Workflows'
    foreach ($row in $wfRows) {
        $dimsStr = if ($row.Dims.Count) { $row.Dims -join ' ' } else { '-' }
        Write-Host (' {0,-8} {1,-6} {2}' -f $row.Name, $row.Flags, $dimsStr)
    }
    Write-Host ''

    Write-Host 'Scripts'
    $scriptHdr = ' {0,-34} {1,4} {2,5} {3,5}' -f 'Script','Caps','Lines','Score'
    if ($Cov) { $scriptHdr += ' cov' }
    if ($Uni) { $scriptHdr += ' uni' }
    $scriptHdr += ' Dims'
    Write-Host $scriptHdr
    foreach ($row in $scriptRows) {
        $dimsStr  = if ($row.Dims.Count) { $row.Dims -join ' ' } else { '-' }
        $scoreStr = if ($row.Score -gt 0) { ('{0:0.000}' -f $row.Score) } else { '-' }
        $capsStr  = if ($row.Caps.Count -gt 0) { "$($row.Caps.Count)" } else { '-' }
        $suffix   = if ($row.LowDensity) { ' (!)' } else { '' }
        $line     = ' {0,-34} {1,4} {2,5} {3,5}' -f $row.Name, $capsStr, $row.Lines, $scoreStr
        if ($Cov) { $cs = $row.CovScore -gt 0 ? ('{0:0.000}' -f $row.CovScore) : '-'; $line += ' {0,-5}' -f $cs }
        if ($Uni) { $us = $row.UniScore -gt 0 ? ('{0:0.000}' -f $row.UniScore) : '-'; $line += ' {0,-5}' -f $us }
        $line += " $dimsStr$suffix"
        Write-Host $line
        if ($CapV -and $row.Caps.Count -gt 0) { Write-Host " caps: $($row.Caps -join ' ')" }
    }
    Write-Host ''
    Write-Host "coverage $coveredDims/$totalDims avg-density $avgDensity composite $composite"
}
exit 0