fix(agent99): validate v5 incident formatter

This commit is contained in:
ogt
2026-07-11 20:42:21 +08:00
parent 83f7838131
commit df26f43b77
2 changed files with 60 additions and 4 deletions

View File

@@ -32,7 +32,18 @@ $controlPath = Join-Path $SourceRoot "agent99-control-plane.ps1"
$controlSource = [IO.File]::ReadAllText($controlPath, [Text.Encoding]::UTF8)
$ast = [System.Management.Automation.Language.Parser]::ParseInput($controlSource, [ref]$tokens, [ref]$errors)
$formatFunctions = @{}
foreach ($functionName in @("Get-AgentObjectValue", "Limit-AgentTextLine", "Format-AgentMetricForCard", "Format-AgentTelegramText", "Convert-AgentRecoveryReadback")) {
foreach ($functionName in @(
"Convert-AgentBool",
"Get-AgentObjectValue",
"Limit-AgentTextLine",
"Format-AgentMetricForCard",
"Format-AgentTelegramLegacyText",
"Get-AgentSha256Hex",
"Get-AgentIncidentCardModel",
"Format-AgentTelegramText",
"Format-AgentTelegramCaption",
"Convert-AgentRecoveryReadback"
)) {
$definition = $ast.Find({
param($node)
$node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $node.Name -eq $functionName
@@ -58,10 +69,18 @@ if ($formatFunctions.ContainsKey("Format-AgentTelegramText")) {
status = "handled_blocked_by_trust_gate"
candidatePath = "C:\Wooo\Agent99\state\pf-test.json"
})
$providerCaption = Format-AgentTelegramCaption "warning" "provider_freshness_triage" "test" ([pscustomobject]@{
target = "provider_freshness_signal"
missingFields = @("lastSeen")
status = "handled_blocked_by_trust_gate"
candidatePath = "C:\Wooo\Agent99\state\pf-test.json"
})
$cards = "$perfCard`n$providerCard"
Add-SyntheticCheck "telegram:localized" ([regex]::IsMatch($cards, "[^\x00-\x7F]")) "localized card is present"
Add-SyntheticCheck "telegram:no_blank_metrics" (-not $perfCard.Contains("load/core=, ")) "failed readback renders unavailable values"
Add-SyntheticCheck "telegram:provider_handled" ($providerCard.Contains("handled_blocked_by_trust_gate") -and $providerCard.Contains("Agent99")) "handled state and agent are visible"
Add-SyntheticCheck "telegram:no_blank_metrics" ($perfCard.Contains("數值目前不可信") -and -not $perfCard.Contains("load/core=, ")) "failed readback is explained without blank metrics"
Add-SyntheticCheck "telegram:provider_handled" ($providerCard.Contains("Provider freshness") -and $providerCard.Contains("事件INC-") -and $providerCard.Contains("Agent99")) "provider incident has human lifecycle fields"
Add-SyntheticCheck "telegram:no_internal_paths" (-not $cards.Contains("C:\Wooo") -and -not $cards.Contains("KM:") -and -not $cards.Contains("verifierName=")) "raw evidence and verifier fields are absent"
Add-SyntheticCheck "telegram:caption_bounded" ($providerCaption.Length -lt 900 -and $providerCaption.Contains("下一次更新:")) "visual caption is concise and actionable"
Add-SyntheticCheck "telegram:no_raw_python" (-not $cards.Contains("urllib.request")) "relay source is absent from user-facing card"
} else {
Add-SyntheticCheck "telegram:formatter" $false "Format-AgentTelegramText not found"

View File

@@ -3,7 +3,6 @@ from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
CONTROL = ROOT / "agent99-control-plane.ps1"
DEPLOY = ROOT / "agent99-deploy.ps1"
@@ -76,6 +75,22 @@ def test_agent99_telegram_v5_hides_raw_evidence_and_has_operator_fields() -> Non
assert 'messageFormat = "incident_card_zh_tw_v5"' in source
def test_agent99_v5_formatter_synthetic_gate_loads_model_dependencies() -> None:
synthetic = (ROOT / "agent99-synthetic-tests.ps1").read_text(encoding="utf-8")
for function_name in (
"Convert-AgentBool",
"Get-AgentSha256Hex",
"Get-AgentIncidentCardModel",
"Format-AgentTelegramText",
"Format-AgentTelegramCaption",
):
assert f'"{function_name}"' in synthetic
assert 'telegram:no_internal_paths' in synthetic
assert 'telegram:caption_bounded' in synthetic
assert 'C:\\Wooo' in synthetic
def test_agent99_telegram_threads_source_alert_and_persists_lifecycle() -> None:
source = CONTROL.read_text(encoding="utf-8")
inbox = SRE_INBOX.read_text(encoding="utf-8")
@@ -149,6 +164,28 @@ def test_agent99_deployer_verifies_promoted_runtime_and_writes_revision() -> Non
assert f'"{name}"' in bootstrap
def test_agent99_completion_callback_waits_for_durable_same_trace_readback() -> None:
source = CONTROL.read_text(encoding="utf-8")
deploy = DEPLOY.read_text(encoding="utf-8")
config = json.loads((ROOT / "agent99.config.99.example.json").read_text())
callback = config["completionCallback"]
assert callback["enabled"] is True
assert callback["url"].startswith("https://awoooi.wooo.work/")
assert callback["tokenEnv"] == "AGENT99_SRE_RELAY_TOKEN"
assert callback["retryAfterMinutes"] == 5
assert 'schema_version = "agent99_completion_callback_v1"' in source
assert '"X-Agent99-Completion-Token" = $token' in source
assert '$receipt.durableReadback' in source
assert '$sameIdentity' in source
assert '$receipt.operationReceiptCount -gt 0' in source
assert 'state\\completion-callbacks\\pending' in source
assert 'Invoke-AgentPendingCompletionCallbacks' in source
assert 'Add-DefaultProperty $config "completionCallback"' in deploy
assert 'rawResponseStored = $false' in source
assert 'secretValueLogged = $false' in source
def test_load_shedding_requires_configured_post_verifier() -> None:
source = CONTROL.read_text(encoding="utf-8")
function = source[source.index("function Invoke-LoadShedding") :]