from pathlib import Path import asyncio import yaml def test_contestation_subject_schema_requires_concrete_invoice_entity(): cfg = yaml.safe_load(Path("config/tools.yaml").read_text(encoding="utf-8")) tools = cfg["tools"] if "tools" in cfg else cfg for tool_name in ("validar_contestacao", "contestar_cobranca"): subject = tools[tool_name]["args_schema"]["subject"] desc = subject["description"].lower() assert "item concreto" in desc assert "evidência da fatura" in desc or "evidencia da fatura" in desc assert subject["user_prompt"] def test_contestation_prompt_forbids_internal_validation_language(): prompt = Path("config/prompts/contestation.yaml").read_text(encoding="utf-8") assert "nunca exponha códigos" in prompt.lower() assert "CVAL" in prompt assert "JSON" in prompt assert "guardrail_code" in prompt def test_validator_turns_unresolved_subject_into_recoverable_parameter_request(monkeypatch): from contas_mcp.servers.contas_mcp_server import main async def no_enrich(_name, _args): return None monkeypatch.setattr(main, "_enrich_invoice_context", no_enrich) monkeypatch.setattr(main, "_preflight_subject", lambda *_args, **_kwargs: None) args = { "subject": "fatura", "valor": 10.0, "target_tool": "contestar_cobranca", "billing_analysis": { "currentInvoice": [ { "type": "servicos_contratados_de_parceiros", "items": [ {"desc": "TIM Fashion Mensal", "value": "10.0", "contestable": True} ], } ] }, } result = asyncio.run(main._validate_contestation(args)) assert result["eligible"] is False assert result["status"] == "NEEDS_PARAMETER" assert result["parameter"] == "subject" assert result["reason"] == "subject_not_resolved" assert result["resolved_value"] == 10.0 assert result["metadata"]["entity_resolution"] == "invoice_evidence" assert "error" not in result