"""Pre-gen data completeness gate.""" from __future__ import annotations from core.projects.data_completeness import ( STATUS_MISSING, STATUS_READY, STATUS_STRUCTURE, apply_project_facts, evaluate_data_completeness, ) from core.projects.instrument_schema import build_instrument_schema def test_eurogranty_missing_target_blocks(): schema = build_instrument_schema(program_name="Granty na Eurogranty FENG.02.12") r = evaluate_data_completeness( external_context={ "company_data": { "nip": "8721990161", "name": "AUTOPROCES", "pkd_codes": ["28.29.Z"], "msp_status": "mikro", "de_minimis": 2738, "closed_financial_year": True, "revenue_3y": [1, 2, 3], "employment_fte": 2, }, "grounding_mode": "regulation", "program_dossier": {"readiness": {"level": "partial"}}, }, instrument_schema=schema, description="Przygotowanie do aplikacji UE", ) assert r["status"] == STATUS_MISSING assert r["full_autopilot_allowed"] is False fields = {m["field"] for m in r["missing_fields"]} assert "eurogrant_call" in fields or "eurogrant_programme" in fields def test_structure_only_allows_generate(): r = evaluate_data_completeness( external_context={ "grounding_mode": "structure_only", # complete eligibility so structure-only is not blocked by spine "company_data": { "nip": "8721990161", "msp_status": "mikro", "de_minimis_manual_eur": 1000, }, }, grounding_mode="structure_only", ) assert r["status"] == STATUS_STRUCTURE assert r["ready_to_generate"] is True assert r["full_autopilot_allowed"] is True assert r.get("eligibility_spine_enforced") is True def test_structure_only_still_gates_full_autopilot_on_large_firm(monkeypatch): """structure_only must not fail-open Full Autopilot past eligibility spine.""" monkeypatch.setenv("ENABLE_ELIGIBILITY_SPINE", "true") r = evaluate_data_completeness( external_context={ "grounding_mode": "structure_only", "company_data": { "nip": "8721990161", "msp_status": "duza", "de_minimis_manual_eur": 1000, }, }, grounding_mode="structure_only", ) assert r["status"] == STATUS_STRUCTURE assert r["ready_to_generate"] is True # structural consent retained assert r["full_autopilot_allowed"] is False assert r.get("eligibility_spine_enforced") is True assert any("duża" in b.lower() or "duza" in b.lower() for b in (r.get("eligibility") or {}).get("blockers") or []) or any( "duż" in w.lower() or "duza" in w.lower() or "large" in w.lower() or "MŚP" in w or "duża" in w for w in (r.get("warnings") or []) ) def test_structure_only_gates_exhausted_de_minimis(monkeypatch): monkeypatch.setenv("ENABLE_ELIGIBILITY_SPINE", "true") r = evaluate_data_completeness( external_context={ "grounding_mode": "structure_only", "company_data": { "nip": "8721990161", "msp_status": "mikro", "sudop": {"configured": True, "de_minimis_total_eur": 300_000}, }, }, grounding_mode="structure_only", ) assert r["ready_to_generate"] is True assert r["full_autopilot_allowed"] is False assert (r.get("eligibility") or {}).get("de_minimis", {}).get("exhausted") is True def test_structure_only_gates_unknown_de_minimis(monkeypatch): monkeypatch.setenv("ENABLE_ELIGIBILITY_SPINE", "true") r = evaluate_data_completeness( external_context={ "grounding_mode": "structure_only", "company_data": { "nip": "8721990161", "msp_status": "mikro", # no sudop / manual de minimis }, }, grounding_mode="structure_only", ) assert r["full_autopilot_allowed"] is False assert r.get("eligibility_spine_enforced") is True def test_apply_facts_then_ready_eurogranty(): schema = build_instrument_schema(program_name="Granty na Eurogranty") ext = { "company_data": { "nip": "8721990161", "name": "AUTOPROCES", "pkd_codes": ["28.29.Z"], "msp_status": "mikro", "de_minimis": 1000, "closed_financial_year": True, "revenue_3y": {"2023": 1, "2024": 2, "2025": 3}, "employment_fte": 3, }, "grounding_mode": "regulation", "program_dossier": {"readiness": {"level": "ready"}}, } ext = apply_project_facts( ext, { "eurogrant_programme": "Horizon Europe Cluster 4", "eurogrant_call": "HORIZON-CL4-2026-AI-MANUFACTURING", "eurogrant_role": "samodzielny", "specialist_analysis_yes_no": "tak — analiza partnerów i stanu techniki", "lump_sum_amount_pln": 110852, }, ) r = evaluate_data_completeness( external_context=ext, instrument_schema=schema, description="Przygotowanie wniosku Horizon dla AI in manufacturing", ) assert r["status"] == STATUS_READY assert r["full_autopilot_allowed"] is True assert not r["missing_fields"] def test_missing_nip_blocks(): schema = build_instrument_schema(program_type="SMART", program_name="SMART") r = evaluate_data_completeness( external_context={"company_data": {}, "grounding_mode": "regulation"}, instrument_schema=schema, description="Projekt innowacyjny", ) assert r["full_autopilot_allowed"] is False assert any(m["field"] == "nip" for m in r["missing_fields"])