fix(agent99): skip deferred preflight evidence
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m14s
CD Pipeline / build-and-deploy (push) Successful in 15m22s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 0s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 22s
CD Pipeline / post-deploy-checks (push) Successful in 2m6s

This commit is contained in:
ogt
2026-07-15 21:03:45 +08:00
parent cc5683c99b
commit 76caef1270
2 changed files with 128 additions and 3 deletions

View File

@@ -169,9 +169,38 @@ function Get-EvidenceReadback {
)
$evidenceDir = Join-Path $AgentRoot "evidence"
$file = Get-ChildItem -Path $evidenceDir -Filter $Pattern -File -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
$candidates = @(Get-ChildItem -Path $evidenceDir -Filter $Pattern -File -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending)
$deferredCandidates = @()
$file = $null
foreach ($candidate in $candidates) {
$candidateDeferred = $false
try {
$candidateEvidence = Get-Content -LiteralPath $candidate.FullName -Raw | ConvertFrom-Json
$candidateSchemaVersion = if ($candidateEvidence.PSObject.Properties["schemaVersion"]) {
[string]$candidateEvidence.schemaVersion
} else {
""
}
$candidateDeferred = [bool](
($candidateEvidence.PSObject.Properties["deferred"] -and [bool]$candidateEvidence.deferred) -or
$candidateSchemaVersion -in @(
"agent99_background_mode_deferred_v1",
"agent99_recovery_transport_deferred_v1"
)
)
} catch {
# A malformed newest non-deferred candidate must remain visible and fail closed.
$file = $candidate
break
}
if ($candidateDeferred) {
$deferredCandidates += $candidate
continue
}
$file = $candidate
break
}
$ageMinutes = if ($file) { [math]::Round(((Get-Date) - $file.LastWriteTime).TotalMinutes, 1) } else { $null }
$fresh = [bool]($file -and $ageMinutes -le $MaxAgeMinutes)
$safeSummary = $null
@@ -331,6 +360,8 @@ function Get-EvidenceReadback {
usable = $usable
healthy = [bool](-not $Required -or $usable)
parseError = $parseError
deferredCandidateCount = [int]$deferredCandidates.Count
latestDeferredTime = if ($deferredCandidates.Count -gt 0) { $deferredCandidates[0].LastWriteTime.ToString("o") } else { "" }
safeSummary = $safeSummary
}
}

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import json
import os
import shutil
import subprocess
from copy import deepcopy
@@ -21,6 +22,13 @@ def _function_source() -> str:
return source[start:end]
def _evidence_function_source() -> str:
source = PREFLIGHT.read_text(encoding="utf-8")
start = source.index("function Get-EvidenceReadback")
end = source.index("$requiredTasks = @(", start)
return source[start:end]
def _base_case() -> dict[str, Any]:
return {
"agentRootPresent": True,
@@ -127,6 +135,92 @@ def test_warning_receipt_is_visible_without_weakening_integrity_blockers() -> No
)
assert 'if ($result.summary.deploymentEligible)' in source
assert 'if ($selfHealthSeverity -ne "ok")' not in source
assert '"agent99_background_mode_deferred_v1"' in source
assert '"agent99_recovery_transport_deferred_v1"' in source
assert "deferredCandidateCount = [int]$deferredCandidates.Count" in source
def test_evidence_selection_skips_deferred_but_not_malformed_candidates(
tmp_path: Path,
) -> None:
powershell = shutil.which("pwsh") or shutil.which("powershell")
if powershell is None:
pytest.skip("PowerShell runtime is not installed on this macOS verifier")
evidence = tmp_path / "evidence"
evidence.mkdir()
canonical = evidence / "agent99-SelfCheck-20260715-200000.json"
deferred = evidence / "agent99-SelfCheck-20260715-200500.json"
canonical.write_text(
json.dumps(
{
"mode": "SelfCheck",
"selfHealth": {
"severity": "warning",
"latestPerformance": {"severity": "ok", "hosts": []},
},
}
),
encoding="utf-8",
)
deferred.write_text(
json.dumps(
{
"schemaVersion": "agent99_background_mode_deferred_v1",
"mode": "SelfCheck",
"deferred": True,
}
),
encoding="utf-8",
)
now = canonical.stat().st_mtime
os.utime(canonical, (now - 10, now - 10))
os.utime(deferred, (now, now))
agent_root = str(tmp_path).replace("'", "''")
command = f"""
{_evidence_function_source()}
$AgentRoot = '{agent_root}'
Get-EvidenceReadback 'self_check' 'agent99-SelfCheck-*.json' 20 $true |
ConvertTo-Json -Depth 8 -Compress
"""
result = subprocess.run(
[powershell, "-NoProfile", "-NonInteractive", "-Command", command],
check=False,
capture_output=True,
text=True,
)
assert result.returncode == 0, result.stdout + result.stderr
payload = json.loads(
next(line for line in reversed(result.stdout.splitlines()) if line.startswith("{"))
)
assert payload["file"] == canonical.name
assert payload["deferredCandidateCount"] == 1
assert payload["parsed"] is True
assert payload["safeSummary"]["selfHealthSeverity"] == "warning"
malformed = evidence / "agent99-SelfCheck-20260715-201000.json"
malformed.write_text("{not-json", encoding="utf-8")
os.utime(malformed, (now + 10, now + 10))
malformed_result = subprocess.run(
[powershell, "-NoProfile", "-NonInteractive", "-Command", command],
check=False,
capture_output=True,
text=True,
)
assert malformed_result.returncode == 0, (
malformed_result.stdout + malformed_result.stderr
)
malformed_payload = json.loads(
next(
line
for line in reversed(malformed_result.stdout.splitlines())
if line.startswith("{")
)
)
assert malformed_payload["file"] == malformed.name
assert malformed_payload["parsed"] is False
assert malformed_payload["healthy"] is False
def test_decision_behavior_when_powershell_is_available() -> None: