#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 单校区开工闸门 / Campus Workflow Gate ===================================== 南通新东方租赁合同梳理——每开一个新校区,动手前必须先跑这个脚本。 为什么存在:防止"开新校区时凭上个校区的印象乱跑/跳步"。 这是物理闸门——脚本把【从头到尾的完整流程】+【单校区独立闭环纪律】打印出来, 逼自己逐条确认,不跑不准动手填表。 🔴 通读强制纪律(悦拾光0703教训,详见 references/fulltext-reading-discipline-0703.md): Step2动作A法律审查必须 read_file 从第1行读到最后一行(每批500行),不得 grep 代替。 I列按21/15固定类目逐项摘录原文(格式:· [类目] 原文(条款号))。 建完表后跑 scripts/i-column-coverage-check.py 报警核查覆盖率。 用法: python3 campus-workflow-gate.py <校区名> 例: python3 campus-workflow-gate.py 人民中路 它会: 1. 打印「单校区独立闭环纪律」——本校区从 Step0 从头做,不受其他校区影响 2. 打印完整 Step 0→7 workflow + 三角色 + 交付物板块的强制清单 3. 定位该校区在 Nextcloud 的源文件夹 + 汇总表应存放的位置(=校区自己的文件夹) 4. 生成一份待打勾的 todo 文本,贴进 todo 工具 """ import sys, os, subprocess NC_CONTAINER = "nextcloud-nextcloud-1" NC_BASE = "/var/www/html/data/admin/files/小Maggie协作区/南通新东方/履约期内非集采合同-综办/房租物业合同" NC_DAV = "小Maggie协作区/南通新东方/履约期内非集采合同-综办/房租物业合同" def campus_dir_exists(campus): p = f"{NC_BASE}/{campus}" r = subprocess.run(["docker","exec",NC_CONTAINER,"test","-d",p], capture_output=True) return r.returncode == 0 def list_campus_files(campus): p = f"{NC_BASE}/{campus}" r = subprocess.run(["docker","exec",NC_CONTAINER,"bash","-c",f'ls -la "{p}"'], capture_output=True, text=True) return r.stdout def main(): if len(sys.argv) < 2: print("用法: python3 campus-workflow-gate.py <校区名>") print("例: python3 campus-workflow-gate.py 人民中路") sys.exit(1) campus = sys.argv[1].strip() bar = "=" * 70 print(bar) print(f" 单校区开工闸门 · 校区 = 【{campus}】") print(bar) # ---- 第一道:独立闭环纪律 + 地基四铁律 ---- print(""" 🔴🔴 单校区独立闭环纪律(Maggie 2026-06-23 立,开工前默念)🔴🔴 1. 本校区从 Step 0 从头做到 Step 6 独立跑一遍(Step 7 总览是全部校区定稿后的全局收尾)。 2. 绝不受其他校区影响——不拿"上个校区做过/世茂悦拾光是这样"的印象代替 本校区的逐字通读、逐条审查、回 07 原件比对。每个校区都是第一次。 3. 别的校区的结论、定级、措辞,统统不假设适用于本校区;一切回本校区原文。 4. 这是一次"全新合同全面审",不是"套上一份的模子"。 🔴🔴 地基四铁律(Maggie 2026-06-26 重申,优先级最高)🔴🔴 1. 逐字逐句:亲自读完整篇OCR,一字不跳。OCR乱码停→vision核实,不准跳过猜值。 🔴 Step1完成后必跑 ocr-garble-detect.py 扫全文乱码,高危行逐条vision消灭(教训: 凤凰文化10.2乱码未核实→整段"初年年租金20%违约金"丢失→审查结论反转→返工) 2. 整体理解:通读全文后再逐条审,先建立全文结构认知。 3. 上下文联系:每读一条问"这条被别处限定/修改了吗?" 4. 逻辑分析:数字、比例、日期、主体用逻辑推一遍——合理吗?自洽吗? """) # ---- 第二道:完整流程强制清单 ---- print("""———— 完整 WORKFLOW(缺一步不交付)———— Step 0 文件盘点归类:按文件夹结构(房租/扩租/物业),含空目录,不跨夹重排 Step 1 取 PDF + OCR→.md(大文件后台跑;纯扫描件文字层=0 必 OCR) Step 2 承办(四眼分离前半)【并行,不串行】: ⚡ 开工第一动作 = 立刻 delegate_task 发动作B 到后台,发出的同一秒自己开读动作A · 动作B 提取分析 = subagent(后台先发):OCR要素+模版比对+退租敞口+填表初稿 · 动作A 法律审查 = 小Maggie本人主审(B发出后立即开读),亲自 read_file 逐字通读全文, 八维框架,当全新合同审(独立法律审查框架)—— 两件事同时跑,绝不先做完A再做B · 🔴 模版比对必须回 07-房屋租赁合同.docx 原件逐条核(subagent context 带原件路径) Step 3 写 Excel:12 列(K=法律风险/L=模版差异,物理分列); 按文件夹分板块;末尾必有「整体风险分析与建议」段 · 各列规则详见 references/column-rules-0701.md(Maggie校准版,优先级最高) · H列四检:①条款号 ②月租换算 ③付款推算 ④❗标注。缺一不过,不过不交付。 · 需客户核实内容整条标红(富文本红是最后一步→WPS另存/sharedStrings XML层) Step 4 三角色校对:法律校对 ‖ 格式校对(六维清单)→ 闭环复核 Step 5 小Maggie终审:合并法律风险栏、回07原件复核L列、确认问题闭环、最后把关 · 🔴 K/L 分工自检(必跑):K列 grep "模版|07模版|07-房屋"=0(独立审查不引模版, 匹配"07模版"而非裸07防误命中金额数字);L列 grep "风险|建议|不利|详见"=0(纯客观不下判断)。 任一非0即回去拆分。判据=遮模版测试:把"模版怎么写"遮住,K列风险论述仍完整成立才算独立。 Step 6 交付前自查+存档:x2t渲染PDF + pdftotext拍平grep验文字 + vision验视觉(图先压<400KB) → 汇总表存本校区文件夹 + files:scan + 清OO缓存 → 发Maggie核 〔全部校区定稿后〕Step 7 整合总览sheet(全局收尾,非单校区步骤) ———— 交付物必含板块(验收必查)———— 逐条风险(🔴🟡🟢分级,标条款号) + 整体风险分析与建议段 + L列模版差异(回07原件) """) # ---- 第三道:存放纪律 + 定位 ---- print(bar) print(" 📁 汇总表存放纪律(Maggie 2026-06-23 立)") print(bar) exists = campus_dir_exists(campus) if exists: print(f"✅ 校区源文件夹已定位:") print(f" 容器路径: {NC_BASE}/{campus}/") print(f" WebDAV : {NC_DAV}/{campus}/") print(f"\n 本校区文件清单:") for line in list_campus_files(campus).splitlines(): if line.strip() and not line.startswith("total"): print(f" {line}") else: print(f"⚠️ 未在标准路径找到校区目录【{campus}】。请先核对校区名,或确认目录是否在别处:") print(f" 预期: {NC_BASE}/{campus}/") print(f" (17 个校区均在 房租物业合同/ 下,标准名单:") print(f" 万达、世茂、人民中路、凤凰文化、北翼玖玖、南通大厦、小石桥晏园、悦拾光、") print(f" 星月、桃坞路、解放中路、跃龙路、通大、通大附、通州金鹰、金飞达、龙信)") print(f""" 🔴 本校区汇总表【必须】存到本校区自己的文件夹下,不放别处、不放公共目录: 存放路径: {NC_DAV}/{campus}/ 命名规则: {campus}-梳理-MJ-YYYYMMDD.xlsx (当事人/项目名+文件名+修改人+日期) —— 每个校区的汇总表归到各自校区文件夹,与该校区合同放一起,便于客户对照查阅。 """) # ---- 第四道:吐出 todo 文本 ---- print(bar) print(" ⬇️ 把下面这份 todo 贴进 todo 工具,逐项打勾(缺一项不交付)") print(bar) todos = [ f"[{campus}] Step0 文件盘点归类(含空目录,不跨夹重排;多租赁物先按租赁物分类再按签约时间排列;详细K/L/I放最早签约那份行里后续写同上)", f"[{campus}] Step1 取PDF+OCR→.md(纯扫描件必OCR)+保存.md到同目录 → 跑 ocr-garble-detect.py 扫乱码 → 高危乱码每处vision核实消灭 → 全灭才进Step2", f"[{campus}] Step2 承办【并行,不串行】⚡开工第一动作=立刻 delegate_task 发动作B(模版比对回07原件,仅租赁合同需比对,物业等其他合同不需要)到后台 → 发出的同一秒自己开读动作A(本人逐字通读全文+八维当全新合同审)。两件事同时跑,绝不先做完A再做B", f"[{campus}] Step3 写12列Excel(K法律风险/L模版差异分列)+H列四检+整体风险分析段+标红。🔴必须用 templates/single-campus-builder.py 照抄改值,禁裸写 openpyxl。🔴建L列前必read_file subagent比对文件,从里面逐条摘差异。🔴各列规则见 references/column-rules-0701.md(多合同时详细K/L放最早签约那份行里,后续行写同上)", f"[{campus}] Step4 三角色校对(法律‖格式)闭环复核", f"[{campus}] Step5 终审:合并法律风险+回07原件复核L列+K/L分工自检(K列grep'模版|07'=0,L列grep'风险|建议|不利|详见'=0)+确认闭环", f"[{campus}] Step6 交付自查(x2t渲染+pdftotext验文字+vision验视觉)+存本校区文件夹", f"[{campus}] 存档:汇总表存到本校区文件夹 {campus}/ + files:scan + 清OO缓存", ] for i, t in enumerate(todos, 1): print(f" {i}. {t}") print() # ---- 🔴 第五道:物理卡口(防跳步)---- print(bar) print(" 🔴🔴 物理卡口(以下两条不做到 = 返工,不交付)🔴🔴") print(bar) print(""" 卡口① 格式强制:Step3 写表必须用模板脚本 → 路径:~/.hermes/skills/legal/contract-portfolio-analysis/templates/single-campus-builder.py → 方法:cp 到工作目录,改 TODO 标记的值(标题、项目信息、D5..L5、D8..L8、整体段、输出路径) → 禁止:自己 openpyxl 裸写样式、自创颜色、改列头措辞 → 自检:交付前打开文件,和人民中路定稿并排对比——标题酒红底白字?段标题红底?行2灰底? K列头="法律风险(站乙方立场)"?L列头="与07标准模版差异"?冻结A5?行高30/76/409.5? 卡口② 模版比对强制:Step2 动作B 必须 delegate_task subagent → 不能:自己读07模版后手写L列差异(会漏、会简略、会凭印象) → 做法:OCR完成后立即 delegate_task,context 含 07模版路径 + 两份合同OCR路径 → 🔴 建表前必做:read_file 读 subagent 比对文件全文,L列从里面逐条摘、不从脑子里摘 → 自检①:subagent 返回的差异清单是否 ≥ 20 条? → 自检②:L列每条差异是否都能在 subagent 比对文件里找到原文对应? "甲方制式格式,与07模版不同"这种一句话概括 = 没读 subagent 文件 = 返工 subagent 抓到的差异(如举报邮箱新增、供电功率矛盾、首期期间变更) 你在 L 列里没写 = 没读 subagent 文件 = 返工 卡口③ 交付前格式自检(跑脚本,不凭眼): → python3 scripts/kl-separation-check.py # K列零模版、L列零判断词 → python3 -c "import openpyxl; wb=openpyxl.load_workbook(''); ws=wb[wb.sheetnames[0]]; assert ws.cell(1,1).fill.start_color.rgb=='FF8B1A2B','标题不是酒红底'; assert ws.cell(3,1).fill.start_color.rgb=='FFC0504D','段标题不是红底'; assert ws.cell(4,11).value=='法律风险(站乙方立场)','K列头不对'; assert ws.cell(4,12).value=='与07标准模版差异','L列头不对'; print('OK')" """) print("提醒:开工前默念独立闭环纪律——本校区从头做,不受其他校区影响。") if __name__ == "__main__": main()