Private/Signal.ps1

# The Signals: what a Finding observed, by a name that stays when its wording changes.
#
# A Finding's Check and Value are worded for a Technician and reworded whenever that helps
# one. What reads several Findings together - a Reference from one to another, a Lead -
# cannot go by that wording, so the Judge that produces a Finding says what it observed
# with a name from this list. See ADR-0005.
#
# One list, because two Kinds that named the same observation differently would never
# meet, and nothing would fail. A Signal is declared when the thing was observed: a
# Finding that says "no disk errors" carries none.

# Each with the Kinds that declare it: a Check that was skipped, or was refused the rights
# it needed, can then say what it would have looked for. "No Lead" and "not looked" must
# not read the same. A Kind that measures Servers through the Server Kind's Judge - Odbc,
# AppConnection - declares what that Judge declares.
$script:SignalValues = [ordered]@{
    'disk-errors'          = @{ Kind = @('Stability');  Description = 'Windows logged errors of a disk, its controller or its file system' }
    'drive-health-warning' = @{ Kind = @('DiskHealth'); Description = 'A drive reports wear, uncorrected errors or a temperature beyond its limits' }
    'stop-code-disk'       = @{ Kind = @('Stability');  Description = 'A blue screen whose stop code says a drive or its file system could not be read' }
    'disk-write-slow'      = @{ Kind = @('DiskTest');   Description = 'The disk write test was slower than its thresholds allow' }
    'system-drive-low'     = @{ Kind = @('Storage');    Description = 'The system drive has less free space than the Storage Check allows' }
    'program-not-paged-in' = @{ Kind = @('Stability');  Description = 'A program installed on a local drive crashed because a page of it could not be read' }
    'stop-code-memory'         = @{ Kind = @('Stability'); Description = 'A blue screen whose stop code says memory or its management was corrupted' }
    'hardware-errors'          = @{ Kind = @('Stability'); Description = 'Windows logged hardware errors (WHEA): processor, memory or a bus' }
    'access-violations-spread' = @{ Kind = @('Stability'); Description = 'Several unrelated programs crashed with an access violation' }
    'stop-code-graphics'       = @{ Kind = @('Stability'); Description = 'A blue screen whose stop code says the display driver could not be reset' }
    'live-kernel-graphics'     = @{ Kind = @('Stability'); Description = 'Windows recovered from a hang or fault of the graphics driver' }
    'graphics-driver-old'      = @{ Kind = @('System');    Description = 'The graphics driver is older than the age the Check notes' }
    'link-dropped'                  = @{ Kind = @('NetworkDisruption'); Description = 'The network was disconnected at the device, or its adapter was reset' }
    'servers-lost'                  = @{ Kind = @('NetworkDisruption'); Description = 'Existing connections to several Servers were lost' }
    'server-lost'                   = @{ Kind = @('NetworkDisruption'); Description = 'Existing connections to one Server only were lost; its subject is that Server' }
    'loss-on-own-network'           = @{ Kind = @('Server', 'Odbc', 'AppConnection'); Description = 'Pings to a Server in the machine''s own network were lost' }
    'usb-network-adapter'           = @{ Kind = @('NetworkDependency'); Description = 'Programs on a share are reached through a USB network adapter' }
    'crash-with-network-disruption' = @{ Kind = @('Stability');         Description = 'A program''s crashes coincide with network disruptions' }
    'server-slow'                   = @{ Kind = @('Server', 'NetworkDependency', 'Odbc', 'AppConnection'); Description = 'A Server answers slowly, with loss or only some of the time; its subject is that Server' }
    'server-unreachable'            = @{ Kind = @('Server', 'NetworkDependency', 'Odbc', 'AppConnection'); Description = 'A Server does not answer; its subject is that Server' }
    'printer-offline'               = @{ Kind = @('Printing'); Description = 'Windows reports a printer other than the default as offline' }
    'print-job-stuck'               = @{ Kind = @('Printing'); Description = 'A print job has been lying in a queue for longer than the Check allows' }
    'dependency-on-server'          = @{ Kind = @('NetworkDependency'); Description = 'A program runs from a share of a Server; its subject is that Server' }
}

function Get-SignalList {
    <#
    .SYNOPSIS
        Every Signal a Judge may declare, with what it marks and which Kinds declare it.
    #>

    [CmdletBinding()]
    [OutputType([psobject])]
    param()

    foreach ($name in $script:SignalValues.Keys) {
        [pscustomobject]@{ Name = $name; Description = $script:SignalValues[$name].Description; Kind = @($script:SignalValues[$name].Kind) }
    }
}

function Get-SignalOfKind {
    <#
    .SYNOPSIS
        The Signals a Kind can declare: what a Check of that Kind would have looked for.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyCollection()][string[]]$Kind)

    $kinds = @($Kind | Where-Object { $_ })
    foreach ($name in $script:SignalValues.Keys) {
        if (@($script:SignalValues[$name].Kind | Where-Object { $_ -in $kinds }).Count) { $name }
    }
}
function Assert-Signal {
    <#
    .SYNOPSIS
        Throws for a Signal that is not on the list, naming it and the list.
    #>

    [CmdletBinding()]
    param([AllowNull()][AllowEmptyCollection()][string[]]$Signal)

    foreach ($name in @($Signal | Where-Object { $_ })) {
        if (-not $script:SignalValues.Contains($name)) {
            throw ("'{0}' is not a Signal. Add it to Private/Signal.ps1, or use one of: {1}." -f $name, (@($script:SignalValues.Keys) -join ', '))
        }
    }
}