""" rules.py Signal — STTIL Solutions Format-tolerant readers for payer_rules.json plus the stable rule-ID registry (build plan 02, item P2; design: readiness-model-design-phase2 section 3.1). A rule value may be FLAT (legacy: `"visit_renewal_days": 180`) or WRAPPED with its citation (`"visit_renewal_days": {"value": 180, "rule_id": "R001"}`). Both engines read through these helpers so the JSON format can carry citation IDs without breaking either reader. RULE IDS ARE STABLE — never change an ID after shipping. The ID names the rule KIND; the plan type plus the value together are the citation. """ from __future__ import annotations from typing import Optional # Universal claim/coverage requirements per LCD L33822, independent of plan # type. They live in code (no plan-type dependency) but carry rule IDs for # citation consistency. UNIVERSAL_RULE_IDS = {"swo": "R100", "visit": "R101", "diagnosis": "R102"} # Plan-scoped keys in payer_rules.json and their registry IDs. PLAN_KEY_RULE_IDS = { "visit_renewal_days": "R001", "refill_window_days": "R002", "pa_required": "R003", "pecos_required": "R004", } def rule_value(cfg: Optional[dict], key: str, default=None): """Read a rule value, accepting flat (180) and wrapped ({'value': 180, 'rule_id': 'R001'}) formats.""" if not cfg: return default raw = cfg.get(key, default) if isinstance(raw, dict) and "value" in raw: return raw["value"] return raw def rule_id_for(cfg: Optional[dict], key: str) -> Optional[str]: """The citation ID for a plan-scoped rule: from the wrapped config when present, else the registry default for that key.""" raw = cfg.get(key) if cfg else None if isinstance(raw, dict) and "rule_id" in raw: return raw["rule_id"] return PLAN_KEY_RULE_IDS.get(key)