"""Finding engine — FACT/REQUIREMENT/INFERENCE, provenance clamp, decisions.""" from __future__ import annotations from backend.periscopex.finding_engine import ( DesignerDecision, apply_decisions, complete_finding, finding_fingerprint, lookup_rule, ) from backend.periscopex.models import Finding from backend.periscopex.validate import assign_finding_ids, _parse_review def test_recommended_never_error(): f = Finding( designator="U1", finding="layout note", why="place close", status="ERROR", rule_id="PE-THM-001", source="pcb_power_thermal", evidence_status="SUFFICIENT", facts="no pour", requirement="datasheet layout page", ) complete_finding(f) assert f.provenance == "RECOMMENDED" assert f.status != "ERROR" assert f.finding_class != "RULE" def test_llm_review_is_never_rule(): result = _parse_review( { "findings": [{ "finding": "strap", "why": "datasheet", "status": "ERROR", "source_page": 2, "source_quote": "PSEL must be high for 3.3 V.", "recommendation": "Tie PSEL high.", }], "checked_areas": [], }, "U1", "PART", ) f = result.findings[0] complete_finding(f) assert f.finding_class == "REVIEW" assert f.facts assert f.requirement assert f.status == "ERROR" def test_insufficient_evidence_does_not_stay_error(): f = Finding( designator="U1", finding="narrow trace", why="", status="ERROR", source="pcb_power_thermal", rule_id="PE-PWR-001", evidence_status="INSUFFICIENT", ) complete_finding(f) assert f.status != "ERROR" assert "Insufficient evidence" in f.inference assert f.finding_class != "RULE" or f.evidence_status == "INSUFFICIENT" def test_decision_suppresses_rescan_nag(): f = Finding( designator="U1", finding="PSEL low", why="must be high", status="ERROR", rule_id="PE-MUX-001", source="pin_mux_check", net="PSEL", aspect="config", facts="PSEL net is GND", requirement="PSEL high for 3V3", ) complete_finding(f) assert f.status == "ERROR" d = DesignerDecision( decision_id="DEC-1", fingerprint=finding_fingerprint(f), rule_id="PE-MUX-001", designator="U1", net="PSEL", aspect="config", intent="wontfix", reason="PSEL low intentional", ) apply_decisions([f], [d]) assert f.suppressed is True assert f.status == "INFO" assert f.finding_class == "INFO" assert "PSEL low intentional" in f.inference def test_schematic_assign_ids_fills_engine_fields(): f = Finding( designator="U3", finding="NC tied", why="NC must float", status="ERROR", rule_id="PE-NC-001", source="nc_pin_check", ) assign_finding_ids([f]) assert f.finding_id == "U3-001" assert f.facts == "NC tied" assert f.requirement assert f.provenance == "MANDATORY" assert f.finding_class == "RULE" assert f.confidence is not None def test_same_object_pcb_and_schema(): assert lookup_rule("PE-NC-001").domain == "schema" assert lookup_rule("PE-LAY-001").domain == "pcb" sch = Finding(designator="U1", finding="x", status="INFO", rule_id="PE-NC-001", source="nc_pin_check") pcb = Finding(designator="U1", finding="y", status="INFO", rule_id="PE-LAY-001", source="pcb_net_match") complete_finding(sch) complete_finding(pcb) for obj in (sch, pcb): assert obj.facts assert obj.finding_class assert obj.provenance assert obj.evidence_status assert (obj.action or "").strip() def test_empty_recommendation_gets_action(): f = Finding(designator="U1", finding="note", status="INFO", source="review") complete_finding(f) assert f.action.strip() assert f.recommendation.strip() == f.action.strip() def test_recommended_rc_cap_is_review_not_rule(): f = Finding( designator="C1", finding="10n vs 100n", why="datasheet typical 100n", status="WARNING", rule_id="PE-DEC-002", source="passive_rail_check", ) complete_finding(f) assert f.finding_class == "REVIEW" assert f.provenance == "RECOMMENDED" assert f.status != "ERROR"