Files
awoooi/apps/api/src/services/agent99_outcome_ingestion.py
ogt 6cf8429d17
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 2m32s
CD Pipeline / build-and-deploy (push) Successful in 8m2s
CD Pipeline / post-deploy-checks (push) Successful in 2m22s
fix(automation): enforce durable alert closure
Restore D037 durable incident readback without weakening database failure semantics.

Fence Agent99 dispatch and terminal learning to canonical identities, durable leases, verifier receipts, and reconciler-owned checkpoints.

Drain backup and restore legacy receipts in bounded cohorts with strict transport, claim, projection, and no-false-green controls.

Keep SSH service refusal visible while separating it from broker network-policy reachability.
2026-07-14 09:40:53 +08:00

120 lines
4.1 KiB
Python

"""Production ingestion for Agent99 outcome, verifier, and learning receipts."""
from __future__ import annotations
from typing import Any
from src.services.agent99_controlled_dispatch_ledger import (
parse_agent99_dispatch_identity,
record_agent99_verifier_receipt,
validate_agent99_outcome_identity,
)
from src.services.agent99_public_receipts import (
extract_agent99_outcome_evidence_refs,
)
def _public_evidence_refs(
payload_refs: dict[str, Any],
outcome_receipt: dict[str, Any],
) -> dict[str, str]:
"""Merge only bounded, public-safe identifiers from authenticated input."""
return extract_agent99_outcome_evidence_refs(
outcome_receipt,
payload_refs,
)
async def ingest_agent99_outcome_receipt(
payload: dict[str, Any],
) -> dict[str, Any]:
"""Write the Agent99 outcome and optional learning acks to one run.
The caller must carry the complete deterministic identity both in the
request identity and in the Agent99 outcome receipt. This prevents a valid
outcome from being rebound to another incident or execution generation.
"""
identity_payload = (
payload.get("identity")
if isinstance(payload.get("identity"), dict)
else {}
)
identity = parse_agent99_dispatch_identity(identity_payload)
outcome_receipt = (
payload.get("outcome_receipt")
if isinstance(payload.get("outcome_receipt"), dict)
else {}
)
if not outcome_receipt:
raise ValueError("agent99_outcome_receipt_required")
if not validate_agent99_outcome_identity(identity, outcome_receipt):
raise ValueError("agent99_outcome_identity_mismatch")
payload_evidence_refs = (
payload.get("evidence_refs")
if isinstance(payload.get("evidence_refs"), dict)
else {}
)
evidence_refs = _public_evidence_refs(
payload_evidence_refs,
outcome_receipt,
)
verifier = await record_agent99_verifier_receipt(
identity=identity,
outcome_receipt=outcome_receipt,
evidence_refs=evidence_refs,
)
if verifier.get("receipt_persisted") is not True:
return {
"schema_version": "agent99_outcome_ingestion_receipt_v1",
"status": str(verifier.get("status") or "verifier_rejected"),
"accepted": False,
"identity": identity.public_dict(),
"verifier": verifier,
"learning_writeback": {
"status": "blocked_verifier_not_persisted",
"receipt_persisted": False,
},
"runtime_closure_verified": False,
}
# The relay is authoritative for the Agent99 outcome, but it is not the
# authority for Telegram/KM/PlayBook/DR delivery acknowledgements. Those
# side effects are created and checkpointed by the server-side reconciler.
# Keep the compatibility field in the webhook schema, but never let its
# caller-provided values enter the terminal transaction.
untrusted_learning_refs = (
payload.get("learning_receipt_refs")
if isinstance(payload.get("learning_receipt_refs"), dict)
else {}
)
learning = {
"status": (
"untrusted_external_receipts_ignored_reconciler_pending"
if verifier.get("post_verifier_passed") is True
and untrusted_learning_refs
else "pending_reconciler_durable_receipts"
if verifier.get("post_verifier_passed") is True
else "blocked_verifier_failed"
),
"receipt_persisted": False,
"runtime_closure_verified": False,
}
return {
"schema_version": "agent99_outcome_ingestion_receipt_v1",
"status": (
"verifier_recorded_learning_pending"
if verifier.get("post_verifier_passed") is True
else "verifier_failed_no_runtime_closure"
),
"accepted": True,
"identity": identity.public_dict(),
"verifier": verifier,
"learning_writeback": learning,
"untrusted_learning_receipt_refs_ignored": bool(
untrusted_learning_refs
),
"runtime_closure_verified": False,
}