fix(agent99): validate v5 incident formatter
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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") :]
|
||||
|
||||
Reference in New Issue
Block a user