#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ K/L 分工自检 / K-L Column Separation Check ========================================== 校区梳理表 Step5 终审必跑:验证 K 列(法律风险) 与 L 列(模版差异) 职责分离。 · K 列(第 11 列)= 独立法律审查,从合同条款本身起笔,**绝不引模版** → 不得出现 "模版 / 07模版 / 07-房屋 / 07标准 / 相对模版 / 被放宽 / 被删除 / 被改为" · L 列(第 12 列)= 纯客观文本对比,只陈述 "模版表述为X;本合同表述为Y" → 不得出现 "风险 / 建议 / 不利 / 详见"(判断词与向 K 列导流的话) ⚠️ K 列匹配 "07模版 / 07-房屋 / 07标准" 而非裸 "07"——裸 07 会误命中金额数字 (如租金 377,507.80 里的 "507"),2026-06-24 跃龙路实证误报,已修正。 判据·遮模版测试:把"模版怎么写"整个遮住,K 列那条风险论述仍完整成立才算独立审查; 遮住就垮 = L 列逻辑混进了 K 列。 用法: python3 kl-separation-check.py <校区梳理表.xlsx> 退出码:0 = 通过;1 = 有违规(需回去拆分 K/L);2 = 用法错误 注:本脚本只查 K(11)/L(12) 两列的数据行。整体段(合并 A:L,在第 1 列)里 "【与07标准模版的文本差异】" 小节合法含"模版/07",不在本脚本检查范围—— 那是整体段按设计单独成段的客观对比,不是 K 列。 """ import sys import re import openpyxl K_FORBIDDEN_LITERAL = ["模版", "相对模版", "被放宽", "被删除", "被改为"] K_FORBIDDEN_REGEX = r"07模版|07-?房屋|07标准" L_FORBIDDEN_LITERAL = ["风险", "建议", "不利", "详见"] def cell_text(cell): """取单元格纯文本,兼容 CellRichText(可迭代) 与标量。""" v = cell.value if v is None: return "" if isinstance(v, str): return v try: return "".join(getattr(t, "text", str(t)) for t in v) except TypeError: return str(v) def is_header(text): """表头行启发式:K 表头='法律风险…'/'风险点…';L 表头='与…模版差异'。""" head = text[:10] if ("法律风险" in head or "风险点" in head) and len(text) < 40: return True if text.startswith("与") and "模版差异" in text and len(text) < 40: return True return False def check(path): wb = openpyxl.load_workbook(path) violations = [] for ws in wb.worksheets: for r in range(1, ws.max_row + 1): k = cell_text(ws.cell(r, 11)) l = cell_text(ws.cell(r, 12)) if k and not is_header(k): kb = [w for w in K_FORBIDDEN_LITERAL if w in k] kb += re.findall(K_FORBIDDEN_REGEX, k) if kb: violations.append((ws.title, f"K{r}", "独立审查不得引模版", kb)) if l and not is_header(l): lb = [w for w in L_FORBIDDEN_LITERAL if w in l] if lb: violations.append((ws.title, f"L{r}", "纯客观对比不得下判断", lb)) return violations def main(): if len(sys.argv) < 2: print("用法: python3 kl-separation-check.py <校区梳理表.xlsx>") sys.exit(2) v = check(sys.argv[1]) if not v: print("✅ K/L 分工自检通过:K 列零模版引用、L 列零判断词。") sys.exit(0) print("❌ K/L 分工自检发现违规(需回去拆分):") for sheet, cell, why, hits in v: print(f" [{sheet}] {cell}: {why} — 命中 {hits}") print("\n判据·遮模版测试:把'模版怎么写'遮住,K 列风险论述仍完整成立才算独立。") print("L 列只陈述'模版表述为X;本合同表述为Y',判断与建议归 K 列。") sys.exit(1) if __name__ == "__main__": main()