fix(agent99): expose verified recovery lifecycle

This commit is contained in:
ogt
2026-07-11 20:19:21 +08:00
parent 244bad7259
commit 0a671bd46a
6 changed files with 203 additions and 33 deletions

View File

@@ -86,6 +86,7 @@ function Get-EvidenceReadback {
$fresh = [bool]($file -and $ageMinutes -le $MaxAgeMinutes)
$safeSummary = $null
$parseError = ""
$contentHealthy = $true
if ($file) {
try {
$rawEvidence = Get-Content -Path $file.FullName -Raw | ConvertFrom-Json
@@ -180,13 +181,17 @@ function Get-EvidenceReadback {
} else { $null }
}
}
if ($Name -in @("sre_alert_inbox", "telegram_inbox")) {
$contentHealthy = [bool]($safeSummary -and $safeSummary.ok)
}
} catch {
$parseError = $_.Exception.GetType().Name
$contentHealthy = $false
}
}
$parsed = [bool]($file -and -not $parseError)
$usable = [bool]($fresh -and $parsed)
$usable = [bool]($fresh -and $parsed -and $contentHealthy)
return [pscustomobject]@{
name = $Name
pattern = $Pattern
@@ -197,6 +202,7 @@ function Get-EvidenceReadback {
maxAgeMinutes = $MaxAgeMinutes
fresh = $fresh
parsed = $parsed
contentHealthy = $contentHealthy
usable = $usable
healthy = [bool](-not $Required -or $usable)
parseError = $parseError
@@ -283,6 +289,7 @@ $taskFailures = @($tasks | Where-Object { -not $_.healthy })
$requiredEvidenceFailures = @($evidence | Where-Object { $_.required -and -not $_.healthy })
$requiredEvidenceStale = @($evidence | Where-Object { $_.required -and -not $_.fresh })
$requiredEvidenceParseFailures = @($evidence | Where-Object { $_.required -and $_.fresh -and -not $_.parsed })
$requiredEvidenceContentFailures = @($evidence | Where-Object { $_.required -and $_.fresh -and $_.parsed -and -not $_.contentHealthy })
$selfCheckEvidence = $evidence | Where-Object { $_.name -eq "self_check" } | Select-Object -First 1
$selfHealthSeverity = if ($selfCheckEvidence -and $selfCheckEvidence.safeSummary) { [string]$selfCheckEvidence.safeSummary.selfHealthSeverity } else { "unknown" }
$alertIncoming = $queues | Where-Object { $_.relativePath -eq "alerts\incoming" } | Select-Object -First 1
@@ -296,6 +303,7 @@ if ($taskFailures.Count -gt 0) { $blockingReasons += "scheduled_task_unhealthy"
if ($relayListeners.Count -eq 0) { $blockingReasons += "sre_alert_relay_not_listening" }
if ($requiredEvidenceStale.Count -gt 0) { $blockingReasons += "required_evidence_stale" }
if ($requiredEvidenceParseFailures.Count -gt 0) { $blockingReasons += "required_evidence_parse_failed" }
if ($requiredEvidenceContentFailures.Count -gt 0) { $blockingReasons += "required_evidence_content_unhealthy" }
if ($selfHealthSeverity -ne "ok") { $blockingReasons += "self_health_not_ok" }
if ($alertRunning.staleOverFiveMinutes -gt 0) { $blockingReasons += "stale_alert_execution" }
if ($alertIncoming.count -gt 0 -or $commandQueue.count -gt 0) { $blockingReasons += "pending_work_before_reboot" }
@@ -322,6 +330,7 @@ $result = [pscustomobject]@{
usableRequiredEvidenceCount = [int]@($evidence | Where-Object { $_.required -and $_.usable }).Count
requiredEvidenceFailureCount = $requiredEvidenceFailures.Count
requiredEvidenceParseFailureCount = $requiredEvidenceParseFailures.Count
requiredEvidenceContentFailureCount = $requiredEvidenceContentFailures.Count
selfHealthSeverity = $selfHealthSeverity
alertIncomingCount = [int]$alertIncoming.count
alertRunningCount = [int]$alertRunning.count

View File

@@ -122,11 +122,13 @@ def test_live_preflight_rejects_fresh_but_unparseable_required_evidence() -> Non
preflight = read("scripts/reboot-recovery/agent99-live-preflight.ps1")
assert '$parsed = [bool]($file -and -not $parseError)' in preflight
assert '$usable = [bool]($fresh -and $parsed)' in preflight
assert '$usable = [bool]($fresh -and $parsed -and $contentHealthy)' in preflight
assert 'healthy = [bool](-not $Required -or $usable)' in preflight
assert '$_.required -and -not $_.healthy' in preflight
assert 'required_evidence_parse_failed' in preflight
assert 'requiredEvidenceParseFailureCount' in preflight
assert 'required_evidence_content_unhealthy' in preflight
assert 'requiredEvidenceContentFailureCount' in preflight
def test_live_preflight_adapts_inbox_evidence_without_raw_message_readback() -> None: