Payload/scripts/kaden/harness/harness-dispatch-preflight.ps1

#Requires -Version 5.1
<#
.SYNOPSIS
    Parent dispatch preflight before Task-dispatching atdd-developer.

.DESCRIPTION
    Runs harness-health summary plus the same Error+Warning verify-local bookend
    turn-start preflight uses (or reuses a fresh PASS verify-local sensor per TTL
    when the working tree is clean). Exit 0 means safe to Task-dispatch; non-zero
    names the failing verify step. Does not print a Task prompt.

.EXAMPLE
    pwsh -File scripts/kaden/harness-invoke.ps1 harness-dispatch-preflight.ps1 -Feature harness-event-journal -Slice wrap-honesty
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [string]$Feature,

    [Parameter(Mandatory = $true)]
    [string]$Slice,

    [ValidateRange(1, 1440)]
    [int]$FreshVerifyMinutes = 20,

    [string]$FeatureRoot = '',

    [string]$RepoRoot = '',

    [switch]$AllowArbitraryFeatureRoot
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Import-Module (Join-Path $PSScriptRoot 'lib\RepoRuntime.psm1') -Force
Import-Module (Join-Path $PSScriptRoot 'lib\HarnessContract.psm1') -Force
Import-Module (Join-Path $PSScriptRoot 'lib\HarnessJournal.psm1') -Force
Import-Module (Join-Path $PSScriptRoot 'lib\HarnessGateProjection.psm1') -Force
Test-HarnessContractModuleReady

if ([string]::IsNullOrWhiteSpace($RepoRoot)) {
    $RepoRoot = Get-HarnessRepoRoot -StartPath $PSScriptRoot
}

Initialize-RepoShellEnvironment -LogPrefix 'harness-dispatch-preflight' | Out-Null

$featureRootPath = Get-HarnessFeatureRoot -RepoRoot $RepoRoot -Feature $Feature `
    -FeatureRootOverride $FeatureRoot -AllowArbitraryFeatureRoot:$AllowArbitraryFeatureRoot

$healthScript = Join-Path $PSScriptRoot 'harness-health.ps1'
$healthArgs = @{
    Feature                      = $Feature
    Slice                        = $Slice
    RepoRoot                     = $RepoRoot
    AllowArbitraryFeatureRoot    = [bool]$AllowArbitraryFeatureRoot
}
if (-not [string]::IsNullOrWhiteSpace($FeatureRoot)) {
    $healthArgs.FeatureRoot = $featureRootPath
}

Write-Output ''
Write-Output "=== Harness dispatch preflight: $Feature / $Slice ==="
& $healthScript @healthArgs | ForEach-Object { Write-Output $_ }

$report = Invoke-HarnessDispatchPreflight `
    -RepoRoot $RepoRoot `
    -FeatureRoot $featureRootPath `
    -Feature $Feature `
    -Slice $Slice `
    -FreshVerifyMinutes $FreshVerifyMinutes

Write-Output ''
if ($report.Verdict -eq 'PASS') {
    Write-Output " Dispatch preflight : PASS"
    Write-Output " $($report.Message)"
    if ($report.ReusedFreshSensor -and -not [string]::IsNullOrWhiteSpace([string]$report.ReusedSensorRelPath)) {
        Write-Output " Reused sensor : $($report.ReusedSensorRelPath)"
    }
    elseif (@($report.StepsRan).Count -gt 0) {
        Write-Output " Steps ran : $(@($report.StepsRan) -join ', ')"
    }
    Write-Output ''
    exit 0
}

Write-Output " Dispatch preflight : FAIL"
Write-Output " $($report.Message)"
if (-not [string]::IsNullOrWhiteSpace([string]$report.FailedStep)) {
    Write-Output " Failed step : $($report.FailedStep)"
}
if (@($report.StepsRan).Count -gt 0) {
    Write-Output " Steps ran : $(@($report.StepsRan) -join ', ')"
}
Write-Output ' Fix the tree before Task-dispatching atdd-developer (do not record-phase while turn_open is false).'
Write-Output ''
exit 1