from __future__ import annotations from src.services.mcp_audit_context import ( MAX_MCP_AUDIT_SESSION_ID_LENGTH, build_mcp_audit_context, normalize_mcp_audit_session_id, with_mcp_audit_context, ) def test_build_mcp_audit_context_keeps_non_empty_fields() -> None: context = build_mcp_audit_context( session_id="incident:INC-1:pre_decision", incident_id="INC-1", flywheel_node="sense", agent_role="pre_decision_investigator", operator_user_id=None, ) assert context == { "gateway_path": "legacy_registry_provider", "session_id": "incident:INC-1:pre_decision", "incident_id": "INC-1", "flywheel_node": "sense", "agent_role": "pre_decision_investigator", } def test_normalize_mcp_audit_session_id_compacts_known_long_patterns() -> None: values = [ ( "incident:INC-20260505-E8033A:pre_decision", "inc:INC-20260505-E8033A:pre", ), ( "incident:INC-20260505-E8033A:post_execution", "inc:INC-20260505-E8033A:post", ), ( "callback:INC-20260505-E8033A:check_process", "cb:INC-20260505-E8033A", ), ( "approval:123e4567-e89b-12d3-a456-426614174000", "apr:123e4567", ), ] for raw, expected_prefix in values: normalized = normalize_mcp_audit_session_id(raw) assert normalized is not None assert len(normalized) <= MAX_MCP_AUDIT_SESSION_ID_LENGTH assert normalized.startswith(expected_prefix) def test_with_mcp_audit_context_merges_existing_context_without_mutating_source() -> None: params = { "namespace": "awoooi-prod", "_mcp_audit": {"trace_id": "trace-1", "flywheel_node": "old"}, } audited = with_mcp_audit_context( params, incident_id="INC-2", flywheel_node="verify", agent_role="post_execution_verifier", ) assert params["_mcp_audit"]["flywheel_node"] == "old" assert audited is not params assert audited["_mcp_audit"]["trace_id"] == "trace-1" assert audited["_mcp_audit"]["incident_id"] == "INC-2" assert audited["_mcp_audit"]["flywheel_node"] == "verify" assert audited["_mcp_audit"]["agent_role"] == "post_execution_verifier"