M3 implementada e backlog atualizado

This commit is contained in:
Marcos Lohmann
2026-09-14 10:11:29 -03:00
parent f3efcc3414
commit c894c1604b
65 changed files with 4261 additions and 74 deletions

View File

@@ -0,0 +1,70 @@
"""Human-in-the-loop gate (EP-11-T05). The actual pause/resume behavior is
covered end to end through the real graph in test_orchestrator_graph.py;
this file covers `approval_gate_node`'s two branches that never interrupt.
"""
from __future__ import annotations
from datetime import datetime
from emcp_bus.common.models import RiskTier
from emcp_bus.orchestrator.hitl_node import approval_gate_node, requires_approval
from emcp_bus.orchestrator.nba_model import NBADecision
from emcp_bus.registry.models import (
ApprovalPolicy,
BackendRef,
CapabilityManifest,
LifecycleInfo,
LifecycleStatus,
)
def _manifest(name: str, *, approval_required: bool) -> CapabilityManifest:
return CapabilityManifest(
name=name,
version="1.0.0",
domain=name.split(".", 1)[0],
owner="finance-team",
risk_tier=RiskTier.R3 if approval_required else RiskTier.R1,
side_effects=True,
idempotent=False,
entitlements=["Finance.Payments"],
backend=BackendRef(type="mcp", service="finance-domain"),
approval=ApprovalPolicy(required=approval_required),
lifecycle=LifecycleInfo(status=LifecycleStatus.ACTIVE),
)
def test_requires_approval_true_for_a_flagged_capability() -> None:
offerings = [_manifest("finance.payment.execute", approval_required=True)]
assert requires_approval(offerings, "finance.payment.execute") is True
def test_requires_approval_false_for_an_unflagged_capability() -> None:
offerings = [_manifest("sales.customer.get", approval_required=False)]
assert requires_approval(offerings, "sales.customer.get") is False
def test_approval_gate_node_skips_when_there_is_no_nba() -> None:
result = approval_gate_node({"nba": None})
assert result == {"approval_status": "not_applicable"}
def test_approval_gate_node_skips_when_approval_is_not_required() -> None:
nba = NBADecision(
decision_id="dec-1",
action="sales.customer.get",
capability_version="1.0.0",
subject_ref="subject:abc123",
channel="app",
agent="engagement-assistant",
reason_codes=["ELIGIBLE"],
policy_context={},
expires_at=datetime(2026, 1, 1),
)
result = approval_gate_node({"nba": nba, "nba_requires_approval": False})
assert result == {"approval_status": "not_required"}