#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 模版比对验证 / Template Diff Verify =================================== 物理依赖链第二环:动作B → 建表 检查subagent的模版比对输出是否存在且内容充实。 如果有问题,拒绝生成checkpoint,建表脚本将因此中止。 用法: python3 template-diff-verify.py <工作目录> 检查项: 1. 工作目录是否有 模版比对-*.md 文件 2. 文件大小是否 > 2000 字节(排除空文件或极简概括) 3. 是否包含条款号(如"第X条"、"X.X条") 4. 是否包含差异描述(如"模版表述为"、"本合同表述为") 通过 → 生成 step2b.verified checkpoint 失败 → 拒绝生成checkpoint 退出码:0=通过,1=有问题 """ import sys, os, re, glob from datetime import datetime def check_template_diff(workdir): """检查模版比对输出文件""" issues = [] # 查找模版比对输出文件 diff_files = glob.glob(os.path.join(workdir, '模版比对-*.md')) diff_files += glob.glob(os.path.join(workdir, 'template-diff-*.md')) if not diff_files: issues.append({ 'type': '文件缺失', 'detail': f'工作目录 {workdir} 未找到模版比对输出文件(模版比对-*.md 或 template-diff-*.md)', 'fix': 'Step2 动作B 必须 delegate_task subagent 做模版比对' }) return issues for diff_file in diff_files: fname = os.path.basename(diff_file) size = os.path.getsize(diff_file) # 检查1:文件大小 if size < 2000: issues.append({ 'type': '内容过短', 'detail': f'{fname} 仅 {size} 字节,疑似极简概括而非逐条比对', 'fix': 'subagent 应产出详细的逐条比对报告,不是"甲方制式格式,与07模版不同"一句话' }) continue # 读取文件内容 with open(diff_file, 'r', encoding='utf-8') as f: content = f.read() # 检查2:是否包含条款号 clause_pattern = r'第[一二三四五六七八九十\d]+条|[一二三四五六七八九十\d]+\.\d+' clause_matches = re.findall(clause_pattern, content) if len(clause_matches) < 10: issues.append({ 'type': '条款号不足', 'detail': f'{fname} 仅找到 {len(clause_matches)} 个条款号引用,疑似未逐条比对', 'fix': '模版比对必须回 07 原件逐条核对,不能概括性描述' }) # 检查3:是否包含差异描述关键词 diff_keywords = [ r'模版表述[为::]', r'本合同表述[为::]', r'模版.*本合同', r'差异', r'缺失', r'新增', r'修改为', r'变更为', r'无此条款', r'不存在', ] keyword_count = sum(1 for kw in diff_keywords if re.search(kw, content)) if keyword_count < 3: issues.append({ 'type': '差异描述不足', 'detail': f'{fname} 差异描述关键词仅 {keyword_count} 个,疑似未详细比对', 'fix': '比对报告应包含"模版表述为X;本合同表述为Y"的具体差异描述' }) # 检查4:行数(逐条比对应该有足够行数) lines = content.split('\n') if len(lines) < 30: issues.append({ 'type': '行数不足', 'detail': f'{fname} 仅 {len(lines)} 行,疑似未逐条展开', 'fix': '逐条比对报告应有足够行数覆盖所有条款差异' }) return issues def main(): if len(sys.argv) < 2: print("用法: python3 template-diff-verify.py <工作目录>") print("例: python3 template-diff-verify.py /tmp/人民中路") sys.exit(1) workdir = sys.argv[1] if not os.path.isdir(workdir): print(f"❌ 工作目录不存在: {workdir}") sys.exit(1) print(f"检查模版比对输出...\n") issues = check_template_diff(workdir) checkpoint_path = os.path.join(workdir, 'step2b.verified') if issues: print("❌ 模版比对验证失败\n") for i, issue in enumerate(issues, 1): print(f" {i}. [{issue['type']}]") print(f" {issue['detail']}") print(f" → {issue['fix']}\n") print(f"⛔ 未生成checkpoint: {checkpoint_path}") print(" 建表脚本将拒绝执行,直到模版比对完成。") sys.exit(1) else: # 找到通过的文件 diff_files = glob.glob(os.path.join(workdir, '模版比对-*.md')) diff_files += glob.glob(os.path.join(workdir, 'template-diff-*.md')) print("✅ 模版比对验证通过\n") for df in diff_files: fname = os.path.basename(df) size = os.path.getsize(df) print(f" ✓ {fname} ({size:,} 字节)") # 生成checkpoint with open(checkpoint_path, 'w', encoding='utf-8') as f: f.write(f"模版比对验证通过\n") f.write(f"时间: {datetime.now().isoformat()}\n") f.write(f"文件数: {len(diff_files)}\n") for df in diff_files: fname = os.path.basename(df) size = os.path.getsize(df) f.write(f" - {fname} ({size} 字节)\n") print(f"\n✓ checkpoint已生成: {checkpoint_path}") sys.exit(0) if __name__ == '__main__': main()