fix(agent99): complete same-run status reconcile
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m46s
CD Pipeline / build-and-deploy (push) Successful in 19m6s
CD Pipeline / post-deploy-checks (push) Successful in 2m4s

This commit is contained in:
ogt
2026-07-14 23:28:19 +08:00
parent 17bdcb194e
commit b233ac5c74
6 changed files with 617 additions and 32 deletions

View File

@@ -13,6 +13,7 @@ $StateDir = Join-Path $AgentRoot "state"
$EvidenceDir = Join-Path $AgentRoot "evidence"
$DeployRoot = Join-Path $AgentRoot "deploy"
$ManifestPath = Join-Path $StateDir "runtime-manifest.json"
$LauncherPath = Join-Path $AgentRoot "agent99-run.ps1"
$WindowsPowerShell = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$RelayTaskName = "Wooo-Agent99-SRE-Alert-Relay"
$RelayTaskPath = "\"
@@ -71,6 +72,48 @@ function Get-AgentSha256File {
return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
function Get-AgentLauncherContract {
$requiredMarkers = @(
'[switch]$ReconcileOnly',
'[string]$ReconcileEvidenceId = ""',
'[switch]$ReconcileQueueOnly',
'[string]$ReconcileQueueId = ""',
'-ReconcileOnly:$ReconcileOnly',
'-ReconcileEvidenceId $ReconcileEvidenceId',
'-ReconcileQueueOnly:$ReconcileQueueOnly',
'-ReconcileQueueId $ReconcileQueueId'
)
if (-not (Test-Path -LiteralPath $LauncherPath -PathType Leaf)) {
return [pscustomobject]@{
schemaVersion = "agent99_launcher_contract_v1"
ok = $false
exists = $false
sha256 = "missing"
parseErrorCount = -1
requiredMarkerCount = $requiredMarkers.Count
missingMarkerCount = $requiredMarkers.Count
reconcileOnlyForwarded = $false
reconcileQueueOnlyForwarded = $false
}
}
$tokens = $null
$parseErrors = $null
[Management.Automation.Language.Parser]::ParseFile($LauncherPath, [ref]$tokens, [ref]$parseErrors) | Out-Null
$content = [IO.File]::ReadAllText($LauncherPath)
$missingMarkers = @($requiredMarkers | Where-Object { -not $content.Contains($_) })
return [pscustomobject]@{
schemaVersion = "agent99_launcher_contract_v1"
ok = [bool](@($parseErrors).Count -eq 0 -and $missingMarkers.Count -eq 0)
exists = $true
sha256 = (Get-AgentSha256File $LauncherPath)
parseErrorCount = @($parseErrors).Count
requiredMarkerCount = $requiredMarkers.Count
missingMarkerCount = $missingMarkers.Count
reconcileOnlyForwarded = [bool]($missingMarkers -notcontains '-ReconcileOnly:$ReconcileOnly' -and $missingMarkers -notcontains '-ReconcileEvidenceId $ReconcileEvidenceId')
reconcileQueueOnlyForwarded = [bool]($missingMarkers -notcontains '-ReconcileQueueOnly:$ReconcileQueueOnly' -and $missingMarkers -notcontains '-ReconcileQueueId $ReconcileQueueId')
}
}
function Get-AgentSafeRuntimeManifest {
if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf)) {
return [pscustomobject]@{
@@ -146,6 +189,7 @@ function Get-AgentLiveBundleDigest {
foreach ($name in $FixedRuntimeFiles) {
$rows += "$name`t$(Get-AgentSha256File (Join-Path $BinDir $name))`n"
}
$rows += "agent99-run.ps1`t$(Get-AgentSha256File $LauncherPath)`n"
return Get-AgentSha256Bytes ([Text.Encoding]::UTF8.GetBytes(($rows -join "")))
}
@@ -555,6 +599,7 @@ function Restore-AgentBundle {
param(
[string]$BackupPath,
[hashtable]$BeforeFilePresence,
[bool]$BeforeLauncherPresent,
[bool]$BeforeConfigPresent,
[bool]$BeforeManifestPresent
)
@@ -573,6 +618,13 @@ function Restore-AgentBundle {
Remove-Item -LiteralPath $livePath -Force
}
}
$backupLauncher = Join-Path $BackupPath "agent99-run.ps1"
if ($BeforeLauncherPresent) {
if (-not (Test-Path -LiteralPath $backupLauncher -PathType Leaf)) { throw "required_launcher_backup_missing" }
Copy-AgentFileWithRetry $backupLauncher $LauncherPath
} elseif (Test-Path -LiteralPath $LauncherPath -PathType Leaf) {
Remove-Item -LiteralPath $LauncherPath -Force
}
$backupConfig = Join-Path $BackupPath "agent99.config.json"
if ($BeforeConfigPresent) {
if (-not (Test-Path -LiteralPath $backupConfig -PathType Leaf)) { throw "required_config_backup_missing" }
@@ -832,6 +884,7 @@ try {
}
$live = Get-AgentSafeRuntimeManifest
$liveLauncherContract = Get-AgentLauncherContract
if (
$prior -and
[string]$prior.status -eq "deployed_verified" -and
@@ -841,10 +894,15 @@ try {
[string]$prior.sourceRevision -eq $sourceRevision -and
$prior.PSObject.Properties["relayReload"] -and
[bool]$prior.relayReload.newGenerationVerified -and
$prior.PSObject.Properties["launcherContract"] -and
[bool]$prior.launcherContract.ok -and
[string]$prior.launcherContract.sha256 -match "^[0-9a-f]{64}$" -and
$live.runtimeMatched -and
$live.sourceRevision -eq $sourceRevision -and
$live.fileCount -eq 14 -and
$live.mismatchCount -eq 0
$live.mismatchCount -eq 0 -and
$liveLauncherContract.ok -and
[string]$liveLauncherContract.sha256 -eq [string]$prior.launcherContract.sha256
) {
$script:ReceiverOperationPhase = "idempotent_replay_post_verifier"
$replayPreflight = Invoke-AgentLivePreflight (Join-Path $stagePath "agent99-live-preflight.ps1")
@@ -852,6 +910,7 @@ try {
$originalOperationBoundaries = $prior.operationBoundaries
$prior | Add-Member -NotePropertyName idempotentReplay -NotePropertyValue $true -Force
$prior | Add-Member -NotePropertyName runtimeManifest -NotePropertyValue $live -Force
$prior | Add-Member -NotePropertyName launcherContract -NotePropertyValue $liveLauncherContract -Force
$prior | Add-Member -NotePropertyName livePreflight -NotePropertyValue $replayPreflight -Force
$prior | Add-Member -NotePropertyName originalOperationBoundaries -NotePropertyValue $originalOperationBoundaries -Force
$prior | Add-Member -NotePropertyName operationBoundaries -NotePropertyValue ([pscustomobject]@{
@@ -979,6 +1038,7 @@ try {
$beforeManifestDigest = Get-AgentSha256File $ManifestPath
$beforeFilePresence = @{}
foreach ($name in $FixedRuntimeFiles) { $beforeFilePresence[$name] = Test-Path -LiteralPath (Join-Path $BinDir $name) -PathType Leaf }
$beforeLauncherPresent = Test-Path -LiteralPath $LauncherPath -PathType Leaf
$beforeConfigPresent = Test-Path -LiteralPath $ConfigPath -PathType Leaf
$beforeManifestPresent = Test-Path -LiteralPath $ManifestPath -PathType Leaf
$beforeRelayRuntime = Get-AgentRelayRuntime
@@ -1034,6 +1094,7 @@ try {
$relayReload = $null
$runtimeManifest = $null
$livePreflight = $null
$launcherContract = $null
$postVerified = $false
$failurePhase = ""
$failureType = ""
@@ -1046,7 +1107,15 @@ try {
if ($deploy.payload -and $deploy.payload.PSObject.Properties["backupDir"]) {
$backupPath = [string]$deploy.payload.backupDir
}
if (-not $deploy.ok -or -not $deploy.payload -or [string]$deploy.payload.status -ne "deployed" -or $deploy.payload.taskRegistration) {
if (
-not $deploy.ok -or
-not $deploy.payload -or
[string]$deploy.payload.status -ne "deployed" -or
$deploy.payload.taskRegistration -or
-not $deploy.payload.PSObject.Properties["launcherContract"] -or
-not [bool]$deploy.payload.launcherContract.ok -or
[string]$deploy.payload.launcherContract.sha256 -notmatch "^[0-9a-f]{64}$"
) {
$failurePhase = "deploy"
$failureType = "deploy_child_failed_or_invalid"
} else {
@@ -1060,6 +1129,7 @@ try {
} else {
$script:ReceiverOperationPhase = "independent_post_verifier"
$runtimeManifest = Get-AgentSafeRuntimeManifest
$launcherContract = Get-AgentLauncherContract
$livePreflight = Invoke-AgentLivePreflight (Join-Path $stagePath "agent99-live-preflight.ps1")
$postVerified = [bool](
$runtimeManifest.exists -and
@@ -1067,6 +1137,8 @@ try {
$runtimeManifest.sourceRevision -eq $sourceRevision -and
$runtimeManifest.fileCount -eq 14 -and
$runtimeManifest.mismatchCount -eq 0 -and
$launcherContract.ok -and
[string]$launcherContract.sha256 -eq [string]$deploy.payload.launcherContract.sha256 -and
$relayReload.oldGenerationsGone -and
$relayReload.newGenerationVerified -and
$relayReload.after.taskEnabled -and
@@ -1108,6 +1180,7 @@ try {
deploy = [pscustomobject]@{ ok = $deploy.ok; exitCode = $deploy.exitCode; timedOut = $deploy.timedOut; status = [string]$deploy.payload.status }
relayReload = $relayReload
runtimeManifest = $runtimeManifest
launcherContract = $launcherContract
livePreflight = $livePreflight
durableReceiptWritten = $true
idempotentReplay = $false
@@ -1147,7 +1220,7 @@ try {
}
$script:ReceiverOperationPhase = "runtime_rollback"
$script:ReceiverRollbackAttempted = $true
$rollback = Restore-AgentBundle $backupPath $beforeFilePresence $beforeConfigPresent $beforeManifestPresent
$rollback = Restore-AgentBundle $backupPath $beforeFilePresence $beforeLauncherPresent $beforeConfigPresent $beforeManifestPresent
$rollbackForbiddenGenerations = @($beforeRelayRuntime.taskGeneration)
if ($relayReload) {
$rollbackForbiddenGenerations += @($relayReload.before.taskGeneration)
@@ -1227,6 +1300,7 @@ try {
attemptReceiptPath = $attemptReceiptPath
relayReload = $relayReload
failedRuntimeManifest = $runtimeManifest
failedLauncherContract = $launcherContract
failedLivePreflight = $livePreflight
rollback = $rollback
rollbackRelayRestart = $rollbackRelayRestart