Files

599 lines
37 KiB
Markdown

---
name: contract-review-general
description: 合同法律审查通用工作流程。适用于各类商事合同的审查,包括主体背景调查、条款审查、审查意见输出。与Maggie共建的标准流程,持续优化迭代中。
version: 0.1.0
tags: [合同审查, 法律, 尽职调查, 背景调查]
---
# 合同法律审查通用工作流程
> 与Maggie共建的标准化合同审查流程,适用于各类商事合同。
> 流程文档同步存放在:~/.hermes/shared/合同审查交付件/合同审查工作流程.md
## 核心原则
1. **信息准确性**:所有检索结果必须来自官方或权威第三方来源,标明出处;无法获取权威来源的如实告知,绝不拼凑
2. **先主体后条款**:开始审查条款之前,必须先完成交易双方的背景调查。原因:主体资格、关联关系、合规问题是地基,条款审查是在地基上盖的房子。如果交易本身存在合法性障碍(如关联交易未披露、同业竞争违规、主体不适格),条款再完美也没有意义。背景调查决定了审查的立场、侧重点和建议方向
3. **整体审查**(铁律,2026-06-17 Maggie):每个条款当作整体审查——识别条款全部要件(适用主体/情形列举/权利义务/例外但书/兜底救济)后再定性,严禁摘单句断章取义;整个合同当作整体审查——条款间交叉比对、关联呼应、前后逻辑自洽、交叉引用核对指向、定义简称全文贯通;逐条逐款不跳不漏(含正文/附件/补充协议/签署页/表格);内容与逻辑并重。详见 contract-reviewer skill「整体审查原则」节
4. **两遍独立审查**(手动审查铁律):法律条款审查和文字校对必须分两遍独立进行。第一遍按审查清单逐项检查法律条款(违约责任、管辖、保密、知识产权、转包等);第二遍逐段通读全文做文字校对(笔误、漏字、重复词语、年份错误、称谓不一致、模板残留如"药品"应为"医疗器械"等)。⚠️ 2026-06-12教训(数字健康城区运维V3):只做一遍遗漏5处文字问题,被Doro指出"认真点"后第二遍才全部发现。法律审查和文字校对是两个独立的认知任务,不能合并做
5. **保密义务**:合同审查的所有信息严格保密,仅限授权人员知悉,未经委托方书面同意不得向第三方披露
6. **逐步推进**:与Maggie一步一步确认,不跳步骤
## 第一阶段:交易主体背景调查
### Step 1: 提取合同中的主体信息
- 从合同文本中提取各方的名称、统一社会信用代码、法定代表人、注册地址
- 核对合同中载明的信息与工商登记是否一致
### Step 2: 工商基本信息检索
对每一方主体检索:
- 公司名称、统一社会信用代码
- 法定代表人
- 注册资本(认缴/实缴)
- 成立日期
- 经营范围(是否涵盖合同涉及的业务)
- 证照情况
**权威来源**:国家企业信用信息公示系统(gsxt.gov.cn)、企查查(qcc.com)、天眼查(tianyancha.com)
### Step 3: 股权结构检索
- 股东构成及持股比例
- 股权变更历史(频繁变更需警惕)
- 实际控制人(穿透股权层级)
- 上市公司关联
### Step 4: 关联关系排查
- 甲乙双方之间是否存在关联关系(交叉持股、共同股东、共同实控人)
- 对外投资企业清单
- 关联交易嫌疑排查
### Step 5: 法律风险排查
- 诉讼/仲裁记录 → 中国裁判文书网(wenshu.court.gov.cn)
- 被执行人/失信被执行人 → 中国执行信息公开网
- 行政处罚 → 信用中国(creditchina.gov.cn)
- 经营异常名录 → 国家企信系统
### Step 6: 履约能力评估
- 注册资本 vs 合同金额
- 经营范围 vs 合同内容
- 企业存续时间
- 财务状况(上市公司查年报)
## 第二阶段:合同条款审查
(待补充 — 随案例实践逐步完善)
## 手动审查流程(Workflow超时降级方案)
当uwf workflow的reviewer阶段连续超时(通常3次以上Timeout waiting for response),不要继续等待重试。按以下流程手动完成审查。
## 触发条件
合同法律审查任务(非卫生中心系列),包括商事合同、劳动合同、服务协议等。
## 审查立场铁律(Doro 2026-07-01 严厉纠正)
### 1. 站客户立场,不站法律合规立场
- 客户的商业安排是客户的决策,审查方无权否定
- 例:客户选择"甲方代发工资"→保留代发安排,在代发框架下最大化保护客户
- ❌ 错误:把"甲方代发"改成"乙方直接发"(=否定客户的商业决策)
- ✅ 正确:保留代发,加批注提示风险,在代发框架下加保护条款
### 2. 不做法律价值判断
- ❌ "强烈建议采用版本1"
- ✅ 呈现两个版本的风险差异,由律师和客户决定
### 3. 不填写合同空白内容
- 合同中空白处(金额、月数、日期等)是当事人商业条款
- 审查方无权擅自填入任何数值
- ❌ 质量保证期空白直接填"12个月"(无任何依据)
- ✅ 批注提示"请根据招标文件/投标文件约定填写具体月数"
### 4. 不编造法律依据
- 没有找到权威来源时如实说"未找到"
- ❌ 编一个"司法实践中认定"糊弄
- ✅ "未检索到直接裁判文书支持,以下为相关法条/学理分析,供参考"
### 5. 修订文本质量
- 修订后的条款必须通读上下文,确保语句通顺、逻辑自洽
- ❌ 机械替换文字后不管上下文是否衔接
- ✅ 每次修订后完整读一遍该段落,确认作为独立语句读得通
- Doro指示手动干预(如"你手动干吧")
### 操作步骤
1. **杀掉卡住的进程**`process(action='kill', session_id=...)`
2. **读取合同**:用python-docx提取全文段落+表格,识别甲乙方和顾问单位
3. **加载审查规则**:读取`/tmp/contract-review/rules/review-rules-root.md`(及目录特定rules)
4. **按审查清单逐项检查**:合并reviewer+editor角色,一次性完成分析+修订——逐条对照review-rules.md中的审查清单(主体、违约责任、争议解决、保密/数据、知识产权、第三方侵权、转包、价款、服务成果使用权、条款逻辑),同时检查笔误和语法错误
5. **执行修订**:修订模式(author=WB)。可用ContractEditor库或直接XML操作,二者均可。直接XML时注意:
- `w:ins`/`w:del`必须有id、author、date属性
- INS run的rPr至少包含`rFonts hint="eastAsia"`
- 新增条款段落用对应样式(如style val='3'对应Heading 2),pPr中包含ins rPr标记
- tracked_replace需正确处理跨run的文本匹配
6. **终审验证**(不可跳过,同workflow终审标准):
- XML级别字体检查(WB INS的rFonts + sz与原文一致)
- **heading INS sz检查**:新增heading段落(style=2/3等)的INS run sz必须匹配styles.xml中对应样式的sz值,不能用body正文sz(2026-06-15教训:heading 2样式sz=24 vs INS实际sz=21导致标题偏小)
- **交叉引用偏移检查**:用`第\s*\d+\s*条`搜索全文硬编码引用,核对新增heading条款后编号是否顺移但引用未更新(2026-06-15教训:新增2个heading条款后"第10条""第13条"引用未更新)\n - **手动编号与自动编号冲突检查(2026-06-15 端午节合同教训)**:新增条款若用手动键入的\"N、\"编号(如INS run里直接打\"6、转包限制\"),必须确认前一条不是用numbering.xml自动编号渲染的。陷阱:某条用`<w:numPr><w:numId w:val=\"3\"/>`且numbering.xml中该num定义`start=6 lvlText=%1、`,正文XML里看不到\"6、\"字样但渲染时自动显示\"6、\"。如果紧接着的INS新增条款手打\"6、\",就会出现两个6。检测方法:\n ```python\n # 1. 读numbering.xml确认每个numId的start值和lvlText格式\n # 2. 在document.xml中找出所有带numPr的段落,推算它们渲染出的实际编号\n # 3. 把自动编号段落和手动\"N、\"段落合并成一条完整序列,检查是否连续无重复\n ```\n 修复:手动编号顺延(6→7),且其后所有手动编号条款全部跟着+1(否则会出现两个7)。本案修复了7、转包→8、违约→9、争议三条。纯文本未跨run时可直接`xml.replace('6、转包限制:','7、转包限制:')`,替换前后用count断言各为1,确保精准。修订模式w:ins包裹要保持不变
- 修订内容文本验证(接受修订后的文本是否正确)
- 删除/插入计数确认
7. **交付**:上传Nextcloud → scan → 清OnlyOffice缓存 → 更新tracker → 更新xlsx → 私信通知Doro
### 手动审查必须分两遍(2026-06-12教训)
**第一遍**只做法律实质审查(按review-rules.md审查清单逐项),**第二遍**做文字校对(逐字通读,按contract-reviewer skill的「文字校对」10项必检清单)。两遍完成后合并issue清单,一次性修订。
**错误做法**:边读边改、读完法律问题就动手 → 遗漏文字级错误(双重用词、笔误、称谓不一致)
**正确做法**:法律审查完 → 放下法律思维 → 逐字通读做校对 → 合并后再动手
2026-06-12数字健康城区运维合同教训:第一遍找到8个法律问题直接修订交付,Doro说"但你认真点",第二遍逐字通读补出5个文字问题(双"进行"、"2027月"、"由于因"、"买卖双方"、"如果或证实"),不得不从原文重做全部13处修订。
### 与workflow审查的区别
- 手动审查是reviewer+editor合一,但**验证标准不降低**
- 效率更高(一次性完成,无角色间传递开销),适合workflow反复超时的复杂合同
- 缺点:没有独立reviewer复核环节,需要更仔细的自检——**必须分两遍**(法律实质+文字校对),不可合并
## Workflow `needs_clarification` 处理(乙方空白/无法识别顾问单位)
当classifier返回 `$status: needs_clarification`(通常因为合同某方名称空白、无法判断顾问单位):
### 第一步:报告Doro并询问
直接告知Doro合同双方信息,请Doro确认乙方/顾问单位。
### 第二步:Doro不知道时——追溯文件来源
如果Doro回复"合同名称无法确认该问谁"(2026-06-12教训),**不要再追问Doro**,自行追溯文件发送人:
1. **查企微缓存**`ls ~/.hermes/cache/documents/*关键词*` → 确认文件到达时间
2. **查session记录**`session_search(query="文件名关键词", sort="newest")` → 找到文件接收的session,识别发送人
3. **查Nextcloud activity**(如果上面找不到):
```sql
-- 容器: nextcloud-db-1, 用户: nextcloud, 密码见docker-compose.yml
SELECT FROM_UNIXTIME(timestamp), user, subject, file
FROM oc_activity WHERE file LIKE '%关键词%' ORDER BY timestamp DESC;
```
4. 确认发送人后,在群里@发送人询问乙方是哪个顾问单位
### 第三步:获得确认后继续workflow
将乙方信息告知后,可以:
- 取消当前thread(`uwf thread cancel <id>`)
- 以明确prompt重新启动(`uwf thread start review-contract -p "审查合同...,站XX立场"`)
- 或手动按已确认的顾问单位直接审查
## 社区卫生服务中心目录路由(手动交付必检)
部分顾问单位(朱家角镇社区卫生服务中心、练塘镇社区卫生服务中心、青浦区爱国卫生和健康促进指导中心等)在 Nextcloud 下有**独立的子目录**,而非放在通用的 `Doro合同审查任务/待审查/` 和 `Doro合同审查任务/任务交付/`:
```
Doro合同审查任务/
├── 待审查/ ← 通用待审查
├── 任务交付/ ← 通用任务交付
├── 朱家角镇社区卫生服务中心/
│ ├── 待审查/ ← 朱家角专属
│ ├── 任务交付/ ← 朱家角交付物
│ └── review-rules.md ← 朱家角特殊规则(含审查意见模板要求)
├── 练塘镇社区卫生服务中心/
│ └── ...
└── 青浦区爱国卫生和健康促进指导中心/
└── ...
```
**Workflow deliverer 只把文件产出到 `/tmp/contract-review/`,不会自动路由到这些子目录。** 交付时必须:
1. 检查该顾问单位是否有独立子目录:`docker exec nextcloud-nextcloud-1 ls "/var/www/html/data/doro/files/Doro合同审查任务/" | grep 关键词`
2. 有 → 复制到该子目录的 `任务交付/`(deliverer 通常投递到通用任务交付/,需手动路由):
```bash
docker exec nextcloud-nextcloud-1 cp "/var/www/html/data/doro/files/Doro合同审查任务/任务交付/【修】XX.docx" "/var/www/html/data/doro/files/Doro合同审查任务/朱家角镇社区卫生服务中心/任务交付/"
docker exec nextcloud-nextcloud-1 cp "/var/www/html/data/doro/files/Doro合同审查任务/任务交付/【审】XX.docx" "/var/www/html/data/doro/files/Doro合同审查任务/朱家角镇社区卫生服务中心/任务交付/"
docker exec nextcloud-nextcloud-1 chown www-data:www-data "/var/www/html/data/doro/files/Doro合同审查任务/朱家角镇社区卫生服务中心/任务交付/【修】XX.docx" "/var/www/html/data/doro/files/Doro合同审查任务/朱家角镇社区卫生服务中心/任务交付/【审】XX.docx"
docker exec nextcloud-nextcloud-1 php occ files:scan doro
```
3. ⚠️ 2026-07-02 教训:恭兴合同和肃言合同都被 deliverer 投递到通用 `任务交付/`,需要手动复制到朱家角子目录
**特殊交付物:审查意见文档** — 部分卫生中心的 `review-rules.md` 要求生成独立的审查意见表格(条文|原文|修订后),使用指定模板(如 `~/.hermes/shared/模版库/朱家角 审查意见【模板】.docx`)。Workflow 的 deliverer 通常能正确生成,但交付路由仍需手动完成。审查意见文件是主合同的 companion,不需要单独的 tracker/xlsx 条目。
## .doc 文件转换(非 .docx 格式)
邱律师有时发送 `.doc` 格式文件(Word 97-2003),workflow 只能处理 `.docx`。
### 转换步骤
```bash
# 1. 复制到 /tmp/contract-review/ 并转换
cp source.doc /tmp/contract-review/
libreoffice --headless --convert-to docx /tmp/contract-review/source.doc --outdir /tmp/contract-review/
# 输出: source.docx
# 2. 启动 workflow 时注明原始格式
uwf thread start review-contract -p "审查合同:source.doc(已转换为source.docx),顾问单位:XXX"
```
### 注意事项
- LibreOffice 转换后文件名自动为 `原名.docx`(去掉 `.doc` 后缀加 `.docx`)
- 转换后 .doc 和 .docx 都保留在 /tmp/contract-review/,workflow 会识别 .docx
- 交付物文件名为 `【修】原名.docx`(不带 .doc 后缀)
- 上传 Nextcloud 待审查目录时保留原始 .doc 格式(不转换)
- 2026-07-02 恭兴合同.doc / 肃言合同.doc 均使用此流程成功审查
### 常见错误
- `Error: source file could not be loaded`:文件名含特殊前缀(如 `doc_xxx_`)。确保复制到 /tmp/ 时用干净文件名
- `failed to launch javaldx`:正常警告,不影响转换
## 大文件预处理(图片切割+缝合)
超大docx文件(常见于含招标公告截图、中标通知书等附件的合同)需要在审查前切割,审查后缝合:
### 切割(classifier阶段,审查前)
```bash
python3 ~/hc-contract-editor/scripts/contract_preprocess.py preprocess <合同文件> /tmp/contract-review/
```
- `action=none`:正常文件(文字为主),直接审查
- `action=cut`:末尾有纯图片附件 → 输出`_stripped.docx`(去图片)+ `cutdata.json`(图片数据)
- `action=ocr`:全文是扫描件图片,需OCR → 标记后人工处理
⚠️ 切割只移除末尾纯图片附件,不碰合同正文和文字附件。
### 缝合(deliverer阶段,交付前)
```bash
# 检查有没有cutdata
ls /tmp/contract-review/*_cutdata.json
# 有 → 还原
python3 ~/hc-contract-editor/scripts/contract_preprocess.py restore <修订文件> <cutdata.json> <输出文件>
# 质检:zipfile检查media文件数 vs cutdata记录一致
```
### 教训(华新镇签约服务费合同,1.7MB→45KB)
- 文件82%是图片(5张,1.6MB),全在末尾附件
- 不切割直接审查:reviewer反复timeout(文件太大)
- 切割后审查+还原:回注后媒体文件逐字节一致
- 剥离脚本位置:`~/.hermes/scripts/strip_docx_media.py`
## 合同审查台账(合同审查清单.xlsx)
位置:Nextcloud `Doro合同审查任务/合同审查清单.xlsx`(根目录,非任务交付/子目录)
- 5列:序号、交付日期、顾问单位名称(全称)、合同名称、文件名
- 这是Doro可以随时打开看的正式工作记录
### 更新规则
1. 终审通过后、通知Doro之前 → 新增一行到xlsx
2. 顾问单位名称从classifier output的`our_party_name`字段获取,不自己解析合同文本
3. 上传Nextcloud覆盖旧版 → 清OnlyOffice缓存
4. xlsx记录永久保留,pass后删的只是合同文件本身
5. ⚠️ Doro收到通知时xlsx必须已经是最新的
6. Doro说pass/completed时,一次性更新所有当批合同到xlsx(不要一份一份更新上传)
### openpyxl样式复制注意事项
复制已有行的样式到新行时,**不能直接赋值border**:
```python
# ❌ 报错 TypeError: unhashable type: 'StyleProxy'
new_cell.border = ref_cell.border
# ✅ 正确:用copy()或重建Side对象
from copy import copy
new_cell.font = copy(ref_cell.font)
new_cell.alignment = copy(ref_cell.alignment)
new_cell.border = Border(
left=Side(style=ref_border.left.style, color=ref_border.left.color),
right=Side(style=ref_border.right.style, color=ref_border.right.color),
top=Side(style=ref_border.top.style, color=ref_border.top.color),
bottom=Side(style=ref_border.bottom.style, color=ref_border.bottom.color),
)
```
### 内部tracker
位置:`~/.hermes/data/contract-tracker.json`
- 记录每份合同的完整生命周期:queued→running→ready→passed→cleaned
- 用于runner脚本流程控制,不是给Doro看的
## 第三阶段:审查意见输出
### 输出方式一:批注+修订模式(推荐用于正式交付)
当律师要求"在文件里批注审核意见+修订条款"时,直接操作docx文件:
**批注(Comments)**:
- ⚠️ ContractEditor 库**没有** add_comment 方法。批注必须用独立的 zipfile+lxml 函数实现。
- ContractEditor.tracked_replace() 也**不接受** author 参数(author 固定为 'WB',在 __init__ 中设置)。
- 批注实现模式:先用 ContractEditor 做 tracked_replace 并 save,然后用独立函数 add_comments_to_docx() 在已保存的文件上追加批注。
- 每条批注需要三个位置协调:comments.xml(定义)+ document.xml(锚点 commentRangeStart/End + commentReference)+ rels/content_types(注册)
- comments.xml 根元素用 `etree.Element(qn('comments'), nsmap={'w': W, 'r': R_NS})`(不能用 .set('xmlns:w', ...),lxml 会报错)
- Content_Types 需添加 Override: `/word/comments.xml` → `application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml`
- document.xml.rels 需添加 Relationship: Type=`.../relationships/comments`, Target=`comments.xml`
- 参考实现见 `/tmp/review_all.py` 的 add_comments_to_docx() 函数(经实测可用)
- 技术细节参见 word-docx skill 的 "Adding Comments Programmatically" 章节
**修订痕迹(Tracked Changes)**:
- 可修改的条款直接用 w:del + w:ins 修订
- 仅做批注建议的条款只加批注不改正文
- 技术细节参见 word-docx skill 的 "Surgical Tracked-Change Edits" 章节
**交付要求**:
- 一份文件同时包含批注(解释原因/建议)和修订(具体修改),律师打开即可审阅
- 批注中给出修改理由和法律依据,修订中直接改条款文字
### 输出方式二:独立审查意见书(适用于分析报告)
当不直接修改合同、仅出具审查意见时:
- 按条款逐项列出问题、风险等级、修改建议
- 适合先发给委托人讨论,确认后再改合同
### 批量独立审查(刘婷律师等批量交办模式)
当律师一次交办多份合同审查(非workflow),流程如下:
**工具链**:ContractEditor(tracked_replace) + add_comments_to_docx(zipfile+lxml手写comments.xml)
**ContractEditor注意事项**:
- `tracked_replace(old_text, new_text)` — 不接受author参数,默认author='WB'
- 不支持 `add_comment()` 方法——必须用独立的zipfile+lxml函数操作comments.xml
- 先做tracked_replace → save → 再调add_comments函数(因为save会重写document.xml)
**add_comments_to_docx函数关键点**:
- comments.xml的根元素用 `etree.Element(qn('comments'), nsmap={'w': W, 'r': R_NS})`,不能用set('xmlns:w', ...)
- commentRangeStart插入位置用 `p.insert(0, crs)` 而非 `p.insert(list(p).index(runs[0]), crs)`——后者在tracked_replace修改过的段落中会报ValueError(runs[0]不在p的直接子元素中)
- Content_Types.xml和document.xml.rels都需要注册comments关系
- 批注author统一用"WB"
**交付方式**:
- 上传Nextcloud对应目录(如 `Doro合同审查任务/刘婷律师合同审查-YYYYMMDD/`)
- 通知Doro(企微私信或send_message)
- wecom_dm.py不支持发文件(无--file参数),发文件超时时改用Nextcloud+通知
**政府采购合同模板常见问题**(朱家角社区医院系列):
- 联系人和电话字段写反("电话:柳老师"/"联系人:021-xxx")
- 质量保证金、履约保证金金额未填("/")
- 调解机构空白("可以向___提请调解")
- 付款方式一次性100%对甲方不利,建议分期
- 仲裁条款需确认是否符合甲方意愿
### 独立审查(非workflow模式)
适用场景:非Doro的合同审查任务(如莎莎、Maggie、刘婷律师直接交办),不走uwf workflow。
**批量审查流程(刘婷律师模式)**:
刘婷律师经常一次发送多份合同要求批量审查。处理方式:
1. 收齐所有文件后确认审查立场和输出方式
2. .doc 文件先用 libreoffice --headless --convert-to docx 转换
3. 用 ContractEditor 做 tracked_replace(修订),然后用 add_comments_to_docx() 追加批注
4. 逐份发送修订版文件 + 简要审查要点说明
5. 不需要走 tracker/xlsx/Nextcloud 流程(非Doro体系)
**常见审查清单(中小型服务/施工/采购合同)**:
- 法律引用是否过时(合同法→民法典)
- 甲方名称是否完整一致(正文 vs 签约页)
- 联系人/电话等空白项是否需要补充
- 违约金比例是否对等/是否过高(千分之五/日=年化182.5%,远超司法保护上限)
- 质保期是否合理(消防≥2年,固定设施≥1年)
- 付款是否与验收挂钩
- 是否缺少争议解决/不可抗力/保密条款
- 知识产权等模板残留条款
- 合同份数是否合理
- 编号/条款标题是否完整
- 错别字(效益→效力等)
**流程**:
1. 确认审查立场(代表哪方?关注什么重点?)
2. 读取合同全文,掌握交易结构
3. 针对性法律研究(政策合规性、法条适用等)
4. 按委托人要求的重点逐条审查
5. 以批注+修订或独立意见书形式输出
6. 邮件/企微发送交付
**与workflow审查的区别**:
- 不走classifier→reviewer→editor→deliverer流程
- 不需要查review-rules.md和tracker
- 不上传Doro的Nextcloud目录
- 审查规则和交付方式由委托律师当场指定
### 双语合同完善 / 模板残留清理(参见 references/bilingual-contract-completion.md)
莎莎/Maggie/客户直接交办"在现有草稿上完善"的**中英对照合同**(法律服务协议、委托代理协议等),草稿常是从所内旧模板/旧案改来、残留前案痕迹时,参见该专题文件。核心铁律:
1. **模板残留是常态**——中文侧和英文侧可能各自残留*不同*旧案内容,且费率/金额/付款等商业条款中英文互相矛盾,必须逐条中英对照
2. **商业条款绝不替客户猜**——费率/金额/工时/付款分期/第三方代付有矛盾时,列清单让委托律师给准数,确认后再动手
3. **"以中文为准"→先定中文再对齐英文**(符合协议兜底条款,也符合用户预期)
4. **vision 报"截断/多空格"先回源核实**——justified 渲染图把跨页断词、字距、自动换行误报为截断,本类任务一次就误报4次;查源 docx `p.text` + `word/settings.xml` 是否含 autoHyphenation 即可证伪
5. **关键数字(账号/金额/信用代码)逐字符回源核对**,不信 vision 读数(曾把15位账号读成14位)
6. 含**段落级 run 合并替换**函数、多页 OnlyOffice 渲染+逐页 vision 验收管线、交付清稿 vs tracked-changes 两版本的处理
### 光伏/能源合同审查要点(参见 references/solar-lease-review.md)
屋顶光伏租赁合同是典型的投资方格式合同,审查时参见专题参考文件。
## 注意事项
### 法律意见边界(2026-07-01 总结,多次纠正)
**角色定位**:执行审查规则、呈现发现。不是法律顾问。
1. **不做法律价值判断**:不说"强烈建议采用版本X"。呈现各方案的法律风险和后果,由律师决定。
2. **不教学**:给客户的意见不用表格对比+教学式分析。律师风格=先列要点(递进排列),再给整体修改文本,不引法条、不用表格(参见 legal-advice-output-style skill)。
3. **区分法律依据与行业惯例**:法条引用必须验证原文逐段数;裁判倾向/司法实践不能说成法律结论;律所文章≠官方,不得作确定性结论。
4. **公益合同不加商事条款**:公益/捐赠/框架协议不适用对抗性违约金、严苛保证金等商事套路。按 contract_nature 分类审查。
5. **批注只写方案不写理由**:批注格式="建议修改为……",不加【新增】【修改】标签,不写法律理由。
6. **金额是商业条款绝对不改**。
7. **法律检索铁律**:信息来源仅限官方资料(法律/法规/政策/裁判文书原文)。引用须标注并说明未经裁判文书验证;给出结论必须列出信息来源链接。
### 邱律师批量文件接收分流(Intake Triage)
邱律师一次性发送多份合同时,**必须先交叉核对再决定是否启动workflow**。四类分流:今日已交付 / 正在审查 / 历史已审重发 / 全新未处理。详见 `references/intake-triage-crosscheck.md`。
- ⚠️ 重发≠重审:邱律师经常重新发送已审查过的文件,必须报告Doro确认是否需要重新审查
- ⚠️ auto_notify可能漏文件:不能假设自动化已处理所有新文件,手动核对xlsx是必要的
- xlsx读取需 `sudo` + venv Python(文件属www-data)
### `uwf thread exec --background` 的 notify_on_complete 陷阱(2026-07-02教训)
通过 `terminal(background=true, notify_on_complete=true)` 运行 `uwf thread exec <id> --count 20 --background` 时:
- **parent进程**立即退出(输出 "Step 1 xxx → running"),触发 terminal 的 notify_on_complete
- **实际工作**在独立的 `--_background-worker` 子进程中继续(可通过 `ps aux | grep <thread_id>` 看到)
- ⚠️ **不要**在收到通知后立即再次 exec —— 会报 "thread is already being executed by PID xxx"
**正确做法**:收到通知后先 `uwf thread show <id>` 检查状态:
- `Status: running` + 有对应进程 → 正在执行,等待
- `Status: idle` + 无进程 → 已完成当前步骤,可继续 exec
- `Status: end` → workflow已结束
**推荐方式**:不要用 terminal 的 background 模式包裹 `uwf thread exec --background`(双层后台)。改用:
```bash
# 直接在前台运行uwf的后台模式,让uwf自己管理后台
/home/maggie/.hermes/node/bin/uwf thread exec <id> --count 20 --background
# 然后用 ps + uwf thread show 轮询状态
```
### ⚠️ 收到新合同后:先检查queue-runner是否已启动thread(2026-07-03白鹤镇教训)
文件到达 `/tmp/contract-review/` 后,`contract-queue-runner.sh`(常驻后台进程)会**自动检测并启动workflow thread**。如果agent也手动 `uwf thread start`,就会产生两个thread竞争同一份合同。
**收到合同后的正确顺序**:
```bash
# 1. 确认文件已到 /tmp/contract-review/
ls /tmp/contract-review/*.docx
# 2. 检查queue-runner是否在跑(在跑=可能已自动启动thread)
ps aux | grep "[c]ontract-queue-runner"
# 3. 检查是否已有该合同的running thread
/home/maggie/.hermes/node/bin/uwf thread list 2>&1 | grep running
# 4. 有running thread → 只监控,不重复启动
# 没有running thread + queue-runner不在 → 才手动start
```
**双线程症状**:`ps aux | grep uwf-hermes` 显示两个进程审查同一份文件(prompt中文件名相同但thread_id不同)。发现后立即kill较晚的那个。
### 批量合同启动前必做:清理僵尸线程+杀queue-runner(2026-07-01/02教训)
多份合同串行处理前,**必须先清理 /tmp/contract-review 和僵尸线程**。详见 `references/workflow-systemic-issues-202607.md` §7-8。
- **第一步:杀 queue-runner**(否则它会自动启动重复线程!2026-07-02恭兴合同教训——queue-runner和手动start同时对恭兴合同启动了两个thread,两个uwf-hermes进程竞争同一个【修】文件)
```bash
kill $(ps aux | grep "[c]ontract-queue-runner" | awk '{print $2}') 2>/dev/null
```
- **第二步:检查+取消已有running threads**
```bash
uwf thread list | grep running # 列出所有running
# 逐个cancel非当前任务的
uwf thread cancel <thread_id>
```
- **第三步:杀死所有 uwf-hermes 进程**(cancel thread 不够,进程不感知status变化)
```bash
ps aux | grep "[u]wf-hermes" | grep -v grep | awk '{print $2}' | xargs kill 2>/dev/null
```
- **第四步:清空 /tmp/contract-review**(保留 rules/)
```bash
cd /tmp/contract-review && rm -f *.docx *.doc *.py *.pdf *.png *.xml *.bak 2>/dev/null
```
- 然后逐份:复制→start→exec→等end→下一份
- ⚠️ 多份合同绝对不能并行启动,共用/tmp/contract-review会互相覆盖
- ⚠️ 双线程竞争症状:`thread is already being executed by PID xxx`错误、/tmp下出现不属于当前合同的文件
### Reviewer/Editor 超时卡死恢复(2026-07-02 夏阳合同教训)
当 thread 卡在某个 role(通常 reviewer)超过 20 分钟且 Head 不变:
**诊断**:
```bash
# 1. 确认 Head 未变化(连续两次 5min 间隔检查)
uwf thread show <thread_id> # 记录 Head 值
sleep 300
uwf thread show <thread_id> # Head 相同 = 卡死
# 2. 找到对应的 uwf-hermes 进程
ps aux | grep "<thread_id>" | grep "uwf-hermes" | grep -v grep
```
**恢复**:
```bash
# 1. 杀死卡住的 uwf-hermes 进程
kill <PID>
# 2. 等 10 秒,thread 变为 suspended 状态
sleep 10
uwf thread show <thread_id>
# 输出: Status=suspended, Suspend="agent command failed (uwf-hermes)"
# 3. 重新执行(从当前 role 继续,不会丢失之前的修订进度)
uwf thread exec <thread_id> --count 15 --background
```
**注意**:
- thread exec 会从 suspended 的当前 role 重新开始该步骤(reviewer 重审/editor 重修)
- 之前 editor 产出的 【修】文件仍在 /tmp/contract-review/,不会丢失
- 如果同一 role 连续卡死 3 次以上(同一 Head 值不变),升级处理:
**Final review 循环退回问题(2026-07-03 白鹤镇教训)**:
Workflow 的 final_review 发现问题后会退回 editor→reviewer→deliverer→final_review 循环。邱律师明确要求**"只审查一次就行"**——当 final_review 退回时,如果第一轮修订已通过 reviewer 第2轮复核(通常复核确认修订无误),应直接杀掉进程交付,不要进入第三轮以后的循环。
**判断时机**:从 deliverer 进程的 prompt 中确认"复核通过"→ 到 final_review 退回 editor → 立即终止整个 thread 进程链,取已有的【修】文件手动交付。
**3次卡死后的升级路径(2026-07-02 家庭医生签约合同教训)**:
当 reviewer 在同一 Head 反复卡死 3 次(kill→resume→再卡死),说明 LLM 对该 prompt 无法正常返回。此时【修】文件通常已经存在且完整(editor 已产出),可直接手动交付:
```python
# 验证【修】文件质量(必做!)
from zipfile import ZipFile
import re
path = '/tmp/contract-review/【修】XXX.docx'
with ZipFile(path) as z:
doc_xml = z.read('word/document.xml')
ins_count = len(re.findall(b'w:ins ', doc_xml))
del_count = len(re.findall(b'w:del ', doc_xml))
wb_count = len(re.findall(b'w:author="WB"', doc_xml))
print(f'INS={ins_count}, DEL={del_count}, WB={wb_count}')
# 确认: ins_count > 0, wb_count == ins_count + del_count
```
验证通过后直接手动上传:
```bash
docker cp "/tmp/contract-review/【修】XXX.docx" "nextcloud-nextcloud-1:/var/www/html/data/doro/files/Doro合同审查任务/任务交付/"
docker exec nextcloud-nextcloud-1 chown www-data:www-data "/var/www/html/data/doro/files/Doro合同审查任务/任务交付/【修】XXX.docx"
docker exec nextcloud-nextcloud-1 php occ files:scan doro
```
⚠️ 手动交付跳过了 final_review 步骤,需要额外注意:
- 检查 INS run 字体(rFonts + sz)是否与原文一致
- 检查交叉引用是否需要更新
- 仍需更新 tracker + xlsx + 清 OO 缓存
### 合同组合梳理(Portfolio Audit)
对已有合同进行批量合规审查时(如客户要求梳理所有在履约合同),参见 `references/contract-portfolio-audit.md`。与逐份审查修订不同,产出物为批注PDF+Excel汇总表。
- 文件命名:客户名称+文件名+批注+日期(非标准版本号格式)
- Excel结构:总览sheet + 每个分组一个sheet(租赁按校区,其他按合同类型)
- 先做2-3份样本验证表头,确认后再批量推进
- ⚠️ 完成sheet后必须做文件数量核对(源文件数 - 已知重复 = 表格行数),并在第四项中添加【文件汇总说明】供客户对照原始文件与表格条目,详见 `references/contract-portfolio-audit.md` step 7
- 租赁合同按校区聚合时,租赁+物业+补充协议打包在一起看,不分家
- ⚠️ 风险点栏(K列)不仅要列常规风险,**必须包含合同变更/提前解除/减面积相关的责任义务分析**(客户最关心)——通知期、违约金、押金处理、已有退租先例。详见 `references/template-comparison-methodology.md` "Thematic risk additions to K column"
- ⚠️ openpyxl生成的Excel在OnlyOffice中**所有多行内容cell的行高都会截断**,必须用脚本逐行计算并设置显式高度,详见 reference 中的 pitfall 说明
### 标准模版对比(新增L列)
当客户有标准合同模版(常见于集团客户),需要对比签订的合同与模版的差异时,参见 `references/template-comparison-methodology.md`。产出物为表格新增一列"与标准模版差异"。
### 多方修订对账(Multi-Party Revision Reconciliation)
当合同经多方修订(如WB、客户方律师、对方等不同修订人),需要核对叠加修订效果是否符合协商一致条件、对比模板差异、评估影响、统一修订人署名时,参见 `references/multi-party-revision-reconciliation.md`。典型场景:MCN合同经双方律师各自修订后需验证商业条件落实情况。
关键技术点(2026-07-03实证):
- **嵌套修订处理**:B在A的`w:ins`内部做`w:del`→先接受嵌套删除→清除空壳→统一作者
- **恢复已删内容**:要把WB之前的del恢复回来时,不能简单删除del元素(原文已消失),需要替换为ins
- **追加模板修改**:在统一后的文件上继续做del+ins tracked changes,找到目标run→remove→insert(del_elem, ins_elem)
### 被问合同内容时必须先查文件(2026-07-09 Maggie纠正)
用户问"这个条款写了什么""保密信息包含什么""这条有没有问题"等**针对具体合同内容的问题**时,**立即找到文件并读取**,不得从一般法律知识或推理回答。
❌ 错误:用户问"保密信息包含什么" → 从一般施工合同常识回答"通常包含..."
✅ 正确:用户问"保密信息包含什么" → 找到文件 → 读取保密条款原文 → 引用原文回答
Maggie原话:"这是修订的内容,我让你看让你查,你做了吗"——被问即查,不凭推测回答。这与memory中"Maggie核查口令"一致:被问即回工具核实。
### 信息检索限制
- 企查查、天眼查、爱企查、国家企信系统等中国工商数据源对境外IP有访问限制
- 遇到此限制时,请Maggie协助查询,或通过国内代理访问
- 上市公司信息可通过巨潮资讯网(cninfo.com.cn)、新浪财经等渠道获取
### xlsx 读取的正确方法(权限问题)
xlsx文件属 www-data,maggie用户无法直接读取。正确流程:
```bash
# 方案1:复制到/tmp后读取
sudo cp "/home/maggie/nextcloud/data/data/doro/files/Doro合同审查任务/合同审查清单.xlsx" /tmp/xlsx_check.xlsx
sudo chmod 644 /tmp/xlsx_check.xlsx
/home/maggie/.hermes/hermes-agent/venv/bin/python3 -c "import openpyxl; ..."
```
注意:`python3` 的 openpyxl 在 `/home/maggie/.hermes/hermes-agent/venv/bin/python3`,系统 python3 和 sudo python3 都没有 openpyxl。
### 工作文档
- 每次合同审查的工作流程文档存放在:~/.hermes/shared/合同审查交付件/
- 流程文档随审查进展同步更新