"""规则轨迹生成与结构化理由核验,不模拟任意自然语言理解。""" import json def tri_or(values): return True if True in values else None if None in values else False def tri_and(values): return False if False in values else None if None in values else True def trace(symbol, row): specs = [("pe", "lt", 20), ("growth", "ge", .10), ("yield", "ge", .04)] leaves = {} for field, op, threshold in specs: value = row.get(field) result = None if value is None else (0 < value < threshold if field == "pe" else value >= threshold) leaves[field] = {"value": value, "threshold": threshold, "operator": op, "lower_exclusive": 0 if field == "pe" else None, "result": result, "source": f"fixture-1:{symbol}:{field}"} decision = tri_and([leaves["pe"]["result"], tri_or([leaves["growth"]["result"], leaves["yield"]["result"]])]) return {"symbol": symbol, "decision": decision, "leaves": leaves} def verify_claims(record, claims): witness = "pe" in claims and bool({"growth", "yield"} & set(claims)) return witness and record["decision"] is True and all(name in record["leaves"] and record["leaves"][name]["result"] is True for name in claims) def render(record, claims): if not verify_claims(record, claims): raise ValueError("unsupported_explanation") parts = [f"{name}={record['leaves'][name]['value']}" for name in claims] return f"{record['symbol']} passes via " + " and ".join(parts) aaa = trace("AAA", {"pe": 18, "growth": .08, "yield": .05}) bbb = trace("BBB", {"pe": 19, "growth": None, "yield": .02}) ccc = trace("CCC", {"pe": 24, "growth": .20, "yield": .05}) assert aaa["decision"] is True and bbb["decision"] is None and ccc["decision"] is False assert verify_claims(aaa, ["pe", "yield"]) assert not verify_claims(aaa, ["growth"]) and not verify_claims(aaa, ["management"]) assert not verify_claims(aaa, []) and not verify_claims(aaa, ["pe"]) assert not verify_claims(bbb, ["growth"]) and not verify_claims(ccc, ["growth"]) assert render(aaa, ["pe", "yield"]) == "AAA passes via pe=18 and yield=0.05" try: render(aaa, ["pe", "growth"]) except ValueError as exc: assert str(exc) == "unsupported_explanation" else: raise AssertionError("错误理由必须阻断") print(json.dumps({"trace": [aaa, bbb, ccc], "approved_reason": render(aaa, ["pe", "yield"]), "blocked_claims": ["AAA:growth", "AAA:management", "BBB:growth", "CCC:selected"]}, sort_keys=True))