fix(sre): bind backup DR evidence into MCP
This commit is contained in:
@@ -503,6 +503,8 @@ async def _ensure_mcp_evidence_writeback(
|
||||
"rag_writeback_ack_id",
|
||||
"playbook_trust_writeback_ack_id",
|
||||
}
|
||||
if "backup_health" in identity.route_id:
|
||||
required.add("dr_scorecard_writeback_ack_id")
|
||||
safe_refs = sanitize_agent99_public_receipt_refs(
|
||||
receipt_refs,
|
||||
allowed_keys=required,
|
||||
@@ -794,13 +796,6 @@ async def _finalize_learning(
|
||||
"telegram_lifecycle_receipt_id",
|
||||
lambda: _ensure_telegram_receipt(identity, mode=mode),
|
||||
),
|
||||
(
|
||||
"mcp_evidence_writeback_ack_id",
|
||||
lambda: _ensure_mcp_evidence_writeback(
|
||||
identity,
|
||||
receipt_refs=receipt_refs,
|
||||
),
|
||||
),
|
||||
]
|
||||
if "backup_health" in identity.route_id:
|
||||
assets.append((
|
||||
@@ -810,6 +805,18 @@ async def _finalize_learning(
|
||||
evidence_refs=evidence_refs,
|
||||
),
|
||||
))
|
||||
# MCP is the final evidence binding: for backup routes it must include the
|
||||
# already-persisted DR scorecard acknowledgement as well as Telegram,
|
||||
# KM/RAG and PlayBook. Writing MCP first would create a durable but
|
||||
# incomplete evidence graph that could never prove the DR asset belonged
|
||||
# to this same run.
|
||||
assets.append((
|
||||
"mcp_evidence_writeback_ack_id",
|
||||
lambda: _ensure_mcp_evidence_writeback(
|
||||
identity,
|
||||
receipt_refs=receipt_refs,
|
||||
),
|
||||
))
|
||||
for key, writer in assets:
|
||||
if not await ensure_checkpointed(key, writer):
|
||||
return {
|
||||
|
||||
@@ -147,6 +147,28 @@ async def test_agent99_mcp_ack_is_same_run_durable_and_idempotent(
|
||||
assert second == expected
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_backup_mcp_ack_requires_dr_scorecard_binding() -> None:
|
||||
identity = build_agent99_dispatch_identity(
|
||||
project_id="awoooi",
|
||||
incident_id="INC-20260719-BACKUP-MCP",
|
||||
source_fingerprint="backup-mcp-fingerprint",
|
||||
route_id="agent99:backup_health:BackupCheck",
|
||||
)
|
||||
|
||||
receipt = await job._ensure_mcp_evidence_writeback(
|
||||
identity,
|
||||
receipt_refs={
|
||||
"telegram_lifecycle_receipt_id": "telegram:1",
|
||||
"km_writeback_ack_id": "km:1",
|
||||
"rag_writeback_ack_id": "rag:1",
|
||||
"playbook_trust_writeback_ack_id": "playbook:1",
|
||||
},
|
||||
)
|
||||
|
||||
assert receipt is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_backup_telegram_ack_is_no_write_lifecycle_not_apply(
|
||||
monkeypatch,
|
||||
@@ -445,30 +467,40 @@ async def test_learning_checkpoint_resumes_without_replaying_assets(
|
||||
"mcp": 0,
|
||||
"dr": 0,
|
||||
}
|
||||
effect_order: list[str] = []
|
||||
terminal_calls = 0
|
||||
|
||||
async def write_playbook(*_args, **_kwargs): # type: ignore[no-untyped-def]
|
||||
effects["playbook"] += 1
|
||||
effect_order.append("playbook")
|
||||
return "playbooks:PB-A99:version:1"
|
||||
|
||||
async def write_km(*_args, **_kwargs): # type: ignore[no-untyped-def]
|
||||
effects["km"] += 1
|
||||
effect_order.append("km")
|
||||
return "knowledge_entries:km-1:embedding_verified"
|
||||
|
||||
async def write_telegram(*_args, **_kwargs): # type: ignore[no-untyped-def]
|
||||
effects["telegram"] += 1
|
||||
effect_order.append("telegram")
|
||||
return "telegram_outbound:1:durable_ack"
|
||||
|
||||
async def write_rag(*_args, **_kwargs): # type: ignore[no-untyped-def]
|
||||
effects["rag"] += 1
|
||||
effect_order.append("rag")
|
||||
return "knowledge_entries:km-1:rag_embedding_verified"
|
||||
|
||||
async def write_mcp(*_args, **_kwargs): # type: ignore[no-untyped-def]
|
||||
effects["mcp"] += 1
|
||||
effect_order.append("mcp")
|
||||
assert _kwargs["receipt_refs"]["dr_scorecard_writeback_ack_id"] == (
|
||||
"knowledge_entries:dr-1:dr_scorecard"
|
||||
)
|
||||
return "awooop_mcp_gateway_audit:call-1:verified"
|
||||
|
||||
async def write_dr(*_args, **_kwargs): # type: ignore[no-untyped-def]
|
||||
effects["dr"] += 1
|
||||
effect_order.append("dr")
|
||||
return "knowledge_entries:dr-1:dr_scorecard"
|
||||
|
||||
async def terminal(**_kwargs): # type: ignore[no-untyped-def]
|
||||
@@ -514,6 +546,7 @@ async def test_learning_checkpoint_resumes_without_replaying_assets(
|
||||
"mcp": 1,
|
||||
"dr": 1,
|
||||
}
|
||||
assert effect_order == ["playbook", "km", "rag", "telegram", "dr", "mcp"]
|
||||
assert terminal_calls == 2
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user