diff --git a/agent99-synthetic-tests.ps1 b/agent99-synthetic-tests.ps1 index 817cc2934..dfb5c691b 100644 --- a/agent99-synthetic-tests.ps1 +++ b/agent99-synthetic-tests.ps1 @@ -363,7 +363,7 @@ Add-SyntheticCheck "recovery:durable_boot_terminal" ($control.Contains("pendingR Add-SyntheticCheck "transport:identity_jump" ($control.Contains("IdentitiesOnly=yes") -and $control.Contains("preferJumpHost") -and $control.Contains("directHosts")) "dedicated identity and bounded routes are present" Add-SyntheticCheck "recovery:host112_apply_receipt_closure" ($control.Contains("managerApplyVerified") -and $control.Contains('durableReceiptTerminal -eq "verified_healthy"') -and $control.Contains('durableReadbackReceiptLinkMatch') -and $control.Contains('durableReadbackTerminalMatch') -and $control.Contains('artifactTransactionStatus -eq "committed_verified_pair"') -and $control.Contains('artifactTransactionPriorPairVerified') -and $control.Contains('managerAttemptCount -eq "1"') -and $control.Contains('managerStartExit -eq "0"') -and $control.Contains("durableReceiptVerified") -and $control.Contains('afterVerifierRole = "independent_second_verifier_only"')) "Host112 apply cannot be closed without its fixed-WAL commit, attributed start and immutable receipt/readback" Add-SyntheticCheck "recovery:host112_candidate_split" ($control.Contains("generalCandidateRequired") -and $control.Contains("managerCandidateRequired") -and $control.Contains("generalApplyEligible") -and $control.Contains("managerApplyEligible") -and $control.Contains("managerNoAttemptPreserved")) "Host112 general guest repair is independent from manager eligibility" -Add-SyntheticCheck "recovery:host112_timeout_contract" ($control.Contains("Get-AgentHost112TimeoutContract") -and $control.Contains("executorReserveSeconds -ge 60") -and $control.Contains("queueReserveSeconds -ge 300") -and $control.Contains("clientReserveSeconds -ge 120") -and $control.Contains('$process.WaitForExit($script:Agent99QueueOuterDeadlineSeconds * 1000)')) "Host112 executor, SSH lock, queue and client deadlines have explicit reserves" +Add-SyntheticCheck "recovery:host112_timeout_contract" ($control.Contains("Get-AgentHost112TimeoutContract") -and $control.Contains("executorReserveSeconds -ge 60") -and $control.Contains("queueReserveSeconds -ge 300") -and $control.Contains("clientReserveSeconds -ge 120") -and $control.Contains('$execution = Invoke-AgentBoundedProcess') -and $control.Contains('-TimeoutSeconds $script:Agent99QueueOuterDeadlineSeconds') -and -not $control.Contains('$process.WaitForExit($script:Agent99QueueOuterDeadlineSeconds * 1000)')) "Host112 executor, SSH lock, queue and client deadlines use the bounded process-tree runner with explicit reserves" $deployer = Get-Content (Join-Path $SourceRoot "agent99-deploy.ps1") -Raw $hostConfig = Get-Content (Join-Path $SourceRoot "agent99.config.99.example.json") -Raw Add-SyntheticCheck "recovery:host112_canonical_vmx" ($deployer.Contains('name = "host112_canonical_vmx_path"') -and $deployer.Contains('Get-AgentHost112CanonicalVm $policyConfigPath') -and $deployer.Contains('Set-AgentProperty $config "vms" @(@($nonHost112Vms) + @($canonicalHost112Vm))') -and $hostConfig.Contains('S:\\VMs\\host112\\kali-linux-2025.4-vmware-amd64.vmx')) "Agent99 normalizes Host112 from one staged VMX identity with a bounded post-verifier" diff --git a/apps/api/tests/test_agent99_transport_recovery_deploy_contract.py b/apps/api/tests/test_agent99_transport_recovery_deploy_contract.py index 714ef754f..dabc9ac10 100644 --- a/apps/api/tests/test_agent99_transport_recovery_deploy_contract.py +++ b/apps/api/tests/test_agent99_transport_recovery_deploy_contract.py @@ -32,6 +32,7 @@ def test_agent99_uses_dedicated_identity_and_preferred_jump_route() -> None: def test_agent99_auto_recovery_is_single_flight_and_slo_measured() -> None: source = CONTROL.read_text(encoding="utf-8") contract = CONTRACT_CHECK.read_text(encoding="utf-8") + synthetic = (ROOT / "agent99-synthetic-tests.ps1").read_text(encoding="utf-8") trigger = source[source.index("function Start-AgentRecoveryFromObservation") :] trigger = trigger[: trigger.index("function Get-AgentRecoverySloConfig")] identity = source[source.index("function New-AgentCanonicalControlledDispatchIdentity") :] @@ -133,6 +134,17 @@ def test_agent99_auto_recovery_is_single_flight_and_slo_measured() -> None: '$control.IndexOf(\'$process = Start-Process -FilePath "powershell.exe" ' "-ArgumentList $args')" ) not in contract + assert 'Add-SyntheticCheck "recovery:host112_timeout_contract"' in synthetic + assert "$control.Contains('$execution = Invoke-AgentBoundedProcess')" in synthetic + assert ( + "$control.Contains('-TimeoutSeconds $script:Agent99QueueOuterDeadlineSeconds')" + in synthetic + ) + assert ( + "-not $control.Contains(" + "'$process.WaitForExit($script:Agent99QueueOuterDeadlineSeconds * 1000)')" + in synthetic + ) assert 'correlationKey = $dispatchIdentity.idempotencyKey' in contract assert 'canonicalDigest = $dispatchIdentity.canonicalDigest' in contract assert 'Record-AgentEvent "recovery_slo_result"' in source