Modules/businessdev.ALbuild.Core/Private/Get-ALbuildModuleInventory.ps1

function Get-ALbuildModuleInventory {
    <#
    .SYNOPSIS
        The completeness fingerprint of a module version folder: how many PowerShell files it contains and
        the hash of its manifest.
    .DESCRIPTION
        Written into the '.albuild-complete' marker at install time (from the freshly-downloaded staging
        copy) and recomputed on every verification. The 2026-08 outage lost exactly one .ps1, dropping the
        count from 208 to 207 while the folder still "looked installed" - so the file COUNT is the cheap,
        decisive signal, and the manifest hash additionally catches a corrupted/edited .psd1. Both must be
        computed the SAME way here and in the bootstrap's self-contained first-install copy.
    .PARAMETER Path
        The version folder (e.g. '...\businessdev.ALbuild\2.18.2').
    .OUTPUTS
        PSCustomObject { FileCount [int]; ManifestHash [string] }.
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param([Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Path)

    # Count the PowerShell files that make up the module (what the nested .psm1 files dot-source, plus the
    # manifests). Filter by extension with Where-Object, NOT -Include: -Include is silently ignored when
    # combined with -LiteralPath, which would count every file and defeat the check.
    $files = @(Get-ChildItem -LiteralPath $Path -Recurse -File -ErrorAction SilentlyContinue |
            Where-Object { $_.Extension -in @('.ps1', '.psm1', '.psd1') })
    $count = $files.Count

    $manifest = Join-Path $Path 'businessdev.ALbuild.psd1'
    $hash = ''
    if (Test-Path -LiteralPath $manifest -PathType Leaf) {
        try { $hash = (Get-FileHash -LiteralPath $manifest -Algorithm SHA256 -ErrorAction Stop).Hash } catch { $hash = '' }
    }

    [PSCustomObject]@{ FileCount = [int]$count; ManifestHash = "$hash" }
}