| """basic_risk_node — Python-deterministic math + date logic. |
| |
| Per-doc fan-out: invoked via Send API on a per-document branch. |
| Input: ``{"doc_index": int, "extracted": dict, "doc_file_name": str, "doc_type": str}`` |
| Output: ``{"risks": [Risk(...)]}`` — merged via the ``merge_risks`` reducer. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from graph.states.pipeline_state import Risk |
| from validation.date_logic import validate_contract_dates, validate_date_logic |
| from validation.invoice_math import validate_invoice_math |
|
|
|
|
| async def basic_risk_node(state: dict) -> dict: |
| extracted = state.get("extracted") or {} |
| doc_type = state.get("doc_type", "other") |
| file_name = state.get("doc_file_name", "") |
|
|
| if not extracted: |
| return {} |
|
|
| |
| errors = validate_invoice_math(extracted) |
| errors.extend(validate_date_logic(extracted)) |
|
|
| |
| if doc_type == "contract": |
| errors.extend(validate_contract_dates(extracted)) |
|
|
| risks = [ |
| Risk( |
| description=err.get("message", ""), |
| severity=_normalize_severity(err.get("severity", "medium")), |
| rationale="Deterministic math/date validation result.", |
| kind="validation", |
| affected_document=file_name, |
| source_check_id=f"basic_{err.get('type', 'unknown')}", |
| ) |
| for err in errors |
| ] |
| return {"risks": risks} if risks else {} |
|
|
|
|
| def _normalize_severity(sev: str) -> str: |
| """Normalize severity to the canonical EN literal set.""" |
| mapping = { |
| |
| "alacsony": "low", |
| "kozepes": "medium", |
| "magas": "high", |
| "kritikus": "high", |
| |
| "low": "low", |
| "medium": "medium", |
| "high": "high", |
| "critical": "high", |
| "info": "info", |
| } |
| return mapping.get(sev.lower(), sev) |
|
|