"""Allowlisted deterministic business executors, never dynamic imports/eval.""" from decimal import Decimal, InvalidOperation, ROUND_HALF_UP EXECUTORS = {"quality", "ratio", "overdue", "compare", "required", "duplicate", "model"} def number(value): if value is None or isinstance(value, bool): raise ValueError("缺少有效数值") try: result = Decimal(str(value)) except (InvalidOperation, ValueError, TypeError): raise ValueError("金额必须是十进制数") from None if not result.is_finite() or abs(result) > Decimal("1e18"): raise ValueError("数值超出支持范围") return result def ratio(numerator, denominator): n, d = number(numerator), number(denominator) if d <= 0: raise ValueError("分母必须大于零") return str((n / d).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)) def execute_skill(skill, values, sources): engine = skill.get("engine") if engine not in EXECUTORS or engine == "model": raise ValueError("不支持的确定性执行器") checks, outputs = [], {} fields = skill.get("inputs", []) def check(code, title, result, refs, action="请核实材料与口径"): checks.append({"code": code, "title": title, "result": result, "fields": refs, "suggested_action": action, "evidence_ids": [r["id"] for f in refs for r in sources.get(f, [])], "basis_ids": [skill["id"] + "@" + skill["version"]], "severity": "attention"}) if engine in ("quality", "required"): for field in (list(values) if "*" in fields else fields): check(skill.get("code", "missing." + field), skill.get("title", field + "完整性"), "unknown" if values.get(field) is None else "pass", [field], "补充对应材料和来源依据") elif engine == "compare": a, b = skill["left"], skill["right"] result = "unknown" if values.get(a) is None or values.get(b) is None else ("pass" if number(values[a]) == number(values[b]) else "issue") refs = sources.get(a, []) + sources.get(b, []) if not sources.get(a) or not sources.get(b) or any(not r.get(k) for r in refs for k in ("currency", "unit", "scope", "period")) or any(len({r.get(k) for r in refs}) != 1 for k in ("currency", "unit", "scope", "period")): result = "unknown" check(skill["code"], skill["name"], result, [a, b]) elif engine == "duplicate": value = values.get(skill["field"]) check(skill["code"], skill["name"], "unknown" if value is None else ("issue" if number(value) > 0 else "pass"), [skill["field"]], "核对设备编号并提交去重清单") elif engine == "ratio": a, b = skill["numerator"], skill["denominator"] refs = sources.get(a, []) + sources.get(b, []) if not sources.get(a) or not sources.get(b) or any(not r.get(k) for r in refs for k in ("currency", "unit", "scope")): raise ValueError("缺少币种、单位或口径依据,不能计算") for dimension in ("currency", "unit", "scope"): if len({r.get(dimension) for r in refs if r.get(dimension)}) > 1: raise ValueError(dimension + "不一致,不能交叉计算") if a.startswith("financial.") and b.startswith("financial.") and len({r.get("period") for r in refs}) > 1: raise ValueError("期间不一致,不能交叉计算") outputs[skill["output"]] = ratio(values.get(a), values.get(b)) else: for field in fields: check("input." + field, field + "输入检查", "unknown" if values.get(field) is None else "pass", [field]) return outputs, checks def execute_rules(rule, values, sources): checks = [] for index, condition in enumerate(rule.get("conditions", [])): field = condition["field"] applicable = condition.get("when", {}) if any(values.get(k) != v for k, v in applicable.items()): result = "not_applicable" else: try: value, threshold = number(values.get(field)), number(condition["threshold"]) hit = {"gt": value > threshold, "lt": value < threshold, "eq": value == threshold, "gte": value >= threshold, "lte": value <= threshold}[condition["operator"]] result = "issue" if hit else "pass" except ValueError: result = "unknown" checks.append({"code": condition.get("code", rule["id"] + "." + str(index)), "title": condition.get("title", field), "result": result, "fields": [field], "value": values.get(field), "evidence_ids": [r["id"] for r in sources.get(field, [])], "basis_ids": [rule["id"] + "@" + rule["version"]], "suggested_action": condition.get("suggestion", "请核实"), "severity": "attention"}) return checks