param( [string]$AgentRoot = "C:\Wooo\Agent99", [string]$Prefix = "http://+:8787/agent99/sre-alert/", [string]$TokenEnv = "AGENT99_SRE_RELAY_TOKEN", [string[]]$AllowedRemotePrefixes = @("127.", "::1", "192.168.0."), [int]$MaxBodyBytes = 262144, [switch]$RunOnce ) $ErrorActionPreference = "Stop" $EvidenceDir = Join-Path $AgentRoot "evidence" $AlertRoot = Join-Path $AgentRoot "alerts" $IncomingDir = Join-Path $AlertRoot "incoming" $LogDir = Join-Path $AgentRoot "logs" $BinDir = Join-Path $AgentRoot "bin" $QueueDir = Join-Path $AgentRoot "queue" $ProcessedDir = Join-Path $QueueDir "processed" $SameRunStateDir = Join-Path $AgentRoot "state\same-run-reconcile" $SameRunRetryAuditDir = Join-Path $SameRunStateDir "retry-audit" $AcceptedIgnoredDir = Join-Path $AlertRoot "ignored" $SreAlertInboxScript = Join-Path $BinDir "agent99-sre-alert-inbox.ps1" New-Item -ItemType Directory -Force -Path $EvidenceDir, $IncomingDir, $LogDir, $QueueDir, $ProcessedDir, $SameRunStateDir, $SameRunRetryAuditDir | Out-Null function Convert-AgentSafeFileToken { param([string]$Value) $safe = [regex]::Replace($Value, "[^A-Za-z0-9_.-]", "_") if (-not $safe) { return "relay-alert" } if ($safe.Length -gt 96) { return $safe.Substring(0, 96) } return $safe } function Get-AgentField { param( [object]$Object, [string]$Name, [object]$Default = $null ) if ($Object -is [Collections.IDictionary] -and $Object.Contains($Name)) { return $Object[$Name] } if ($Object -and $Object.PSObject.Properties[$Name]) { return $Object.PSObject.Properties[$Name].Value } return $Default } function Get-AgentEnvValue { param([string]$Name) foreach ($target in @("Process", "User", "Machine")) { $value = [Environment]::GetEnvironmentVariable($Name, $target) if ($value) { return $value } } return "" } function Test-AgentPublicReceiptRef { param([string]$Value) if (-not $Value -or $Value.Length -gt 256) { return $false } if ($Value -match "(?i)(authorization|bearer|password|passwd|token|secret|api[_-]?key|private[_-]?key|cookie|session)(\s|:|=)|-----BEGIN.*PRIVATE KEY-----|(^|[/\.])\.env($|[/\.])") { return $false } if ($Value -match "\.\.|://|[\\?&#=\s]") { return $false } return [bool]($Value -match "^[A-Za-z0-9][A-Za-z0-9._:/@+%-]{0,255}$") } function Get-AgentCanonicalOutcomeIdentity { param([object]$Result, [object]$Outcome) $outer = Get-AgentField $Result "identity" $null $nested = Get-AgentField $Outcome "identity" $null $required = @( "schema_version", "project_id", "incident_id", "source_fingerprint", "route_id", "execution_generation", "approval_id", "run_id", "trace_id", "work_item_id", "idempotency_key", "single_flight_key", "lock_owner", "canonical_digest" ) if (-not $outer -or -not $nested) { return $null } foreach ($name in $required) { $outerValue = [string](Get-AgentField $outer $name "") $nestedValue = [string](Get-AgentField $nested $name "") if ($name -ne "approval_id" -and (-not $outerValue -or -not $nestedValue)) { return $null } if ($outerValue -ne $nestedValue) { return $null } } return $outer } function Get-AgentOutcomeReadback { param([string]$RunId) $parsedRunId = [guid]::Empty if (-not [guid]::TryParse($RunId, [ref]$parsedRunId)) { return @{ ok = $false; found = $false; error = "invalid_run_id" } } foreach ($file in @(Get-ChildItem -Path $ProcessedDir -Filter "processed-*.json" -File -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 256)) { try { $result = Get-Content $file.FullName -Raw | ConvertFrom-Json if ([string](Get-AgentField $result "automationRunId" "") -ne $RunId) { continue } $outcome = Get-AgentField $result "outcome" $null $canonicalIdentity = Get-AgentCanonicalOutcomeIdentity $result $outcome if (-not $canonicalIdentity) { continue } $safeChecks = @() foreach ($check in @((Get-AgentField $outcome "checks" @()) | Select-Object -First 32)) { $safeChecks += @{ name = [string](Get-AgentField $check "name" "") required = [bool](Get-AgentField $check "required" $false) passed = [bool](Get-AgentField $check "passed" $false) } } $safeEvidenceRefs = @{} $outcomeEvidenceRefs = Get-AgentField $outcome "evidenceRefs" $null foreach ($name in @( "backup_status_evidence_ref", "freshness_evidence_ref", "offsite_verify_evidence_ref", "escrow_evidence_ref", "restore_drill_evidence_ref", "source_resolution_receipt_ref" )) { $value = [string](Get-AgentField $outcomeEvidenceRefs $name "") if (Test-AgentPublicReceiptRef $value) { $safeEvidenceRefs[$name] = $value } } $sourceEventEvidence = [string](Get-AgentField $outcome "sourceEventEvidence" "") if (-not (Test-AgentPublicReceiptRef $sourceEventEvidence)) { $sourceEventEvidence = "" } $evidenceReceiptId = [string](Get-AgentField $result "evidenceReceiptId" "") if ([bool](Get-AgentField $result "reconcileOnly" $false)) { $digest = [string](Get-AgentField $canonicalIdentity "canonical_digest" "") $expectedEvidenceReceiptId = if ($digest -match "^[0-9a-f]{64}$") { "same-run-status-$RunId-$($digest.Substring(0, 12))" } else { "" } if ($evidenceReceiptId -ne $expectedEvidenceReceiptId) { $evidenceReceiptId = "" } } $topLevelStringFieldsComplete = $true foreach ($name in @( "automationRunId", "traceId", "workItemId", "projectId", "incidentId", "routeId", "executionGeneration", "approvalId", "evidenceReceiptId", "mode" )) { if (-not $result.PSObject.Properties[$name] -or (Get-AgentField $result $name $null) -isnot [string]) { $topLevelStringFieldsComplete = $false break } } $outcomeStringFieldsComplete = $true foreach ($name in @("schemaVersion", "state", "verifierName", "sourceEventEvidence")) { if (-not $outcome -or -not $outcome.PSObject.Properties[$name] -or (Get-AgentField $outcome $name $null) -isnot [string]) { $outcomeStringFieldsComplete = $false break } } $sameRunContractFieldsComplete = [bool]( $topLevelStringFieldsComplete -and $outcomeStringFieldsComplete -and $result.PSObject.Properties["automationRunId"] -and $result.PSObject.Properties["traceId"] -and $result.PSObject.Properties["workItemId"] -and $result.PSObject.Properties["projectId"] -and $result.PSObject.Properties["incidentId"] -and $result.PSObject.Properties["routeId"] -and $result.PSObject.Properties["executionGeneration"] -and $result.PSObject.Properties["approvalId"] -and $result.PSObject.Properties["evidenceReceiptId"] -and $result.PSObject.Properties["controlledApply"] -and (Get-AgentField $result "controlledApply" $null) -is [bool] -and $result.PSObject.Properties["reconcileOnly"] -and (Get-AgentField $result "reconcileOnly" $null) -is [bool] -and $result.PSObject.Properties["runtimeWritePerformed"] -and (Get-AgentField $result "runtimeWritePerformed" $null) -is [bool] -and $result.PSObject.Properties["mode"] -and $outcome -and $outcome.PSObject.Properties["schemaVersion"] -and $outcome.PSObject.Properties["state"] -and $outcome.PSObject.Properties["resolved"] -and (Get-AgentField $outcome "resolved" $null) -is [bool] -and $outcome.PSObject.Properties["transportOk"] -and (Get-AgentField $outcome "transportOk" $null) -is [bool] -and $outcome.PSObject.Properties["verifierName"] -and $outcome.PSObject.Properties["verifierPassed"] -and (Get-AgentField $outcome "verifierPassed" $null) -is [bool] -and $outcome.PSObject.Properties["sourceEventResolved"] -and (Get-AgentField $outcome "sourceEventResolved" $null) -is [bool] -and $outcome.PSObject.Properties["sourceEventEvidence"] -and $outcome.PSObject.Properties["identity"] ) return @{ ok = $true found = $true schemaVersion = "agent99_outcome_readback_v1" automationRunId = $RunId traceId = [string](Get-AgentField $result "traceId" "") workItemId = [string](Get-AgentField $result "workItemId" "") projectId = [string](Get-AgentField $result "projectId" "") idempotencyKey = [string](Get-AgentField $result "idempotencyKey" "") executionGeneration = [string](Get-AgentField $result "executionGeneration" "1") incidentId = [string](Get-AgentField $result "incidentId" "") approvalId = [string](Get-AgentField $result "approvalId" "") routeId = [string](Get-AgentField $result "routeId" "") evidenceReceiptId = $evidenceReceiptId sameRunContractFieldsComplete = $sameRunContractFieldsComplete identity = $canonicalIdentity controlledApply = [bool](Get-AgentField $result "controlledApply" $false) reconcileOnly = [bool](Get-AgentField $result "reconcileOnly" $false) runtimeWritePerformed = [bool](Get-AgentField $result "runtimeWritePerformed" $false) mode = [string](Get-AgentField $result "mode" "") outcome = @{ schemaVersion = [string](Get-AgentField $outcome "schemaVersion" "") state = [string](Get-AgentField $outcome "state" "unknown") resolved = [bool](Get-AgentField $outcome "resolved" $false) transportOk = [bool](Get-AgentField $outcome "transportOk" $false) verifierName = [string](Get-AgentField $outcome "verifierName" "") verifierPassed = [bool](Get-AgentField $outcome "verifierPassed" $false) sourceEventResolved = [bool](Get-AgentField $outcome "sourceEventResolved" $false) sourceEventEvidence = $sourceEventEvidence identity = $canonicalIdentity failedChecks = @((Get-AgentField $outcome "failedChecks" @()) | Select-Object -First 32) checks = $safeChecks evidenceRefs = $safeEvidenceRefs verifiedAt = [string](Get-AgentField $outcome "verifiedAt" "") } storesRawEvidence = $false } } catch { continue } } return @{ ok = $true found = $false schemaVersion = "agent99_outcome_readback_v1" automationRunId = $RunId storesRawEvidence = $false } } function Write-AgentRelayEvent { param([hashtable]$Event) $path = Join-Path $LogDir "agent99-sre-alert-relay.jsonl" $Event["timestamp"] = (Get-Date).ToString("o") ($Event | ConvertTo-Json -Compress -Depth 8) | Add-Content -Encoding UTF8 $path } function Send-AgentRelayResponse { param( [System.Net.HttpListenerContext]$Context, [int]$StatusCode, [hashtable]$Body ) $json = $Body | ConvertTo-Json -Compress -Depth 8 $bytes = [System.Text.Encoding]::UTF8.GetBytes($json) $Context.Response.StatusCode = $StatusCode $Context.Response.ContentType = "application/json; charset=utf-8" $Context.Response.ContentLength64 = $bytes.Length $Context.Response.OutputStream.Write($bytes, 0, $bytes.Length) $Context.Response.Close() } function Test-AgentRelayRemoteAllowed { param([System.Net.HttpListenerContext]$Context) $remote = [string]$Context.Request.RemoteEndPoint.Address foreach ($prefix in $AllowedRemotePrefixes) { if ($remote.StartsWith($prefix)) { return $true } } return $false } function Start-AgentSreAlertInbox { if (-not (Test-Path $SreAlertInboxScript)) { return [pscustomobject]@{ started = $false; reason = "sre_alert_inbox_script_missing" } } $ps = Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe" $stamp = Get-Date -Format "yyyyMMdd-HHmmss" $stdout = Join-Path $LogDir "agent99-sre-alert-relay-trigger-$stamp.out" $stderr = Join-Path $LogDir "agent99-sre-alert-relay-trigger-$stamp.err" $args = @( "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $SreAlertInboxScript, "-AgentRoot", $AgentRoot, "-RunNow" ) $proc = Start-Process -FilePath $ps -ArgumentList $args -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr return [pscustomobject]@{ started = $true processId = $proc.Id stdout = $stdout stderr = $stderr } } function Get-AgentSha256Text { param([string]$Value) $sha = [Security.Cryptography.SHA256]::Create() try { $bytes = [Text.Encoding]::UTF8.GetBytes($Value) return ([BitConverter]::ToString($sha.ComputeHash($bytes))).Replace("-", "").ToLowerInvariant() } finally { $sha.Dispose() } } function Test-AgentSameRunDispatchIdentity { param([object]$Identity) $required = @( "schema_version", "project_id", "incident_id", "source_fingerprint", "route_id", "execution_generation", "approval_id", "run_id", "trace_id", "work_item_id", "idempotency_key", "single_flight_key", "lock_owner", "canonical_digest" ) if (-not $Identity) { return [pscustomobject]@{ ok = $false; reason = "identity_missing" } } foreach ($name in $required) { if (-not $Identity.PSObject.Properties[$name]) { return [pscustomobject]@{ ok = $false; reason = "identity_field_missing_$name" } } if ($name -ne "approval_id" -and -not [string](Get-AgentField $Identity $name "")) { return [pscustomobject]@{ ok = $false; reason = "identity_field_empty_$name" } } } $runId = [string](Get-AgentField $Identity "run_id" "") $parsedRunId = [guid]::Empty if (-not [guid]::TryParse($runId, [ref]$parsedRunId)) { return [pscustomobject]@{ ok = $false; reason = "identity_run_id_invalid" } } if ($runId -ne "bf30ca01-1080-5725-b2d1-3e1534dfc811") { return [pscustomobject]@{ ok = $false; reason = "identity_run_not_eligible" } } if ([string](Get-AgentField $Identity "schema_version" "") -ne "agent99_controlled_dispatch_identity_v1") { return [pscustomobject]@{ ok = $false; reason = "identity_schema_invalid" } } if ([string](Get-AgentField $Identity "project_id" "") -ne "awoooi") { return [pscustomobject]@{ ok = $false; reason = "identity_project_not_eligible" } } if ([string](Get-AgentField $Identity "work_item_id" "") -ne "agent99-dispatch:awoooi:INC-20260711-11C751:legacy-cold-start") { return [pscustomobject]@{ ok = $false; reason = "identity_work_item_not_eligible" } } if ([string](Get-AgentField $Identity "trace_id" "") -notmatch "^00-[0-9a-f]{32}-[0-9a-f]{16}-01$") { return [pscustomobject]@{ ok = $false; reason = "identity_trace_not_eligible" } } if ([string](Get-AgentField $Identity "route_id" "") -ne "agent99:host_recovery:Recover") { return [pscustomobject]@{ ok = $false; reason = "identity_route_not_eligible" } } if ([string](Get-AgentField $Identity "incident_id" "") -ne "INC-20260711-11C751") { return [pscustomobject]@{ ok = $false; reason = "identity_incident_not_eligible" } } if ([string](Get-AgentField $Identity "execution_generation" "") -ne "1") { return [pscustomobject]@{ ok = $false; reason = "identity_generation_advance_forbidden" } } if ([string](Get-AgentField $Identity "lock_owner" "") -ne $runId) { return [pscustomobject]@{ ok = $false; reason = "identity_lock_owner_mismatch" } } if (-not ([string](Get-AgentField $Identity "source_fingerprint" "")).StartsWith("legacy-cold-start:")) { return [pscustomobject]@{ ok = $false; reason = "identity_source_not_legacy_cold_start" } } $canonical = [ordered]@{ approval_id = [string](Get-AgentField $Identity "approval_id" "") execution_generation = [string](Get-AgentField $Identity "execution_generation" "") idempotency_key = [string](Get-AgentField $Identity "idempotency_key" "") incident_id = [string](Get-AgentField $Identity "incident_id" "") lock_owner = [string](Get-AgentField $Identity "lock_owner" "") project_id = [string](Get-AgentField $Identity "project_id" "") route_id = [string](Get-AgentField $Identity "route_id" "") run_id = $runId schema_version = [string](Get-AgentField $Identity "schema_version" "") single_flight_key = [string](Get-AgentField $Identity "single_flight_key" "") source_fingerprint = [string](Get-AgentField $Identity "source_fingerprint" "") trace_id = [string](Get-AgentField $Identity "trace_id" "") work_item_id = [string](Get-AgentField $Identity "work_item_id" "") } $expectedDigest = Get-AgentSha256Text ($canonical | ConvertTo-Json -Compress -Depth 4) if ($expectedDigest -ne [string](Get-AgentField $Identity "canonical_digest" "")) { return [pscustomobject]@{ ok = $false; reason = "identity_canonical_digest_mismatch" } } return [pscustomobject]@{ ok = $true; reason = "identity_valid" } } function Convert-AgentStoredDispatchIdentity { param([object]$Stored) $identity = Get-AgentField $Stored "identity" $null if ($identity) { return $identity } $awoooi = Get-AgentField $Stored "awoooi" $null $acceptedAlertIdentity = Get-AgentField $awoooi "agent99DispatchIdentity" $null if ($acceptedAlertIdentity) { return $acceptedAlertIdentity } return [pscustomobject]@{ schema_version = "agent99_controlled_dispatch_identity_v1" project_id = [string](Get-AgentField $Stored "projectId" "") incident_id = [string](Get-AgentField $Stored "incidentId" "") source_fingerprint = [string](Get-AgentField $Stored "sourceFingerprint" "") route_id = [string](Get-AgentField $Stored "dispatchRouteId" "") execution_generation = [string](Get-AgentField $Stored "executionGeneration" "") approval_id = [string](Get-AgentField $Stored "approvalId" "") run_id = [string](Get-AgentField $Stored "automationRunId" "") trace_id = [string](Get-AgentField $Stored "traceId" "") work_item_id = [string](Get-AgentField $Stored "workItemId" "") idempotency_key = [string](Get-AgentField $Stored "idempotencyKey" "") single_flight_key = [string](Get-AgentField $Stored "singleFlightKey" "") lock_owner = [string](Get-AgentField $Stored "lockOwner" "") canonical_digest = [string](Get-AgentField $Stored "canonicalDigest" "") } } function Get-AgentExistingRecoverIdentity { param([string]$RunId) $files = @() $files += @(Get-ChildItem -LiteralPath $ProcessedDir -Filter "processed-*.json" -File -ErrorAction SilentlyContinue) $files += @(Get-ChildItem -LiteralPath $QueueDir -Filter "running-*.json" -File -ErrorAction SilentlyContinue) $files += @(Get-ChildItem -LiteralPath $QueueDir -Filter "*.json" -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -notmatch "^(processed|failed|running|same-run-status)-" }) # The API's durable receipt predates the inbox's final classification. The # exact legacy Recover envelope was accepted by the relay and then moved to # ignored by an older inbox build. Admit only that immutable source envelope # as identity evidence so the externally-resolved incident can run Status; # never replay Recover or accept a generic ignored/reconcile payload. $acceptedIgnoredPattern = "ignored-awoooi-agent99-$RunId-*.json" $files = @($files | Sort-Object LastWriteTime -Descending | Select-Object -First 256) $files += @(Get-ChildItem -LiteralPath $AcceptedIgnoredDir -Filter $acceptedIgnoredPattern -File -ErrorAction SilentlyContinue) foreach ($file in $files) { try { $stored = Get-Content -LiteralPath $file.FullName -Raw | ConvertFrom-Json if ([bool](Get-AgentField $stored "reconcileOnly" $false)) { continue } $storedMode = [string](Get-AgentField $stored "mode" (Get-AgentField $stored "suggestedMode" "")) if ($storedMode -ne "Recover") { continue } $identity = Convert-AgentStoredDispatchIdentity $stored if ([string](Get-AgentField $identity "run_id" "") -ne $RunId) { continue } if ($file.DirectoryName -eq $AcceptedIgnoredDir) { if ( [string](Get-AgentField $stored "id" "") -ne "awoooi-agent99-$RunId" -or [string](Get-AgentField $stored "source" "") -ne "awoooi-api-alertmanager" -or [string](Get-AgentField $stored "kind" "") -ne "host_recovery" -or [string](Get-AgentField $stored "service" "") -ne "cold-start-gate" -or (Get-AgentField $stored "controlledApply" $null) -isnot [bool] -or -not [bool](Get-AgentField $stored "controlledApply" $false) ) { continue } } $check = Test-AgentSameRunDispatchIdentity $identity if ($check.ok) { return $identity } } catch { continue } } return $null } function Test-AgentSameRunIdentityMatchesExisting { param([object]$Requested, [object]$Existing) foreach ($name in @( "schema_version", "project_id", "incident_id", "source_fingerprint", "route_id", "execution_generation", "approval_id", "run_id", "trace_id", "work_item_id", "idempotency_key", "single_flight_key", "lock_owner", "canonical_digest" )) { if ([string](Get-AgentField $Requested $name "") -ne [string](Get-AgentField $Existing $name "")) { return $false } } return $true } function Test-AgentSameRunOutcomeEligible { param( [object]$Existing, [object]$Identity, [string]$SourceEvidence, [string]$EvidenceReceiptId ) if (-not $Existing -or -not [bool](Get-AgentField $Existing "found" $false)) { return $false } $outcome = Get-AgentField $Existing "outcome" $null $existingIdentity = Get-AgentField $Existing "identity" $null $nestedIdentity = Get-AgentField $outcome "identity" $null return [bool]( [string](Get-AgentField $Existing "schemaVersion" "") -eq "agent99_outcome_readback_v1" -and [bool](Get-AgentField $Existing "sameRunContractFieldsComplete" $false) -and [string](Get-AgentField $Existing "automationRunId" "") -eq [string](Get-AgentField $Identity "run_id" "") -and [string](Get-AgentField $Existing "traceId" "") -eq [string](Get-AgentField $Identity "trace_id" "") -and [string](Get-AgentField $Existing "workItemId" "") -eq [string](Get-AgentField $Identity "work_item_id" "") -and [string](Get-AgentField $Existing "projectId" "") -eq [string](Get-AgentField $Identity "project_id" "") -and [string](Get-AgentField $Existing "incidentId" "") -eq [string](Get-AgentField $Identity "incident_id" "") -and [string](Get-AgentField $Existing "routeId" "") -eq [string](Get-AgentField $Identity "route_id" "") -and [string](Get-AgentField $Existing "executionGeneration" "") -eq [string](Get-AgentField $Identity "execution_generation" "") -and [string](Get-AgentField $Existing "approvalId" "") -eq [string](Get-AgentField $Identity "approval_id" "") -and [string](Get-AgentField $Existing "evidenceReceiptId" "") -eq $EvidenceReceiptId -and (Test-AgentSameRunIdentityMatchesExisting $existingIdentity $Identity) -and (Test-AgentSameRunIdentityMatchesExisting $nestedIdentity $Identity) -and [string](Get-AgentField $Existing "mode" "") -eq "Status" -and (Get-AgentField $Existing "controlledApply" $null) -is [bool] -and -not [bool](Get-AgentField $Existing "controlledApply" $true) -and (Get-AgentField $Existing "reconcileOnly" $null) -is [bool] -and [bool](Get-AgentField $Existing "reconcileOnly" $false) -and (Get-AgentField $Existing "runtimeWritePerformed" $null) -is [bool] -and -not [bool](Get-AgentField $Existing "runtimeWritePerformed" $true) -and [string](Get-AgentField $outcome "schemaVersion" "") -eq "agent99_outcome_contract_v1" -and [string](Get-AgentField $outcome "state" "") -eq "resolved" -and (Get-AgentField $outcome "resolved" $null) -is [bool] -and [bool](Get-AgentField $outcome "resolved" $false) -and (Get-AgentField $outcome "transportOk" $null) -is [bool] -and [bool](Get-AgentField $outcome "transportOk" $false) -and [string](Get-AgentField $outcome "verifierName" "") -eq "agent99-status-same-run-no-write-post-condition-v1" -and (Get-AgentField $outcome "verifierPassed" $null) -is [bool] -and [bool](Get-AgentField $outcome "verifierPassed" $false) -and (Get-AgentField $outcome "sourceEventResolved" $null) -is [bool] -and [bool](Get-AgentField $outcome "sourceEventResolved" $false) -and [string](Get-AgentField $outcome "sourceEventEvidence" "") -eq $SourceEvidence ) } function Test-AgentSameRunFailedNoWriteOutcomeRetryEligible { param( [object]$Result, [object]$Identity, [string]$SourceEvidence, [string]$EvidenceReceiptId, [string]$QueueId ) if (-not $Result) { return $false } $outcome = Get-AgentField $Result "outcome" $null $canonicalIdentity = Get-AgentCanonicalOutcomeIdentity $Result $outcome if (-not $outcome -or -not $canonicalIdentity) { return $false } foreach ($name in @( "id", "source", "reason", "mode", "reconcileEvidenceId", "evidenceReceiptId", "automationRunId", "traceId", "workItemId", "idempotencyKey", "executionGeneration", "incidentId", "approvalId", "projectId", "routeId", "sourceEventResolutionPolicy" )) { if (-not $Result.PSObject.Properties[$name] -or (Get-AgentField $Result $name $null) -isnot [string]) { return $false } } foreach ($name in @("schemaVersion", "state", "verifierName", "sourceEventEvidence")) { if (-not $outcome.PSObject.Properties[$name] -or (Get-AgentField $outcome $name $null) -isnot [string]) { return $false } } if (-not [string](Get-AgentField $outcome "verifierName" "")) { return $false } $previousSourceEvidence = [string](Get-AgentField $outcome "sourceEventEvidence" "") if ( -not (Test-AgentPublicReceiptRef $SourceEvidence) -or -not $SourceEvidence.StartsWith("prometheus:cold-start:") -or -not (Test-AgentPublicReceiptRef $previousSourceEvidence) -or -not $previousSourceEvidence.StartsWith("prometheus:cold-start:") ) { return $false } return [bool]( [string](Get-AgentField $Result "id" "") -eq $QueueId -and [string](Get-AgentField $Result "source" "") -eq "agent99-same-run-reconcile" -and [string](Get-AgentField $Result "reason" "") -eq "source_event_resolved_status_reconcile" -and [string](Get-AgentField $Result "mode" "") -eq "Status" -and (Get-AgentField $Result "controlledApply" $null) -is [bool] -and -not [bool](Get-AgentField $Result "controlledApply" $true) -and (Get-AgentField $Result "reconcileOnly" $null) -is [bool] -and [bool](Get-AgentField $Result "reconcileOnly" $false) -and (Get-AgentField $Result "runtimeWritePerformed" $null) -is [bool] -and -not [bool](Get-AgentField $Result "runtimeWritePerformed" $true) -and (Get-AgentField $Result "suppressTelegram" $null) -is [bool] -and [bool](Get-AgentField $Result "suppressTelegram" $false) -and [string](Get-AgentField $Result "reconcileEvidenceId" "") -eq $EvidenceReceiptId -and [string](Get-AgentField $Result "evidenceReceiptId" "") -eq $EvidenceReceiptId -and [string](Get-AgentField $Result "automationRunId" "") -eq [string](Get-AgentField $Identity "run_id" "") -and [string](Get-AgentField $Result "traceId" "") -eq [string](Get-AgentField $Identity "trace_id" "") -and [string](Get-AgentField $Result "workItemId" "") -eq [string](Get-AgentField $Identity "work_item_id" "") -and [string](Get-AgentField $Result "idempotencyKey" "") -eq [string](Get-AgentField $Identity "idempotency_key" "") -and [string](Get-AgentField $Result "executionGeneration" "") -eq [string](Get-AgentField $Identity "execution_generation" "") -and [string](Get-AgentField $Result "incidentId" "") -eq [string](Get-AgentField $Identity "incident_id" "") -and [string](Get-AgentField $Result "approvalId" "") -eq [string](Get-AgentField $Identity "approval_id" "") -and [string](Get-AgentField $Result "projectId" "") -eq [string](Get-AgentField $Identity "project_id" "") -and [string](Get-AgentField $Result "routeId" "") -eq [string](Get-AgentField $Identity "route_id" "") -and (Test-AgentSameRunIdentityMatchesExisting $canonicalIdentity $Identity) -and [string](Get-AgentField $Result "sourceEventResolutionPolicy" "") -eq "external_source_receipt_required" -and [string](Get-AgentField $outcome "schemaVersion" "") -eq "agent99_outcome_contract_v1" -and [string](Get-AgentField $outcome "state" "") -eq "failed" -and (Get-AgentField $outcome "resolved" $null) -is [bool] -and -not [bool](Get-AgentField $outcome "resolved" $true) -and (Get-AgentField $outcome "transportOk" $null) -is [bool] -and -not [bool](Get-AgentField $outcome "transportOk" $true) -and (Get-AgentField $outcome "verifierPassed" $null) -is [bool] -and -not [bool](Get-AgentField $outcome "verifierPassed" $true) -and (Get-AgentField $outcome "sourceEventResolved" $null) -is [bool] -and [bool](Get-AgentField $outcome "sourceEventResolved" $false) ) } function Move-AgentSameRunFailedNoWriteOutcomeForRetry { param( [string]$ProcessedPath, [string]$LockPath, [string]$RetryMarkerPath, [string]$QueueId, [object]$Identity, [string]$SourceEvidence, [string]$EvidenceReceiptId ) if (Test-Path -LiteralPath $RetryMarkerPath) { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_already_consumed_fail_closed" } } if (-not (Test-Path -LiteralPath $ProcessedPath) -or -not (Test-Path -LiteralPath $LockPath)) { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_artifact_missing_fail_closed" } } try { $failedResult = Get-Content -LiteralPath $ProcessedPath -Raw | ConvertFrom-Json $lockReceipt = Get-Content -LiteralPath $LockPath -Raw | ConvertFrom-Json $failedOutcomeSha256 = (Get-FileHash -LiteralPath $ProcessedPath -Algorithm SHA256).Hash.ToLowerInvariant() $previousLockSha256 = (Get-FileHash -LiteralPath $LockPath -Algorithm SHA256).Hash.ToLowerInvariant() } catch { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_artifact_invalid_fail_closed" } } if ($failedOutcomeSha256 -notmatch "^[0-9a-f]{64}$" -or $previousLockSha256 -notmatch "^[0-9a-f]{64}$") { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_artifact_digest_invalid_fail_closed" } } if (-not (Test-AgentSameRunFailedNoWriteOutcomeRetryEligible $failedResult $Identity $SourceEvidence $EvidenceReceiptId $QueueId)) { return [pscustomobject]@{ ok = $false; reason = "existing_same_run_status_outcome_invalid_fail_closed" } } $runId = [string](Get-AgentField $Identity "run_id" "") $canonicalDigest = [string](Get-AgentField $Identity "canonical_digest" "") $lockValid = [bool]( [string](Get-AgentField $lockReceipt "schemaVersion" "") -eq "agent99_same_run_single_flight_lock_v1" -and [string](Get-AgentField $lockReceipt "automationRunId" "") -eq $runId -and [string](Get-AgentField $lockReceipt "evidenceReceiptId" "") -eq $EvidenceReceiptId -and [string](Get-AgentField $lockReceipt "canonicalDigest" "") -eq $canonicalDigest -and (Get-AgentField $lockReceipt "storesRawEvidence" $null) -is [bool] -and -not [bool](Get-AgentField $lockReceipt "storesRawEvidence" $true) ) if (-not $lockValid) { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_lock_invalid_fail_closed" } } $outcomeAuditPath = Join-Path $SameRunRetryAuditDir "$QueueId.attempt-1.processed.json" $lockAuditPath = Join-Path $SameRunRetryAuditDir "$QueueId.attempt-1.lock.json" if ((Test-Path -LiteralPath $outcomeAuditPath) -or (Test-Path -LiteralPath $lockAuditPath)) { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_audit_collision_fail_closed" } } try { $markerStream = [IO.File]::Open($RetryMarkerPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None) try { $markerReceipt = @{ schemaVersion = "agent99_same_run_status_retry_v1" status = "retry_reserved" retryOrdinal = 1 automationRunId = $runId evidenceReceiptId = $EvidenceReceiptId canonicalDigest = $canonicalDigest failedOutcomeAuditFile = (Split-Path -Leaf $outcomeAuditPath) failedOutcomeSha256 = $failedOutcomeSha256 previousLockAuditFile = (Split-Path -Leaf $lockAuditPath) previousLockSha256 = $previousLockSha256 preservesFailedOutcome = $true controlledApply = $false reconcileOnly = $true runtimeWriteAuthorized = $false storesRawEvidence = $false createdAt = (Get-Date -Format o) } | ConvertTo-Json -Compress $markerBytes = [Text.Encoding]::UTF8.GetBytes($markerReceipt) $markerStream.Write($markerBytes, 0, $markerBytes.Length) $markerStream.Flush($true) } finally { $markerStream.Dispose() } } catch [System.IO.IOException] { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_already_consumed_fail_closed" } } try { Move-Item -LiteralPath $ProcessedPath -Destination $outcomeAuditPath Move-Item -LiteralPath $LockPath -Destination $lockAuditPath } catch { return [pscustomobject]@{ ok = $false; reason = "same_run_status_retry_archive_failed_fail_closed" } } return [pscustomobject]@{ ok = $true reason = "same_run_status_failed_no_write_outcome_archived_for_single_retry" retryOrdinal = 1 } } function Start-AgentSameRunStatusReconcile { param([object]$Request) $identity = Get-AgentField $Request "identity" $null $identityCheck = Test-AgentSameRunDispatchIdentity $identity if (-not $identityCheck.ok) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = $identityCheck.reason; httpStatus = 400 } } $controlledApply = Get-AgentField $Request "controlledApply" $null $reconcileOnly = Get-AgentField $Request "reconcileOnly" $null $sourceEventResolved = Get-AgentField $Request "sourceEventResolved" $null $suppressTelegram = Get-AgentField $Request "suppressTelegram" $null if ( [string](Get-AgentField $Request "action" "") -ne "same_run_status_reconcile" -or [string](Get-AgentField $Request "mode" "") -ne "Status" -or $controlledApply -isnot [bool] -or $controlledApply -or $reconcileOnly -isnot [bool] -or -not $reconcileOnly -or $sourceEventResolved -isnot [bool] -or -not $sourceEventResolved -or [string](Get-AgentField $Request "sourceEventResolutionPolicy" "") -ne "external_source_receipt_required" -or $suppressTelegram -isnot [bool] -or -not $suppressTelegram ) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "same_run_reconcile_contract_invalid"; httpStatus = 400 } } $sourceEvidence = [string](Get-AgentField $Request "sourceEventEvidence" "") if (-not (Test-AgentPublicReceiptRef $sourceEvidence) -or -not $sourceEvidence.StartsWith("prometheus:cold-start:")) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "source_event_evidence_invalid"; httpStatus = 400 } } $runId = [string](Get-AgentField $identity "run_id" "") $canonicalDigest = [string](Get-AgentField $identity "canonical_digest" "") $evidenceReceiptId = [string](Get-AgentField $Request "evidenceReceiptId" "") $expectedEvidenceReceiptId = if ($canonicalDigest -match "^[0-9a-f]{64}$") { "same-run-status-$runId-$($canonicalDigest.Substring(0, 12))" } else { "" } if (-not $expectedEvidenceReceiptId -or $evidenceReceiptId -ne $expectedEvidenceReceiptId) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "same_run_evidence_receipt_id_invalid"; httpStatus = 400 } } $existingRecoverIdentity = Get-AgentExistingRecoverIdentity $runId if (-not $existingRecoverIdentity) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "existing_dispatch_identity_not_found"; httpStatus = 409 } } if (-not (Test-AgentSameRunIdentityMatchesExisting $identity $existingRecoverIdentity)) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "existing_dispatch_identity_mismatch"; httpStatus = 409 } } $safeRunId = Convert-AgentSafeFileToken $runId $queueId = "same-run-status-$safeRunId" $queuePath = Join-Path $QueueDir "$queueId.json" $runningPath = Join-Path $QueueDir "running-$queueId.json" $processedPath = Join-Path $ProcessedDir "processed-$queueId.json" $lockPath = Join-Path $SameRunStateDir "$queueId.lock.json" $retryMarkerPath = Join-Path $SameRunStateDir "$queueId.retry-1.json" $singleRetryPrepared = $false $existing = Get-AgentOutcomeReadback $runId if (Test-AgentSameRunOutcomeEligible $existing $identity $sourceEvidence $evidenceReceiptId) { return [pscustomobject]@{ ok = $true status = "same_run_status_outcome_already_available" httpStatus = 200 automationRunId = $runId reconcileOnly = $true controlledApply = $false evidenceReceiptId = $evidenceReceiptId queued = $false } } if ($existing.found -and [bool](Get-AgentField $existing "reconcileOnly" $false)) { $retryPreparation = Move-AgentSameRunFailedNoWriteOutcomeForRetry ` $processedPath $lockPath $retryMarkerPath $queueId $identity $sourceEvidence $evidenceReceiptId if (-not $retryPreparation.ok) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = [string]$retryPreparation.reason; httpStatus = 409 } } $singleRetryPrepared = $true } $queuePending = Test-Path -LiteralPath $queuePath -PathType Leaf $runningPending = Test-Path -LiteralPath $runningPath -PathType Leaf $lockPending = Test-Path -LiteralPath $lockPath -PathType Leaf if (-not $singleRetryPrepared -and (Test-Path -LiteralPath $retryMarkerPath -PathType Leaf)) { if (-not (($queuePending -or $runningPending) -and $lockPending)) { return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "same_run_status_retry_already_consumed_fail_closed"; httpStatus = 409 } } return [pscustomobject]@{ ok = $true status = "same_run_status_reconcile_pending" httpStatus = 202 automationRunId = $runId reconcileOnly = $true controlledApply = $false evidenceReceiptId = $evidenceReceiptId queued = $false } } if ($queuePending -or $runningPending -or $lockPending) { return [pscustomobject]@{ ok = $true status = "same_run_status_reconcile_pending" httpStatus = 202 automationRunId = $runId reconcileOnly = $true controlledApply = $false evidenceReceiptId = $evidenceReceiptId queued = $false } } try { $lockStream = [IO.File]::Open($lockPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None) try { $lockReceipt = @{ schemaVersion = "agent99_same_run_single_flight_lock_v1" automationRunId = $runId evidenceReceiptId = $evidenceReceiptId canonicalDigest = $canonicalDigest createdAt = (Get-Date -Format o) storesRawEvidence = $false } | ConvertTo-Json -Compress $lockBytes = [Text.Encoding]::UTF8.GetBytes($lockReceipt) $lockStream.Write($lockBytes, 0, $lockBytes.Length) $lockStream.Flush($true) } finally { $lockStream.Dispose() } } catch [System.IO.IOException] { return [pscustomobject]@{ ok = $true status = "same_run_status_reconcile_pending" httpStatus = 202 automationRunId = $runId reconcileOnly = $true controlledApply = $false evidenceReceiptId = $evidenceReceiptId queued = $false } } $command = [ordered]@{ id = $queueId mode = "Status" controlledApply = $false reconcileOnly = $true reconcileEvidenceId = $evidenceReceiptId requestedBy = "awoooi-agent99-controlled-dispatch-reconciler" source = "agent99-same-run-reconcile" reason = "source_event_resolved_status_reconcile" instruction = "Read-only Status verifier for the existing run; do not recover, advance generation, page Telegram, or write runtime state." correlationKey = ([string](Get-AgentField $identity "idempotency_key" "")) + ":same-run-status" alertId = "same-run-reconcile:$runId" alertSource = "awoooi-production-source-verifier" alertKind = "host_recovery" alertSeverity = "info" alertService = "cold-start-gate" alertHost = "" suppressTelegram = $true sourceEventResolutionRequired = $true sourceEventResolutionPolicy = "external_source_receipt_required" sourceEventResolved = $true sourceEventEvidence = $sourceEvidence automationRunId = $runId traceId = [string](Get-AgentField $identity "trace_id" "") workItemId = [string](Get-AgentField $identity "work_item_id" "") idempotencyKey = [string](Get-AgentField $identity "idempotency_key" "") executionGeneration = [string](Get-AgentField $identity "execution_generation" "") incidentId = [string](Get-AgentField $identity "incident_id" "") approvalId = [string](Get-AgentField $identity "approval_id" "") projectId = [string](Get-AgentField $identity "project_id" "") sourceFingerprint = [string](Get-AgentField $identity "source_fingerprint" "") dispatchRouteId = [string](Get-AgentField $identity "route_id" "") singleFlightKey = [string](Get-AgentField $identity "single_flight_key" "") lockOwner = [string](Get-AgentField $identity "lock_owner" "") canonicalDigest = [string](Get-AgentField $identity "canonical_digest" "") createdAt = (Get-Date -Format o) } $tmpPath = Join-Path $QueueDir ".$queueId-$([guid]::NewGuid().ToString("N")).tmp" $command | ConvertTo-Json -Depth 8 | Set-Content -Encoding UTF8 $tmpPath Move-Item -Force $tmpPath $queuePath $launcher = Join-Path $AgentRoot "agent99-run.ps1" if (-not (Test-Path $launcher)) { Remove-Item -Force $queuePath -ErrorAction SilentlyContinue Remove-Item -Force $lockPath -ErrorAction SilentlyContinue return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "agent99_launcher_missing"; httpStatus = 503 } } $stamp = Get-Date -Format "yyyyMMdd-HHmmss" $stdout = Join-Path $LogDir "agent99-same-run-status-$stamp.out" $stderr = Join-Path $LogDir "agent99-same-run-status-$stamp.err" try { $process = Start-Process -FilePath "powershell.exe" -ArgumentList @( "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $launcher, "-Mode", "ControlTick", "-ReconcileQueueOnly", "-ReconcileQueueId", $queueId, "-SuppressAlerts", "-SuppressReason", "same_run_reconcile_no_telegram" ) -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr -PassThru } catch { Remove-Item -Force $queuePath -ErrorAction SilentlyContinue Remove-Item -Force $lockPath -ErrorAction SilentlyContinue return [pscustomobject]@{ ok = $false; status = "rejected"; reason = "control_tick_start_failed"; httpStatus = 503 } } return [pscustomobject]@{ ok = $true status = "same_run_status_reconcile_queued" httpStatus = 202 automationRunId = $runId reconcileOnly = $true controlledApply = $false evidenceReceiptId = $evidenceReceiptId queued = $true processId = $process.Id } } if (-not $Prefix.EndsWith("/")) { $Prefix = "$Prefix/" } $listener = [System.Net.HttpListener]::new() $listener.Prefixes.Add($Prefix) $startupStamp = Get-Date -Format "yyyyMMdd-HHmmss" $startupEvidence = Join-Path $EvidenceDir "agent99-SreAlertRelay-start-$startupStamp.json" @{ ok = $true prefix = $Prefix tokenEnv = $TokenEnv tokenConfigured = [bool](Get-AgentEnvValue $TokenEnv) allowedRemotePrefixes = $AllowedRemotePrefixes maxBodyBytes = $MaxBodyBytes runOnce = [bool]$RunOnce startedAt = (Get-Date).ToString("o") } | ConvertTo-Json -Depth 6 | Set-Content -Encoding UTF8 $startupEvidence try { $listener.Start() Write-AgentRelayEvent @{ event = "relay_started" ok = $true prefix = $Prefix tokenConfigured = [bool](Get-AgentEnvValue $TokenEnv) evidence = $startupEvidence } do { $context = $listener.GetContext() $remote = [string]$context.Request.RemoteEndPoint.Address try { if (-not (Test-AgentRelayRemoteAllowed $context)) { Send-AgentRelayResponse $context 403 @{ ok = $false; error = "remote_not_allowed" } Write-AgentRelayEvent @{ event = "relay_rejected"; ok = $false; remote = $remote; reason = "remote_not_allowed" } continue } $expectedToken = Get-AgentEnvValue $TokenEnv if (-not $expectedToken) { Send-AgentRelayResponse $context 503 @{ ok = $false; error = "relay_auth_not_configured" } Write-AgentRelayEvent @{ event = "relay_rejected"; ok = $false; remote = $remote; reason = "relay_auth_not_configured" } continue } $actualToken = [string]$context.Request.Headers["X-Agent99-Relay-Token"] if ($actualToken -ne $expectedToken) { Send-AgentRelayResponse $context 401 @{ ok = $false; error = "invalid_relay_token" } Write-AgentRelayEvent @{ event = "relay_rejected"; ok = $false; remote = $remote; reason = "invalid_relay_token" } continue } if ($context.Request.HttpMethod -eq "GET") { $runId = [string]$context.Request.QueryString["run_id"] $readback = Get-AgentOutcomeReadback $runId $statusCode = if ($readback.ok) { 200 } else { 400 } Send-AgentRelayResponse $context $statusCode $readback Write-AgentRelayEvent @{ event = "outcome_readback" ok = [bool]$readback.ok found = [bool]$readback.found remote = $remote runId = if ($readback.ok) { $runId } else { "invalid" } storesRawEvidence = $false } continue } if ($context.Request.HttpMethod -ne "POST") { Send-AgentRelayResponse $context 405 @{ ok = $false; error = "method_not_allowed" } Write-AgentRelayEvent @{ event = "relay_rejected"; ok = $false; remote = $remote; reason = "method_not_allowed" } continue } if ($context.Request.ContentLength64 -gt $MaxBodyBytes) { Send-AgentRelayResponse $context 413 @{ ok = $false; error = "payload_too_large" } Write-AgentRelayEvent @{ event = "relay_rejected"; ok = $false; remote = $remote; reason = "payload_too_large" } continue } $reader = [System.IO.StreamReader]::new($context.Request.InputStream, $context.Request.ContentEncoding) $body = $reader.ReadToEnd() if ($body.Length -gt $MaxBodyBytes) { Send-AgentRelayResponse $context 413 @{ ok = $false; error = "payload_too_large" } Write-AgentRelayEvent @{ event = "relay_rejected"; ok = $false; remote = $remote; reason = "payload_too_large_readback" } continue } $requestPayload = $body | ConvertFrom-Json if ([string](Get-AgentField $requestPayload "schemaVersion" "") -eq "agent99_same_run_status_reconcile_v1") { $reconcile = Start-AgentSameRunStatusReconcile $requestPayload $reconcileBody = @{ ok = [bool]$reconcile.ok status = [string]$reconcile.status reason = [string](Get-AgentField $reconcile "reason" "") automationRunId = [string](Get-AgentField $reconcile "automationRunId" "") reconcileOnly = [bool](Get-AgentField $reconcile "reconcileOnly" $true) controlledApply = $false evidenceReceiptId = [string](Get-AgentField $reconcile "evidenceReceiptId" "") queued = [bool](Get-AgentField $reconcile "queued" $false) } Send-AgentRelayResponse $context ([int]$reconcile.httpStatus) $reconcileBody Write-AgentRelayEvent @{ event = "same_run_status_reconcile" ok = [bool]$reconcile.ok status = [string]$reconcile.status reason = [string](Get-AgentField $reconcile "reason" "") httpStatus = [int]$reconcile.httpStatus remote = $remote runId = if ($reconcile.ok) { [string]$reconcile.automationRunId } else { "rejected" } reconcileOnly = $true controlledApply = $false storesRawEvidence = $false } continue } $alert = $requestPayload $alertId = [string](Get-AgentField $alert "id" ("relay-" + [guid]::NewGuid().ToString("N"))) $safeId = Convert-AgentSafeFileToken $alertId $fileStamp = Get-Date -Format "yyyyMMdd-HHmmss" $tmpPath = Join-Path $IncomingDir ".$safeId-$fileStamp-$([guid]::NewGuid().ToString("N")).tmp" $finalPath = Join-Path $IncomingDir "$safeId-$fileStamp.json" $alert | ConvertTo-Json -Depth 20 | Set-Content -Encoding UTF8 $tmpPath Move-Item -Force $tmpPath $finalPath $trigger = Start-AgentSreAlertInbox Send-AgentRelayResponse $context 202 @{ ok = $true alertId = $alertId incomingFile = $finalPath inboxTriggered = [bool]$trigger.started inboxProcessId = $trigger.processId } Write-AgentRelayEvent @{ event = "relay_accepted" ok = $true remote = $remote alertId = $alertId incomingFile = $finalPath inboxTriggered = [bool]$trigger.started inboxProcessId = $trigger.processId } } catch { try { Send-AgentRelayResponse $context 500 @{ ok = $false; error = "relay_exception"; errorType = $_.Exception.GetType().Name } } catch { } Write-AgentRelayEvent @{ event = "relay_exception" ok = $false remote = $remote errorType = $_.Exception.GetType().Name error = $_.Exception.Message } } } while (-not $RunOnce) } finally { if ($listener.IsListening) { $listener.Stop() } $listener.Close() }