Files
awoooi/agent99-sre-alert-relay.ps1
ogt 29072e4004
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m8s
CD Pipeline / build-and-deploy (push) Successful in 13m33s
CD Pipeline / post-deploy-checks (push) Has been cancelled
fix(agent99): reconcile live cold-start dispatches
2026-07-15 03:18:33 +08:00

1081 lines
49 KiB
PowerShell

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 ([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 "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 "lock_owner" "") -ne $runId) {
return [pscustomobject]@{ ok = $false; reason = "identity_lock_owner_mismatch" }
}
$incidentId = [string](Get-AgentField $Identity "incident_id" "")
$workItemId = [string](Get-AgentField $Identity "work_item_id" "")
$sourceFingerprint = [string](Get-AgentField $Identity "source_fingerprint" "")
$executionGeneration = [string](Get-AgentField $Identity "execution_generation" "")
$legacyIdentity = [bool](
$incidentId -eq "INC-20260711-11C751" -and
$workItemId -eq "agent99-dispatch:awoooi:INC-20260711-11C751:legacy-cold-start" -and
$sourceFingerprint -match "^legacy-cold-start:[0-9a-f]{64}$" -and
$executionGeneration -eq "1"
)
$liveIdentity = [bool](
$incidentId -match "^INC-[0-9]{8}-[0-9A-F]{6}$" -and
$workItemId -eq "agent99-dispatch:awoooi:$incidentId`:agent99:host_recovery:Recover" -and
$sourceFingerprint -match "^[0-9a-f]{32,64}$" -and
$executionGeneration -match "^[1-3]$"
)
if (-not ($legacyIdentity -or $liveIdentity)) {
return [pscustomobject]@{ ok = $false; reason = "identity_cold_start_scope_not_eligible" }
}
$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 Test-AgentStoredColdStartRecoverEnvelope {
param([object]$Stored)
if (-not $Stored -or [bool](Get-AgentField $Stored "reconcileOnly" $false)) {
return $false
}
$mode = [string](Get-AgentField $Stored "mode" (Get-AgentField $Stored "suggestedMode" ""))
$source = [string](Get-AgentField $Stored "alertSource" (Get-AgentField $Stored "source" ""))
$kind = [string](Get-AgentField $Stored "alertKind" (Get-AgentField $Stored "kind" ""))
$service = [string](Get-AgentField $Stored "alertService" (Get-AgentField $Stored "service" ""))
$controlled = Get-AgentField $Stored "controlledApply" $null
return [bool](
$mode -eq "Recover" -and
$source -eq "awoooi-api-alertmanager" -and
$kind -eq "host_recovery" -and
$service -eq "cold-start-gate" -and
$controlled -is [bool] -and
$controlled
)
}
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)-" })
# One legacy envelope was moved to ignored by an older inbox build. Current
# runs are admitted only from an immutable cold-start Recover envelope; a
# generic ignored, queue, or reconcile payload can never authorize Status.
$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 (-not (Test-AgentStoredColdStartRecoverEnvelope $stored)) { 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 }
$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()
}