148 lines
4.9 KiB
Python
148 lines
4.9 KiB
Python
from types import SimpleNamespace
|
|
|
|
from app.services.ai_pmo.ai_pmo_intent import (
|
|
INTENT_QUERY,
|
|
INTENT_SIGNAL_CREATE,
|
|
CanonicalIntent,
|
|
)
|
|
from app.services.ai_pmo.ai_pmo_kernel.mixins.ingress.ai_pmo_kernel_mixins_ingress_storage import (
|
|
KernelIngressStorageMixin,
|
|
)
|
|
|
|
|
|
class _FakeStorage(KernelIngressStorageMixin):
|
|
def __init__(self) -> None:
|
|
self.tenant_id = 9
|
|
|
|
@staticmethod
|
|
def _primary_operation_code(intent_name: str) -> str | None:
|
|
normalized = str(intent_name or "").strip().lower()
|
|
if normalized == "project_signal.discover":
|
|
return "project_signal.discover"
|
|
if normalized == INTENT_QUERY:
|
|
return "query.answer"
|
|
return None
|
|
|
|
|
|
def _build_intent(name: str, *, project_id: int = 11) -> CanonicalIntent:
|
|
return CanonicalIntent(
|
|
name=name,
|
|
confidence=0.9,
|
|
project_id=project_id,
|
|
signal_title="",
|
|
signal_summary="",
|
|
metadata={},
|
|
)
|
|
|
|
|
|
def test_build_execution_action_contract_uses_plan_route_and_result() -> None:
|
|
storage = _FakeStorage()
|
|
contract = storage._build_execution_action_contract(
|
|
intent=_build_intent(INTENT_SIGNAL_CREATE),
|
|
workflow_route=SimpleNamespace(
|
|
key="project_signal.discover",
|
|
action="discover",
|
|
project_id=22,
|
|
requested_count=3,
|
|
),
|
|
decision_payload={
|
|
"execution_plan": {
|
|
"project_id": 33,
|
|
"actions": [
|
|
{"operation_code": "project_signal.discover", "mode": "write"},
|
|
{"operation_code": "signal.enter", "mode": "write"},
|
|
],
|
|
}
|
|
},
|
|
execution_result={"signal_id": 88, "requested_count": 5},
|
|
source_system="feishu",
|
|
source_message_id="msg-1",
|
|
channel_ref="oc_xxx",
|
|
)
|
|
|
|
assert contract["operation_code"] == "project_signal.discover"
|
|
assert contract["mode"] == "write"
|
|
assert contract["workflow_route"] == "project_signal.discover"
|
|
assert contract["workflow_action"] == "discover"
|
|
assert contract["params"]["project_id"] == 22
|
|
assert contract["params"]["requested_count"] == 5
|
|
assert contract["params"]["signal_id"] == 88
|
|
assert contract["params"]["source_system"] == "feishu"
|
|
assert contract["params"]["source_message_id"] == "msg-1"
|
|
assert contract["params"]["channel_ref"] == "oc_xxx"
|
|
assert contract["param_source"] == "decision.execution_plan.actions+workflow_route+execution_result"
|
|
|
|
|
|
def test_apply_execution_action_contract_sets_uniform_fields() -> None:
|
|
storage = _FakeStorage()
|
|
applied = storage._apply_execution_action_contract(
|
|
intent=_build_intent(INTENT_QUERY, project_id=77),
|
|
workflow_route=SimpleNamespace(
|
|
key=INTENT_QUERY,
|
|
action="answer",
|
|
project_id=77,
|
|
requested_count=None,
|
|
),
|
|
decision_payload={"execution_plan": {"actions": []}},
|
|
execution_result={"status": "succeeded"},
|
|
source_system="pmflow_manual",
|
|
source_message_id="manual-1",
|
|
channel_ref=None,
|
|
)
|
|
|
|
assert applied["action_param_source"] == "decision.execution_plan.actions+workflow_route+execution_result"
|
|
assert applied["operation_code"] == "query.answer"
|
|
action_contract = applied["action_contract"]
|
|
assert action_contract["operation_code"] == "query.answer"
|
|
assert action_contract["mode"] == "read_only"
|
|
assert action_contract["params"]["project_id"] == 77
|
|
|
|
|
|
def test_execution_ledger_idempotency_key_is_stable() -> None:
|
|
key_a = KernelIngressStorageMixin._build_execution_ledger_idempotency_key(
|
|
tenant_id=9,
|
|
work_item_id=101,
|
|
operation_code="task.create",
|
|
source_message_id="feishu-msg-abc",
|
|
)
|
|
key_b = KernelIngressStorageMixin._build_execution_ledger_idempotency_key(
|
|
tenant_id=9,
|
|
work_item_id=101,
|
|
operation_code="task.create",
|
|
source_message_id="feishu-msg-abc",
|
|
)
|
|
key_c = KernelIngressStorageMixin._build_execution_ledger_idempotency_key(
|
|
tenant_id=9,
|
|
work_item_id=102,
|
|
operation_code="task.create",
|
|
source_message_id="feishu-msg-abc",
|
|
)
|
|
|
|
assert key_a == key_b
|
|
assert key_a != key_c
|
|
assert len(key_a) == 40
|
|
|
|
|
|
def test_normalize_execution_ledger_status_maps_work_item_state() -> None:
|
|
assert (
|
|
KernelIngressStorageMixin._normalize_execution_ledger_status(
|
|
work_item_state="succeeded",
|
|
execution_status="failed_safe",
|
|
)
|
|
== "applied"
|
|
)
|
|
assert (
|
|
KernelIngressStorageMixin._normalize_execution_ledger_status(
|
|
work_item_state="waiting_manual",
|
|
execution_status="succeeded",
|
|
)
|
|
== "pending_manual"
|
|
)
|
|
assert (
|
|
KernelIngressStorageMixin._normalize_execution_ledger_status(
|
|
work_item_state="failed",
|
|
execution_status="succeeded",
|
|
)
|
|
== "failed"
|
|
)
|