---
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/合同审查交付件/
- 流程文档随审查进展同步更新
